Reputation: 20658
I took the sticky force layout example and tried adding an extra link and updating the layout using enter()
, but then all the links disappeared and FireBug shows no error either.
Shouldn't these lines have added a link?
graph.links.push({"source": 0, "target": 11});
link = link.data(graph.links).enter().append("line").attr("class", function(d,i) {console.log(i);return "link";});
Also, the console.log(i)
outputs 18
instead of 19
. It's like as though it never took into account the increase in size of the graph
array.
I checked this example, but even here it seems like using the data()
and enter()
functions should have been enough.
The code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.link {
stroke: #000;
stroke-width: 1.5px;
}
.node {
cursor: move;
fill: #ccc;
stroke: #000;
stroke-width: 1.5px;
}
.node.fixed {
fill: #f00;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var graph =
{
"nodes": [
{"x": 469, "y": 410},
{"x": 493, "y": 364},
{"x": 442, "y": 365},
{"x": 467, "y": 314},
{"x": 477, "y": 248},
{"x": 425, "y": 207},
{"x": 402, "y": 155},
{"x": 369, "y": 196},
{"x": 350, "y": 148},
{"x": 539, "y": 222},
{"x": 594, "y": 235},
{"x": 582, "y": 185},
{"x": 633, "y": 200}
],
"links": [
{"source": 0, "target": 1},
{"source": 1, "target": 2},
{"source": 2, "target": 0},
{"source": 1, "target": 3},
{"source": 3, "target": 2},
{"source": 3, "target": 4},
{"source": 4, "target": 5},
{"source": 5, "target": 6},
{"source": 5, "target": 7},
{"source": 6, "target": 7},
{"source": 6, "target": 8},
{"source": 7, "target": 8},
{"source": 9, "target": 4},
{"source": 9, "target": 11},
{"source": 9, "target": 10},
{"source": 10, "target": 11},
{"source": 11, "target": 12},
{"source": 12, "target": 10}
]
};
var width = 960,
height = 500;
var force = d3.layout.force()
.size([width, height])
.charge(-400)
.linkDistance(40)
.on("tick", tick);
var drag = force.drag()
.on("dragstart", dragstart);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
//d3.json("graph.json", function(error, graph) {
force.nodes(graph.nodes).links(graph.links).start();
link = link.data(graph.links).enter().append("line").attr("class", "link");
node = node.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", 12)
.on("dblclick", dblclick)
.call(drag);
//});
console.log(graph.links.length);
graph.links.push({"source": 0, "target": 11});
console.log(graph.links.length);
link = link.data(graph.links).enter().append("line").attr("class", "link");
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
function dblclick(d) {
d3.select(this).classed("fixed", d.fixed = false);
}
function dragstart(d) {
d3.select(this).classed("fixed", d.fixed = true);
}
</script>
Upvotes: 0
Views: 782
Reputation: 109232
The main problem is
link = link.data(graph.links).enter().append("line").attr("class", "link");
After this, link
will contain only the links that were just added to the visualisation as you're using .enter()
. This in turn means that only those will be updated during the tick
event of the force layout, as you're using the same link
variable there. It's the same problem for node
.
To fix, set the selection variables to contain all relevant elements after adding the new elements.
link = svg.selectAll(".link");
Complete demo here.
Upvotes: 2