globetrotter globetrotter - 1 month ago 17
Javascript Question

return percentage in chart.js (v2+) legend

Chart.js 2+ does not return percentages for legend items in pie charts anymore.

I am storing the legend in the separate item in my html named

#legend
. Then I set it's
innerHTML
to
myPieChart.generateLegend()
. It returns both the color and name but I'd like to be able to override this HTML template to also return percentages, so the output goes from looking like:



  • A

  • B

  • C




to:



  • A (13%)

  • B (50%)

  • C (37%)




I used to do it with the
legendTemplate
argument but it does not seem to work anymore:

legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%> (<%=segments[i].value%>%)<%}%></li><%}%></ul>"

Answer

Chart.js v2 has a completely different API than earlier versions. You should read the new documentation carefully before upgrading (and then having to wonder what wen't wrong).

The fundamental changes (related to your question) are:

  • legendTemplate and segments are not available anymore. You should instead use legendCallback (in options) to override the default legend implementation. Here's what the documentation says about this callback:

Function to generate a legend. Receives the chart object to generate a legend from. Default implementation returns an HTML string.

  • The data you used from segments are available in the chart parameter (i.e. your actual chart object) of your legendCallback function here: chart.data.datasets[0].data.
  • Now that we know where to get our required data from, we can loop through chart.data.datasets[0].data to collect the values and append them to the legend HTML string.
  • Then we can simply call myPieChart.generateLegend(), which will invoke our legendCallback.

Complete example:

var myPieChart = new Chart(ctx, {
    type: 'pie',
    data: d,
    options: {
        responsive: true,
        maintainAspectRatio: false,
        tooltips: {
            callbacks: {
                label: function (tooltipItem, data) {
                    return data.labels[tooltipItem.index] + ' (' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index] + '%)';
                }
            }
        },
        legendCallback: function (chart) {
            var text = [];
            text.push('<ul class="' + chart.id + '-legend">');

            var data = chart.data;
            var datasets = data.datasets;
            var labels = data.labels;

            if (datasets.length) {
                for (var i = 0; i < datasets[0].data.length; ++i) {
                    text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
                    if (labels[i]) {
                        text.push(labels[i] + ' (' + datasets[0].data[i] + '%)');
                    }
                    text.push('</li>');
                }
            }
            text.push('</ul>');
            return text.join('');
        },
        legend: {
            // since you're providing your own legend
            display: false,
        },                
    }
});

var legend = myPieChart.generateLegend();
document.getElementById("legend").innerHTML = legend;

For purposes of completeness, I've also added the same TEXT (PERCENTAGE%) template on the tooltips labels (which similarly to legends, provide their own callbacks for overriding default implementations).

I would also suggest browsing through the actual Chart.js source code, in particular having a look at legendCallBack, generateLegend(), etc, to gain a better understanding of how things work under the hood.

Comments