Reputation: 943
I try to port to d4.v4.js some graph drawing built with version 3.
I quite don't understand how to attach svg nodes and links to the simulation with atlas force.
The simplified version using d3.v3 is shared on fiddle, note that all nodes are grouped in a <g>
element, and each node, simplified as a circle in this example is inserted in a <g>
element as well. Similarly, links are grouped in a <g>
element. I need those to draw more complexe networks.
svg.append("g").attr("class", "links");
svg.append("g").attr("class", "nodes");
var force = d3.layout.force()
.gravity(.15)
.distance(100)
.charge(-1200)
.friction(0.8)
.size([width, height]);
// push initial sets of nodes and links
var nodes = force.nodes(), links = force.links();
Array.prototype.push.apply(nodes, data.nodes);
Array.prototype.push.apply(links, data.edges);
My reference for drawing a network with d3.v4 in shared on fiddle as well, it actually works, however each node is not in a <g>
element as required (I guess) for my more complex graphs.
This last fiddle shows the d3.v4 version of the simplified graph, as one can see, nodes remain in the upper left corner, only zoom works.
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.call(zoom);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink()
.id(function(d) { return d.id; })
.distance(function(d) { return (1-d.value*d.value*d.value)*20; }))
.force("charge", d3.forceManyBody().strength(-200))
.force("center", d3.forceCenter(width / 2, height / 2));
var pane = svg.append("g");
var link = pane.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return d.value*d.value*d.value*10; });
var node = pane.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("class", "node")
.attr("r", function(d) { return d.value*5 })
.style("fill", function(d) { return color(d.group); })
My question is how should I attach nodes (<g>
) and links to "simulation"? What is wrong in my script?
Many thanks in advance for your help.
Upvotes: 3
Views: 1056
Reputation: 737
Let's take your last fiddle with the d3v4 implementation. 2 changes and it will work.
1) the ticked
function to move the elements. Since nodes are svg groups now, you can't use cx
and cy
attributes (good for circles). You need to use transform translate
like this:
node
.attr("transform", function(d) {
return "translate(" + d.x + ", " + d.y + ")";
});
2) The node
variable there contains only the update selection, since you called the enter selection nodeEnter
. And since all elements are in the enter selection (just created), you don't move anything.
So you just need to merge the two selections like this:
nodeEnter.append("circle")
.attr("r", function(d) { return d.value*10 })
node.exit().remove();
node = nodeEnter.merge(node);
You can read more details in Mike Bostock documentation about this. Check also this and other similar bl.ocks.
To correctly target the links in ticked
you should also merge enter and update link selections in the same way.
As a side note, you don't need to link source and target objects in the links as you do in getGraph
function, since this is done by d3 simulation
already. So you could just use your json
object as data.
Here is a working fiddle. Hope it is clearer how to upgrade d3 v3 force directed layout to d3 v4 force simulation :D
Upvotes: 1