You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ChartJS堆叠柱状图如何在图例中按堆叠名称分组展示数据集标签

ChartJS 堆叠柱状图按堆叠分组图例实现方案

方案1:使用原生图例配置自定义标签(无需额外DOM)

这种方法利用ChartJS自带的图例生成钩子,直接在图例项中插入分组表头,无需额外编写HTML结构。

实现步骤:

  • 先对所有数据集按stack字段做分组,记录每个堆叠名称对应的数据集列表
  • 配置options.plugins.legend.labels.generateLabels自定义生成图例项:
    首先遍历所有堆叠分组,每个分组先插入一个不可点击的表头项,样式可自定义区分;再遍历分组下的每个数据集,生成对应的数据标签项,前面可加缩进效果
  • 同时配置options.plugins.legend.onClick,点击时判断如果是分组表头就不触发隐藏/显示逻辑,普通标签正常切换对应数据集显隐

核心代码示例:

const options = {
  plugins: {
    legend: {
      labels: {
        generateLabels: (chart) => {
          const datasets = chart.data.datasets;
          // 按stack字段分组
          const groups = datasets.reduce((res, ds) => {
            if (!res[ds.stack]) res[ds.stack] = [];
            res[ds.stack].push(ds);
            return res;
          }, {});
          
          const labels = [];
          Object.keys(groups).forEach(stackName => {
            // 插入分组表头,设置不可点击、样式区分
            labels.push({
              text: stackName,
              font: { weight: 'bold' },
              fillStyle: 'transparent', // 不显示左侧色块
              strokeStyle: 'transparent',
              hidden: false,
              isGroupHeader: true // 自定义标记区分表头
            });
            // 插入分组下的数据集标签
            groups[stackName].forEach(ds => {
              labels.push({
                text: `  ${ds.label}`, // 加空格做缩进
                fillStyle: ds.backgroundColor,
                strokeStyle: ds.borderColor,
                hidden: !chart.getDataVisibility(datasets.indexOf(ds)),
                datasetIndex: datasets.indexOf(ds),
                isGroupHeader: false
              });
            });
          });
          return labels;
        }
      },
      onClick: (e, legendItem, legend) => {
        // 点击表头不触发操作
        if (legendItem.isGroupHeader) return;
        // 普通标签正常切换显隐
        const chart = legend.chart;
        const index = legendItem.datasetIndex;
        chart.toggleDataVisibility(index);
        chart.update();
      }
    }
  },
  scales: {
    x: { stacked: true },
    y: { stacked: true }
  }
}

方案2:完全自定义HTML图例(自由度最高)

如果需要更复杂的分组样式(比如折叠展开分组、自定义间距等),可以关闭原生图例,自己渲染HTML结构:

实现步骤:

  • 配置options.plugins.legend.display = false关闭原生图例
  • 在图表容器外准备一个自定义图例的DOM容器
  • 监听图表的render事件,每次图表渲染时按stack分组生成对应的HTML结构插入到容器中
  • 给每个数据标签绑定点击事件,调用chart.toggleDataVisibility切换对应数据集显隐,之后调用chart.update()更新图表

核心代码示例:

<div>
  <canvas id="myChart"></canvas>
  <div id="custom-legend"></div>
</div>
const chart = new Chart(ctx, {
  type: 'bar',
  data: data,
  options: {
    plugins: {
      legend: { display: false },
    },
    scales: { x: { stacked: true }, y: { stacked: true } }
  },
  plugins: [{
    id: 'customLegend',
    afterRender: (chart) => {
      const legendContainer = document.getElementById('custom-legend');
      // 按stack字段分组
      const groups = chart.data.datasets.reduce((res, ds) => {
        if (!res[ds.stack]) res[ds.stack] = [];
        res[ds.stack].push({...ds, index: chart.data.datasets.indexOf(ds)});
        return res;
      }, {});
      
      // 生成图例HTML
      let html = '';
      Object.keys(groups).forEach(stackName => {
        html += `<div style="font-weight: bold; margin: 8px 0 4px 0;">${stackName}</div>`;
        groups[stackName].forEach(ds => {
          const isHidden = !chart.getDataVisibility(ds.index);
          html += `
            <div style="margin-left: 16px; cursor: pointer; ${isHidden ? 'opacity: 0.5;' : ''}" data-index="${ds.index}">
              <span style="display: inline-block; width: 12px; height: 12px; background: ${ds.backgroundColor}; margin-right: 8px;"></span>
              ${ds.label}
            </div>
          `;
        });
      });
      legendContainer.innerHTML = html;
      
      // 绑定点击切换事件
      legendContainer.querySelectorAll('[data-index]').forEach(el => {
        el.addEventListener('click', () => {
          const index = parseInt(el.getAttribute('data-index'));
          chart.toggleDataVisibility(index);
          chart.update();
        });
      });
    }
  }]
});

内容的提问来源于stack exchange,提问作者dickey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 04:21:03