Reputation: 2342
See image below, I'm trying to set the value of each bar in the center of my stacked bar; so far I only got on the top and sometimes the position is off (see the 4% yellow in the third bar)
This is the code:
context.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
var textY = model.y + 50;
if ((scale_max - model.y) / scale_max >= 0.5)
textY = model.y + 20;
fadeIn(ctx, dataset.data[i], model.x, textY, model.y > topThreshold, step);
}
});
var fadeIn = function(ctx, obj, x, y, black, step) {
var ctx = modifyCtx(ctx);
var alpha = 0;
ctx.fillStyle = black ? 'rgba(' + outsideFontColor + ',' + step + ')' : 'rgba(' + insideFontColor + ',' + step + ')';
ctx.fillText(obj.toString() + "%", x, y);
};
Upvotes: 1
Views: 1055
Reputation: 26150
This can be done with the Plugin Core API. The API offers different hooks that may be used for executing custom code (that's probably what you already do). In your case, you can use the afterDraw
hook as follows to draw text at the desired positions.
afterDraw: chart => {
let ctx = chart.chart.ctx;
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = "12px Arial";
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
let datasets = chart.chart.data.datasets.filter(ds => !ds._meta[0].hidden);
xAxis.ticks.forEach((value, xIndex) => {
let x = xAxis.getPixelForTick(xIndex);
datasets.forEach((dataset, iDataset) => {
if (dataset.data[xIndex] > 3) {
let yValue = datasets.slice(0, iDataset)
.map(ds => ds.data[xIndex])
.reduce((a, b) => a + b, 0) +
dataset.data[xIndex] / 2;
let y = yAxis.getPixelForValue(yValue);
ctx.fillStyle = dataset.textColor;
ctx.fillText(dataset.data[xIndex] + '%', x, y);
}
});
});
ctx.restore();
}
Please take a look at below runnable code and see how it works.
const chart = new Chart('myChart', {
type: 'bar',
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = "12px Arial";
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
let datasets = chart.chart.data.datasets.filter(ds => !ds._meta[0].hidden);
xAxis.ticks.forEach((value, xIndex) => {
let x = xAxis.getPixelForTick(xIndex);
datasets.forEach((dataset, iDataset) => {
if (dataset.data[xIndex] > 3) {
let yValue = datasets.slice(0, iDataset)
.map(ds => ds.data[xIndex])
.reduce((a, b) => a + b, 0) +
dataset.data[xIndex] / 2;
let y = yAxis.getPixelForValue(yValue);
ctx.fillStyle = dataset.textColor;
ctx.fillText(dataset.data[xIndex] + '%', x, y);
}
});
});
ctx.restore();
}
}],
data: {
labels: ['A', 'B', 'C', 'D', 'E'],
datasets: [{
label: 'Dataset 1',
data: [2.5, 48, 9, 17, 23],
backgroundColor: 'red',
textColor: 'white'
}, {
label: 'Dataset 2',
data: [2.5, 4, 4, 11, 11],
backgroundColor: 'orange',
textColor: 'black'
}, {
label: 'Dataset 3',
data: [95, 48, 87, 72, 66],
backgroundColor: 'green',
textColor: 'white'
}]
},
options: {
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true,
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="myChart" height="160"></canvas>
Upvotes: 1