Reputation: 53
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
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