(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.mapboxgl1.RainfallEffect = factory()); }(window,(function(){ const createCanvas = id => { const canvasID ='rain-canvas' + id; let canvas = document.getElementById(canvasID); if(!canvas) canvas = document.createElement('canvas'),canvas.id = canvasID,document.body.append(canvas); canvas.style.width= '100%'; canvas.style.height= '100%'; canvas.style.position= 'absolute'; canvas.style.zIndex=10; canvas.style.top= '0'; canvas.style.left= '0'; canvas.style.pointerEvents= 'none'; return canvas; }; // 雨滴类 class Drop { constructor(x, y, speed, length, opacity,canvas) { this.x = x; this.y = y; this.speed = speed; this.length = length; this.opacity = opacity; this.canvas = canvas; } update() { this.y += this.speed; if (this.y > this.canvas.height) { this.y = 0 - this.length; } } draw() { let ctx = this.canvas.getContext('2d'); ctx.beginPath(); ctx.strokeStyle = `rgba(174,194,224,${this.opacity})`; ctx.lineWidth = 1; ctx.moveTo(this.x, this.y); ctx.lineTo(this.x, this.y + this.length); ctx.stroke(); } } function createRain(level,canvas) { let drops = []; let rainDensity, rainSpeed, rainLength; switch (level) { case '1': // 小雨 rainDensity = 100; rainSpeed = [1, 2]; rainLength = [5, 10]; break; case '2': // 中雨 rainDensity = 200; rainSpeed = [2, 3]; rainLength = [10, 15]; break; case '3': // 大雨 rainDensity = 300; rainSpeed = [3, 4]; rainLength = [15, 20]; break; } for (let i = 0; i < rainDensity; i++) { const x = Math.random() * canvas.width; const y = Math.random() * canvas.height; const speed = Math.random() * (rainSpeed[1] - rainSpeed[0]) + rainSpeed[0]; const length = Math.random() * (rainLength[1] - rainLength[0]) + rainLength[0]; const opacity = Math.random() * 0.5 + 0.5; drops.push(new Drop(x, y, speed, length, opacity,canvas)); } return drops } function animateRain(drops,lightningTimer,flashOpacity,canvas) { let ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); drops.forEach(drop => { drop.update(); drop.draw(); }); // 控制闪电效果 if (lightningTimer <= 0 && false) { if (Math.random() > 0.98) { // 设置闪电随机出现的概率 lightningTimer = Math.random() * 30 + 10; // 控制闪电持续的帧数 flashOpacity = 1; // 闪电时的屏幕亮度 createLightning(canvas); // 生成闪电 } } else { lightningTimer--; flashOpacity -= 0.05; // 闪电逐渐消失 } // 绘制闪电的亮光效果 if (flashOpacity > 0) { ctx.fillStyle = `rgba(255, 255, 255, ${flashOpacity})`; ctx.fillRect(0, 0, canvas.width, canvas.height); } return requestAnimationFrame(()=> animateRain(drops,lightningTimer,flashOpacity,canvas)); } // 生成闪电 function createLightning(canvas) { let ctx = canvas.getContext('2d'); const lightningX = Math.random() * canvas.width; // 闪电的横向位置 const lightningY = Math.random() * (canvas.height / 2); // 闪电的起点(从屏幕上半部分) ctx.strokeStyle = 'rgba(255, 255, 255, 1)'; ctx.lineWidth = 2; // 生成多个随机折线段构成闪电 let x = lightningX; let y = lightningY; for (let i = 0; i < 10; i++) { let nextX = x + (Math.random() * 80 - 40); // 随机向左或向右偏移 let nextY = y + (Math.random() * 80 + 20); // 向下移动 ctx.beginPath(); ctx.moveTo(x, y); ctx.lineTo(nextX, nextY); ctx.stroke(); x = nextX; y = nextY; if (y > canvas.height) break; // 闪电到达屏幕底部结束 } } function resizeCanvas(canvas) { canvas.width = window.innerWidth; canvas.height = window.innerHeight; } return class RainfallEffect { canvas = null; animateId = null; drops = []; rainLevel = 'light'; lightningTimer = 0; flashOpacity = 0; level = 1; constructor(props) { let canvas = createCanvas(1); this.canvas = canvas; window.addEventListener('resize', () => resizeCanvas(canvas)); } rain(level){ this.level = level; this.drops = createRain(this.level,this.canvas); if(this.animateId) cancelAnimationFrame(this.animateId); this.animateId = animateRain(this.drops,this.lightningTimer,this.flashOpacity,this.canvas); } hide(){ this.canvas.style.display = 'none'; } show(){ this.canvas.style.display = 'block'; } destroy(){ if(this.animateId) cancelAnimationFrame(this.animateId); if(this.canvas) this.canvas.remove(); } } })));