Javascript d3合并嵌套的选择

Javascript d3合并嵌套的选择,javascript,d3.js,Javascript,D3.js,给定以下调用更新函数的代码,该函数创建4个节点,其中一个圆和一个嵌套在g元素中的文本元素,等待500毫秒,然后使用更新的数据再次调用该函数: var data1 = [ { x: 10, y: 10, text: "A" }, { x: 30, y: 30, text: "B" }, { x: 50, y: 50, text: "C" }, { x: 70, y: 70, text: "D" } ]; var data2 = [ { x: 30, y: 10, text:

给定以下调用更新函数的代码,该函数创建4个节点,其中一个圆和一个嵌套在g元素中的文本元素,等待500毫秒,然后使用更新的数据再次调用该函数:

var data1 = [
  { x: 10, y: 10, text: "A" },
  { x: 30, y: 30, text: "B" },
  { x: 50, y: 50, text: "C" },
  { x: 70, y: 70, text: "D" }
];

var data2 = [
  { x: 30, y: 10, text: "X" },
  { x: 50, y: 30, text: "Y" },
  { x: 70, y: 50, text: "Z" },
  { x: 90, y: 70, text: "W" }
];


var svg = d3.select("body").append("svg");

update(data1);
setTimeout(function() { update(data2); }, 500);

function update(data) {

  var nodes = svg.selectAll(".node")
      .data(data);

  var nodesUpdate = nodes
      .attr("class", "node update")

  var nodesEnter = nodes.enter();

  var node = nodesEnter.append("g")
      .attr("class", "node enter")

  node
      .attr("transform", function(d) { return  "translate("+d.x+","+d.y+")"; });

  node.append("circle")
      .attr("r", 10)
      .style("opacity", 0.2);

  node.append("text")
      .text(function(d) { return  d.text; });
}
按原样使用代码,第二次调用无效,因为所有内容都是在enter选择中设置的。我正在尝试使用新数据调用update,并更改enter和update选项的属性,而无需重复代码。通过进行以下更改,我可以为顶级元素(即使用merge的g元素)实现这一点:

node
  .merge(nodesUpdate)
    .attr("transform", function(d) { return  "translate("+d.x+","+d.y+")"; });
现在,节点在500毫秒后更新其位置。但是,我还没有弄清楚如何更新文本元素。如果我执行nodes.selectAlltext,我将以嵌套数据结束,这不起作用

我仔细阅读了以下文档,试图解决这个问题:


在不重构大量代码的情况下,最简单的解决方案是在数据函数中使用一个键,然后选择退出:

var nodes = svg.selectAll(".node")
    .data(data, d=> d.text);

nodes.exit().remove();
以下是演示:

变量数据1=[{ x:10, y:10, 正文:A }, { x:30, y:30, 正文:B }, { x:50, y:50, 正文:C }, { x:70, y:70, 正文:D }]; 变量数据2=[{ x:30, y:10, 文本:X }, { x:50, y:30, 文本:Y }, { x:70, y:50, 文本:Z }, { x:90, y:70, 正文:W }]; var svg=d3.selectbody.appendsvg; 更新数据TA1; setTimeoutfunction{ 更新数据TA2; }, 500; 函数更新数据{ var nodes=svg.selectAll.node .datadata,d=>d.text; nodes.exit.remove; var nodesUpdate=节点 .attr类,节点更新 var nodesEnter=nodes.enter; var node=nodesEnter.appendg .attrclass,节点输入 节点 .mergenodesUpdate .attr转换,函数{ 返回translate+d.x+,+d.y+; }; node.appendcircle attrr先生,10岁 .不透明度,0.2; node.appendtext .textfunctiond{ 返回d.text; }; }
在不重构大量代码的情况下,最简单的解决方案是在数据函数中使用一个键,然后选择退出:

var nodes = svg.selectAll(".node")
    .data(data, d=> d.text);

nodes.exit().remove();
以下是演示:

变量数据1=[{ x:10, y:10, 正文:A }, { x:30, y:30, 正文:B }, { x:50, y:50, 正文:C }, { x:70, y:70, 正文:D }]; 变量数据2=[{ x:30, y:10, 文本:X }, { x:50, y:30, 文本:Y }, { x:70, y:50, 文本:Z }, { x:90, y:70, 正文:W }]; var svg=d3.selectbody.appendsvg; 更新数据TA1; setTimeoutfunction{ 更新数据TA2; }, 500; 函数更新数据{ var nodes=svg.selectAll.node .datadata,d=>d.text; nodes.exit.remove; var nodesUpdate=节点 .attr类,节点更新 var nodesEnter=nodes.enter; var node=nodesEnter.appendg .attrclass,节点输入 节点 .mergenodesUpdate .attr转换,函数{ 返回translate+d.x+,+d.y+; }; node.appendcircle attrr先生,10岁 .不透明度,0.2; node.appendtext .textfunctiond{ 返回d.text; }; } 处理子选择时,它应仅为nodes.select

下面是一个带有注释和更清晰变量名的快速重构:

变量数据1=[{ x:10, y:10, 正文:A }, { x:30, y:30, 正文:B }, { x:50, y:50, 正文:C }, { x:70, y:70, 正文:D }]; 变量数据2=[{ x:30, y:10, 文本:X }, { x:50, y:30, 文本:Y }, { x:70, y:50, 文本:Z }, { x:90, y:70, 正文:W }]; var svg=d3.selectbody.appendsvg; 更新数据TA1; setTimeoutfunction{ 更新数据TA2; }, 500; 函数更新数据{ var nodesUpdate=svg.selectAll.node .datadata;//更新所选内容 var nodesEnter=nodesUpdate.enter .附录 .attrclass,node;//输入Gs nodesEnter.appendtext;//追加文本 nodesEnter.appendcircle//追加圆 attrr先生,10岁 .不透明度,0.2; var nodesEnterUpdate=nodesEnter.mergenodesUpdate;//更新+输入 nodesEnterUpdate//移动位置 .attr转换,函数{ 返回translate+d.x+,+d.y+; }; nodesEnterUpdate.selecttext//SUB-选择文本 .textfunctiond{ 返回d.text; }; } 处理子选择时,它应仅为nodes.select

下面是一个带有注释和更清晰变量名的快速重构:

变量数据1=[{ x:10, y:10, 正文:A }, { x:30, y:30, 正文:B }, { x:50, y:50, 正文:C }, { x:70, y:70, 正文:D }]; 变量数据2=[{ x:30, y:10, 文本:X }, { x:50, y:30, 文本:Y }, { x:70, y:50, 文本:Z }, { x:90, y:70, 正文:W }]; var svg=d3.selectbody.appendsvg; 更新数据TA1; SetTimeOutpu 运动{ 更新数据TA2; }, 500; 函数更新数据{ var nodesUpdate=svg.selectAll.node .datadata;//更新所选内容 var nodesEnter=nodesUpdate.enter .附录 .attrclass,node;//输入Gs nodesEnter.appendtext;//追加文本 nodesEnter.appendcircle//追加圆 attrr先生,10岁 .不透明度,0.2; var nodesEnterUpdate=nodesEnter.mergenodesUpdate;//更新+输入 nodesEnterUpdate//移动位置 .attr转换,函数{ 返回translate+d.x+,+d.y+; }; nodesEnterUpdate.selecttext//SUB-选择文本 .textfunctiond{ 返回d.text; }; }
谢谢你的回答。我被这个代码弄糊涂了。我看不出它是怎么工作的。由于使用键函数仅访问每个基准的文本,因此x和y如何可用?还有,为什么必须退出?我的答案并不完全符合您的要求:通过使用键功能,每次更新数据时它都会创建一个新的输入选择,因此需要退出选择。我现在很忙,但我很快会发布一个依赖于更新选择的解决方案。anderspitman没关系,我正要使用更新选择编写一个解决方案,但我看到@Mark,看看他的答案。简单地说,在我的回答中,我为新数据创建了一个新的enter选择,并删除了旧的选择。在他的回答中,只有一个输入选择,元素保留在图表上,它们的数据在更新选择中更改。他的答案正是你想要的。谢谢你的回答。我被这个代码弄糊涂了。我看不出它是怎么工作的。由于使用键函数仅访问每个基准的文本,因此x和y如何可用?还有,为什么必须退出?我的答案并不完全符合您的要求:通过使用键功能,每次更新数据时它都会创建一个新的输入选择,因此需要退出选择。我现在很忙,但我很快会发布一个依赖于更新选择的解决方案。anderspitman没关系,我正要使用更新选择编写一个解决方案,但我看到@Mark,看看他的答案。简单地说,在我的回答中,我为新数据创建了一个新的enter选择,并删除了旧的选择。在他的回答中,只有一个输入选择,元素保留在图表上,它们的数据在更新选择中更改。他的答案是你想要的。有一件事我仍然感到困惑:我认为选择。选择只选择第一个匹配的元素。它是如何抓取这里所有的文本元素的?@anderspitman,它抓取子选择中的第一个。它仍在迭代父选择。nodesEnterUpdate是一个g的集合,foreach g给我第一个文本并更新它。我想这是我一直缺少的理解的关键部分。谢谢有一件事我仍然感到困惑:我认为selection.select只选择第一个匹配元素。它是如何抓取这里所有的文本元素的?@anderspitman,它抓取子选择中的第一个。它仍在迭代父选择。nodesEnterUpdate是一个g的集合,foreach g给我第一个文本并更新它。我想这是我一直缺少的理解的关键部分。谢谢