I have a chartjs doughnut that I want to have text inside the ring/middle of it. I have created/registered a plugin for it.
If I hardcode the value it will work. If I pass a value from the doughnut chart to the plugin, I can see the plugin has that value, but becomes undefined during later stage at runtime. I added a conditional, but does not give any effect.
My plugin;
ChartJS.register({
id: "doughnutInnerText",
beforeDraw: (chart, args, options) => {
const width = chart.width,
height = chart.height,
ctx = chart.ctx;
ctx.restore();
const fontSize = (height / 160).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "top";
const espnVal = chart.options.plugins.doughnutInnerText.myVal; //works if its hardcoded, otherwise will have a value but will become undefined later on
if (espnVal) {
const textX = Math.round((width - ctx.measureText(espnVal).width) / 2),
textY = height / 2.2;
ctx.fillText(espnVal, textX, textY);
}
ctx.save();
},
});
Inside the chartJS chart itself, under plugin I have:
doughnutInnerText: {
espnVal: "My Text",
},
if I would log it inside the plugin it would look something like this
console.log(chart.options.plugins.doughnutInnerText.myVal) //"My Text"
console.log(chart.options.plugins.doughnutInnerText.myVal) //"My Text"
console.log(chart.options.plugins.doughnutInnerText.myVal) //"My Text"
console.log(chart.options.plugins.doughnutInnerText.myVal) //"undefined"
My full chartjs code (yes, have tried to remove the destroy() without noticing any improvements
const config = {
type: "doughnut",
data: data,
options: {
plugins: {
doughnutInnerText: {
espnVal: "My Text",
},
legend: {
position: "top",
labels: {
font: {
size: 66,
},
},
},
},
animation: {
onComplete: () => {
const canvas = chart.canvas;
const img = canvas.toDataURL("image/png", 1);
this.modifyCardURL(this.state.adaptiveCard, img);
//delete chart from DOM after we get the Base64 value
chart.destroy();
},
},
},
};
const ctx = document.createElement("canvas");
ctx.style.display = "none";
//since we are not rendering the chart, we have to manually add it to the DOM
document.documentElement.appendChild(ctx);
const chart = new Chart(ctx, config as any);
chart.render();
}
2 thins, you configure your plugin to listen to the value myVal
while you configure it in your options as espnVal
so you need to read that. Also it is better practice to use the options object since it is the object of your plugin options so you dont need to drill through the entire chart path.
With that you will get this:
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.2.1"></script>
<canvas id="myChart"></canvas>
<style>
#myChart {
width: 400px;
height: 400px;
}
</style>
<script>
Chart.register({
id: "doughnutInnerText",
beforeDraw: (chart, args, options) => {
const width = chart.width,
height = chart.height,
ctx = chart.ctx;
ctx.restore();
const fontSize = (height / 160).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "top";
const espnVal = options.espnVal; //works if its hardcoded, otherwise will have a value but will become undefined later on
if (espnVal) {
const textX = Math.round((width - ctx.measureText(espnVal).width) / 2),
textY = height / 2.2;
ctx.fillText(espnVal, textX, textY);
}
ctx.save();
},
});
const data = {
labels: ["hello", "world", "!"],
datasets: [{
data: [2, 5, 6]
}]
};
// Chart options
const options = {
plugins: {
doughnutInnerText: {
espnVal: "My Text",
}
}
};
// Create the chart
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'doughnut',
data: data,
options: options
});
</script>