【问题标题】:Chart.js sync legend toggle on multiple chartsChart.js 在多个图表上同步图例切换
【发布时间】:2018-08-19 18:05:47
【问题描述】:

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

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

由于我没有找到现有的解决方案,所以我发布了这个。

【问题讨论】:

    标签: chart.js


    【解决方案1】:

    为此,我将所有图表放在一个全局变量中并循环遍历它们以通过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();
                        }
                    });
                }
            }
        }
    };
    

    【讨论】:

      【解决方案2】:

      在这里使用 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() 处理程序。

      【讨论】:

      • 调用自定义的onClick,调用的是同一个东西,导致死循环,浏览器窗口崩溃。 chart.legend 也未定义。
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多