Donut with labels

by Rob Carroll

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.js"></script>

JavaScript

var data = [
    {name: "abolitionist-all", val: 98},  
    {name: "abolitionist-ordinary", val: 7}, 
    {name: "abolitionist-practice", val: 35},
    {name: "retentionist", val: 58}
];

var w = 400,
    h = 400,
    r = Math.min(w, h) / 2,
    labelr = r + 1000, // radius for label anchor
    donut = d3.layout.pie(),
    arc = d3.svg.arc().innerRadius(r*.5).outerRadius(r);

var color = d3.scale.ordinal()
 .domain(["abolitionist-all","abolitionist-ordinary","abolitionist-practice","retentionist"])
 .range(["#FFFF00", "#515151", "#808080", "#000000"]);

var vis = d3.select("body")
  .append("svg:svg")
    .data([data])
    .attr("width", w +150)
    .attr("height", h);

var arcs = vis.selectAll("g.arc")
    .data(donut.value(function(d) { return d.val }))
    .enter().append("svg:g")
    .attr("class", "arc")
    .attr("transform", "translate(" + (r + 30) + "," + r + ")");

arcs.append("svg:path")
    .attr("fill", function(d, i) { return color(i); })
    .attr("d", arc);

arcs.append("text")
    .attr("text-anchor", "end")
    .attr("x", function(d) {
        var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
        d.cx = Math.cos(a) * (r - 45);
        return d.x = Math.cos(a) * (r+30);
    })
    .attr("y", function(d) {
        var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
        d.cy = Math.sin(a) * (r - 45);
        return d.y = Math.sin(a) * (r+30);
    })
    .text(function(d) { 
    	return d.value.toFixed(2);  
    })
    
    .each(function(d) {
        var bbox = this.getBBox();
        d.sx = d.x - bbox.width/2 - 2;
        d.ox = d.x + bbox.width/2 + 2;
        d.sy = d.oy = d.y + 5;
    });


arcs.append("path")
    .attr("class", "pointer")
    .style("fill", "none")
    .style("stroke", "black")
    .attr("d", function(d) {
        if(d.cx > d.ox) {
            return "M" + d.sx + "," + d.sy + "L" + d.ox + "," + d.oy + " " + d.cx + "," + d.cy;
        } else {
            return "M" + d.ox + "," + d.oy + "L"...