[Chartjs]-Multi-colored legend stacked bar chart Chartjs

1👍

It is possible with a custom html legend, implementation is not perfect but I think its enough for you to finetune it so it will work execlty as you want

Example:

const getOrCreateLegendList = (chart, id) => {
  const legendContainer = document.getElementById(id);
  let listContainer = legendContainer.querySelector('ul');

  if (!listContainer) {
    listContainer = document.createElement('ul');
    listContainer.style.display = 'flex';
    listContainer.style.flexDirection = 'row';
    listContainer.style.margin = 0;
    listContainer.style.padding = 0;

    legendContainer.appendChild(listContainer);
  }

  return listContainer;
};

const htmlLegendPlugin = {
  id: 'htmlLegend',
  afterUpdate(chart, args, options) {
    const ul = getOrCreateLegendList(chart, options.containerID);

    // Remove old legend items
    while (ul.firstChild) {
      ul.firstChild.remove();
    }

    // Reuse the built-in legendItems generator
    const items = chart.options.plugins.legend.labels.generateLabels(chart);

    items.forEach((item, i) => {
      const li = document.createElement('li');
      li.style.alignItems = 'center';
      li.style.cursor = 'pointer';
      li.style.display = 'flex';
      li.style.flexDirection = 'row';
      li.style.marginLeft = '10px';

      li.onclick = () => {
        const {
          type
        } = chart.config;
        if (type === 'pie' || type === 'doughnut') {
          // Pie and doughnut charts only have a single dataset and visibility is per item
          chart.toggleDataVisibility(item.index);
        } else {
          chart.setDatasetVisibility(item.datasetIndex, !chart.isDatasetVisible(item.datasetIndex));
        }
        chart.update();
      };

      const datasets = chart.data.datasets;

      // Color box
      const boxSpan = document.createElement('span');
      boxSpan.style.background = datasets[item.datasetIndex].backgroundColor[i];
      boxSpan.style.borderColor = item.strokeStyle;
      boxSpan.style.borderWidth = item.lineWidth + 'px';
      boxSpan.style.display = 'inline-block';
      boxSpan.style.height = '20px';
      boxSpan.style.marginRight = '10px';
      boxSpan.style.width = '20px';

      const boxSpan2 = document.createElement('span');
      boxSpan2.style.background = datasets[item.datasetIndex].backgroundColor[i + 1] || datasets[item.datasetIndex].backgroundColor[i - 1];
      boxSpan2.style.borderColor = item.strokeStyle;
      boxSpan2.style.borderWidth = item.lineWidth + 'px';
      boxSpan2.style.borderColor = item.strokeStyle;
      boxSpan2.style.borderWidth = item.lineWidth + 'px';
      boxSpan2.style.display = 'inline-block';
      boxSpan2.style.height = '20px';
      boxSpan2.style.marginRight = '10px';
      boxSpan2.style.width = '20px';

      // Text
      const textContainer = document.createElement('p');
      textContainer.style.color = item.fontColor;
      textContainer.style.margin = 0;
      textContainer.style.padding = 0;
      textContainer.style.textDecoration = item.hidden ? 'line-through' : '';

      const text = document.createTextNode(item.text);
      textContainer.appendChild(text);

      li.appendChild(boxSpan);
      li.appendChild(boxSpan2);
      li.appendChild(textContainer);
      ul.appendChild(li);
    });
  }
};

var options = {
  type: 'bar',
  data: {
    labels: ["Red", "Blue"],
    datasets: [{
        label: '# of Votes',
        data: [12, 19],
        borderWidth: 1,
        backgroundColor: ['rgb(224, 178, 40)', 'rgb(78, 235, 255)']
      },
      {
        label: '# of Points',
        data: [7, 11],
        borderWidth: 1,
        backgroundColor: ['rgb(204, 158, 20)', 'rgb(58, 215, 240)']
      }
    ]
  },
  options: {
    responsive: true,
    scales: {
      x: {
        stacked: true,
        grid: {
          display: false
        }
      },

      y: {
        stacked: true,
        grid: {
          display: false
        },
        title: {
          display: true,
          text: 'Use, %'
        }
      }
    },
    plugins: {
      htmlLegend: {
        // ID of the container to put the legend in
        containerID: 'chartjs-legend',
      },
      legend: {
        display: false,
      }
    }
  },
  plugins: [htmlLegendPlugin],
}

var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
  <div id="chartjs-legend">

  </div>
  <canvas id="chartJSContainer" width="600" height="400"></canvas>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.3.2/chart.js"></script>
</body>

Leave a comment