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

能否用Chart.js对堆叠柱状图二次分组并按四季展示月份?

用Chart.js实现堆叠柱状图的双层分组(季节+月份)

嘿,很高兴能帮你搞定这两个Chart.js的需求!咱们直接上思路和可运行的代码方案,完美匹配你要的效果~

1. 关于堆叠柱状图的两次分组实现

Chart.js本身没有原生的“双层分组”配置项,但咱们可以通过自定义x轴网格线+插件绘制分组标题的方式,模拟出外层(季节)+内层(月份)的双层分组效果。核心思路是:

  • 把所有月份作为基础x轴标签
  • 在季节分界处隐藏网格线,制造分组间隔
  • 用自定义插件在每个季节的上方绘制分组标题

2. 季节分组+月份显示的完整实现

下面是完整的代码示例,直接就能运行,完全匹配你给出的季节划分和效果参考:

HTML 部分

<canvas id="seasonalStackedChart" style="width: 100%; height: 400px;"></canvas>

JavaScript 部分

// 定义季节与对应月份的映射关系
const seasonMonthMap = {
  'Season 1': ['January', 'February', 'March'],
  'Season 2': ['April', 'May', 'June'],
  'Season 3': ['July', 'August', 'September'],
  'Season 4': ['October', 'November', 'December']
};

// 扁平化所有月份,作为x轴的基础标签
const allMonths = Object.values(seasonMonthMap).flat();

// 模拟堆叠数据(这里用两个类别示例,你可以根据需求扩展)
const categoryAData = [12, 19, 3, 5, 2, 3, 7, 11, 8, 6, 4, 9];
const categoryBData = [5, 10, 8, 3, 7, 4, 9, 5, 12, 7, 6, 3];

// 计算每个季节最后一个月份的索引,用于后续控制网格线和分组间隔
const seasonBreakIndices = [
  seasonMonthMap['Season 1'].length - 1,
  seasonMonthMap['Season 1'].length + seasonMonthMap['Season 2'].length - 1,
  seasonMonthMap['Season 1'].length + seasonMonthMap['Season 2'].length + seasonMonthMap['Season 3'].length - 1
];

// 自定义插件:在x轴上方绘制季节分组标题
const seasonTitlePlugin = {
  id: 'seasonTitle',
  afterDraw: (chart) => {
    const { ctx, scales: { x } } = chart;
    ctx.save();
    ctx.font = '14px Arial';
    ctx.fillStyle = '#333';
    ctx.textAlign = 'center';
    
    let currentStartIndex = 0;
    // 遍历每个季节,计算标题的居中位置并绘制
    Object.entries(seasonMonthMap).forEach(([seasonName, months]) => {
      const currentEndIndex = currentStartIndex + months.length - 1;
      const startX = x.getPixelForValue(currentStartIndex);
      const endX = x.getPixelForValue(currentEndIndex);
      const midX = (startX + endX) / 2;
      // 把季节标题绘制在x轴上方15px的位置
      ctx.fillText(seasonName, midX, x.top - 15);
      currentStartIndex = currentEndIndex + 1;
    });
    ctx.restore();
  }
};

// 初始化堆叠柱状图
new Chart(document.getElementById('seasonalStackedChart'), {
  type: 'bar',
  plugins: [seasonTitlePlugin],
  data: {
    labels: allMonths,
    datasets: [
      {
        label: 'Category A',
        data: categoryAData,
        backgroundColor: 'rgba(75, 192, 192, 0.6)',
        stack: 'mainStack' // 统一stack值实现堆叠
      },
      {
        label: 'Category B',
        data: categoryBData,
        backgroundColor: 'rgba(255, 99, 132, 0.6)',
        stack: 'mainStack'
      }
    ]
  },
  options: {
    responsive: true,
    scales: {
      x: {
        stacked: true,
        grid: {
          // 在季节分界的刻度处不绘制网格线,形成分组间隔
          drawOnChartArea: (context) => !seasonBreakIndices.includes(context.tick.index)
        },
        ticks: {
          maxRotation: 0, // 月份标签不旋转,保持横向
          padding: 8
        }
      },
      y: {
        stacked: true,
        title: {
          display: true,
          text: 'Value'
        }
      }
    },
    plugins: {
      legend: {
        position: 'top'
      },
      title: {
        display: true,
        text: 'Seasonal Stacked Bar Chart'
      }
    }
  }
});

关键实现细节说明

  • 堆叠效果:通过给每个dataset设置相同的stack属性值,实现同一月份内的柱子堆叠。
  • 季节分组视觉:利用x轴网格线的drawOnChartArea回调,在季节分界处隐藏网格线,让不同季节之间有明显的空白间隔。
  • 季节标题绘制:自定义插件在图表绘制完成后,计算每个季节对应的x轴像素范围,居中绘制季节名称,完美实现“上方季节+下方月份”的标签布局。

这样配置后,你就能得到和参考图一致的效果,同时满足两次分组的需求啦!


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:55:10