cynichole
cynichole

Reputation: 53

Data binding in d3 v3 donut chart

So I've been trying to create a donut chart in d3.js and am having trouble adding labels to the chart. My chart data is in an array, but I think because of the "pie" variable, only the "value" from the data is being passed through and not the "text". Have tried multiple ways to try and bring the "text" in but with no luck. Hopefully a fresh set of eyes can see where my mistake is!

var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 750 - margin.left - margin.right,
    height = 520 - margin.top - margin.bottom;

var r = height/3;

var aColor = [
    '#0652DD',
    '#C4E538',
    '#F79F1F', 
    '#5758BB',
    '#D980FA',
    "#EA2027"
]

var piedata = [
    {text:"Facebook", "value":76}, 
    {text:"Website", "value":13},
    {text:"HardwareZone", "value":4}, 
    {text:"YouTube", "value":5},
    {text:"Instagram", "value":1},
    {text:"Twitter","value":1},
];

var vis = d3.select('#chart2')
.append("svg:svg")
.data([piedata])
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");


var pie = d3.layout.pie().sort(null).value(function(d){return d.value;});

// Declare an arc generator function
var arc = d3.svg.arc().innerRadius(r *0.5).outerRadius(r*0.8);

var outerArc = d3.svg.arc()
              .innerRadius(r*0.95)
              .outerRadius(r*0.95);

// Select paths, use arc generator to draw
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice").attr("transform", "translate("  + width/2 + "," + height/2 + ")");

arcs.append("g:path")
    .attr("fill", function(d, i){return aColor[i];})
    .attr("d", function (d) {return arc(d);})
    .attr("stroke", "white")
    .style("stroke-width", "3px")
    .style("opacity", 0.7)  
;

  // Add the polylines between chart and labels:
arcs.append("g:polyline")
    .attr("stroke", "black")
    .style("fill", "none")
    .attr("stroke-width", "1px")
    .attr('points', function(d) {
      var posA = arc.centroid(d) // line insertion in the slice
      var posB = outerArc.centroid(d) + 5 // line break: we use the other arc generator that has been built only for that
      var posC = outerArc.centroid(d) + 5; // Label position = almost the same as posB
      var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
      posC[0] = r * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
      return [posA, posB, posC]
    });
  
    //Add text labels

    arcs.append("g:label")
      .attr('transform', function(d) {
      var pos = outerArc.centroid(d);
      var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
      pos[0] = r * 0.99 * (midangle < Math.PI ? 1 : -1);
      return 'translate(' + pos + ')';
      })
      .style('text-anchor', function(d) {
      var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
      return (midangle < Math.PI ? 'start' : 'end')
       })
      .text(function(d) { return d.text; }); //this is where the problem is!
    

Upvotes: 2

Views: 120

Answers (1)

Michael Rovinsky
Michael Rovinsky

Reputation: 7210

Here is how you can add labels:

arcs.append('text')
  .text(d => d.data.text)
  .attr('dy', 4)
  .attr('text-anchor', d => (d.startAngle + d.endAngle) / 2 > Math.PI ? 'end' : 'start')
  .attr('x', d => outerArc.centroid(d)[0])
  .attr('y', d => outerArc.centroid(d)[1]);

var margin = {top: 10, right: 30, bottom: 30, left: 60},
    width = 750 - margin.left - margin.right,
    height = 520 - margin.top - margin.bottom;

var r = height/3;

var aColor = [
    '#0652DD',
    '#C4E538',
    '#F79F1F', 
    '#5758BB',
    '#D980FA',
    "#EA2027"
]

var piedata = [
    {text:"Facebook", "value":76}, 
    {text:"Website", "value":13},
    {text:"HardwareZone", "value":4}, 
    {text:"YouTube", "value":5},
    {text:"Instagram", "value":1},
    {text:"Twitter","value":1},
];

var vis = d3.select('#chart2')
.append("svg:svg")
.data([piedata])
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");


var pie = d3.layout.pie().sort(null).value(function(d){return d.value;});

// Declare an arc generator function
var arc = d3.svg.arc().innerRadius(r *0.5).outerRadius(r*0.8);

var outerArc = d3.svg.arc()
              .innerRadius(r*0.95)
              .outerRadius(r*1.1);

// Select paths, use arc generator to draw
var arcs = vis.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class", "slice").attr("transform", "translate("  + width/2 + "," + height/2 + ")");

arcs.append("g:path")
    .attr("fill", function(d, i){return aColor[i];})
    .attr("d", function (d) {return arc(d);})
    .attr("stroke", "white")
    .style("stroke-width", "3px")
    .style("opacity", 0.7)  
;

  // Add the polylines between chart and labels:
arcs.append("g:polyline")
    .attr("stroke", "black")
    .style("fill", "none")
    .attr("stroke-width", "1px")
    .attr('points', function(d) {
      var posA = arc.centroid(d) // line insertion in the slice
      var posB = outerArc.centroid(d) + 5 // line break: we use the other arc generator that has been built only for that
      var posC = outerArc.centroid(d) + 5; // Label position = almost the same as posB
      var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
      posC[0] = r * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
      return [posA, posB, posC]
    });
  
    //Add text labels
    arcs.append('text')
        .text(d => d.data.text)
      .attr('dy', 4)
      .each(d => console.log(d))
      .attr('text-anchor', d => (d.startAngle + d.endAngle) / 2 > Math.PI ? 'end' : 'start')
      .attr('x', d => outerArc.centroid(d)[0])
      .attr('y', d => outerArc.centroid(d)[1]);
      
text {
  font-size: 16px;
  font-family: "Ubuntu";
  fill: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<div id="chart2" />

Upvotes: -2

Related Questions