Omar Wagih
Omar Wagih

Reputation: 8732

Freezing force directed network graph and make draggable in D3

I am trying to freeze a force directed network in d3 completely! I have tried setting the friction value to 0, but the network becomes more condensed and the nodes still hover slightly.

var force = d3.layout.force()
.charge(-220)
.linkDistance(70)
.friction(0);

I also want my nodes to be draggable i.e. move position when they are dragged.

Ultimately, I'm trying to get something similar to Cytoscape js which looks like this.

Thanks!

Upvotes: 3

Views: 5491

Answers (1)

Christopher Chiche
Christopher Chiche

Reputation: 15325

First if you want to "freeze" the graph at a certain time, you can use the stop command of force layout:

force.stop()

A good use would be to to first let the graph self organize (using tick) and then stop the force:

// include in beginning of script
force.start();
for (var i = 0; i < n; ++i) force.tick();
force.stop();

Then if you want to drag and drop nodes, one good idea would have been to search drag on the d3 example page, you would have found the following link: Drag and Drop Support to set nodes to fixed position when dropped which has all you want. By the way it is also related to a stackoverflow question you might find interesting: D3 force directed graph with drag and drop support to make selected node position fixed when dropped

Here is the interesting code for drag and drop, adapted for graphs where the force is already stopped (I just commented some lines, not sure though, so verify by uncommenting if it doesn't work as expected)

var node_drag = d3.behavior.drag()
    .on("dragstart", dragstart)
    .on("drag", dragmove)
    .on("dragend", dragend);

function dragstart(d, i) {
    //force.stop() // stops the force auto positioning before you start dragging
}

function dragmove(d, i) {
    d.px += d3.event.dx;
    d.py += d3.event.dy;
    d.x += d3.event.dx;
    d.y += d3.event.dy; 
    tick(); // this is the key to make it work together with updating both px,py,x,y on d !
}

function dragend(d, i) {
    //d.fixed = true; // of course set the node to fixed so the force doesn't include the node in its auto positioning stuff
    //tick();
    //force.resume();
}

function tick() {
  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 + ")"; });
};

Upvotes: 6

Related Questions