I am learning d3 by coding a force directed graph from basics. My code is below.What I don’t understand is the purpose of force.on('tick'...
Surely if we are using a in-built class for the layout I would have thought that it is enough to give d3.layout.force() your nodes and links and it should be able to draw the graph in a balanced layout.
If I comment out the section force.on('tick'... then all my circles and lines end up in the top left hand corner. Is there are difference between what is happening internally and what is happening in the svg container hence we need the force.on('tick' to redraw the layout to match the current set of internal values each time?
var nodes = [ {}, {}, {} ]; var links = [ {'source': 0, 'target': 1} ]; // append svg element to container var mychart = d3.select('#chart') .append('svg') .attr('width', w) .attr('height', h); // create force layout in memory var force = d3.layout.force() .nodes(nodes) .links(links) .size([w, h]); // append a group for each data element var node = mychart.selectAll('circle') .data(nodes).enter() .append('g') .call(force.drag); // append circle onto each 'g' node node.append('circle') .attr('fill', palette.green) .attr('r', circleWidth); /*force.on('tick', function(e) { node.attr('transform', function(d, i) { return 'translate('+ d.x +', '+ d.y +')'; }) 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 }) });*/ var link = mychart.selectAll('line') .data(links).enter() .append('line') .attr('stroke', palette.gray) force.start();
D3's force layout uses physics based rules to position visual elements. This article shows how to use D3's force layout and how to use it to create network visualisations and circle clusters. D3's force layout uses a physics based simulator for positioning visual elements.
The "tick" events are dispatched for each tick of the simulation. Listen to tick events to update the displayed positions of nodes and links. For example, if you initially display the nodes and links like so: var link = vis. selectAll("line") .
The force layout runs asynchronously. That is, when you call force.start()
it starts doing its computations that determine the position of the nodes in parallel in the background. These computations are not a single step, but a simulation running over a long time (several seconds).
The tick
handler is the function that enables you to get the state of the layout when it has changed (the simulation has advanced by a tick) and act on it -- in particular, redraw the nodes and links where they currently are in the simulation.
You don't have to handle the tick
event though, you could simply run the layout for a certain number of steps and then draw without handling the tick
event at all, as in this example. Doing it dynamically in the tick
handler function has the advantage that you can see how the layout progresses. However, technically it is not needed if you're just interested in the result.
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