D3.js 如何在基础数据更改时更新D3 force布局的元素

D3.js 如何在基础数据更改时更新D3 force布局的元素,d3.js,force-layout,D3.js,Force Layout,我正在使用一个force布局示例()在我的网站上显示一个网络 我允许用户在任何给定时间选择要查看的链接类型。我注意到,当我选择查看链接类型A,然后添加链接类型B,然后删除链接类型A时,类型B的剩余链接将以A颜色显示 这是用于将链接添加到svg图的代码。我正在通过添加和删除链接来更改数组this.links。如您所见,我设置了class属性,但它没有更新-它仍然是链接A的类型 var path = svg.append("svg:g") .selectAll("path") .da

我正在使用一个force布局示例()在我的网站上显示一个网络

我允许用户在任何给定时间选择要查看的链接类型。我注意到,当我选择查看链接类型A,然后添加链接类型B,然后删除链接类型A时,类型B的剩余链接将以A颜色显示

这是用于将链接添加到svg图的代码。我正在通过添加和删除链接来更改数组
this.links
。如您所见,我设置了class属性,但它没有更新-它仍然是链接A的类型

var path = svg.append("svg:g")
    .selectAll("path")
    .data(this.links)
   .enter()
    .append("svg:path")
    .attr("class", function(d) { return "link " + d.type; })
    .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
我目前通过更新tick函数中的class属性来解决这个问题,但这会导致很多不必要的工作

我读到enter操作返回了exist元素和新元素的合并选择,因此attr操作应该更新exist元素并设置新元素

我遗漏了什么?

在上有一个示例,显示如何从强制导向布局中添加和删除节点。必须分别处理链接和节点,然后重新启动force布局

function restart() {
  var link = vis.selectAll("line.link")
      .data(links, function(d) { return d.source.id + "-" + d.target.id; });

  link.enter().insert("svg:line", "g.node")
      .attr("class", "link");

  link.exit().remove();

  var node = vis.selectAll("g.node")
      .data(nodes, function(d) { return d.id;});

  var nodeEnter = node.enter().append("svg:g")
      .attr("class", "node")
      .call(force.drag);

  nodeEnter.append("svg:image")
      .attr("class", "circle")
      .attr("xlink:href", "https://d3nwyuy0nl342s.cloudfront.net/images/icons/public.png")
      .attr("x", "-8px")
      .attr("y", "-8px")
      .attr("width", "16px")
      .attr("height", "16px");

  nodeEnter.append("svg:text")
      .attr("class", "nodetext")
      .attr("dx", 12)
      .attr("dy", ".35em")
      .text(function(d) { return d.id });

  node.exit().remove();

  force.start();
}
我已经找到了答案


答案是我需要对selectAll.data的结果调用attr操作符,而不是对append操作符的结果调用attr操作符。

这还不够。我正在添加和删除链接,问题是它没有顺序。当我选择查看类型A的链接时,链接数组是[A1,A2,A3],然后我选择查看类型B的链接,数组是[A1,A2,A3,B1,B2],然后我选择不查看类型A的链接,数组是[B1,B2]。D3然后选择保留2个元素并删除3个元素,但我必须更新这两个元素,因为它们当前绑定到A1和A2,我需要它们绑定到B1和B2。我通过保存vis.selectAll(“g.Node”).数据(节点)并进行更新来做到这一点。如果您创建一个JSFIDLE来显示您当前正在做什么以及问题是什么,那么我们可能能够帮助找到更好的解决方案。我知道这是一篇老文章,但我相信我遇到了与您相同的问题,我仍然不明白这个解决方案。你能解释一下它是如何工作的吗?它是如何解决你原来的问题的?谢谢。该解决方案之所以有效,是因为cx和cy的attr更新不在enter()上下文中,所以每次都会发生。在原始代码中,attr函数在enter()上下文中调用,因此根据对象标识只创建一次。它为我做的是学习关键函数作为data()的第二个参数:
var circle = svg.selectAll("circle")
    .data(data);

circle.enter().append("circle")
    .attr("r", 2.5);

circle
    .attr("cx", function(d) { return d.x; })
    .attr("cy", function(d) { return d.y; });

circle.exit().remove();