我无法弄清楚如何最好地将对父节点(例如SVG g
元素)发生的数据的更改传递给它的子节点(例如SVG {{1元素)。
这是一个最低限度的工作示例。该示例假设您有一个名为circle
的对象,该对象引用包含SVG元素的d3选择。
svg
任何人都可以帮我找到一个简洁的方法来将新名称放入一个组的所有子元素中吗?在我的现实示例中,每个data = [{"id":"A","name":"jim"},{"id":"B","name":"dave"},{"id":"C","name":"pete"}];
g = svg.selectAll("g").data(data, function(d) { return d.id; }).enter().append("g");
g.append("circle")
.attr("r", 3)
.attr("cx", 100)
.attr("cy", function(d,i) {return 100 + (i * 30);})
// The data gets passed down to the circles (I think):
console.log("circle data:");
d3.selectAll("g circle").each(function(d) { console.log(d.name); });
// Now change the data, and update the groups' data accordingly
data = [{"id":"A","name":"carol"},{"id":"B","name":"diane"},{"id":"C","name":"susan"}];
svg.selectAll("g").data(data, function(d) { return d.id;});
// These are the results of the change:
console.log("after change, the group has:");
d3.selectAll("g").each(function(d) { console.log(d.name); });
console.log("but the circles still have:");
d3.selectAll("g circle").each(function(d) { console.log(d.name); });
包含许多g
s。
答案 0 :(得分:31)
有两种方法可以将数据从父母传播到儿童:
selection.select会隐式执行此操作。 (selection.append
和selection.insert
的实现实际上基于selection.select
内部)
svg.selectAll("g").select("circle")
您可以使用函数显式重做数据连接以接收父数据并将其返回到子数组中。
svg.selectAll("g").selectAll("circle")
.data(function(d) { return [d]; });
这些相同的东西。第一个选项依赖于select中的一些特殊行为,因此它起初可能有点令人惊讶,但它的好处在于它使节点更新的模式与通过insert / append创建节点的模式对称。如果您需要在传播数据时对数据应用任何更改,则第二个选项很有用。
以下是您未链接到的另一篇文章,可能也很有用:Thinking with Joins
答案 1 :(得分:2)
不确定你是否弄明白,但这绝对不在文档中。所有处理元素分组的文档似乎都没有处理子项选择和子项的数据继承。
答案是使用.each
构造来更新子元素并将子元素附加到组enter()调用。
data = [{"id":"A","name":"jim"},{"id":"B","name":"dave"},{"id":"C","name":"pete"}];
function draw(data) {
var g = svg.selectAll("g").data(data, function(d) { return d.id; })
genter = g.enter().append("g");
// This is the update of the circle elements -
// note that it is attached to the g data, not the enter()
// This will update any circle elements that already exist
g.each(function(d, i) {
var group = d3.select(this);
group.select("circle")
.transition()
.attr("r", 3)
.attr("cx", 100)
.attr("cy", function(d,i) {return 100 + (i * 30);})
}
// The data DOES get passed down to the circles, and the enter() statement
// will create a circle child for each data entry
genter.append("circle")
.attr("r", 3)
.attr("cx", 100)
.attr("cy", function(d,i) {return 100 + (i * 30);})
}
// Original drawing
draw(data);
// Now change the data, and update the groups' data accordingly
data = [{"id":"A","name":"carol"},{"id":"B","name":"diane"},{"id":"C","name":"susan"}];
// Second drawing, the SVG will be updated
draw(data);
如果有效,请告诉我。
[此答案基于此编码墙帖子中的一些代码分组:https://coderwall.com/p/xszhkg]