Chartjs-Multiple bar charts side by side chartjs

0👍

Your problem can be solved with Chart.js but the labels and the single dataset need to be generated.

Further you need to define your own legend by defining a plugins.legend.labels.generateLabels together with with a plugins.legend.labels.onClick function.

For further information, consult the Legend page from the Chart.js. documentation.

Please take a look at your amended and runnable code below and see how it works.

const baseData = {
  labels:  ['2000','2010','2020'],
  datasets: [
    { label: 'Frogs', data: [30.2, 20.8, 36.2], bgColor: 'red', hidden: false },
    { label: 'Monkeys', data: [16.3, 13.0, 22.3], bgColor: 'blue', hidden: false },
    { label: 'Squirrels', data: [5.8,3.1, 14.9], bgColor: 'cyan', hidden: false },
    { label: 'Bats', data: [0.1, 3.6, 2.6], bgColor: 'aquamarine', hidden: false }
  ]
};
const iLastDs = baseData.datasets.length - 1;

const data = {
  labels: baseData.datasets
    .map(() => baseData.labels)
    .map((labels, i) => i < iLastDs ? [...labels, null] : labels)
    .flatMap(v => v),
  datasets: [{
    data: baseData.datasets
      .map(ds => ds.data)
      .map((data, i) => i < iLastDs ? [...data, null] : data)
      .flatMap(v => v),
    backgroundColor: baseData.datasets
      .map(ds => ds.data.map(v => ds.bgColor))
      .map((bgColors, i) => i < iLastDs ? [...bgColors, null] : bgColors)
      .flatMap(v => v),
    categoryPercentage: 1,
    barPercentage: 0.9
  }]
};

const options = {
  maintainAspectRatio: true,
  responsive: true,
  interaction: {
    intersect: true,
    mode: 'index',
  },
  plugins: {
    legend: {
      position: 'bottom',
      labels: {
        generateLabels: chart => baseData.datasets.map((ds, i) => ({
          datasetIndex: i,
          text: ds.label,
          fillStyle: ds.bgColor,
          strokeStyle: 'lightgray',
          hidden: baseData.datasets[i].hidden
        }))
      },
      onClick: (event, legendItem, legend) => {
        baseData.datasets[legendItem.datasetIndex].hidden = !baseData.datasets[legendItem.datasetIndex].hidden;
        const iFirstValue = legendItem.datasetIndex + legendItem.datasetIndex * baseData.labels.length;
        for (let i = iFirstValue; i < iFirstValue + baseData.labels.length; i++) {
          legend.chart.toggleDataVisibility(i);
        }
        legend.chart.update();
      }
    },
    tooltip: {
      callbacks: {
        title: ctx => {
          const dsIndex = Math.floor(ctx[0].dataIndex / baseData.datasets.length);
          return baseData.datasets[dsIndex].label + ' / ' + ctx[0].label;
        }
      }
    }
  },
  scales: {
    x: {
      grid: {
        display: false
      }
    }, 
    y: {
      title: {
        display: true,
        text: 'Horsepower',
      }
    }
  }
};

new Chart('mychart',  {
  type: 'bar',  
  data,
  options
});
span {
  font-style: italic;
  font-size: 12px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="mychart" height="100"></canvas>  
<span>Source: Animals Index, June 2022</span>

Leave a comment