canvas 动态折线图填充区域的核心是路径控制、坐标映射与逐帧更新:将数据点映射为反向y坐标,用path构造封闭路径(左下→数据点→右下→闭合),fill()填充后配合requestanimationframe增量重绘,并支持鼠标交互提示。

Canvas 实现动态折线图并填充下方区域,核心在于路径控制、坐标映射和逐帧更新。不是单纯画线,而是把数据点转为可视路径,再用 fill() 封闭区域,配合定时器或数据流实现“动起来”的效果。
坐标系与数据映射要合理
原始数据通常是数值数组(如 [120, 85, 140, 90, 160]),需映射到画布坐标。关键不是固定缩放,而是动态计算:先预留边距(如左右各 40px、上下各 30px),再将 Y 值反向映射(画布 Y 轴向下,数值越大应越靠上)。
- 设画布高为
h,内容区高度 =h - topMargin - bottomMargin - 最大值
max映射到topMargin,最小值min映射到h - bottomMargin - 单个点的 Y 坐标 =
topMargin + (max - value) / (max - min) * 内容区高度
用 Path 绘制折线+填充区域
不能只用 lineTo 连点,否则无法填充。必须构造一个封闭路径:从起点开始,依次连接所有数据点,再沿底部边界回到起点。
- 调用
beginPath()开始新路径 -
moveTo(leftMargin, bottomY)—— 先跳到底部左端(即区域左下角) - 对每个数据点:
lineTo(x, y)—— 画折线上沿 - 再
lineTo(rightMargin, bottomY)—— 沿底边回到右下角 - 最后
closePath()自动连回起点,形成封闭图形 - 设置
fillStyle后调用fill(),再用strokeStyle+stroke()描边
实现“动态”靠增量重绘与缓动
所谓动态,不是 CSS 动画,而是 JS 控制的帧更新。常见做法是维护一个当前显示的数据长度(比如初始只画前 3 个点),然后每几十毫秒增加一个点,重新计算并绘制整个路径。
- 用
requestAnimationFrame或setInterval触发重绘 - 每次只取
data.slice(0, currentLength),避免全量重算 - 若需平滑过渡,可对 X 坐标做插值(如
startX + (endX - startX) * progress),让点“滑入”而非突显 - 注意清空画布:
ctx.clearRect(0, 0, width, height)必须在每次绘制前执行
加交互提升实用性
用户常需要知道某点对应什么值。可在 mousemove 事件中,根据鼠标 X 坐标反推最邻近的数据索引,再绘制提示框或高亮该点。
- 监听 canvas 的
mousemove,获取event.offsetX - 减去 leftMargin,除以单点水平间距,得到近似索引
i - 用
fillText()在该点上方显示data[i],加背景矩形提升可读性 - 为避免频繁重绘,可节流(throttle)该逻辑,或仅在 hover 状态激活











