Chart.js 2.0 doughnut tooltip percentages
Update: The below answer shows a percentage based on total data but @William Surya Permana
has an excellent answer that updates based on the shown data https://stackoverflow.com/a/49717859/2737978
In options
you can pass in a tooltips
object (more can be read at the chartjs docs)
A field of tooltips
, to get the result you want, is a callbacks
object with a label
field. label
will be a function that takes in the tooltip item which you have hovered over and the data which makes up your graph. Just return a string, that you want to go in the tooltip, from this function.
Here is an example of what this can look like
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
//get the concerned dataset
var dataset = data.datasets[tooltipItem.datasetIndex];
//calculate the total of this data set
var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue;
});
//get the current items value
var currentValue = dataset.data[tooltipItem.index];
//calculate the precentage based on the total and current item, also this does a rough rounding to give a whole number
var percentage = Math.floor(((currentValue/total) * 100)+0.5);
return percentage + "%";
}
}
}
and a full example with the data you provided
fiddle
var randomScalingFactor = function() {
return Math.round(Math.random() * 100);
};
var randomColorFactor = function() {
return Math.round(Math.random() * 255);
};
var randomColor = function(opacity) {
return 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',' + (opacity || '.3') + ')';
};
var config = {
type: 'doughnut',
data: {
datasets: [{
data: [
486.5,
501.5,
139.3,
162,
263.7,
],
backgroundColor: [
"#F7464A",
"#46BFBD",
"#FDB45C",
"#949FB1",
"#4D5360",
],
label: 'Expenditures'
}],
labels: [
"Hospitals: $486.5 billion",
"Physicians & Professional Services: $501.5 billion",
"Long Term Care: $139.3 billion",
"Prescription Drugs: $162 billion",
"Other Expenditures: $263.7 billion"
]
},
options: {
responsive: true,
legend: {
position: 'bottom',
},
title: {
display: false,
text: 'Chart.js Doughnut Chart'
},
animation: {
animateScale: true,
animateRotate: true
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var dataset = data.datasets[tooltipItem.datasetIndex];
var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue;
});
var currentValue = dataset.data[tooltipItem.index];
var percentage = Math.floor(((currentValue/total) * 100)+0.5);
return percentage + "%";
}
}
}
}
};
var ctx = document.getElementById("chart-area").getContext("2d");
window.myDoughnut = new Chart(ctx, config); {
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.bundle.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="canvas-holder" style="width:75%">
<canvas id="chart-area" />
</div>
In 3.5 it will be:
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context){
var data = context.dataset.data,
label = context.label,
currentValue = context.raw,
total = 0;
for( var i = 0; i < data.length; i++ ){
total += data[i];
}
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return label + ": " +currentValue + ' (' + percentage + '%)';
}
}
}
}
}
but better, dynamic version:
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context){
var label = context.label,
currentValue = context.raw,
total = context.chart._metasets[context.datasetIndex].total;
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return label + ": " +currentValue + ' (' + percentage + '%)';
}
}
}
}
}
For those who want to display dynamic percentages based on what currently displayed on the chart (not based on total data), you can try this code:
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var dataset = data.datasets[tooltipItem.datasetIndex];
var meta = dataset._meta[Object.keys(dataset._meta)[0]];
var total = meta.total;
var currentValue = dataset.data[tooltipItem.index];
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return currentValue + ' (' + percentage + '%)';
},
title: function(tooltipItem, data) {
return data.labels[tooltipItem[0].index];
}
}
},
I came across this question because I needed to show percentage on stacked bar charts. The percentage I needed was per stacked columns. I accomplished this by modifying Willian Surya's answer like this:
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var index = tooltipItem.index;
var currentValue = data.datasets[tooltipItem.datasetIndex].data[index];
var total = 0;
data.datasets.forEach(function(el){
total = total + el.data[index];
});
var percentage = parseFloat((currentValue/total*100).toFixed(1));
return currentValue + ' (' + percentage + '%)';
},
title: function(tooltipItem, data) {
return data.datasets[tooltipItem[0].datasetIndex].label;
}
}
}
This is the final result: