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

时间:2018-08-19 18:05:48

标签: chart.js

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

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

由于找不到现有解决方案,因此我将其发布。

3 个答案:

答案 0 :(得分:1)

为此,我将所有图表放在全局变量中并遍历它们,以legendItem.text而不是legendItem.datasetindex来匹配数据集,因为标签可能存在或可能不存在,甚至不在在其他图表上的相同索引位置。

这是我创建/替换多个图表的方法:https://stackoverflow.com/a/51882403/1181367

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

答案 1 :(得分:0)

在这里使用克里斯的答案https://stackoverflow.com/a/51920456/671140之后,我创建了一个简化的解决方案。

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()处理程序。

答案 2 :(得分:0)

如果任何人正在寻找一种将饼图图例与折线图图例同步的方法,请尝试执行此操作(如果图表的类型相同,它也应该可以正常工作):

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)。 我确定您可以将其扩展为其他图表类型,但是我只为设置“线形”和“饼形”图表而烦恼。