Chart.js同步图例在多个图表上切换

Chart.js同步图例在多个图表上切换,chart.js,Chart.js,有一些解决方案可以使用legend onClick在单击的图表上打开/关闭所有其他数据集的可见性,但是如果多个图表具有相同的标签/图例,我需要一种方法在多个图表上同步此切换。例如,我有6个图表显示了关于相同数据的不同信息。然而,并非所有的图表都有所有的数据集。一个可能有5个数据集,另一个有3个,以此类推。它们也可能不会以相同的顺序出现 目标是能够在一个图表上单击一个图例项,并在所有图表上切换相同的项 因为我没有找到一个现有的解决方案,所以我发布了这篇文章。为了做到这一点,我将所有图表放在一个全局

有一些解决方案可以使用legend onClick在单击的图表上打开/关闭所有其他数据集的可见性,但是如果多个图表具有相同的标签/图例,我需要一种方法在多个图表上同步此切换。例如,我有6个图表显示了关于相同数据的不同信息。然而,并非所有的图表都有所有的数据集。一个可能有5个数据集,另一个有3个,以此类推。它们也可能不会以相同的顺序出现

目标是能够在一个图表上单击一个图例项,并在所有图表上切换相同的项


因为我没有找到一个现有的解决方案,所以我发布了这篇文章。

为了做到这一点,我将所有图表放在一个全局变量中,并通过它们循环,以通过legendItem.text而不是legendItem.datasetindex匹配dataset,因为标签可能存在,也可能不存在,甚至在其他图表上处于相同的索引位置

以下是我如何创建/替换多个图表:

下面是legend onClick切换解决方案:

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();
                    }
                });
            }
        }
    }
};

在使用Chris的答案后,我创建了一个简化的解决方案

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();
              }
            });
          });
        }
      }
    }
  };

使用此解决方案的好处是,它将调用已添加到任何图表图例中的任何自定义onClick处理程序。

如果有人正在寻找将饼图图例与折线图图例同步的方法,请尝试此方法。如果图表的类型相同,也可以正常工作:

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();

    }

  });

});
将此onClick函数放置在选项的图例部分,就像您在其他答案中看到的一样

我的折线图是一种日常趋势,而饼图则比较了整个范围内的总数。 当然,图表的标签必须使用相同的名称才能起作用

与其他解决方案一样,您必须将两个图表存储在一个全局变量中,如:

window.myCharts['pieChart1']
window.myCharts['lineChart1']
由于隐藏数据集以及在整个数据集中获取其索引因图表类型而异,因此此函数将检查图表类型并相应地执行操作。 还要注意,对于饼图,隐藏设置为true或false,但是对于折线图,隐藏设置为true或null,谢谢chart.js。
我相信您可以将其扩展到其他图表类型,但我只为“直线”和“饼图”图表设置了它。

调用自定义onClick,调用相同的东西,导致无休止的循环和浏览器窗口崩溃。另外,chart.legend未定义。