/** * 文件功能:聊天室下雨特效 * * 使用 Canvas 绘制斜向雨线,模拟真实降雨视觉效果。 * 加粗加深雨线颜色,在浅色背景上清晰可见。 * 特效总时长约 8 秒,结束后自动清理并回调。 */ const RainEffect = (() => { // 雨滴类:一条从顶部往下落的斜线 class Drop { constructor(w, h) { this.reset(w, h); } /** * 重置/初始化雨滴位置 */ reset(w, h) { this.x = Math.random() * w; this.y = Math.random() * -h; this.len = Math.random() * 25 + 12; // 雨线长度(稍加长) this.speed = Math.random() * 10 + 7; // 下落速度(加快) this.angle = (Math.PI / 180) * (75 + Math.random() * 10); this.alpha = Math.random() * 0.5 + 0.4; // 提高透明度上限 (0.4-0.9,原 0.2-0.5) this.strokeW = Math.random() * 1.5 + 0.8; // 线条宽度随机(原 0.8 固定) this.w = w; this.h = h; } /** 每帧更新雨滴位置 */ update() { this.x += Math.cos(this.angle) * this.speed * 0.3; this.y += Math.sin(this.angle) * this.speed; if (this.y > this.h + this.len) { this.reset(this.w, this.h); } } /** 绘制雨滴线段(加深蓝色,在浅色背景上更明显) */ draw(ctx) { ctx.save(); ctx.strokeStyle = `rgba(50, 130, 220, ${this.alpha})`; // 加深蓝色(原浅蓝 155,200,255) ctx.lineWidth = this.strokeW; ctx.shadowColor = "rgba(30, 100, 200, 0.4)"; ctx.shadowBlur = 2; ctx.beginPath(); ctx.moveTo(this.x, this.y); ctx.lineTo( this.x + Math.cos(this.angle) * this.len, this.y + Math.sin(this.angle) * this.len, ); ctx.stroke(); ctx.restore(); } } /** * 启动下雨特效 * * @param {HTMLCanvasElement} canvas 全屏 Canvas * @param {Function} onEnd 特效结束回调 */ function start(canvas, onEnd) { const ctx = canvas.getContext("2d"); const w = canvas.width; const h = canvas.height; const DURATION = 8000; const DROP_COUNT = 200; // 增加雨滴数量(原 180) const drops = Array.from({ length: DROP_COUNT }, () => { const d = new Drop(w, h); d.y = Math.random() * h; return d; }); let animId = null; const startTime = performance.now(); function animate(now) { // 清除画布(透明,不遮挡聊天背景) ctx.clearRect(0, 0, w, h); drops.forEach((d) => { d.update(); d.draw(ctx); }); if (now - startTime < DURATION) { animId = requestAnimationFrame(animate); } else { cancelAnimationFrame(animId); ctx.clearRect(0, 0, w, h); onEnd(); } } animId = requestAnimationFrame(animate); } return { start }; })();