3

In the answer to this question, mbostock notes that "if a node is fixed, it can only be moved by dragging and not by the simulation."

What if I'd like to position the nodes programmatically, however, perhaps by setting the d.x and d.y values? My attempts thus far have failed. I have tried the obvious setting of d.x and d.y, but these values are ignored for fixed nodes. I've also attempted to temporarily "un-fix", redraw, then "re-fix" the nodes, but this also doesn't work -- the nodes are magically reset to their original positions on the next tick.

Here's a running example of this latter approach.

Here's the key bit of that code, executed on click:

function explicitlyPosition() {
  node.each(function(d) {
    d.x = 0;
    d.y = 0;
    d.fixed = false;
  });
  tick();
  node.each(function(d) {
    d.fixed = true;
  });
  force.resume();
}

Is there a way to do this using the approach I've tried or one similar? Or I could use a totally different graph layout in D3, but I would ideally like large portions of my graph to be laid out in a force-directed manner.

Thanks!

Community
  • 1
  • 1
Eric Nguyen
  • 40,312
  • 4
  • 25
  • 31
  • 1
    If I understand what you're trying to do correctly, all you need to do is swap true and false for `fixed`. That is, when you set `.x` and `.y` explicitly, `fixed` should be true, else false. http://jsfiddle.net/2ov2La89/16/ – Lars Kotthoff Aug 12 '14 at 17:46
  • 1
    manually (re-)set the position of fixed nodes in a tick handler. – Stephen Thomas Aug 12 '14 at 17:46

2 Answers2

5

When you fire tick, the previous positions of nodes are used to determine the new positions, and are stored in the px and py attributes. If you change these attributes, running tick will update the x and y attributes to these values.

Fiddle.

Essentially, your nodes will magically fix to the new values when you redraw, rather than magically fix back to their old values.

ckersch
  • 7,507
  • 2
  • 37
  • 44
  • 1
    Nice! That's it. In fact, this even works when nodes are fixed, so all that malarkey with the un-fixing and fixing can also be avoided. Here's another version, simplified: http://jsfiddle.net/2ov2La89/29/ – Eric Nguyen Aug 12 '14 at 21:47
3

The jsfiddles used in the 2014 answer and comments for this question are outdated for D3 version 4. In version 4, the process for making fixed nodes is greatly simplified. You can simply set an fx and fy value for each node you want to fix.

For example, like this:

var graph = {
    "nodes": [
        // unfixed
        {"id":0},
        // fixed
        {"id":1, "fx": 200, "fy": 200},
        {"id":2, "fx": 200, "fy": 300},
        {"id":3, "fx": 300, "fy": 250}
    ],
    "links": [
        {"source": 0, "target": 1},
        {"source": 0, "target": 2},
        {"source": 1, "target": 3},
        {"source": 2, "target": 3}
    ]
};

or this:

graph.nodes[3].fx = 500;
graph.nodes[3].fy = 250;

or this:

graph.nodes.each(function(d) {
    if(d.id == 2) {
        d.fx = 0;
        d.fy = 0;       
    }
});
Chris Redford
  • 16,982
  • 21
  • 89
  • 109