title: force graph in d3.js - disappearing nodes
body: <p>I'm trying to construct a directed force graph in d3.js that has a click listener on it that changes the the underlying data and redraws the graph. I belive I'm following Mr. Bostock's update pattern, but the issue that I'm having is that when I run the update triggered by the click listener the nodes disappear off the bottom of the screen leaving the links and labels behind.</p>
  
  <p>This update seems to run, updates the existing nodes (turns them green in this case) then ignores the "enter" and "exit" sections (which is the desired behaviour) then hits the tick() function which send the nodes south.</p>
  
  <p>I can get this working by removing the "g" tag on the node and thus decoupling the labels and the node, which is obviously not desirable. </p>
  
  <p>I can't help feeling I'm missing something obvious! Or perhaps I should be tacking this a different way? </p>
  
  <p>Here's the code:</p>
  
  <pre><code>var width = 960,
      height = 500,
      links,
      nodes,
      root;
  
  var force = d3.layout.force()
      .size([width, height])
      .charge(-200)
      .linkDistance(50)
      .on("tick", tick);
  
  var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);
  
  var link = svg.selectAll(".link"),
      node = svg.selectAll(".node");
  
  d3.json("test.json", function(json) {
    root = json;
    update();
  });
  
  function update() {
    nodes = root.nodes
    links = root.links
  
    // Restart the force layout.
    force
        .nodes(nodes)
        .links(links)
        .start();
  
      svg.append("svg:defs").append("marker")
          .attr("id", "end")
          .attr("refX", 15)
          .attr("refY", 2)
          .attr("markerWidth", 6)
          .attr("markerHeight", 4)
          .attr("orient", "auto")
          .append("svg:path")
          .attr("d", "M 0,0 V 4 L8,2 Z");
  
    // Update the links…
    //link = link.data(links, function(d) { return d.target.name; });
    link = link.data(links)
  
    // Exit any old links.
    link.exit().remove();
  
    // Enter any new links.
    link.enter().insert("svg:line", ".node")
        .attr("class", "link")
        .attr("marker-end", "url(#end)")
        .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; });
  
    // Update the nodes…
    node = svg.selectAll("g").select(".node").data(nodes, function(d) { return d.name; });
  
  
    node.style("fill", "green")
  
    // Exit any old nodes.
    node.exit().remove();
  
    // Enter any new nodes.
    node.enter().append("g")
        .append("svg:circle")
        .attr("class", "node")
        .attr("id", function(d) {return "node" + d.index; })
        .attr("r", 12)
        .style("fill", "#BBB")
        .on("click", click)
        .call(force.drag);
  
    node.append("svg:text")
        .attr("dx", 16)
        .attr("dy", ".15em")
        .attr("class", "nodelabel")
        .text(function(d) { return d.name });
  }
  
  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 + ")"; });
  
  }
  
  
  function click(d) {
    if (!d3.event.defaultPrevented) {
  
      // DO ANYTHING
      update()
    }
  }
  </code></pre>
  
  <p>and the contents of test.json is:</p>
  
  <pre><code>{
    "nodes": [
      {"name" : "John"},
      {"name" : "Alison"},
      {"name" : "Phil"},
      {"name" : "Jim"},
      {"name" : "Jane"},
      {"name" : "Mary"},
      {"name" : "Joe"}
    ],
    "links": [
      {"source":  1, "target":  0},
      {"source":  2, "target":  0},
      {"source":  3, "target":  0},
      {"source":  4, "target":  0},
      {"source":  5, "target":  1},
      {"source":  6, "target":  1}
    ]
  }
  </code></pre>