使用带有 ChartJS v3 的 generateLabels 删除图表上的冗余图例

Remove redundant legends on the chart using generateLabels with ChartJS v3

我有如下图表,我只需要一对图例(数据1和数据2)显示在图表上。

在 ChartJS v2 中,我可以使用类似 this 的 generateLabels,但它在 v3 中的工作方式似乎与我正在使用的不同。

在 v3 中是否有使用 generateLabels 实现此目的的简单方法,或者我是否必须更改 DOM 结构?

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
      }
    },
  },
  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/chart.js@3.0.0/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>

options.plugins.legend.labels.generateLabels 仍然可以在 Chart.js v3 中使用。对于您的情况,这可能如下所示:

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>

该方法的问题在于,显示的 legend 元素仍然仅与单个数据集相关联。如果你还想 show/hide 其他数据集,你还需要定义一个 legend.onClick 函数,类似于 this answer.

中的函数