d3.js 自定义布局 exit() 不工作

d3.js custom layout exit() not working

我想构建一个 Windows 资源管理器,如分层可视化。由于我想手动计算 x 和 y 坐标,因此我根据此处描述的第一个示例创建了自定义布局:

我的布局函数如下所示:

function myTreeLayout(data) {
   var nodes = [];   // or reuse data directly depending on layout
   //load all nodes and their subnodes:
   var coreelement=data;
   coreelement.x=0;
   coreelement.y=0;
   positions(coreelement,0);
   //nodes.push(coreelement); //core element
   
   function child_recursion(element) {
       nodes.push(element);
       if (element.children!=null){
       element.children.forEach(function(child) {
           child_recursion(child);});
   };
   }
   child_recursion(coreelement);
   return nodes;
}
    
      function positions(d,pos_y) { //pos_y is the target position (y) of the element
      var sum_y;
      sum_y=rowheight; //the sum of all vertical space used by that element
      if (d.parent!=null) 
          {d.x=d.parent.x+10;}
      else
          { d.x=0;}
      d.y=pos_y;
    if (d.children) {
          d.children.forEach(function(child) {
              child.parent=d;
              sum_y+=positions(child,pos_y+sum_y);
          });
    }
    return sum_y;
  }

坐标计算正常。然后我使用以下代码绑定数据:

d3.json("data/kdsf-neu.json", function(error, data) {

  root = data;
  root.x0 = 0;
  root.y0 = 0;



  function collapse(d) {
    if (d.children) {
      d._children = d.children;
      d._children.forEach(collapse);
      d.children = null;
    }
  }

  root.children.forEach(collapse);
  update(root);
});


function update(source) {

  // Compute the new tree layout.
  var nodes = myTreeLayout(root);
  /*,links = tree.links(nodes);*/

  // Update the nodes…
  var node = vis.selectAll("g.node_coltree")
    .data(nodes, function(d) {
      return d.Nodeid;
    });

  // Enter any new nodes at the parent's previous position.
  var nodeEnter = node.enter().append("g").classed("g.node_coltree", true)
    .attr("x", function(d) {
      return d.x;
    })
    .attr("y", function(d) {
      return d.y;
    })
    .attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    });

  nodeEnter.append("svg:rect")
    .attr("x", function(d) {
      return 0;
    })
    .attr("y", function(d) {
      return 0;
    })
    .attr("width", 10)
    .attr("height", rowheight - 2)
    .attr("class", function(d) {

      var codearray = jQuery.makeArray(d.tags);

      if ($.inArray(tags.Extended, codearray) >= 0) {
        return 'erweiterungsteil_Fill';
      } else if ($.inArray(tags.NotIncluded, codearray) >= 0) {
        return 'nichtAufgenommen_Fill';
      } else if ($.inArray(tags.Optional, codearray) >= 0) {
        return 'optional_Fill';
      } else if ($.inArray(tags.obligatorischWennVorhanden, codearray) >= 0) {
        return 'obligatorisch_Fill';
      } else if ($.inArray(tags.teilweiserForschungsbezug, codearray) >= 0) {
        return 'pubSchale2_Fill';
      } else if ($.inArray(tags.PublikationenSchale2, codearray) >= 0) {
        return 'pubSchale2_Fill';
      } else if ($.inArray(tags.Included, codearray) >= 0) {
        return 'aufgenommen_Fill';
      } else {
        return "#FEFEFE";
      }
    })
    .on("click", click)
    .on("mouseover", function(d) {
      updatedetails(d);
    });

  nodeEnter.append("text")
    .attr("x", function(d) {
      return 12;
    })
    .attr("y", function(d) {
      return 7;
    })

  .text(function(d) {
      return d.name;
    })
    .attr("dy", "0.35em")
    .on("mouseover", function(d) {
      updatedetails(d);
    });

  // Transition nodes to their new position.
  var nodeUpdate = node.transition()
    .duration(duration)
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
      
    });

  // Transition exiting nodes to the parent's new position.
  var nodeExit = node.exit().transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + source.x + "," + source.y + ")";
    })
    .remove();

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

}

当我启动脚本时,元素位于正确的位置:

(因为我不允许post图片,这里放一个link:)

但是,当我点击一个元素时,退出功能似乎不起作用:

https://www.dropbox.com/s/3phyu3tx9m13ydt/2.PNG?dl=0

点击某个元素后,子元素位于合适的目标位置,但旧元素不退出。 我尽量接近 coltree 的示例,因此每次单击后我也会完全重新计算整棵树:

function update(source) {
// Compute the new tree layout.
var nodes = myTreeLayout(root);

我已经检查了节点元素,点击后它只包含所需的元素。因此,我怀疑退出功能和自定义布局存在一些问题。

相关问题: 我的问题可能与这个问题有关:

D3.js exit() not seeming to get updated information

因此,我按照那里的步骤操作:

  1. 我在调用数据时使用自定义(外部计算的单一)索引:

    .data(nodes , function(d) { return d.Nodeid; });
    
  2. 我在附加节点时添加了分类函数:

    var nodeEnter = node.enter().append("g").classed("g.node_coltree",true)
    

仍然,元素留在图中 - none 正在退出。

我是否需要向布局函数添加一些东西,让 d3 知道如何处理现有元素?还是有其他问题?非常感谢任何帮助。


编辑:这是 jsfiddle: http://jsfiddle.net/MathiasRiechert/nhgejcy0/8/

单击根节点时,所有子元素都应该消失。同样,当打开一个节点时,元素应该是移动的。两者似乎都没有发生。

你的代码中有一个相当简单的错误。

这是更新后的 fiddle:http://jsfiddle.net/nhgejcy0/11/

唯一的区别是:

    var nodeEnter = node.enter().append("g").classed("node_coltree", true)
        .attr("x", function (d) {
            return d.x;
    })
        .attr("y", function (d) {
            return d.y;
    })
       .attr("transform", function (d) {
            return "translate(" + d.x + "," + d.y + ")";
    });

具体来说,第一行更改为:

    var nodeEnter = node.enter().append("g").classed("g.node_coltree", true)

至:

    var nodeEnter = node.enter().append("g").classed("node_coltree", true)

在您的版本中,您使用 classed(...) 将 class 添加到 g.node_coltree 的节点,但您选择使用 .node_coltree,这并没有匹配,因此您的代码只是不断向 svg 添加越来越多的 g 元素。您的 enter 选择包含 nodes 数组中每个项目的新 g 元素。这意味着您的 updateexit 选择始终为空,因此不会删除任何内容。

我通过检查 DOM 发现了这一点,发现每次折叠或展开节点时都会附加一个新的 g 元素列表。如果选择工作正常,就不会发生这种情况。然后只需跟踪选择是否错误,或者您是否在创建节点时附加了不同的属性。在这种情况下,看起来属性创建不正确。