ChartJS Customised tooltip and LegendText not displaying after version update

144 views Asked by At

Earlier i was using 2.7.2 version of ChartJS, now im updating to 4.4.1 So in my chart i was creating customized tooltip and customized Legend text but after version update both are not working

Here is the screenshot of 2.7.2 version :

DonutChart with LegendText and Tooltip

I want Legend text and tooltip like this but now using 4.4.1 and unable to display like this

Below is my code : `new Chart(document.getElementById('donutChart'), { type: 'doughnut',

data: {
    labels: ['Red', 'Blue', 'Green', 'Teal', 'Yellow'],
    datasets: [{
        data: [123, 321, 213, 111, 222],
        backgroundColor: ['Red', 'Blue', 'Green', 'Teal', 'Yellow'],
        hoverOffset: 4
    }]
},
options: {
    plugins: {
        datalabels: {
            color: 'white',
            font: {
                weight: 'bold'
            },
        },
    },
    tooltips: {
        callbacks: {
            title: function(tooltipItem, data) {
                return data['labels'][tooltipItem[0]['index']];
            },
            label: function(tooltipItem, data) {
                return data['datasets'][0]['data'][tooltipItem['index']];
            },
            afterLabel: function(tooltipItem, data) {
                var dataset = data['datasets'][0];
                var total = dataset.data.reduce((a, b) => a + b, 0);
                var percent = Math.round((dataset['data'][tooltipItem['index']] / total) * 100);
                return '(' + percent + '%)';
            }
        },
        backgroundColor: '#FFF',
        titleFontSize: 14,
        titleFontColor: 'black',
        bodyFontColor: '#000',
        bodyFontSize: 14,
        displayColors: false
    },
    maintainAspectRatio: false,
    legend: { position: 'bottom' },
},
plugins: [{
    afterLayout: function(chart) {
        let total = chart.data.datasets[0].data.reduce((a, b) => {
            return a + b;
        });
        chart.legend.legendItems.forEach(
            (label) => {
                let value = chart.data.datasets[0].data[label.index];
                label.text = value + ' | ' + label.text + ' | ' + (value / total * 100).toFixed(0) + '%';
                return label.text;
            }
        )
    }
}],

});`

During debugging, I can observe that the label.text values are correct, but they are not displaying as intended.

1

There are 1 answers

5
FiddlingAway On BEST ANSWER

You can do it like this.

Chart.register(ChartDataLabels);

var chart = new Chart(document.getElementById('donutChart'), {
    type: 'doughnut',
    data: {
        labels: ['Red', 'Blue', 'Green', 'Teal', 'Yellow'],
        datasets: [{
            data: [123, 321, 213, 111, 222],
            backgroundColor: ['Red', 'Blue', 'Green', 'Teal', 'Yellow'],
            originalLabels: ['Red', 'Blue', 'Green', 'Teal', 'Yellow'],
            hoverOffset: 4
        }]
    },
    options: {
        plugins: {
            tooltip: {
                backgroundColor: '#FFF',
                titleFontSize: 14,
                titleColor: '#000',
                titleFont: {
                    weight: 'bold'
                },
                bodyColor: '#000',
                bodyFontSize: 14,
                displayColors: false,
                yAlign:'top',
                callbacks: {
                    title: function(tooltipItem) {
                        var data = tooltipItem;
                        var dataset = data[0].dataset;
                        var originalLabel = dataset.originalLabels[tooltipItem[0].dataIndex];
                        return originalLabel;
                    },
                    label: function(tooltipItem) {
                        var data = tooltipItem;
                        var dataset = data.dataset;
                        return dataset.data[data.dataIndex];
                    },
                    afterLabel: function(tooltipItem) {
                        var data = tooltipItem;
                        var dataset = data.dataset;
                        var total = dataset.data.reduce((a, b) => a + b, 0);
                        var percent = Math.round((dataset.data[data.dataIndex] / total) * 100);
                        return '(' + percent + '%)';
                    }
                }
            },
            datalabels: {
                color: 'white',
                font: {
                    weight: 'bold'
                }
            },
            legend: {
                position: 'bottom',
                align: 'center',
                labels: {
                    align: 'start',
                    //boxHeight: 95, // this controls the height of the legend color box / marker
                    padding: 0,
                    color: 'green',
                    font: {
                        weight: 'bold'
                    },
                    textAlign: 'top'
                }
            },
        },
        maintainAspectRatio: false,
    },
    plugins: [{
        beforeInit: function (chart, options) {
            var dataset = chart.data.datasets[0];
            var total = dataset.data.reduce((a, b) => a + b, 0);

            // Modify the labels before initializing the chart
            chart.data.labels = chart.data.labels.map(function (label, index) {
                var value = dataset.data[index];
        // Instead of a string, as it was before, we're returning an array, and that turns the legend label text into a multiline text
                return [value , label , ((value / total) * 100).toFixed(0) + '%'];
            });
        }
    }],
});
<div>
  <canvas id="donutChart"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>

You'll notice that I've made some changes to your original code.

I've added the originalLabels property within the datasets. This was needed because the afterLayout` was changing the labels, and transferring that change to the tooltips as well.

This way, I kept what was originally set as the label, and could use it later on for the tooltips.

The second change is that the tooltip (notice the singular vs the plural in your code) was moved to be within the options.plugins, as suggested by @kikon in the comments to your question.