Chart.js sync legend toggle on multiple charts

六月ゝ 毕业季﹏ 提交于 2020-01-06 05:36:06

问题


There are solutions to using legend onClick to toggle on/off visibility of (all other) datasets on the clicked chart, but I needed a way to sync this toggle on multiple charts if they have the same label/legend. For example, I have 6 charts presenting different information about the same data. However, not all the charts have all the datasets. One may have 5 datasets, another has 3 and so on. And they may not show up in the same order either.

The goal was to be able to click a legend item on one chart, and that same item be toggled on all the charts.

Since I did not find an existing solution, I'm posting this.


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



回答2:


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.



来源:https://stackoverflow.com/questions/51920455/chart-js-sync-legend-toggle-on-multiple-charts

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!