Chartjs-Two chart for the same set of data – Chart.js

1👍

You can filter out the labels for the line series via:

options: {
  legend: {
    labels: {
      filter: function(item, chart) {
        return chart.datasets[item.datasetIndex].type === 'bar';
      }
    },
    onClick: function(e, legendItem) {
      let chart = this.chart;
      let index = legendItem.datasetIndex;
      let visible = !chart.getDatasetMeta(index).hidden;
      chart.data.datasets.forEach((dataset, i) => {
        if (dataset.label === legendItem.text) {
          chart.getDatasetMeta(i).hidden = visible;
        }
      });
      chart.update();
    }
  }
}

This has been adapted from: Is it possible in chartjs to hide certain dataset legends?

For toggling the similar datasets, I followed this example.


Demo

const ctx = document.querySelector('#chart-container').getContext('2d');
new Chart(ctx, getConfig());

function getConfig() {
  return {
    type: 'bar',
    data: {
      labels: ["Mar-20", "Apr-20"],
      datasets: [{
        type: "line",
        label: "en-US",
        borderColor: "#8c856f",
        data: [2, 3],
        borderWidth: 2,
        fill: false
      }, {
        type: "bar",
        label: "en-US",
        backgroundColor: "#beb391",
        data: [2, 3]
      }, {
        type: "line",
        label: "sv-SE",
        borderColor: "#b3cbaa",
        data: [1, 2],
        borderWidth: 2,
        fill: false
      }, {
        type: "bar",
        label: "sv-SE",
        backgroundColor: "#683e3a",
        data: [1, 2]
      }]
    },
    options: {
      legend: {
        labels: {
          filter: function(item, chart) {
            return chart.datasets[item.datasetIndex].type === 'bar';
          }
        },
        // Override hide/show for multiple series with same label.
        onClick: function(e, legendItem) {
          let chart = this.chart;
          let index = legendItem.datasetIndex;
          let visible = !chart.getDatasetMeta(index).hidden;
          chart.data.datasets.forEach((dataset, i) => {
            if (dataset.label === legendItem.text) {
              chart.getDatasetMeta(i).hidden = visible;
            }
          });
          chart.update();
        }
      },
      scales: {
        yAxes: [{
          ticks: {
            min: 0
          }
        }]
      }
    }
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
<canvas id="chart-container"></canvas>

Alternatively, you could create a plugin… This makes it so that you can configure each individual series.

var hideLegendItemsPlugin = {
  beforeInit: function(chartInstance) {
    if (chartInstance.options.hideLegendItemsPlugin) {
      Object.assign(chartInstance.options.legend, {
        labels : {
          filter : (item, chart) => {
            return chart.datasets[item.datasetIndex].hideLegendItem !== true;
          }
        },
        onClick: function(e, legendItem) {
          let chart = this.chart;
          let index = legendItem.datasetIndex;
          let visible = !chart.getDatasetMeta(index).hidden;
          chart.data.datasets.forEach((dataset, i) => {
            if (dataset.label === legendItem.text) {
              chart.getDatasetMeta(i).hidden = visible;
            }
          });
          chart.update();
        }
      });
    }
  }
};
Chart.pluginService.register(hideLegendItemsPlugin);

const ctx = document.querySelector('#chart-container').getContext('2d');
new Chart(ctx, getConfig());

function getConfig() {
  return {
    type: 'bar',
    data: {
      labels: ["Mar-20", "Apr-20"],
      datasets: [{
        type: "line",
        label: "en-US",
        borderColor: "#8c856f",
        data: [2, 3],
        borderWidth: 2,
        fill: false,
        hideLegendItem: true // Hide it!
      }, {
        type: "bar",
        label: "en-US",
        backgroundColor: "#beb391",
        data: [2, 3]
      }, {
        type: "line",
        label: "sv-SE",
        borderColor: "#b3cbaa",
        data: [1, 2],
        borderWidth: 2,
        fill: false,
        hideLegendItem: true // Hide it!
      }, {
        type: "bar",
        label: "sv-SE",
        backgroundColor: "#683e3a",
        data: [1, 2]
      }]
    },
    options: {
      hideLegendItemsPlugin : true, // Enable the plugin
      scales: {
        yAxes: [{
          ticks: {
            min: 0
          }
        }]
      }
    }
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart-container"></canvas>

If you want to have the chart figure-out label uniqueness, you can build a set of series names behind the scenes.

I also added an option to specify priority of series type i.e. bar, line, etc… If you do not specify a priority, the last appearance of the label will take priority. This works in your example, because the bar series are after the line series. Obviously this can be tweaked a bit.

var hideLegendItemsPlugin = {
  beforeInit: function(chartInstance) {
    let pluginOptions = chartInstance.options.hideLegendItemsPlugin;
    if (pluginOptions) {
      if (pluginOptions.priority) {
        const labelMap = chartInstance.data.datasets.reduce((ret, dataset) => {
          return Object.assign(ret, {
            [dataset.label] : (ret[dataset.label] || []).concat(dataset.type)
          });
        }, {});
        chartInstance.options.legend.labels.filter = (item, chart) => {
          let dataset = chart.datasets[item.datasetIndex];
          if (dataset.type !== pluginOptions.priority) {
            if (labelMap[dataset.label].includes(pluginOptions.priority)) {
              return false;
            }
          }
          return true;
        };
      } else {
        // Default prioritization is the last index (appearance) of that label.
        const labelMap = chartInstance.data.datasets.reduce((ret, dataset, index) => {
          return Object.assign(ret, { [dataset.label] : index });
        }, {});
        chartInstance.options.legend.labels.filter = (item, chart) => {
          let dataset = chart.datasets[item.datasetIndex];
          return item.datasetIndex === labelMap[dataset.label];
        };
      }
      chartInstance.options.legend.onClick = function(e, legendItem) {
        let chart = this.chart;
        let index = legendItem.datasetIndex;
        let visible = !chart.getDatasetMeta(index).hidden;
        chart.data.datasets.forEach((dataset, i) => {
          if (dataset.label === legendItem.text) {
            chart.getDatasetMeta(i).hidden = visible;
          }
        });
        chart.update();
      };
    }
  }
};
Chart.pluginService.register(hideLegendItemsPlugin);

const ctx = document.querySelector('#chart-container').getContext('2d');
new Chart(ctx, getConfig());

function getConfig() {
  return {
    type: 'bar',
    data: {
      labels: ["Mar-20", "Apr-20"],
      datasets: [{
        type: "line",
        label: "en-US",
        borderColor: "#8c856f",
        data: [2, 3],
        borderWidth: 2,
        fill: false
      }, {
        type: "bar",
        label: "en-US",
        backgroundColor: "#beb391",
        data: [2, 3]
      }, {
        type: "line",
        label: "sv-SE",
        borderColor: "#b3cbaa",
        data: [1, 2],
        borderWidth: 2,
        fill: false,
        hideLegendItem: true
      }, {
        type: "bar",
        label: "sv-SE",
        backgroundColor: "#683e3a",
        data: [1, 2]
      }]
    },
    options: {
      // This could also be simply `true` instead of an object.
      hideLegendItemsPlugin : {
        priority : 'bar' 
      },
      scales: {
        yAxes: [{
          ticks: {
            min: 0
          }
        }]
      }
    }
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart-container"></canvas>

Leave a comment