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

时间:2015-02-16 01:05:13

标签: javascript svg d3.js

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

我的布局功能如下所示:

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;
  });

}

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

(因为我不允许发布图片,这里有链接:)

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

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

单击元素后,子元素位于相应的目标位置,但旧元素不会退出。 我试图接近coltree的例子,因此我也在每次点击后完全重新计算整个树:

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

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

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

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)
    
  3. 但是,元素仍保留在图表中 - 没有人退出。

    我是否需要在布局功能中添加一些内容,d3知道如何使用现有元素?还是别的错了?任何帮助都非常感谢。


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

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

1 个答案:

答案 0 :(得分:0)

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

这是一个更新的小提琴: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(...)g.node_coltree的节点添加了一个类,但是您使用的.node_coltree选择了不匹配的类,因此您的代码只是不断向svg添加越来越多的g元素。您的enter选项包含g数组中每个项目的新nodes元素。这意味着您的updateexit选项始终为空,导致无法删除任何内容。

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