Reputation: 3
I am new to writing JS/jquery and looking to build a doughnut charts.js chart with two lines of text: a larger size percentage on top and a smaller text only 'category' on the bottom as in the image below.
I have had limited success with the code below taken from a fiddle link found on another similar stackoverflow post https://jsfiddle.net/cmyker/ooxdL2vj/
Struggling to understand how to have two lines of responsive text. Ex. getting the "prepaid" to scale without affecting the size of the percentage text above. Any help is greatly appreciated.
HTML:
<canvas id="myChart"> </canvas>
Code:
Chart.pluginService.register({
beforeDraw: function (chart) {
if (chart.config.options.elements.center) {
//Get ctx from string
var ctx = chart.chart.ctx;
//Get options from the center object in options
var centerConfig = chart.config.options.elements.center;
var fontStyle = centerConfig.fontStyle || 'Arial';
var txt = centerConfig.text;
var txtB = centerConfig.textB;
var color = centerConfig.color || '#000';
var sidePadding = centerConfig.sidePadding || 20;
var sidePaddingCalculated = (sidePadding/100) * (chart.innerRadius * 2)
//Start with a base font of 30px
ctx.font = "30px " + fontStyle;
//Get the width of the string and also the width of the element minus 10 to give it 5px side padding
var stringWidth = ctx.measureText(txt).width;
var elementWidth = (chart.innerRadius * 2) - sidePaddingCalculated;
// Find out how much the font can grow in width.
var widthRatio = elementWidth / stringWidth;
var newFontSize = Math.floor(30 * widthRatio);
var elementHeight = (chart.innerRadius * 2);
// Pick a new font size so it will not be larger than the height of label.
var fontSizeToUse = Math.min(newFontSize, elementHeight);
//Set font settings to draw it correctly.
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
var centerX = ((chart.chartArea.left + chart.chartArea.right) / 2);
var centerY = ((chart.chartArea.top + chart.chartArea.bottom) / 2);
ctx.font = fontSizeToUse+"px " + fontStyle;
ctx.fillStyle = color;
//Draw text in center
ctx.fillText(txt, centerX, centerY);
}
}
});
var config = {
type: 'doughnut',
data: {
labels: [
"Red",
"Green",
"Yellow"
],
datasets: [{
data: [300, 50, 100],
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
},
options: {
legend: {
display: false},
cutoutPercentage: 70,
aspectRatio: 1.5,
elements: {
center: {
text: '80%' ,
color: 'black', // Default is #000000
fontStyle: 'Arial', // Default is Arial
sidePadding: 20 // Defualt is 20 (as a percentage)
}
}
}
};
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, config);
Upvotes: 0
Views: 1015
Reputation: 26150
If I use your sample chart as a template, this can be done with the following code.
Chart.pluginService.register({
beforeDraw: (chart) => {
let ctx = chart.chart.ctx;
ctx.save();
let fontSize = (chart.chart.height / 75).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
let text = chart.data.datasets[0].data[0] + '%';
let textX = Math.round((chart.chart.width - ctx.measureText(text).width) / 2);
let textY = chart.chart.height / 2.25;
ctx.fillText(text, textX, textY);
fontSize = (chart.chart.height / 124).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
text = chart.data.labels[0];
textX = Math.round((chart.chart.width - ctx.measureText(text).width) / 2);
textY = chart.chart.height / 1.6;
ctx.fillText(text, textX, textY);
ctx.restore();
}
});
var config = {
type: 'doughnut',
data: {
labels: ["Prepaid", "Others"],
datasets: [{
data: [90.8, 9.2],
backgroundColor: ["yellow", "white" ]
}]
},
options: {
legend: {
display: false
},
tooltips: {
enabled: false
},
cutoutPercentage: 80,
aspectRatio: 5,
rotation: 70
}
};
var ctx = document.getElementById("myChart").getContext("2d");
var myChart = new Chart(ctx, config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart"> </canvas>
Upvotes: 1