Alex K
Alex K

Reputation: 3

Adding responsive text inside chart in Charts Js

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.

Sample Chart

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

Answers (1)

uminder
uminder

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

Related Questions