1

I'm trying to get my D3 network to freeze after it reaches a nice layout (alpha reaches 0). I want the force to stop completely, even when a node is dragged (the user should be able to rearrange the nodes manually). I think I know how to do the second part of this, by modifying the functions that are called on mousedown and mouseup for the nodes. However, I can't get the original layout and freezing to work.

I've looked at the examples for "static" force layouts, where the network is displayed only after the layout is completed. However, I want the network to display as it's reaching the stable layout. I added this to the end of the function that draws the network:

while (force.alpha() >0.005) {
    force.tick();
}
force.stop();

With this addition, the network doesn't display until it gets to force.stop(). Does anyone know how I can get it to display while it's "ticking"?

EDIT: Here's my implementation of the tick function:

function tick(e) {

console.log(force.alpha());
if (force.alpha() <0.05) {
    force.stop();
}
var h = svgH;

if (e.alpha < 0.05) {
    var q = d3.geom.quadtree(nodes),
    i = 0,
    n = nodes.length;

    while (++i < n) {
        q.visit(collide(nodes[i], e.alpha));
    }
}   


path.attr("d", function(d) {

    // Total difference in x and y from source to target
    diffX = d.target.x - d.source.x;
    diffY = d.target.y - d.source.y;

    // Length of path from center of source node to center of target node
    pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY));

    // x and y distances from center to outside edge of target node
    offsetX = (diffX * d.target.radius) / pathLength;
    offsetY = (diffY * d.target.radius) / pathLength;

    if (d.target.y < d.source.y) {
        var avgY = (d.target.y + d.source.y)/2;

        if (d.target.fixed != true) {
            d.target.y = avgY;
        }
        if (d.source.fixed != true) {
            d.source.y = avgY;
        }
    } 

    return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
});

// Keep circles within bounds of screen
var r = 6;
circle.attr("cx", function(d) { return d.x = Math.max(r + d.radius, Math.min(w - r, d.x)); })
        .attr("cy", function(d) {
            return d.y = Math.max(d.radius, Math.min(h - d.radius, d.y));
        });

        text.attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
        });
}
FrancesKR
  • 1,200
  • 1
  • 12
  • 27

1 Answers1

0

Check the stop condition in the tick event handler -- this way you can redraw the network on each tick and stop.

Lars Kotthoff
  • 107,425
  • 16
  • 204
  • 204
  • I added this check at the beginning of the `tick` handler: `if (force.alpha() <0.005) { force.stop(); }`. I also print alpha right before the check. `stop()` is setting alpha to zero, but for some reason my network keeps drifting even when alpha is zero... could this be the way I've implemented the tick function? – FrancesKR Jun 24 '13 at 19:22
  • Possible. If you show your implementation I would be able to judge it better :) – Lars Kotthoff Jun 25 '13 at 08:13
  • I've added the implementation to my post (I'm using 0.05 instead of 0.005). The odd thing is that once it reaches a stable network, every time I disturb it after that it will "reheat" then freeze once alpha < 0.05. It's only the first time that this doesn't work. – FrancesKR Jun 25 '13 at 16:30