Javascript d3合并嵌套的选择
给定以下调用更新函数的代码,该函数创建4个节点,其中一个圆和一个嵌套在g元素中的文本元素,等待500毫秒,然后使用更新的数据再次调用该函数: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:
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给我第一个文本并更新它。我想这是我一直缺少的理解的关键部分。谢谢