2016-07-11 3 views
3

Я пытаюсь подражать этому collapsible tree, используя самую новую версию d3.js, но я столкнулся с некоторыми проблемами.D3.js v4.0.0-alpha.35 Переходы не работают

nodeEnter часть кода выполняется просто отлично, но по какой-либо причине nodeUpdate, иначе переходная часть кода не будет выполнена. Я смотрю в консоли, чтобы убедиться, что это не просто проблема видимости, я не получаю никаких ошибок, ничего ... Координаты остаются такими же, как они были, когда они были инициированы частью кода nodeEnter. Мое единственное предположение, что что-то изменилось с новой версией d3.js и я что-то не хватает ...

var t = d3.transition() 
 
.duration(750) 
 
.ease(d3.easeLinear); 
 

 
var tree = d3.tree() 
 
    .size([height, width]); 
 

 
function updateDisplay(source){ 
 
    
 
    var treeData = tree(root).descendants(), 
 
     linkData = treeData.slice(1); 
 
    
 
    treeData.forEach(function(d) { 
 
    
 
    /*Normalize for fixed-depth between levels, so that y value 
 
    ** stays the same through transition as opposed to being 
 
    ** an even division of the svg width. */ 
 
    d.y = d.depth *180; 
 
    
 
    }); 
 
    
 
          
 
    var node = svg.selectAll("g.node") 
 
       .data(treeData); 
 

 
    var nodeEnter = node.enter() 
 
         .append("g") 
 
         .attr("class", function(d) {return "node" + (d.children ? " node--internal" : " node--leaf");}) 
 
         .attr("transform", function(d) {return "translate(" + source.y0 + "," + source.x0 + ")";}); 
 
    
 
    console.log(nodeEnter); 
 
    
 
    nodeEnter.append("rect") 
 
      .attr("x", 3) 
 
      .attr("y", -10) 
 
      .attr("rx", 1e-6)//goes to 8 after transition 
 
      .attr("ry", 1e-6)//goes to 8 after transition 
 
      .attr("width", 1e-6) 
 
      .attr("height", 1e-6) 
 
      .attr("transform", function(d) {return d.children ? "scale(-1,1) translate(-20,0)" : "";}) 
 
      .attr("style", "fill:#EEEEEE;filter:url(#dropshadow)"); 
 

 
    nodeEnter.append("text") 
 
      .attr("dy", 3) 
 
      .attr("x", function(d) {return d.children ? -8 : 30;}) 
 
      .style("text-anchor", function(d) {return d.children ? "end" : "start";}) 
 
      .text(function(d) {return d.id;}) 
 
      .each(function(d) {d.NameWidth = this.getBBox().width;}) 
 
      .style("fill-opacity", 1e-6); 
 
    
 

 
    var avatar = nodeEnter.append("g").attr("style", "filter:url(#dropshadow)"); 
 

 
    avatar.append("clipPath") 
 
      .attr("id", "avatarClip") 
 
      .append("circle") 
 
      .attr("cx", 1e-6)//12.5 
 
      .attr("cy", 1e-6)//12.5 
 
      .attr("r", 1e-6);//12.5 
 

 
    avatar.append("circle") 
 
      .attr("cx", 1e-6)//12.5 
 
      .attr("cy", 1e-6)//12.5 
 
      .attr("r", 1e-6)//12.5 
 
      .attr("style", "fill:white") 
 
      .attr("transform", "translate(0,-12)"); 
 

 
    avatar.append("image") 
 
      .attr("xlink:href", function(d) {return (d.data.img ? d.data.img : "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/ic_person_black_48px.svg");}) 
 
      .attr("clip-path", "url(#avatarClip)") 
 
      .attr("class", function(d) {return (d.children ? "avatar--manager" : "");}) 
 
      .attr("width", 25) 
 
      .attr("height", 25) 
 
      .attr("transform", "translate(0,-12)"); 
 
    
 
    avatar.on("click", function(d) {toggle(d);}); 
 
    
 
    //TRANSITION OF NODES TO NEW POSITIONS 
 
    var nodeUpdate = node.transition(t) 
 
         .attr("class", function(d) {return "node" + (d.children ? " node--internal" : " node--leaf");}) 
 
         .attr("transform", function(d) {return "translate(" + d.y + "," + d.x + ")";}); 
 
    
 
    nodeUpdate.select("text") 
 
    .attr("x", function(d) {return d.children ? -8 : 30;}) 
 
    .style("text-anchor", function(d) {return d.children ? "end" : "start";}) 
 
    .text(function(d) {return d.id;}) 
 
    .style("fill-opacity", 1); 
 

 
    nodeUpdate.select("rect") 
 
       .attr("transform", function(d) {return d.children ? "scale(-1,1) translate(-20,0)" : "";}) 
 
       .attr("height", 20) 
 
       .attr("width", function(d) {return (d.NameWidth + 35);}); 
 
    
 
    nodeUpdate.select("clipPath") 
 
       .attr("cx", 12.5) 
 
       .attr("cy", 12.5) 
 
       .attr("r", 12.5); 
 
    
 
    nodeUpdate.select("circle") 
 
      .attr("cx", 12.5) 
 
      .attr("cy", 12.5) 
 
      .attr("r", 12.5); 
 

 
    nodeUpdate.select("image") 
 
    .attr("xlink:href", function(d) {return (d.data.img ? d.data.img : "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-342/ic_person_black_48px.svg");}) 
 
    .attr("clip-path", "url(#avatarClip)") 
 
    .attr("class", function(d) {return (d.children ? "avatar--manager" : "");}); 
 
    
 
    //TRANSITIONING EXITING NODES 
 
    var nodeExit = node.exit() 
 
        .transition(t) 
 
        .attr("transform", function(d) {return "translate(" + source.y + "," + source.x + ")";}) 
 
        .remove(); 
 
    
 
    
 
    
 
    /*var link = svg.selectAll(".link") 
 
       .data(linkData);*/ 
 
    
 

 
    // Stash the old positions for transition. 
 
    root.each(function(d) { 
 
    d.x0 = d.x; 
 
    d.y0 = d.y; 
 
    }); 
 
    
 
}

PS: Мой код не является точной копией ссылки выше, я поставил свое собственное вращение, когда дело дошло до дизайна ...

ответ

10

Произошло концептуальное изменение вариантов ввода и обновления с v3 по v4. Если в v3 выбор ввода был автоматически объединен с выбором обновления, вы должны явно позвонить selection.merge() из v4 вверх, чтобы получить тот же результат.

Документация selection.enter() У3 говорит нам:

ВВЕСТИ выбор сливается в выборе обновления, когда вы добавляете или вставки.

В документации той же метода v4, с другой стороны, гласит:

ввод выбор, как правило, используется только транзиторен для добавления элементов, и часто merged с выбором обновлений после добавления , так что модификации могут применяться как к элементам ввода, так и к обновлению.

Посмотрите на этом упрощенном примере с помощью v3, который должен прийти без неожиданностей:

var update = d3.select("svg").selectAll("circle") 
 
    .data([1]); 
 
    
 
var enter = update.enter() 
 
    .append("circle") 
 
    .attr("cx", "50") 
 
    .attr("cy", "50") 
 
    .attr("r", "20") 
 
    .attr("fill", "red"); 
 
    
 
update 
 
    .transition().duration(2000) 
 
    .attr("fill", "blue"); 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<svg></svg>

Проделав то же самое с v4 требует небольшой модификации, хотя:

var update = d3.select("svg").selectAll("circle") 
 
    .data([1]); 
 
    
 
var enter = update.enter() 
 
    .append("circle") 
 
    .attr("cx", "50") 
 
    .attr("cy", "50") 
 
    .attr("r", "20") 
 
    .attr("fill", "red"); 
 
    
 
update 
 
    .merge(enter) // This merges both the enter and the update selection 
 
    .transition().duration(2000) 
 
    .attr("fill", "blue");
<script src="https://d3js.org/d3.v4.min.js"></script> 
 

 
<svg></svg>

Замечание строки .merge() показывает описанный вами эффект, поскольку выбор обновления будет пустым, даже если вы ввели новые элементы, используя ранее введенный выбор.

+0

Это огромная помощь. Я добавил некоторые вещи на свой пост. Если вы не против взглянуть на него. @altocumulus – Tekill

+1

@Yourinium Если это решит вашу первую проблему, пожалуйста, верните свои изменения и отправьте еще один вопрос. Это все об изменениях в параметрах ввода/обновления и потому, что сейчас это очень плохо документировано, у меня появилось ощущение, что мы увидим массу вопросов об этом. Я хотел бы сохранить это как можно более сжатым для будущей справки. – altocumulus

+0

Очень хорошая точка здесь - новое сообщение http: // stackoverflow.com/questions/38310768/d3-js-v4-wacky-link-transition-in-collapsible-tree-example @altocumulus – Tekill