71

I am trying to add some text into circle. I have been following example from a mbostock tutorial, but wasn't able to get the right output.

The code snippet is:

var data;
var code;

d3.json("/json/trace.json", function(json) {
  data = json;
  console.log(data);
  // get code for visualization
  code = data["code"];
  alert(code);
  var mainSVG = d3
    .select("#viz")
    .append("svg")
    .attr("width", 900)
    .attr("height", 900);
  mainSVG
    .append("circle")
    .style("stroke", "gray")
    .style("fill", "white")
    .attr("r", 100)
    .attr("cx", 300)
    .attr("cy", 300);
  circle = mainSVG.selectAll("circle").data([code]);
});

Any suggestions how to get this work?

Wyck
  • 10,311
  • 6
  • 39
  • 60
gizmo
  • 7,989
  • 6
  • 23
  • 22

3 Answers3

88

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/

meetar
  • 7,443
  • 8
  • 42
  • 73
Christopher Chiche
  • 15,075
  • 9
  • 59
  • 98
  • Jup, it's not showing anything - even when I fix ';' from .attr("cy", 300); As long as I have code that is not adding some text it works – gizmo Jan 04 '13 at 04:09
6

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

Manish Kumar
  • 1,131
  • 15
  • 28
  • Hi, A small help is needed. In my case the text between the circle is hiding behind. If I increase the opacity of the circle I can see the text, but it is hidden if the circle color is solid. Am I missing something which brings the text above the circle. Thanks – Subhasish Bhattacharjee Dec 08 '16 at 06:25
  • The only problem which can be is make sure you write text on circles only after circles are created. If you write text before circles get created, then text will not be visible. Basically in D3 everything is a layer. Layer created later will override the earlier one. – Manish Kumar Dec 09 '16 at 07:34
4

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)
Kenaa
  • 49
  • 3