Why do we need force.on('tick'.. in d3
d3.js, javascript
Solution
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.
Problem
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(); ```