This is the second “Animal Donut Chart” example of the Blog Placing Texts on Arcs with D3.js in which the texts are placed along arcs and they are centered. All without writing the SVG path notations yourself.
Other examples of text along a path from the same blog
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Donut Chart - Centered Labels</title>
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<!-- Month names -->
<link href='//fonts.googleapis.com/css?family=Pacifico' rel='stylesheet' type='text/css'>
<style>
body {
font-family: 'Pacifico', sans-serif;
fill: #333333;
font-size: 16px;
text-align: center;
}
</style>
</head>
<body>
<div id="chart"></div>
<script>
////////////////////////////////////////////////////////////
//////////////////////// Set-up ////////////////////////////
////////////////////////////////////////////////////////////
var screenWidth = window.innerWidth;
var margin = {left: 20, top: 20, right: 20, bottom: 20},
width = Math.min(screenWidth, 500) - margin.left - margin.right,
height = Math.min(screenWidth, 500) - margin.top - margin.bottom;
var svg = d3.select("#chart").append("svg")
.attr("width", (width + margin.left + margin.right))
.attr("height", (height + margin.top + margin.bottom))
.append("g").attr("class", "wrapper")
.attr("transform", "translate(" + (width / 2 + margin.left) + "," + (height / 2 + margin.top) + ")");
//////////////////////////////////////////////////////////////
///////////////////// Data & Scales /////////////////////////
//////////////////////////////////////////////////////////////
//Some random data
var donutData = [
{name: "Antelope", value: 15},
{name: "Bear", value: 9},
{name: "Cheetah", value: 19},
{name: "Dolphin", value: 12},
{name: "Elephant", value: 14},
{name: "Flamingo", value: 21},
{name: "Giraffe", value: 18},
{name: "Other", value: 8}
];
//Create a color scale
var colorScale = d3.scale.linear()
.domain([1,3.5,6])
.range(["#2c7bb6", "#ffffbf", "#d7191c"])
.interpolate(d3.interpolateHcl);
//Create an arc function
var arc = d3.svg.arc()
.innerRadius(width*0.75/2)
.outerRadius(width*0.75/2 + 30);
//Turn the pie chart 90 degrees counter clockwise, so it starts at the left
var pie = d3.layout.pie()
.startAngle(-90 * Math.PI/180)
.endAngle(-90 * Math.PI/180 + 2*Math.PI)
.value(function(d) { return d.value; })
.padAngle(.01)
.sort(null);
//////////////////////////////////////////////////////////////
//////////////////// Create Donut Chart //////////////////////
//////////////////////////////////////////////////////////////
//Create the donut slices and also the invisible arcs for the text
svg.selectAll(".donutArcSlices")
.data(pie(donutData))
.enter().append("path")
.attr("class", "donutArcSlices")
.attr("d", arc)
.style("fill", function(d,i) {
if(i === 7) return "#CCCCCC"; //Other
else return colorScale(i);
})
.each(function(d,i) {
//A regular expression that captures all in between the start of a string (denoted by ^) and a capital letter L
//The letter L denotes the start of a line segment
//The "all in between" is denoted by the .+?
//where the . is a regular expression for "match any single character except the newline character"
//the + means "match the preceding expression 1 or more times" (thus any single character 1 or more times)
//the ? has to be added to make sure that it stops at the first L it finds, not the last L
//It thus makes sure that the idea of ^.*L matches the fewest possible characters
//For more information on regular expressions see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
var firstArcSection = /(^.+?)L/;
//Grab everything up to the first Line statement
//The [1] gives back the expression between the () (thus not the L as well) which is exactly the arc statement
var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1];
//Replace all the comma's so that IE can handle it -_-
//The g after the / is a modifier that "find all matches rather than stopping after the first match"
newArc = newArc.replace(/,/g , " ");
//Create a new invisible arc that the text can flow along
svg.append("path")
.attr("class", "hiddenDonutArcs")
.attr("id", "donutArc"+i)
.attr("d", newArc)
.style("fill", "none");
});
//Append the label names on the outside
svg.selectAll(".donutText")
.data(donutData)
.enter().append("text")
.attr("class", "donutText")
.attr("dy", -13)
.append("textPath")
.attr("startOffset","50%")
.style("text-anchor","middle")
.attr("xlink:href",function(d,i){return "#donutArc"+i;})
.text(function(d){return d.name;});
</script>
</body>
</html>