Pie Chart Legend - Chart.js
Asked Answered
S

4

30

I need help to put the number of the pie chart in the legend

Chart Image

If i hover the chart with mouse i can see the number relative to each item

i want to display it in the legend either

the important code so far:

var tempData = {
    labels: Status,
    datasets: [
        {
            label: "Status",
            data: Qtd,
            backgroundColor: randColor
        },

    ]
};

var ctx = $("#pieStatus").get(0).getContext("2d");
var chartInstance = new Chart(ctx, {
    type: 'pie',
    data: tempData,
    options: {
         title: {
            display: true,
            fontsize: 14,
            text: 'Total de Pedidos por Situação'
        },
        legend: {
            display: true,
            position: 'bottom',

        },
        responsive: false
    }

});

"Qtd","randColor" are "var" already with values

Silvertongued answered 12/9, 2016 at 16:12 Comment(0)
H
54

You need to edit the generateLabels property in your options :

options: {
    legend: {
        labels: {
            generateLabels: function(chart) {
                 // Here
            }
        }
    }
}


Since it is quite a mess to create on your own a great template. I suggest using the same function as in the source code and then edit what is needed.

Here are a small jsFiddle, where you can see how it works (edited lines - from 38 - are commented), and its result :

enter image description here

Houseman answered 13/9, 2016 at 7:55 Comment(2)
in fiddler you are showing Mouse hover tool-tip has also changed, which i didn't found where is it in your code?Centennial
@UzairXlade I haven't touched the tooltip in the fiddler. Tooltips are automatically defined with the labels set in the data (in the first lines)Houseman
P
5

Maybe this is a hacky solution, but for me seems simpler.

The filter parameter

ChartJS legend options have a filter parameter. This is a function that is called for each legend item, and that returns true/false whether you want to show this item in the legend or not.

filter has 2 arguments:

  • legendItem : The legend item to show/omit. Its properties are described here
  • data : The data object passed to the chart.

The hack

Since JS passes objects by reference, and filter is called for each legend item, then you can mutate the legendItem object to show the text that you want.

legend : {
  labels: {
    filter: (legendItem, data) => {
      // First, retrieve the data corresponding to that label
      const label = legendItem.text
      const labelIndex = _.findIndex(data.labels, (labelName) => labelName === label) // I'm using lodash here
      const qtd = data.datasets[0].data[labelIndex]
      
      // Second, mutate the legendItem to include the new text
      legendItem.text = `${legendItem.text} : ${qtd}`
      
      // Third, the filter method expects a bool, so return true to show the modified legendItem in the legend
      return true
    }
  }
}

Partridge answered 2/8, 2021 at 10:14 Comment(0)
W
1

Following on from tektiv's answer, I've modified it for ES6 which my linter requires;

options: {
  legend: {
    labels: {
      generateLabels: (chart) => {
        const { data } = chart;
        if (data.labels.length && data.datasets.length) {
          return data.labels.map((label, i) => {
            const meta = chart.getDatasetMeta(0);
            const ds = data.datasets[0];
            const arc = meta.data[i];
            const custom = (arc && arc.custom) || {};
            const { getValueAtIndexOrDefault } = Chart.helpers;
            const arcOpts = chart.options.elements.arc;
            const fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
            const stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
            const bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
            const value = chart.config.data.datasets[arc._datasetIndex].data[arc._index];

            return {
              text: `${label}: ${value}`,
              fillStyle: fill,
              strokeStyle: stroke,
              lineWidth: bw,
              hidden: Number.isNaN(ds.data[i]) || meta.data[i].hidden,
              index: i,
            };
          });
        }
        return [];
      },
    },
  },
},
Wehrle answered 25/2, 2021 at 14:58 Comment(0)
A
0

I wanted to let the user select from 100+ data sets, but rather than adding/removing them from my Chart I decided to set the showLine: false on any dataset that I want hidden. Unfortunately the default legend would show all 100+. So in my solution I generate the legend manually, filtering out any dataset that has showLine: false.

Your settings will have this:

legend: {
  labels: {
    generateLabels: (a) => {
      return a.data.labels
    }
  }

And you'll generate your own labels with a helper function:

function updateAllLabels() {
  const myNewLabels = [];

  myChart.data.datasets.forEach((element) => {
    if (element.showLine) {
      myNewLabels.push(generateLabel(element));
    }
  });

  myChart.data.labels = myNewLabels;
}

And you'll generate the label with another function:

function generateLabel(data) {
  return {
    fillStyle: data.borderColor,
    lineWidth: 1,
    strokeStyle: data.borderColor,
    text: data.countyName, // I attach countryName to my datasets for convenience
  }
}

Now just don't forget to call the function whenever updating your chart:

updateAllLabels();
myChart.update();

Happy graphing!

Alliteration answered 23/5, 2019 at 5:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.