Looking through the advanced tooltips and legend configuration for chart.js, I am not sure how to achieve the following label style for my charts.
How can I output my numbers for each section of this donut chart and connect those numbers to each segment of the chart?
If it's not possible with Chart.js, then can anyone point me to a chart library that will allow me to do this?
new Chart(document.querySelector('#chart'), {
type: 'doughnut',
data: {
labels: [
'Red',
'Blue',
'Yellow'
],
datasets: [{
data: [300, 50, 100],
backgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56'
],
hoverBackgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56'
]
}]
},
options: {
legend: {
display: false
}
}
});
<script src=".js/2.3.0/Chart.bundle.min.js"></script>
<canvas id="chart" width="400" height="400"/>
Looking through the advanced tooltips and legend configuration for chart.js, I am not sure how to achieve the following label style for my charts.
How can I output my numbers for each section of this donut chart and connect those numbers to each segment of the chart?
If it's not possible with Chart.js, then can anyone point me to a chart library that will allow me to do this?
new Chart(document.querySelector('#chart'), {
type: 'doughnut',
data: {
labels: [
'Red',
'Blue',
'Yellow'
],
datasets: [{
data: [300, 50, 100],
backgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56'
],
hoverBackgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56'
]
}]
},
options: {
legend: {
display: false
}
}
});
<script src="https://cdnjs.cloudflare./ajax/libs/Chart.js/2.3.0/Chart.bundle.min.js"></script>
<canvas id="chart" width="400" height="400"/>
Share
Improve this question
asked Oct 2, 2016 at 11:33
James CraigJames Craig
6,86410 gold badges48 silver badges77 bronze badges
2 Answers
Reset to default 3I find that chartjs is difficult to work with (but it's nice in a pinch). You could try D3, which is highly customisable. It creates charts using svgs instead of canvas so the elements are a easier to access and work with.
Here's the code, but it won't run in situ as it requires an external CSV file with the data, and a webserver to prevent CORs errors. Here's the CSV for your data (data.csv):
percentage_label,percentage
19,19
10,10
32,32
39,39
var width = 960,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.ordinal()
.range(["#fdb92e", "#c02f8e", "#1aaaa9", "#ffffff"]);
var arc = d3.svg.arc()
.outerRadius(radius - 70)
.innerRadius(radius - 180);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) { return d.population; });
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
d3.csv("data.csv", type, function(error, data) {
if (error) throw error;
var g = svg.selectAll(".arc")
.data(pie(data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("fill", function(d) { return color(d.data.percentage_label); })
.style("stroke-width","0px");
g.append("text")
.attr("transform", function(d) {
return "translate(" + ( (radius + 30) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) + ", " + ( -1 * (radius - 10) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +")";})
.attr("dy", ".5em")
.style("fill","#ffffff")
.style("font-size","40px")
.text(function(d) { return (d.data.percentage_label + "%"); });
g.append("circle")
.attr("transform", function(d) {return "translate(" + arc.centroid(d) + ")";})
.attr("r", 5)
.style("fill","#ffffff");
g.append("circle")
.attr("transform", function(d) {return "translate(" + ( (radius - 20) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) + ", " + ( -1 * (radius - 50) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) ) +")";})
.attr("r", 5)
.style("fill","#ffffff");
function lineCoordinates(d,x) {
/* x: coordinate to return */
//not the most efficient method
var pa = [];
var p1 = arc.centroid(d);
pa.push(p1[0]);
pa.push(p1[1]);
pa.push( (radius - 20) * Math.sin( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) );
pa.push( -1 * (radius - 50) * Math.cos( ((d.endAngle - d.startAngle) / 2) + d.startAngle ) );
return pa[x];
}
g.append("line")
.style("stroke","white")
.style("stroke-width","2px")
.attr("x1",function(d) { return lineCoordinates(d,0);})
.attr("y1", function(d) { return lineCoordinates(d,1);})
.attr("x2", function(d) { return lineCoordinates(d,2);})
.attr("y2", function(d) { return lineCoordinates(d,3);});
});
function type(d) {
d.population = +d.percentage_label;
return d;
}
body {
background-color: #F68135;
}
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
<script src="https://cdnjs.cloudflare./ajax/libs/d3/3.4.11/d3.min.js"></script>
My result is fairly close:
Here are the modifications I made to the basic D3 doughnut chart (based on this example: https://bl.ocks/mbostock/3887193):
- changed inner and out radiuses (radii?)
- changed colours (this is the scale.ordinal part)
- added styles for the labels
- moved the labels out from the centers of the segments (as there is some arc math involved, this was helpful: Label outside arc (Pie chart) d3.js)
- added a pair of circles for the endpoints of the callout lines
- added lines for the callouts
- added a small function (lineCoordinates) to make the positioning math a little easier to deal with
I'm sure this could all be trimmed up and made a little more efficient. I'd also remend making the segment colours different from the label/callout colours (that one callout get's lost on the last segment).
I don't have the same label font, but because this is done using SVGs you can easily change the font with styles. That's not the case with Chartjs (I ran into the same problem when I tried to modify label styles in Chartjs).
D3 has a steeper learning curve than Chartjs, but once you get the hang of it, you can do pretty much anything graph related with it.Official site is here https://d3js/
Custom positioning of individual point labels is possible with Charts.js Data Labels Plugin.
Source: https://github./chartjs/chartjs-plugin-datalabels
The radial positioning is illustrated here: https://chartjs-plugin-datalabelslify./guide/positioning.html