Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recentering D3 force layout diagram on node click

I am trying to create a force diagram that gets re-centered on click.

I am following this as a base:

enter image description here

I tried to adjust the click function to set d.fixed=true and also assign fixed points for d.x and d.y.

However, I need to turn d.fixed=false for all the other nodes. Also, the node does not transition to the center on click.

My question is how do I set all other fixed properties to false and then redraw the force diagram with the new center?

I have prepared an example here:

enter image description here

The click function is fairly straightforward:

  function click(d) {
        d.fixed=true;
        d.x=10;
        d.y=10;
        update();
    }

I tried adding this to the function:

root.forEach(function (d) { d.fixed = false; });
like image 699
mrkb80 Avatar asked Dec 31 '13 16:12

mrkb80


2 Answers

You can access the nodes using force.nodes() and iterate to set the fixed attribute to false.

force.nodes().forEach(function(d) { d.fixed = false; });

and then update the graph. I forked your example here and added a double click listener that restart the force layout. Regards,

like image 77
Pablo Navarro Avatar answered Oct 19 '22 14:10

Pablo Navarro


A few things, in the order I approached the problem. Here's the final fiddle if you want to follow along.

First, your update() method does a lot more than just update the position of the nodes; it recalculates the whole tree. It's overkill for what you're trying to do, and while in the end it turned out to not be the source of the problem, I'd still recommend just using force.resume() to get the timer ticking and the nodes moving again.

Second, you were on the right track with adding a forEach statement to turn off the former fixed nodes. But forEach works on arrays, and root is an object. So either reuse the flatten method (slow) or do as @Pablo suggested and use force.nodes() to get the nodes as an array (better).

Third, and this took a bit to figure out: Once you set a node to be "fixed", the force layout ignores any new d.x and d.y values, resetting them back to d.px and d.py (the previous values). (I assume this is so that if the node is dragged, it will automatically jump back to its fixed position). So to move it to be fixed where you want it to be, you have to set the "previous" values, not the new values. The only problem is that this causes an immediate jump in position, instead of a smooth movement. You might want to add in a transition for that one node (to make it look like it's being dragged to the centre) before calling force.resume().

like image 4
AmeliaBR Avatar answered Oct 19 '22 13:10

AmeliaBR