I have a D3 force-graph that has functionality on tick
. I've noticed that once the graph hits a standstill, the functionality will be lost until it is moved again. I am wondering how to prevent this or how to have tick
always on?
An example is I have the following code
force.on("tick", function() {
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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.style("fill", function(d) { if (d.selected===true) {return "yellow"} else return d.data['color'] }).select("circle").style("stroke", "black");
});
// highlight node on dblclick
function highlight(d) {
if (d.selected == false) {
d.selected = true;
}
else {
d.selected = false;
}
}
It is constantly checking the node's data whether the selected
(from the JSON) attribute is true or false. If it is true then it turns the node yellow. I've noticed that once the graph is still, and you double click, it will not turn the node yellow until you move the graph around again.
The tick
event is generated by the force layout when its internal status changes, i.e. when the nodes have moved. At some point, the force simulation will reach an equilibrium point where all the forces effecting the nodes are balanced and you won't see any further movement. At this point, no more tick
events will be generated.
There are ways to "stretch out" the time required to reach an equilibrium, but you can't delay this indefinitely unless you disturb the nodes to unbalance the forces.
A better solution here (as pointed out in the comments) is to separate the functionality for updating the visualization to display the state of the force layout and the functionality for interacting with the nodes. In your case, you simply need run the code that highlights the node that was clicked on in the click handler.