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

Chart.js 3.x(CDN引入)绘制水平线失败求助

在Chart.js 3.0.0-beta.6中实现折线图叠加三条水平线的解决方案

哎,这个坑我之前踩过!Chart.js 3.x的API和2.x简直是推倒重来了,旧的chartjs-annotation-plugin当时还没适配beta版本,自定义插件如果沿用2.x的写法肯定会炸——你遇到的canvas is undefined就是因为3.x不再直接给插件暴露全局canvas对象了。

下面直接给你能跑通的完整方案,一步步来:

1. 正确引入Chart.js Beta版

先确保你用的是指定的3.0.0-beta.6版本,CDN地址直接用这个:

<script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.0-beta.6/dist/chart.min.js"></script>

2. 编写适配3.x的自定义水平线插件

这个插件会在图表绘制完成后,根据你设定的Y轴数值,自动计算对应的画布位置并绘制水平线。核心是从chart实例里获取绘图上下文,而不是找全局canvas:

// 自定义水平线插件
const horizontalLinePlugin = {
  id: 'horizontalLines',
  afterDraw: (chart) => {
    // 这里替换成你实际需要的三条水平线的Y轴数值
    const lineValues = [20, 50, 80];
    const ctx = chart.ctx; // 从chart实例获取绘图上下文
    const yScale = chart.scales.y; // 获取Y轴刻度对象
    
    lineValues.forEach(value => {
      // 将Y轴数值转换为画布上的像素位置
      const yPixel = yScale.getPixelForValue(value);
      
      // 开始绘制线条
      ctx.save();
      ctx.beginPath();
      // 线条从图表区域的左边界开始,到右边界结束
      ctx.moveTo(chart.chartArea.left, yPixel);
      ctx.lineTo(chart.chartArea.right, yPixel);
      ctx.strokeStyle = '#ff0000'; // 线条颜色
      ctx.lineWidth = 2; // 线条宽度
      ctx.setLineDash([5, 5]); // 可选:改成虚线,不需要就删掉这行
      ctx.stroke();
      ctx.restore();
    });
  }
};

// 注册插件到Chart.js
Chart.register(horizontalLinePlugin);

3. 完整的HTML页面示例

把插件和折线图配置整合到一起,直接复制就能运行:

<!DOCTYPE html>
<html>
<head>
  <title>Chart.js 3.x 折线图+水平线</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.0-beta.6/dist/chart.min.js"></script>
</head>
<body>
  <div style="width: 80%; margin: 2rem auto;">
    <canvas id="myChart"></canvas>
  </div>

  <script>
    // 自定义水平线插件
    const horizontalLinePlugin = {
      id: 'horizontalLines',
      afterDraw: (chart) => {
        const lineValues = [20, 50, 80]; // 替换成你的目标数值
        const ctx = chart.ctx;
        const yScale = chart.scales.y;
        
        lineValues.forEach(value => {
          const yPixel = yScale.getPixelForValue(value);
          
          ctx.save();
          ctx.beginPath();
          ctx.moveTo(chart.chartArea.left, yPixel);
          ctx.lineTo(chart.chartArea.right, yPixel);
          ctx.strokeStyle = '#ff0000';
          ctx.lineWidth = 2;
          ctx.setLineDash([5, 5]);
          ctx.stroke();
          ctx.restore();
        });
      }
    };

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

    // 初始化折线图
    const chartCtx = document.getElementById('myChart').getContext('2d');
    const myChart = new Chart(chartCtx, {
      type: 'line',
      data: {
        labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
        datasets: [{
          label: '业务数据',
          data: [10, 30, 45, 60, 70, 55, 85],
          borderColor: '#36a2eb',
          backgroundColor: 'rgba(54, 162, 235, 0.1)',
          fill: true
        }]
      },
      options: {
        scales: {
          y: {
            beginAtZero: true,
            max: 100 // 根据你的数据调整Y轴最大值
          }
        }
      }
    });
  </script>
</body>
</html>

关键细节说明

  • 为什么之前报错?Chart.js 3.x把插件的上下文逻辑改了,不再提供全局canvas,必须通过chart.ctx获取绘图上下文。
  • afterDraw钩子:确保在图表所有元素绘制完成后再画水平线,避免被折线覆盖。
  • chart.chartArea:获取图表的实际绘制区域,让水平线只在图表内部显示,不会超出容器。
  • 样式调整:直接修改strokeStyle(颜色)、lineWidth(宽度)、setLineDash(虚实)就能自定义水平线样式。

内容的提问来源于stack exchange,提问作者Mr.Rulez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:26:39