title: D3: Show network reaching layout, then stop force
body: <p>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.</p>
  
  <p>I've looked at the examples for <a href="http://bl.ocks.org/mbostock/1667139" rel="nofollow">"static" force layouts</a>, 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:</p>
  
  <pre><code>while (force.alpha() &gt;0.005) {
      force.tick();
  }
  force.stop();
  </code></pre>
  
  <p>With this addition, the network doesn't display until it gets to <code>force.stop()</code>.  Does anyone know how I can get it to display while it's "ticking"?</p>
  
  <p>EDIT: Here's my implementation of the <code>tick</code> function:</p>
  
  <pre><code>function tick(e) {
  
  console.log(force.alpha());
  if (force.alpha() &lt;0.05) {
      force.stop();
  }
  var h = svgH;
  
  if (e.alpha &lt; 0.05) {
      var q = d3.geom.quadtree(nodes),
      i = 0,
      n = nodes.length;
  
      while (++i &lt; 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 &lt; 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 + ")";
          });
  }
  </code></pre>