D3.js Pie Chart with labels

A simple Pie with labels and debugging info.

by Saurabh Khemka

HTML

<script src="https://raw.github.com/mbostock/d3/master/d3.v2.js"></script>
<div id="pie"></div>

CSS

.slice {
    stroke: #fff;
    stroke-width: 1px;
}

JavaScript

var sourceData = [ 50, 40, 40, 30, 5, 4, 3, 2, 1, 1],
    width = 500,
    height = 500,
    radius = 200,
    labelRadius = 220;



var vis = d3.select('#pie').append('svg')
    .attr('width', width)
    .attr('height', height)
    // create a group to center pie chart
    .append('g')
    .attr('transform', 'translate(' + width/2 + ',' + height/2 + ')');

// Use the pie layout helper to create the pie slices
var pie = d3.layout.pie();

// Color helper for the fill colors
var color = d3.scale.category10();

// Arc is used to generate the path shape with the slices
var arc = d3.svg.arc()
    .innerRadius(0)
    .outerRadius(radius);

// Create the slices group to hold the slice shape and label
var slices = vis
    .selectAll('g.slice-group')
    // wrap the data with the pie which calculates the start and end angles
    .data(pie(sourceData))
    .enter()
      .append('g')
      .attr('class', 'slice-group');

// The slices
slices
    .append('path')
    .attr('class', 'slice')
    .attr('d', arc) // The shape is created by the arc and pie helpers
    .attr('fill', function(d, i) { return color(i); });

// The labels
var total = d3.sum(sourceData);

slices
    .append('text')
    // d.data is the original datum remember the data is wrapped in the pie helper
    .text(function(d) { return Math.round(d.data*100/total) + '%'; })
    // Move the labels to the outside
    .each(function(d) {
        // Get the center of the slice and then move the label out
        var center = arc.centroid(d), // gives you the center point of the slice
            x = center[0],
            y = center[1],
            h = Math.sqrt(x*x + y*y),
            lx = x/h * labelRadius,
            ly = y/h * labelRadius;
        
        d3.select(this)
            .attr('y', ly)
            .attr('x', lx)
            .style('text-anchor', ((d.endAngle - d.startAngle)*0.5 + d.startAngle > Math.PI) ? 'end' : 'start');
    })
    // For demenstration, the labels without enough room will be...