3👍
✅
Your idea is actually quite good, but as you declared in your question, it won’t be dynamic and then won’t work with every chart of this type.
A way to make it dynamic is to use Chart.js plugins where the beforeInit
event will be handled to edit the data to fit your percentage problem, and where the afterDraw
event will be handled to write the percentage over the bar :
Chart.pluginService.register({
// This event helps to edit the data in our datasets to fit a percentage scale
beforeInit: function(chartInstance) {
// We first get the total of datasets for every data
var totals = [];
chartInstance.data.datasets.forEach(function(dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var total = 0;
chartInstance.data.datasets.forEach(function(dataset) {
total += dataset.data[i];
});
totals.push(total);
}
});
// And use it to calculate the percentage of the current data
chartInstance.data.datasets.forEach(function(dataset) {
for (var i = 0; i < dataset.data.length; i++) {
// This ----------¬ is useful to add it as a string in the dataset
// It solves V the problem of values with `.0` at decimals
dataset.data[i] = '' + (dataset.data[i] / totals[i]) * 100;
}
});
},
// This event allows us to add the percentage on the bar
afterDraw: function(chartInstance) {
// We get the canvas context
var ctx = chartInstance.chart.ctx;
// And set the properties we need
ctx.font = Chart.helpers.fontString(14, 'bold', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = '#666';
// For every dataset ...
chartInstance.data.datasets.forEach(function(dataset) {
// If it is not the first dataset, we return now (no action)
if (dataset._meta[0].controller.index != 0) return;
// For ervery data in the dataset ...
for (var i = 0; i < dataset.data.length; i++) {
// We get the model of the data
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
// And use it to display the text where we want
ctx.fillText(parseFloat(dataset.data[i]).toFixed(2) + "%", ((model.base + model.x) / 2), (model.y + model.height / 3));
}
});
}
});
You can see this code working on this jsFiddle and here is its result :
Source:stackexchange.com