Newer
Older
DH_Apicture / public / static / libs / mapbox / extend / RainfallEffect.js
@zhangqy zhangqy on 29 Nov 4 KB first commit
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ?
  3. module.exports = factory() :
  4. typeof define === 'function' && define.amd ? define(factory) :
  5. (global = typeof globalThis !== 'undefined' ? globalThis :
  6. global || self, global.mapboxgl1.RainfallEffect = factory());
  7. }(window,(function(){
  8. const createCanvas = id => {
  9. const canvasID ='rain-canvas' + id;
  10. let canvas = document.getElementById(canvasID);
  11. if(!canvas) canvas = document.createElement('canvas'),canvas.id = canvasID,document.body.append(canvas);
  12. canvas.style.width= '100%';
  13. canvas.style.height= '100%';
  14. canvas.style.position= 'absolute';
  15. canvas.style.zIndex=10;
  16. canvas.style.top= '0';
  17. canvas.style.left= '0';
  18. canvas.style.pointerEvents= 'none';
  19. return canvas;
  20. };
  21.  
  22. // 雨滴类
  23. class Drop {
  24. constructor(x, y, speed, length, opacity,canvas) {
  25. this.x = x;
  26. this.y = y;
  27. this.speed = speed;
  28. this.length = length;
  29. this.opacity = opacity;
  30. this.canvas = canvas;
  31. }
  32.  
  33. update() {
  34. this.y += this.speed;
  35. if (this.y > this.canvas.height) {
  36. this.y = 0 - this.length;
  37. }
  38. }
  39.  
  40. draw() {
  41. let ctx = this.canvas.getContext('2d');
  42. ctx.beginPath();
  43. ctx.strokeStyle = `rgba(174,194,224,${this.opacity})`;
  44. ctx.lineWidth = 1;
  45. ctx.moveTo(this.x, this.y);
  46. ctx.lineTo(this.x, this.y + this.length);
  47. ctx.stroke();
  48. }
  49. }
  50.  
  51. function createRain(level,canvas) {
  52. let drops = [];
  53. let rainDensity, rainSpeed, rainLength;
  54.  
  55. switch (level) {
  56. case '1': // 小雨
  57. rainDensity = 100;
  58. rainSpeed = [1, 2];
  59. rainLength = [5, 10];
  60. break;
  61. case '2': // 中雨
  62. rainDensity = 200;
  63. rainSpeed = [2, 3];
  64. rainLength = [10, 15];
  65. break;
  66. case '3': // 大雨
  67. rainDensity = 300;
  68. rainSpeed = [3, 4];
  69. rainLength = [15, 20];
  70. break;
  71. }
  72.  
  73. for (let i = 0; i < rainDensity; i++) {
  74. const x = Math.random() * canvas.width;
  75. const y = Math.random() * canvas.height;
  76. const speed = Math.random() * (rainSpeed[1] - rainSpeed[0]) + rainSpeed[0];
  77. const length = Math.random() * (rainLength[1] - rainLength[0]) + rainLength[0];
  78. const opacity = Math.random() * 0.5 + 0.5;
  79. drops.push(new Drop(x, y, speed, length, opacity,canvas));
  80. }
  81.  
  82. return drops
  83. }
  84.  
  85. function animateRain(drops,lightningTimer,flashOpacity,canvas) {
  86. let ctx = canvas.getContext('2d');
  87. ctx.clearRect(0, 0, canvas.width, canvas.height);
  88. drops.forEach(drop => {
  89. drop.update();
  90. drop.draw();
  91. });
  92.  
  93. // 控制闪电效果
  94. if (lightningTimer <= 0 && false) {
  95. if (Math.random() > 0.98) { // 设置闪电随机出现的概率
  96. lightningTimer = Math.random() * 30 + 10; // 控制闪电持续的帧数
  97. flashOpacity = 1; // 闪电时的屏幕亮度
  98. createLightning(canvas); // 生成闪电
  99. }
  100. } else {
  101. lightningTimer--;
  102. flashOpacity -= 0.05; // 闪电逐渐消失
  103. }
  104.  
  105. // 绘制闪电的亮光效果
  106. if (flashOpacity > 0) {
  107. ctx.fillStyle = `rgba(255, 255, 255, ${flashOpacity})`;
  108. ctx.fillRect(0, 0, canvas.width, canvas.height);
  109. }
  110.  
  111. return requestAnimationFrame(()=> animateRain(drops,lightningTimer,flashOpacity,canvas));
  112. }
  113.  
  114. // 生成闪电
  115. function createLightning(canvas) {
  116. let ctx = canvas.getContext('2d');
  117. const lightningX = Math.random() * canvas.width; // 闪电的横向位置
  118. const lightningY = Math.random() * (canvas.height / 2); // 闪电的起点(从屏幕上半部分)
  119. ctx.strokeStyle = 'rgba(255, 255, 255, 1)';
  120. ctx.lineWidth = 2;
  121.  
  122. // 生成多个随机折线段构成闪电
  123. let x = lightningX;
  124. let y = lightningY;
  125.  
  126. for (let i = 0; i < 10; i++) {
  127. let nextX = x + (Math.random() * 80 - 40); // 随机向左或向右偏移
  128. let nextY = y + (Math.random() * 80 + 20); // 向下移动
  129.  
  130. ctx.beginPath();
  131. ctx.moveTo(x, y);
  132. ctx.lineTo(nextX, nextY);
  133. ctx.stroke();
  134.  
  135. x = nextX;
  136. y = nextY;
  137.  
  138. if (y > canvas.height) break; // 闪电到达屏幕底部结束
  139. }
  140. }
  141.  
  142.  
  143. function resizeCanvas(canvas) {
  144. canvas.width = window.innerWidth;
  145. canvas.height = window.innerHeight;
  146. }
  147.  
  148. return class RainfallEffect {
  149. canvas = null;
  150. animateId = null;
  151. drops = [];
  152. rainLevel = 'light';
  153. lightningTimer = 0;
  154. flashOpacity = 0;
  155. level = 1;
  156. constructor(props) {
  157. let canvas = createCanvas(1);
  158. this.canvas = canvas;
  159. window.addEventListener('resize', () => resizeCanvas(canvas));
  160. }
  161.  
  162. rain(level){
  163. this.level = level;
  164. this.drops = createRain(this.level,this.canvas);
  165. if(this.animateId) cancelAnimationFrame(this.animateId);
  166. this.animateId = animateRain(this.drops,this.lightningTimer,this.flashOpacity,this.canvas);
  167. }
  168.  
  169. hide(){
  170. this.canvas.style.display = 'none';
  171. }
  172.  
  173. show(){
  174. this.canvas.style.display = 'block';
  175. }
  176.  
  177. destroy(){
  178. if(this.animateId) cancelAnimationFrame(this.animateId);
  179. if(this.canvas) this.canvas.remove();
  180. }
  181. }
  182. })));