Reputation: 33
I am using the D3.js force layout to create a graph. To update nodes and edges I follow the example code at http://bl.ocks.org/mbostock/1095795. This means I have this code to initialize the layout:
var nodes = [];
var edges = [];
var force = d3.layout
.force()
.nodes(nodes)
.links(edges)
...
var link = svg.selectAll('.link');
var node = svg.selectAll('.node');
And I update the data in a function:
//(nodes and edges array has been updated before)
link = link.data(force.links());
link.enter()
.append('g')
.attr('class', 'link');
link.append('line')
.style('stroke-width', function (d) {
return d.bond*2 + 'px';
});
link.exit().remove();
node = node.data(force.nodes());
node.enter()
.append('g')
.attr('class', 'node')
.call(force.drag);
node.append('circle')
.attr('r', function (d) { return radius(d.size) })
.style('fill', function (d) { return color(d.type) });
node.exit().remove();
force.start();
I inspected the content of the nodes and edges arrays and the force.nodes() and force.links() and it seems like everything is correct,
but the graph shows edges of previous data.
So I also looked at the svg and it seems like the group (<g>
) of nodes and edges contains more than one 'line' and 'circle' element respectively:
<g class="link">
<line x1="39.28621930166058" y1="256.22690655336356"
x2="217.9040028325144" y2="12.304247302113906"
style="stroke-width: 2px;"></line>
<line x1="199.64928632623412" y1="275.35140495955585"
x2="275.5229250036658" y2="100.33170397523202"
style="stroke-width: 2px;"></line>
</g>
The same applies to the nodes.
How can I remove the previous elements from the group when updating? I can't seem to find the answer in the linked example or in the d3 docs.
Upvotes: 2
Views: 1512
Reputation: 6207
link.enter()
.append('g')
.attr('class', 'link');
link.append('line')
.style('stroke-width', function (d) {
return d.bond*2 + 'px';
});
link.exit().remove();
link is the selection/data join of g.link elements with your data.
Looking at the above you append a new g element for each new link via .enter(), but then you append a new line element to the new and existing links because there's no enter() qualifier there.
Try
var newLinks = link.enter()
.append('g')
.attr('class', 'link');
newLinks.append('line')
.style('stroke-width', function (d) {
return d.bond*2 + 'px';
});
PS. If that works for the lines then it's the same situation for the nodes.
Upvotes: 2