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

如何使用Chart.js实现单药物多状态分段柱状图并解决标签与圆角问题?

针对Chart.js柱状图两个问题的解决方案

1. 同一药物多段记录添加统一顶部标签

通过自定义Chart.js插件就能实现,核心是按药物名称分组柱子,计算每组的中心位置后绘制统一标签。

示例代码:

const drugLabelPlugin = {
  id: 'drugLabel',
  afterDatasetsDraw(chart) {
    const ctx = chart.ctx;
    ctx.save();
    ctx.font = '14px Arial';
    ctx.fillStyle = '#333';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';

    // 按药物名称分组所有柱子
    const drugGroups = {};
    chart.data.datasets.forEach((dataset) => {
      dataset.data.forEach((_, index) => {
        const drugName = dataset.label; // 假设dataset的label为药物名称
        if (!drugGroups[drugName]) drugGroups[drugName] = [];
        const bar = chart.getDatasetMeta(dataset.index).data[index];
        drugGroups[drugName].push(bar);
      });
    });

    // 绘制每组的顶部标签
    Object.values(drugGroups).forEach(group => {
      const firstBar = group[0];
      const lastBar = group[group.length - 1];
      // 计算整个药物分段的中心X坐标
      const centerX = (firstBar.x - firstBar.width/2 + lastBar.x + lastBar.width/2) / 2;
      const labelY = firstBar.y - 10; // 标签距离柱子顶部10px
      ctx.fillText(group[0]._dataset.label, centerX, labelY);
    });
    ctx.restore();
  }
};

// 注册插件
Chart.register(drugLabelPlugin);

如果药物名称不是存在dataset.label中,只需调整分组的判断字段即可。

2. 多段记录的整体圆角效果

默认borderRadius会给每个独立柱子加圆角,要实现整体圆角,需自定义柱子绘制逻辑,判断当前柱子是同一药物的首段、末段还是中间段,只保留对应方向的圆角:

示例代码:

const roundedGroupBarPlugin = {
  id: 'roundedGroupBar',
  beforeDraw(chart) {
    const datasets = chart.data.datasets;
    datasets.forEach((mainDs) => {
      const drugName = mainDs.label;
      // 收集同一药物的所有柱子信息
      const sameDrugBars = [];
      datasets.forEach((ds, dsIdx) => {
        if (ds.label === drugName) {
          ds.data.forEach((_, dataIdx) => {
            const bar = chart.getDatasetMeta(dsIdx).data[dataIdx];
            sameDrugBars.push({bar, dsIdx, dataIdx});
          });
        }
      });
      // 按X轴位置排序(确保时间顺序正确)
      sameDrugBars.sort((a, b) => a.bar.x - b.bar.x);
      // 为每个柱子设置对应圆角
      sameDrugBars.forEach((item, idx) => {
        const bar = item.bar;
        if (idx === 0) {
          // 首段:仅保留左圆角
          bar.borderRadius = {topLeft: 8, bottomLeft: 8, topRight: 0, bottomRight: 0};
        } else if (idx === sameDrugBars.length - 1) {
          // 末段:仅保留右圆角
          bar.borderRadius = {topLeft: 0, bottomLeft: 0, topRight: 8, bottomRight: 8};
        } else {
          // 中间段:无圆角
          bar.borderRadius = 0;
        }
      });
    });
  }
};

// 注册插件
Chart.register(roundedGroupBarPlugin);

可自行修改8调整圆角大小,注意确保数据按时间顺序排列,或在插件排序逻辑中正确识别前后段。

额外提示

  • 两个插件可同时注册使用,互不冲突
  • 若你的数据结构和示例不同,只需对应调整分组、排序的判断逻辑
  • 测试时可单独启用一个插件,验证效果后再组合使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:23:14