I'm trying to create a static d3 donut chart with labels and connectors from a json object. I've been able to get it to work with an array in this fiddle but can't get the connectors or label text to appear with the data object that I need.
The donut chart is working and the labels are appearing with the percentages, but I need them to appear with the labels and connectors. I think that it has something to do with the way that I am trying to map the connectors but can't figure out the error.
Code is below and also here is a link to a working fiddle: https://jsfiddle.net/hef1u71o/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
var data = [{
percentage: 19,
label: 'Consulting'
},{
percentage: 3,
label: 'Consumer Goods'
},{
percentage: 5,
label: 'Energy/Chemical/Gas'
},{
percentage: 3,
label: 'Entrepreneurship'
},{
percentage: 1,
label: 'Environment & Sustainability'
},{
percentage: 19,
label: 'Financial Services'
},{
percentage: 3,
label: 'General Management'
},{
percentage: 6,
label: 'Government'
},{
percentage: 7,
label: 'Hospital/Health Care/Health Services'
},{
percentage: 2,
label: 'Human Resources'
},{
percentage: 4,
label: 'IT'
},{
percentage: 2,
label: 'International Development'
},{
percentage: 3,
label: 'Manufacturing/Operations'
},{
percentage: 4,
label: 'Marketing/PR/Advertising'
},{
percentage: 1,
label: 'Media/Sports/Entertainment'
},{
percentage: 7,
label: 'Nonprofit/Education/Special Org.'
},{
percentage: 6,
label: 'Other'
},{
percentage: 2,
label: 'Research & Development'
},{
percentage: 4,
label: 'Sales/Business Development'
},];
var width = 300,
height = 300,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#243668", "#2b7eb4", "#186b97", "#6391a1", "#d2c5b7", "#9c9286", "#5b5b59"]);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.percentage; });
var arc = d3.svg.arc()
.innerRadius(radius - 100)
.outerRadius(radius - 50);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var path = svg.selectAll("path")
.data(pie(data))
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("d", arc);
svg.selectAll("text").data(pie(data))
.enter()
.append("text")
.attr("text-anchor", "middle")
.attr("x", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cx = Math.cos(a) * (radius - 75);
return d.x = Math.cos(a) * (radius - 20);
})
.attr("y", function(d) {
var a = d.startAngle + (d.endAngle - d.startAngle)/2 - Math.PI/2;
d.cy = Math.sin(a) * (radius - 75);
return d.y = Math.sin(a) * (radius - 20);
})
.text(function(d) { return d.value; })
.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;
});
svg.append("defs").append("marker")
.attr("id", "circ")
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("refX", 3)
.attr("refY", 3)
.append("circle")
.attr("cx", 3)
.attr("cy", 3)
.attr("r", 3);
svg.selectAll("path.pointer").data(pie(data)).enter()
.append("path")
.attr("class", "pointer")
.style("fill", "none")
.style("stroke", "black")
.attr("marker-end", "url(#circ)")
.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" + d.sx + "," + d.sy + " " + d.cx + "," + d.cy;
}
});
</script>
</body>
</html>
Save your data into variable:
And use this variable here:
and here:
It's important because of you extend the data (see
each
method). You will use extended properties for calculating of connectors position and you should use the same dataset for both cases.Check working demo.