0

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.

4
  • For one thing, tooltip configuration should be under options.plugins.tooltip, not options.tooltips; the same with legend. Check the migration guides, e.g., v3 migration guide, search for tooltip and legend
    – kikon
    Commented Dec 22, 2023 at 18:50
  • @kikon Thank you :) I have one more doubt that can we break line in LegendText that instead of this "123 | Red | 12%" it should display like one below another. And one more thing i have added datalabels in options.plugins.datalabels is this a correct way? datalabels: { color: 'white', font: { weight: 'bold' }, },
    – Aishwarya
    Commented Dec 27, 2023 at 9:54
  • The datalabels options seem to be OK. As for the legend, I'm not sure how exactly you want to set it up. You may use options.plugins.legend.position: 'right' for a vertical layout legend positioned to the right. You may also try an HTML legend for more options.
    – kikon
    Commented Dec 27, 2023 at 19:53
  • If it's something very specific, you may describe it with a drawing, and adding the code from this question, you may ask another question just for the legend; the questions here are supposed to be very focused, i.e., just one question per post.
    – kikon
    Commented Dec 27, 2023 at 19:54

1 Answer 1

0

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.

5
  • Thank you for helping me out. I have one more doubt that can we break line in LegendText that instead of this "123 | Red | 12%" it should display like one below another. And one more thing i have added datalabels in options.plugins.datalabels is this a correct way? datalabels: { color: 'white', font: { weight: 'bold' }, },
    – Aishwarya
    Commented Dec 27, 2023 at 9:53
  • Please see the edited code, and the comments. You will notice that instead of your placement (present in the code, but commented out) of the labels styling, I've used something else. There's also the multiline legend text, but that introduces a new problem - remove the comment for the boxHeight property, and you will see what I mean. Aligning the label text to match the marker / color box is not supported in this version of ChartJS (as per documentation showing available options). Commented Dec 27, 2023 at 18:22
  • Thank you alot :) , with your code im able to show LegendText and tooltip according to my requirements :)
    – Aishwarya
    Commented Dec 28, 2023 at 15:11
  • Regarding position of datalabels, According to ChartJS v4.4.1 its correct. Here you can have a look : v2_2_0--chartjs-plugin-datalabels.netlify.app/guide/… ** per chart: options.plugins.datalabels.*
    – Aishwarya
    Commented Dec 28, 2023 at 15:15
  • Apologies for misunderstanding the original request - you wanted the labels to show in the chart / doughnut slices. I've edited my code to reflect on that. Your initial question (and setting) is correct - you just need to add this Chart.register(ChartDataLabels); before instantiating the chart. Commented Jan 2 at 10:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.