D3 Enter() / Merge() Creates Copies Instead Of Updating
I'm building an interactive graph with D3.js (v4) where each parent node has a collapsible set of child nodes. Because I also want to create tooltips etc, I'm wrapping each circle
Solution 1:
Just skimming through your code we can see that you have the "update"/"enter"/"exit" selections for the groups, but not for the circles.
Therefore, when a group is neither in the "enter" nor in the "exit" selections, meaning that it is in the "update" selection, you're appending a new circle to it every time you run the update
function.
Here is a very basic demo to show it. This is a wrong code: data
here is a random array with 10 elements maximum. But, as you can see, sometimes the number of circles is way more than 10:
var svg = d3.select("svg");
d3.select("button").on("click", update);
var color = d3.scaleOrdinal(d3.schemeCategory20)
functionupdate() {
var data = d3.range(~~(Math.random() * 10)).map(function(d) {
return {
size: ~~(Math.random() * 20),
x: ~~(Math.random() * 300),
y: ~~(Math.random() * 150)
}
})
var node = svg.selectAll(".node").data(data);
node.exit().remove();
node.enter()
.append("g")
.classed("node", true)
.merge(node)
.append("circle")
.attr("fill", function(d) {
returncolor(d.size)
})
.attr("r", function(d) {
return d.size;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
}
<scriptsrc="https://d3js.org/d3.v4.min.js"></script><button>Update</button><br><svg></svg>
Answer :
Don't use merge
, separate your enter and update selections for the groups. And, in the update selection, select existing circles.
node.select("circle")
.attr("r", etc...
Here is the demo of a correct code, it never has more than 10 circles:
var svg = d3.select("svg");
d3.select("button").on("click", update);
var color = d3.scaleOrdinal(d3.schemeCategory20)
functionupdate() {
var data = d3.range(~~(Math.random() * 10)).map(function(d) {
return {
size: ~~(Math.random() * 20),
x: ~~(Math.random() * 300),
y: ~~(Math.random() * 150)
}
})
var node = svg.selectAll(".node").data(data);
node.exit().remove();
node.enter()
.append("g")
.classed("node", true)
.append("circle")
.attr("fill", function(d) {
returncolor(d.size)
})
.attr("r", function(d) {
return d.size;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
node.select("circle")
.transition()
.duration(1000)
.attr("fill", function(d) {
returncolor(d.size)
})
.attr("r", function(d) {
return d.size;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
}
<scriptsrc="https://d3js.org/d3.v4.min.js"></script><button>Update</button><br><svg></svg>
Post a Comment for "D3 Enter() / Merge() Creates Copies Instead Of Updating"