Newer
Older
DH_Apicture / public / static / libs / mapbox / extend / RainfallEffect.js
@zhangqy zhangqy 29 days ago 4 KB first commit
(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();
		}
	}
})));