Chartjs-Remove redundant legends on the chart using generateLabels with ChartJS v3

2👍

options.plugins.legend.labels.generateLabels can still be used in Chart.js v3. For your case, this could look as follows:

generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
     datasetIndex: i,
     text: l,
     fillStyle: chart.data.datasets[i].backgroundColor,
     strokeStyle: chart.data.datasets[i].backgroundColor,
     hidden: chart.getDatasetMeta(i).hidden
  }))
const trend_options = {
  responsive: true,
  maintainAspectRatio: false,
  plugins: {
    datalabels: {
      formatter: function(value, ctx) {
        const otherDatasetIndex = ctx.datasetIndex % 2 === 0 ? ctx.datasetIndex + 1 : ctx.datasetIndex - 1;
        const total = ctx.chart.data.datasets[otherDatasetIndex].data[ctx.dataIndex] + value;
        return `${(value / total * 100).toFixed()}%`;
      },
      font: {
        weight: "bold"
      },
      color: "#fff",
      display: function(context) {
        let index = context.dataIndex;
        let value = context.dataset.data[index];
        return value > 0; // display labels with a value greater than 0
      }
    },
    legend: {
      labels: {
        generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
          datasetIndex: i,
          text: l,
          fillStyle: chart.data.datasets[i].backgroundColor,
          strokeStyle: chart.data.datasets[i].backgroundColor,
          hidden: chart.getDatasetMeta(i).hidden
        }))
      }
    },
  },
  scales: {
    x: {
      stacked: true
    },
    y: {
      stacked: true,
      suggestedMax: 15,
      ticks: {
        beginAtZero: true,
        stepSize: 5,
      }
    }
  },
};


const app_data_trend = [{
    label: 'data 1',
    data: [3, 4, 5, 6, 4, 4, 4],
    backgroundColor: '#007bff',
    stack: 'Stack 0',
  },
  {
    label: 'data 2',
    data: [3, 4, 5, 4, 3, 2, 3],
    backgroundColor: '#6DB526',
    stack: 'Stack 0',
  },
  {
    label: 'data 1',
    data: [4, 4, 4, 3, 2, 5, 4],
    backgroundColor: '#007bff',
    stack: 'Stack 1',
  },
  {
    label: 'data 2',
    data: [4, 2, 5, 2, 3, 3, 4],
    backgroundColor: '#6DB526',
    stack: 'Stack 1',
  },
  {
    label: 'data 1',
    data: [2, 4, 5, 2, 4, 5, 3],
    backgroundColor: '#007bff',
    stack: 'Stack 2',
  },
  {
    label: 'data 2',
    data: [1, 1, 2, 4, 4, 3, 5],
    backgroundColor: '#6DB526',
    stack: 'Stack 2',
  },

]

const ctx8 = document.getElementById("tsa-applications-trending");
const chart8 = new Chart(ctx8, {
  plugins: [ChartDataLabels],
  type: 'bar',
  data: {
    labels: ['person1', 'person2', 'person3', 'person4'],
    datasets: app_data_trend
  },
  options: trend_options,
});
.chart-container {
  position: relative;
  height: 80vh;
  width: 80vw
}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0"></script>
<div class="chart-container">
  <canvas id="tsa-applications-trending"></canvas>
</div>

The problem with the approach is, that the displayed legend elements are still tied to individual datasets only. If you want to show/hide other datasets as well, you also need to define a legend.onClick function, similar to the one from this answer.

Leave a comment