title: How do I add labels to d3.js force bubble chart
body: <p>I'm trying to modify this code bl.ocks.org/mbostock/7881887 so that I can use the technique to show a word cloud where the circle size would be relative to the no of words in a file but my main problem at the moment finding out how to add text to the circles in the first place. Tantalizingly I can see what looks like a function that does this in the code ... node.append("text")? So I assumed I would be able to add a "name" value to "d" in the nodes function and away we'd go. As you can see I've just added name: text where text = "Test" to d.
  Any help getting any text at all to appear within or near these circles would be very greatly appreciated! I'm new D3 as you can probably tell and have spent many evenings googling this to find nothing at all. I can see examples on a different kind of chart... the force layout eg <a href="http://bl.ocks.org/mbostock/1093130" rel="noreferrer">http://bl.ocks.org/mbostock/1093130</a> but they appear so different I can't apply one to the other :-(</p>
  
  <p>here is my jsfiddle <a href="https://jsfiddle.net/TimBrighton/vn7reroe/1/" rel="noreferrer">https://jsfiddle.net/TimBrighton/vn7reroe/1/</a></p>
  
  <pre><code>var width = 960,
      height = 500,
      padding = 1.5, // separation between same-color nodes
      clusterPadding = 6, // separation between different-color nodes
      maxRadius = 12;
  
  var n = 100, // total number of nodes
      m = 5; // number of distinct clusters
  
  var color = d3.scale.category10()
      .domain(d3.range(m));
  
  // The largest node for each cluster.
  var clusters = new Array(m);
  
  var nodes = d3.range(n).map(function() {
    test="Test";
    var i = Math.floor(Math.random() * m),
        r = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius,      
        d = {
          name: test,
          cluster: i,
          radius: r,
          name: "test",
          x: Math.cos(i / m * 2 * Math.PI) * 200 + width / 2 + Math.random(),
          y: Math.sin(i / m * 2 * Math.PI) * 200 + height / 2 + Math.random()
        };
    if (!clusters[i] || (r &gt; clusters[i].radius)) clusters[i] = d;
    console.log(d.name);
    return d;
  
  });
  
  var force = d3.layout.force()
      .nodes(nodes)
      .size([width, height])
      .gravity(.02)
      .charge(0)
      .on("tick", tick)
      .start();
  
  var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);
  
  var node = svg.selectAll("circle")
      .data(nodes)
    .enter().append("circle")
      .style("fill", function(d) { return color(d.cluster); })
      .call(force.drag);
  
  
  node.append("text")
  .text(function(d) { return d.name; })
       // .style("font-size", function(d) { return Math.min(2 * d.r, (2 * d.r - 8) / this.getComputedTextLength() * 24) + "px"; })
       //.attr("dy", ".35em");
  
      .attr("dx", 10)
      .attr("dy", ".35em")
      .text(function(d) { return d.name })
      .style("stroke", "gray");
  
  node.transition()
      .duration(750)
      .delay(function(d, i) { return i * 5; })
      .attrTween("r", function(d) {
        var i = d3.interpolate(0, d.radius);
        return function(t) { return d.radius = i(t); };
      });
  
  
  
  
  function tick(e) {
    node
        .each(cluster(10 * e.alpha * e.alpha))
        .each(collide(.5))
        .attr("cx", function(d) { return d.x; })
        .attr("cy", function(d) { return d.y; });
  }
  
  // Move d to be adjacent to the cluster node.
  function cluster(alpha) {
    return function(d) {
      var cluster = clusters[d.cluster];
      if (cluster === d) return;
      var x = d.x - cluster.x,
          y = d.y - cluster.y,
          l = Math.sqrt(x * x + y * y),
          r = d.radius + cluster.radius;
      if (l != r) {
        l = (l - r) / l * alpha;
        d.x -= x *= l;
        d.y -= y *= l;
        cluster.x += x;
        cluster.y += y;
      }
    };
  }
  
  // Resolves collisions between d and all other circles.
  function collide(alpha) {
    var quadtree = d3.geom.quadtree(nodes);
    return function(d) {
      var r = d.radius + maxRadius + Math.max(padding, clusterPadding),
          nx1 = d.x - r,
          nx2 = d.x + r,
          ny1 = d.y - r,
          ny2 = d.y + r;
      quadtree.visit(function(quad, x1, y1, x2, y2) {
        if (quad.point &amp;&amp; (quad.point !== d)) {
          var x = d.x - quad.point.x,
              y = d.y - quad.point.y,
              l = Math.sqrt(x * x + y * y),
              r = d.radius + quad.point.radius + (d.cluster === quad.point.cluster ? padding : clusterPadding);
          if (l &lt; r) {
            l = (l - r) / l * alpha;
            d.x -= x *= l;
            d.y -= y *= l;
            quad.point.x += x;
            quad.point.y += y;
          }
        }
        return x1 &gt; nx2 || x2 &lt; nx1 || y1 &gt; ny2 || y2 &lt; ny1;
      });
    };
  }
  </code></pre>