Given the following layout:
<g>
... // many nodes
<g>
<circle></circle>
<text></text>
</g>
...
</g>
How would a correct update pattern look like in d3 v4? What do I have to use as parameter in merge(?), how often do I have to call merge (only on node? node + circle + text ?)
I created an working example on fiddle: https://jsfiddle.net/cvvfsg97/6/
Code:
function update(items) {
node = nodeLayer.selectAll(".node")
.data(items, function(d) { return d.id; })
node = node.enter() // insert
.append("g")
.attr("class", "node");
node.append("circle") // insert
.attr("r", 2.5)
.attr('class', 'circle')
.merge(nodeLayer.selectAll('.node > circle')) // is this correct?! // merge
.attr('fill', 'red') // just for testing purposes
.exit().remove(); // exit
node.append("text") // insert
.attr("dy", 3)
.text(function(d) { return d.name; })
.merge(nodeLayer.selectAll('.node > text')) // is this correct?! // merge
.attr('fill', 'green') // just for testing purposes
.exit().remove();
node.merge(nodeLayer.selectAll('.node')) // is this correct?! // merge
.attr('class', 'anotherClass')
.exit().remove(); // does not work // exit
}
Could someone bring some clarity in terms of how to use enter(), merge(), exit() in groups?
I potentially like to do changes in every stage for every element.
Update: I simplified the example, I don't need links or a force-layout. My question is only about the update-pattern, not about forces. The updated jsfiddle does not have the force-layout.
You are over complicating the pattern. Here's your update function written properly:
function update(items) {
var node = nodeLayer.selectAll(".node") // bind the data, this is update
.data(items, function(d) {
return d.id;
});
node.exit().remove(); // exit, remove the g
nodeEnter = node.enter() // enter, append the g
.append("g")
.attr("class", "node");
nodeEnter.append("circle") // enter, append the circle on the g
.attr("r", 2.5)
.attr('class', 'circle')
.attr('fill', 'red');
nodeEnter.append("text") // enter, append the text on the g
.attr("dy", 3)
.text(function(d) {
return d.name;
})
.attr('fill', 'green');
node = nodeEnter.merge(node); // enter + update on the g
node.attr('transform', function(d){ // enter + update, position the g
return 'translate(' + d.x + ',' + d.y + ')';
});
node.select("text") // enter + update on subselection
.text(function(d) {
return d.name;
});
}
Here it is running with multiple calls:
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
var nodeLayer = d3.select('body')
.append('svg')
.attr('width',500)
.attr('height',500);
update([
{
id: 1,
name: 'A',
x: Math.random() * 500,
y: Math.random() * 500
},{
id: 2,
name: 'B',
x: Math.random() * 500,
y: Math.random() * 500
},{
id: 3,
name: 'C',
x: Math.random() * 500,
y: Math.random() * 500
}
]);
setTimeout(function(){
update([
{
id: 1,
name: 'A',
x: Math.random() * 500,
y: Math.random() * 500
},{
id: 4,
name: 'This is a new name...',
x: Math.random() * 500,
y: Math.random() * 500
},{
id: 3,
name: 'C',
x: Math.random() * 500,
y: Math.random() * 500
}
]);
}, 3000);
function update(items) {
var node = nodeLayer.selectAll(".node")
.data(items, function(d) {
return d.id;
});
node.exit().remove(); // exit, remove the g
nodeEnter = node.enter() // enter the g
.append("g")
.attr("class", "node");
nodeEnter.append("circle") // enter the circle on the g
.attr("r", 2.5)
.attr('class', 'circle')
.attr('fill', 'red');
nodeEnter.append("text") // enter the text on the g
.attr("dy", 3)
.attr('fill', 'green');
node = nodeEnter.merge(node); // enter + update
node.attr('transform', function(d){
return 'translate(' + d.x + ',' + d.y + ')';
});
node.select("text")
.text(function(d) {
return d.name;
});
}
</script>
</body>
</html>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With