效果说明
本案例实现了一个平滑的画笔跟随效果。鼠标或触摸移动时会生成一条彩色的轨迹,并添加了渐变色和渐隐效果。
核心实现
1. 画笔状态管理
使用一个配置对象统一管理画笔的所有状态:
const brush = {
points: [], // 存储轨迹点数组
maxPoints: 50, // 轨迹最大点数(影响轨迹长度)
minDistance: 10, // 相邻点最小距离(影响轨迹平滑度)
lastX: 0, // 上一个点的X坐标
lastY: 0, // 上一个点的Y坐标
isDrawing: false, // 是否正在绘制
hue: 0 // HSL色相值(0-360)
};
2. 轨迹点控制
通过计算点间距离来控制轨迹的平滑度:
function addPoint(x, y) {
// 计算与上一个点的距离
const dx = x - brush.lastX;
const dy = y - brush.lastY;
const distance = Math.sqrt(dx * dx + dy * dy);
// 只有距离大于最小距离时才添加新点
if (distance >= brush.minDistance) {
brush.points.push({ x, y });
brush.lastX = x;
brush.lastY = y;
// 限制轨迹点数,移除最老的点
if (brush.points.length > brush.maxPoints) {
brush.points.shift();
}
}
}
3. 平滑轨迹绘制
使用线性插值连接点,实现平滑效果:
function drawTrail() {
if (brush.points.length < 2) return;
ctx.beginPath();
ctx.moveTo(brush.points[0].x, brush.points[0].y);
// 连接所有点
for (let i = 1; i < brush.points.length - 1; i++) {
ctx.lineTo(brush.points[i].x, brush.points[i].y);
}
// 设置渐变色和线条样式
brush.hue = (brush.hue + 1) % 360; // 循环改变色相
ctx.strokeStyle = `hsl(${brush.hue}, 100%, 50%)`;
ctx.lineWidth = 2;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.stroke();
}
4. 事件处理
统一处理鼠标和触摸事件:
function mousedown(e) {
brush.isDrawing = true;
brush.points = []; // 清空之前的点
brush.lastX = e.clientX; // 记录起始位置
brush.lastY = e.clientY;
}
// 添加事件监听
canvas.addEventListener('mousedown', mousedown);
canvas.addEventListener('mousemove', mousemove);
canvas.addEventListener('mouseup', mouseup);
参数调优
- 轨迹长度(maxPoints)
- 值越大: 轨迹越长,但内存占用更大
- 值越小: 轨迹更短,性能更好
- 50是一个比较平衡的值
- 点间距(minDistance)
- 值越大: 轨迹更粗糙,但性能更好
- 值越小: 轨迹更平滑,但点更密集
- 10像素是一个比较合适的值
- 渐隐速度(透明度)
- 值越大: 消失更快
- 值越小: 停留更久
- 0.05是一个比较理想的值
扩展思路
- 添加速度感知
- 添加压感支持