Chartjs-Chart.js sync legend toggle on multiple charts

1👍

To do this, I put all the charts in a global var and loop through them to match dataset by legendItem.text instead of legendItem.datasetindex, since the label may or may not exist or even be in the same index position on other charts.

Here’s how I create/replace the multiple charts: https://stackoverflow.com/a/51882403/1181367

And here’s the legend onClick toggle solution:

var config = {
    type: type,
    data: {
        labels: labels,
        datasets: datasets
    },
    options: {
        responsive: true,
        maintainAspectRatio: false,
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true,
                }
            }]
        },
        legend: {
            position: 'right',
            onClick: function (e, legendItem) {
                var text = legendItem.text;
                Object.keys(charts).forEach(function (id) {
                    // loop through the charts
                    var ci = charts[id].chart
                    var cindex = (function () {
                        var match = null;
                        ci.legend.legendItems.forEach(function (item) {
                            if (item.text == text) {
                                // get index for legend.text that matches clicked legend.text 
                                match = item.datasetIndex;
                            }
                        });
                        return match;
                    })();
                    if (cindex !== null) {
                        // if there's a match
                        var alreadyHidden = (ci.getDatasetMeta(cindex).hidden === null) ? false : ci.getDatasetMeta(cindex).hidden;
                        ci.data.datasets.forEach(function (e, i) {
                            var meta = ci.getDatasetMeta(i);
                            if (i !== cindex) {
                                if (!alreadyHidden) {
                                    meta.hidden = meta.hidden === null ? !meta.hidden : null;
                                } else if (meta.hidden === null) {
                                    meta.hidden = true;
                                }
                            } else if (i === cindex) {
                                meta.hidden = null;
                            }
                        });
                        ci.update();
                    }
                });
            }
        }
    }
};

0👍

After using Chris’s answer here https://stackoverflow.com/a/51920456/671140 I created a simplified solution.

var config = {
    type: type,
    data: {
      labels: labels,
      datasets: datasets
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      scales: {
        yAxes: [{
          ticks: {
            beginAtZero: true,
          }
        }]
      },
      legend: {
        position: 'right',
        onClick: function (e, legendItem) {
          var text = legendItem.text;
          Object.keys(charts).forEach(function (id) {
            // loop through the charts
            var ci = charts[id].chart
            ci.legend.legendItems.forEach(function (item) {
              if (item.text == text) {
                ci.options.legend.onClick.call(chart.legend, null, item);
                ci.update();
              }
            });
          });
        }
      }
    }
  };

The benefit of using this solution is that it will call any custom onClick() handlers that have been added to any of the chart legends.

0👍

If anyone’s looking for a way to sync a pie chart legend with a line chart legend, try this (it should also work just fine if the charts are the same type, too):

onClick: function(e, legendItem) {

  // Save name of clicked label, for later comparison
  var legendName = legendItem.text; 

  // Iterate through global charts array
  Object.keys(myCharts).forEach(function(id) {

    // Assign shorthand variable to address chart easier
    var chrt = myCharts[id];

    // Determine chart type
    var chartType = chrt.config.type;

    // Iterate through each legend in the chart
    chrt.legend.legendItems.forEach(function(item) {

      // If legend name matches clicked label
      if (item.text == legendName) {

        if (chartType == 'pie') { // If pie chart

          if (chrt.getDatasetMeta(0).data[item.index].hidden === true) chrt.getDatasetMeta(0).data[item.index].hidden = false;
          else if (chrt.getDatasetMeta(0).data[item.index].hidden === false) chrt.getDatasetMeta(0).data[item.index].hidden = true;

        } else if (chartType == 'line') { // If line chart

          if (chrt.getDatasetMeta(item.datasetIndex).hidden === true) chrt.getDatasetMeta(item.datasetIndex).hidden = null;
          else if (chrt.getDatasetMeta(item.datasetIndex).hidden === null) chrt.getDatasetMeta(item.datasetIndex).hidden = true;

        }

      // Trigger chart update
      chrt.update();

    }

  });

});

Place this onClick function in the legend section of the options, just like you can see in the other answers.

My line chart was a day-to-day trend, while the pie chart compared totals across the entire range.
The chart’s labels must be identically named for this to work, of course.

Like the other solutions, you must store both charts in one, global variable, like:

window.myCharts['pieChart1']
window.myCharts['lineChart1']

Since hiding datasets, and getting their indexes within the whole dataset, is different depending on the chart type, this function will check the chart type and act accordingly.
Also notice that for pie charts, the “hidden” setting is either true or false, but for line charts, it’s either true or null (thanks, chart.js).
I’m sure you can expand this for other chart types, but I’ve only bothered setting it up for ‘line’ and ‘pie’ charts.

0👍

If someone is looking for this, here is the working solution:

onClick: function (e, legendItem, legend) {
                var text = legendItem.text;
                Object.keys(charts).forEach(function (id) {
                    var ci = charts[id]
                    ci.legend.legendItems.forEach(function (item) {             
                      if (item.text == text) {
                        if (ci.data.datasets[item.datasetIndex].hidden == true) {
                            ci.data.datasets[item.datasetIndex].hidden = false;
                        } else {
                            ci.data.datasets[item.datasetIndex].hidden = true;
                        }  
                      }
                    });
                    ci.update();
                });
            }

Leave a comment