如何实现类似Bornfight Studio的网页涂鸦自动擦除效果?
实现涂鸦自动擦除效果
要实现类似的涂鸦绘制后自动消失的效果,核心思路是记录每一笔绘制的图形数据,通过动画循环逐步淡化并移除旧的绘制内容。下面是基于你提供的代码修改后的完整实现:
修改后的完整代码
HTML
<canvas id="canvas"></canvas>
CSS(可选,优化canvas显示)
#canvas { background: #000; display: block; margin: 0 auto; cursor: crosshair; }
JavaScript
var canvas = document.getElementById("canvas"), ctx = canvas.getContext("2d"), painting = false, lastX = 0, lastY = 0, lineThickness = 1; // 存储所有绘制的图形数据 const draws = []; // 线条最大存活时间(毫秒,可调整) const MAX_LIFETIME = 2000; canvas.width = canvas.height = 600; // 初始化画布背景 ctx.fillStyle = "#000"; ctx.fillRect(0, 0, 600, 600); canvas.onmousedown = function(e) { painting = true; lastX = e.pageX - this.offsetLeft; lastY = e.pageY - this.offsetTop; }; canvas.onmouseup = function(e){ painting = false; } canvas.onmousemove = function(e) { if (painting) { const mouseX = e.pageX - this.offsetLeft; const mouseY = e.pageY - this.offsetTop; // 保留原有的线条插值逻辑,确保绘制连贯 var x1 = mouseX, x2 = lastX, y1 = mouseY, y2 = lastY; var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1)); if (steep){ var x = x1; x1 = y1; y1 = x; var y = y2; y2 = x2; x2 = y; } if (x1 > x2) { var x = x1; x1 = x2; x2 = x; var y = y1; y1 = y2; y2 = y; } var dx = x2 - x1, dy = Math.abs(y2 - y1), error = 0, de = dy / dx, yStep = -1, y = y1; if (y1 < y2) { yStep = 1; } lineThickness = 5 - Math.sqrt((x2 - x1) *(x2-x1) + (y2 - y1) * (y2-y1))/10; if(lineThickness < 1){ lineThickness = 1; } // 不再直接绘制,而是将图形数据存入数组 for (var x = x1; x < x2; x++) { const drawX = steep ? y : x; const drawY = steep ? x : y; draws.push({ x: drawX, y: drawY, size: lineThickness, timestamp: Date.now() }); error += de; if (error >= 0.5) { y += yStep; error -= 1.0; } } lastX = mouseX; lastY = mouseY; } } // 动画循环,负责绘制和清理旧线条 function animate() { // 清除画布(重新绘制黑色背景) ctx.fillStyle = "#000"; ctx.fillRect(0, 0, canvas.width, canvas.height); const now = Date.now(); // 过滤存活线条并绘制,实现渐变消失 draws.forEach(draw => { const age = now - draw.timestamp; if (age > MAX_LIFETIME) return; // 根据存活时间计算透明度,越旧越淡 const alpha = 1 - (age / MAX_LIFETIME); ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`; ctx.fillRect(draw.x, draw.y, draw.size, draw.size); }); // 清理已过期的线条数据,避免内存占用过高 while (draws.length > 0 && (Date.now() - draws[0].timestamp) > MAX_LIFETIME) { draws.shift(); } requestAnimationFrame(animate); } // 启动动画循环 animate();
关键改动说明
- 绘制数据存储:新增
draws数组,记录每一个绘制矩形的位置、大小和时间戳,不再直接将图形画到画布上。 - 动画循环控制:通过
requestAnimationFrame实现持续渲染,每次循环先清空画布,再根据时间戳筛选存活线条。 - 渐变消失效果:根据线条存活时间计算透明度,旧线条会逐渐变淡直至消失,调整
MAX_LIFETIME数值可控制线条保留时长(数值越大,保留时间越长)。 - 内存优化:定期移除数组中已过期的线条数据,避免数组无限增长导致内存占用过高。
内容的提问来源于stack exchange,提问作者Neko Nin
相关产品推荐
相关产品推荐

