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

bxpogfeg  于 2023-01-13  发布在  Chart.js
关注(0)|答案(4)|浏览(177)

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

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

由于我没有找到一个现有的解决方案,我张贴这一点。

zpqajqem

zpqajqem1#

为此,我将所有图表放在一个全局变量中,并循环通过它们,以便按legendItem.text而不是legendItem.datasetindex匹配数据集,因为标签可能存在,也可能不存在,甚至可能在其他图表的相同索引位置。
下面是我如何创建/替换多个图表:https://stackoverflow.com/a/51882403/1181367
下面是图例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();
                    }
                });
            }
        }
    }
};
5anewei6

5anewei62#

使用Chris的答案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()处理程序。

iyfjxgzm

iyfjxgzm3#

如果有人正在寻找一种同步饼图图例和折线图图例的方法,请尝试以下方法(如果图表类型相同,它也应该可以正常工作):

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)我相信你可以把它扩展到其他图表类型,但是我只为“折线图”和“饼图”设置了它。

7eumitmz

7eumitmz4#

如果有人正在寻找这个,这里是工作的解决方案:

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

相关问题