d3 add text to circle

Here is an example showing some text in circles with data from a json file: http://bl.ocks.org/4474971. Which gives the following:

enter image description here

The main idea behind this is to encapsulate the text and the circle in the same "div" as you would do in html to have the logo and the name of the company in the same div in a page header.

The main code is:

var width = 960,
    height = 500;
 
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
    
d3.json("data.json", function(json) {
    /* Define the data for the circles */
    var elem = svg.selectAll("g")
        .data(json.nodes)
  
    /*Create and place the "blocks" containing the circle and the text */  
    var elemEnter = elem.enter()
        .append("g")
        .attr("transform", function(d){return "translate("+d.x+",80)"})
 
    /*Create the circle for each block */
    var circle = elemEnter.append("circle")
        .attr("r", function(d){return d.r} )
        .attr("stroke","black")
        .attr("fill", "white")
 
    /* Create the text for each block */
    elemEnter.append("text")
        .attr("dx", function(d){return -20})
        .text(function(d){return d.label})
})

and the json file is:

{"nodes":[
  {"x":80, "r":40, "label":"Node 1"}, 
  {"x":200, "r":60, "label":"Node 2"}, 
  {"x":380, "r":80, "label":"Node 3"}
]}

The resulting html code shows the encapsulation you want:

<svg width="960" height="500">
    <g transform="translate(80,80)">
        <circle r="40" stroke="black" fill="white"></circle>
        <text dx="-20">Node 1</text>
    </g>
    <g transform="translate(200,80)">
        <circle r="60" stroke="black" fill="white"></circle>
        <text dx="-20">Node 2</text>
    </g>
    <g transform="translate(380,80)">
        <circle r="80" stroke="black" fill="white"></circle>
        <text dx="-20">Node 3</text>
    </g>
</svg>

jsfiddle with working code: http://jsfiddle.net/chrisJamesC/DY7r4/


Extended the example above to fit the actual requirements, where circled is filled with solid background color, then with striped pattern & after that text node is placed on the center of the circle.

var width = 960,
  height = 500,
  json = {
    "nodes": [{
      "x": 100,
      "r": 20,
      "label": "Node 1",
      "color": "red"
    }, {
      "x": 200,
      "r": 25,
      "label": "Node 2",
      "color": "blue"
    }, {
      "x": 300,
      "r": 30,
      "label": "Node 3",
      "color": "green"
    }]
  };

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)

svg.append("defs")
  .append("pattern")
  .attr({
    "id": "stripes",
    "width": "8",
    "height": "8",
    "fill": "red",
    "patternUnits": "userSpaceOnUse",
    "patternTransform": "rotate(60)"
  })
  .append("rect")
  .attr({
    "width": "4",
    "height": "8",
    "transform": "translate(0,0)",
    "fill": "grey"
  });

function plotChart(json) {
  /* Define the data for the circles */
  var elem = svg.selectAll("g myCircleText")
    .data(json.nodes)

  /*Create and place the "blocks" containing the circle and the text */
  var elemEnter = elem.enter()
    .append("g")
    .attr("class", "node-group")
    .attr("transform", function(d) {
      return "translate(" + d.x + ",80)"
    })

  /*Create the circle for each block */
  var circleInner = elemEnter.append("circle")
    .attr("r", function(d) {
      return d.r
    })
    .attr("stroke", function(d) {
      return d.color;
    })
    .attr("fill", function(d) {
      return d.color;
    });

  var circleOuter = elemEnter.append("circle")
    .attr("r", function(d) {
      return d.r
    })
    .attr("stroke", function(d) {
      return d.color;
    })
    .attr("fill", "url(#stripes)");

  /* Create the text for each block */
  elemEnter.append("text")
    .text(function(d) {
      return d.label
    })
    .attr({
      "text-anchor": "middle",
      "font-size": function(d) {
        return d.r / ((d.r * 10) / 100);
      },
      "dy": function(d) {
        return d.r / ((d.r * 25) / 100);
      }
    });
};

plotChart(json);
.node-group {
  fill: #ffffff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Output:

enter image description here

Below is the link to codepen also:

See the Pen D3-Circle-Pattern-Text by Manish Kumar (@mkdudeja) on CodePen.

Thanks, Manish Kumar


Here's a way that I consider easier: The general idea is that you want to append a text element to a circle element then play around with its "dx" and "dy" attributes until you position the text at the point in the circle that you like. In my example, I used a negative number for the dx since I wanted to have text start towards the left of the centre.

const nodes = [ {id: ABC, group: 1, level: 1}, {id:XYZ, group: 2, level: 1}, ]

const nodeElems = svg.append('g')
.selectAll('circle')
.data(nodes)
.enter().append('circle')
.attr('r',radius)
.attr('fill', getNodeColor)

const textElems = svg.append('g')
.selectAll('text')
.data(nodes)
.enter().append('text')
.text(node => node.label)
.attr('font-size',8)//font size
.attr('dx', -10)//positions text towards the left of the center of the circle
.attr('dy',4)