canvas自由绘制应采用距离阈值节流(如4px),仅当移动距离达标时记录新点,并配合线性插值补点提升流畅度,同时将stroke延迟至mouseup或节流执行,避免mousemove中频繁渲染。

Canvas 自由绘制时,鼠标或触摸移动事件频率很高(尤其在高刷屏或快速滑动时),若每次 mousemove 或 touchmove 都执行 lineTo + stroke,不仅产生大量冗余点,还会拖慢渲染、造成卡顿。节流不是简单地用 setTimeout 限频,而是要兼顾流畅性和性能——关键在于“按距离节流”,而非固定时间间隔。
距离阈值节流:只在移动足够远时记录新点
这是最实用、视觉效果最好的方式。它避免了稀疏采样导致的线条锯齿,也防止密集采样引发的性能压力。
- 每次移动时,计算当前坐标与上一个已记录点之间的欧氏距离
- 仅当距离 ≥ 设定阈值(如
3px~5px)时,才调用lineTo(x, y)并更新“上一点”坐标 - 阈值太小 → 点太多,无意义;太大 → 转折生硬、弧线失真
let lastX = 0, lastY = 0;
let isDrawing = false;
canvas.addEventListener('mousedown', (e) => {
const { x, y } = getCanvasPoint(e);
ctx.beginPath();
ctx.moveTo(x, y);
[lastX, lastY] = [x, y];
isDrawing = true;
});
canvas.addEventListener('mousemove', (e) => {
if (!isDrawing) return;
const { x, y } = getCanvasPoint(e);
const dist = Math.hypot(x - lastX, y - lastY);
if (dist >= 4) { // 距离阈值设为 4px
ctx.lineTo(x, y);
[lastX, lastY] = [x, y];
}
});
配合插值补点,缓解快速移动时的“虚线感”
单纯距离节流在高速拖动时,相邻点间距大,直线连接会显得断续。可在两点间插入 1~2 个中间点,用线性插值平滑过渡:
- 若
dist > 10,在lastX→x和lastY→y上等分插入 1 个中点 - 若
dist > 20,插入 2 个等距点 - 插值后仍走
lineTo,不增加beginPath开销
function addSmoothedLine(x, y) {
const dist = Math.hypot(x - lastX, y - lastY);
if (dist 20 ? 3 : dist > 10 ? 2 : 1;
for (let i = 1; i <h3>渲染节奏控制:不在每帧都 stroke</h3><p><code>stroke()</code> 是开销较大的操作,频繁调用会阻塞主线程。应改为:</p>
- 移动过程中只构建路径(
moveTo/lineTo),不stroke -
mouseup或touchend时统一stroke()一次 - 若需实时反馈(如压感粗细变化),可每
10~15ms节流调用一次stroke(),但必须搭配ctx.beginPath()重置路径,避免累积
注意:不要在
mousemove里反复beginPath()—— 那会切断路径,变成一堆短线段;正确做法是mousedown时beginPath(),移动中持续lineTo,结束时stroke()。
不复杂但容易忽略细节,把事件、坐标、路径管理和渲染节奏理清楚,就能做出响应灵敏、视觉自然的自由画笔。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











