canvas自由曲线平滑插值需路径建模、插值策略与渲染优化协同:用二次/三次贝塞尔替代lineto,配合round线帽/线连接、轨迹降噪重采样、catmull-rom或自适应贝塞尔插值实现g¹连续,并可选参数重映射保障匀速。

Canvas 实现自由曲线的平滑插值,核心不是“画得快”,而是让鼠标/触控轨迹在采样和连接时避免生硬折线、锯齿与速度突变。关键在于路径建模 + 插值策略 + 渲染优化三者配合。
用贝塞尔曲线替代直线连接
直接用 lineTo() 连接连续鼠标点,会形成大量小线段,拐角尖锐、视觉抖动明显。应改用二次或三次贝塞尔曲线拟合轨迹:
- 每采集 3–4 个点(如上一锚点、当前点、下一预测点),用
quadraticCurveTo(cpX, cpY, x, y)生成一段平滑弧线,控制点可设为前后两点中点偏移 ±1~3px 模拟手绘自然弯曲 - 若需更高精度,可用三次贝塞尔:用
bezierCurveTo(cp1X, cp1Y, cp2X, cp2Y, x, y),两个控制点分别影响前半段与后半段曲率,适合长距离拖拽 - 务必设置
ctx.lineCap = 'round'和ctx.lineJoin = 'round',消除端点与转角的棱角感
对原始轨迹做预处理降噪与重采样
原始 pointermove 坐标常含高频抖动、密度过高或不均匀。直接绘制既卡顿又不平滑:
- 记录所有点到数组,但不实时绘制;等
pointerup后再统一处理 - 先用滑动平均或 RDP(Douglas-Peucker)算法简化点列,剔除冗余点,保留关键转向位置
- 再对简化后的点列做 Catmull-Rom 或自适应贝塞尔插值:每段取相邻 4 点构造三次贝塞尔,确保 G¹ 连续(切线方向一致),视觉无断层
匀速运动需要参数重映射(非必须但推荐)
贝塞尔曲线的参数 t ∈ [0,1] 是匀速参数化,但对应的实际弧长非线性——直接按 t 等步长绘制会导致起始慢、中间快、收尾急停。要真正匀速:
- 预先对整条路径做高密度采样(如 t 步长 0.002),计算累计弧长数组
arcLengths[] - 动画或回放时,按真实时间换算目标弧长位置,用二分查找反推对应 t 值,再调用
getPointOnCubicBezier(t)获取坐标 - 轻量项目可跳过此步,改用 5~10 段贝塞尔拼接+缓动函数(如
easeInOutCubic)模拟近似匀速
性能与视觉平衡技巧
平滑不能以卡顿为代价。实际项目中建议:
- 移动端优先用
pointer事件而非mouse,支持触控压感与惯性 - 启用离屏 canvas 缓存已绘制路径,仅在新增笔画时重绘增量部分
- 禁用
shadowBlur做“伪抗锯齿”——它会造成重影和性能下降;真正抗锯齿由 Canvas 自动处理,关键是保证设备像素比适配:canvas.width = canvas.clientWidth * window.devicePixelRatio
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











