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

ChartJS实现带分组平均值线的堆叠水平条形图及替代方案咨询

ChartJS 堆叠水平条形图添加分组平均值线解决方案

示例效果参考图

一、现有代码改造实现方法

实现逻辑:通过ChartJS自定义插件机制,在数据集渲染完成后,计算每个分组的平均值,再根据坐标轴坐标转换绘制对应的红色标记线。

完整修改后代码如下:

var data = {
  labels: ["January", "February", "March"],
  datasets: [
    {
      label: "Dogs",
      backgroundColor: "rgba(237, 192, 169)",
      data: [20, 10, 25],
      stack: 1,
      xAxisID: 'x-axis-0',
      yAxisID: 'y-axis-0'
    },
    {
      label: "Cats",
      backgroundColor: "rgba(253, 234, 175)",
      data: [70, 85, 65],
      stack: 1,
      xAxisID: 'x-axis-0',
      yAxisID: 'y-axis-0'
    },
    {
      label: "Birds",
      backgroundColor: "rgba(179, 211, 200)",
      data: [10, 5, 10],
      stack: 1,
      xAxisID: 'x-axis-0',
      yAxisID: 'y-axis-0'
    }
  ]
};

// 计算每个分类的平均值,可根据业务需求调整计算规则
const groupAverages = data.labels.map((_, idx) => {
  let total = 0;
  data.datasets.forEach(ds => total += ds.data[idx]);
  return total / data.datasets.length;
});

// 自定义平均值线绘制插件
const averageLinePlugin = {
  id: 'averageLine',
  afterDatasetsDraw: (chart) => {
    const ctx = chart.ctx;
    const yAxis = chart.scales['y-axis-0'];
    const xAxis = chart.scales['x-axis-0'];
    
    yAxis.ticks.forEach((tick, idx) => {
      const avgValue = groupAverages[idx];
      // 坐标转换:数值转画布像素位置
      const xPos = xAxis.getPixelForValue(avgValue);
      const barHeight = yAxis.getPixelForTick(1) - yAxis.getPixelForTick(0);
      const yTop = yAxis.getPixelForTick(idx) - barHeight / 2;
      const yBottom = yAxis.getPixelForTick(idx) + barHeight / 2;
      
      // 绘制红色标记线
      ctx.save();
      ctx.strokeStyle = 'red';
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(xPos, yTop);
      ctx.lineTo(xPos, yBottom);
      ctx.stroke();
      ctx.restore();
    });
  }
};

var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, {
  type: 'groupableHBar',
  data: data,
  plugins: [averageLinePlugin], // 注册自定义插件
  options: {
    scales: {
      yAxes: [{
        stacked: true,
        type: 'category',
        id: 'y-axis-0'
      }],
      xAxes: [{
        stacked: true,
        type: 'linear',
        ticks: {
          beginAtZero:true
        },
        gridLines: {
          display: false,
          drawTicks: true,
        },
        id: 'x-axis-0'
      },
      {
        stacked: true,
        position: 'top',
        type: 'linear',
        ticks: {
          beginAtZero:true
        },
        id: 'x-axis-1',
        gridLines: {
          display: true,
          drawTicks: true,
        },
        display: false
      }]
    }
  }
});

二、替代开源库方案

如果不想做复杂的自定义开发,可以选择以下支持原生标记线能力的可视化库:

  • ECharts:开源免费,中文文档完善,原生支持markLine配置项,只需要传入平均值数据,几行配置就能实现需求,是国内项目的首选。
  • Plotly.js:开源数据可视化库,交互能力强,自带堆叠条形图和自定义注释线能力,适合需要数据导出、复杂交互的场景。
  • Highcharts:非商用场景免费,标记线配置成熟,兼容性好,适合需要兼容低版本浏览器的项目。

内容的提问来源于stack exchange,提问作者Dinh-Lam Pham

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 10:39:04