Newer
Older
urbanLifeline_YanAn / src / views / oneMap / cityGK / canvasRain.vue
@zhangqy zhangqy on 18 Oct 4 KB 效果提交
  1. <template>
  2. <!-- 降雨效果canvas -->
  3. <div class="canvasRainPage">
  4. <!-- 降雨 -->
  5. <canvas id="canvasRain"></canvas>
  6.  
  7. <!-- 降雪 -->
  8. <canvas id="canvasSnow"></canvas>
  9. </div>
  10. </template>
  11.  
  12. <script setup>
  13. const { proxy } = getCurrentInstance();
  14. const timer = ref(null);
  15. const timerAll = ref(null);
  16.  
  17. // 画笔
  18. const ctx = ref(null);
  19. const ctxSnow = ref(null);
  20. // 画布的宽高
  21. let w = window.innerWidth;
  22. let h = window.innerHeight;
  23. // 存放雨滴的数组
  24. let arr = [];
  25. // 雨滴的数量
  26. const size = ref(300);
  27. // 雨滴的构造函数
  28. class Rain {
  29. x = random(w);
  30. y = random(h);
  31. ySpeed = random(2) + 8;
  32. show() {
  33. drawLine(this.x, this.y);
  34. }
  35. run() {
  36. if (this.y > h) {
  37. this.y = 0;
  38. this.x = random(w);
  39. }
  40. this.y = this.y + this.ySpeed;
  41. }
  42. }
  43. // 画线(雨滴)
  44. function drawLine(x1, y1) {
  45. ctx.value.beginPath();
  46. ctx.value.strokeStyle = "rgba(35, 195, 255, 1)";
  47. ctx.value.moveTo(x1, y1);
  48. // 雨长度
  49. ctx.value.lineTo(x1, y1 + 20);
  50. ctx.value.stroke();
  51. }
  52. // 生成随机数
  53. function random(num) {
  54. return Math.random() * num;
  55. }
  56. // 开始
  57. function start() {
  58. for (let i = 0; i < size.value; i++) {
  59. let rain = new Rain();
  60. arr.push(rain);
  61. rain.show();
  62. }
  63. timer.value = setInterval(() => {
  64. ctx.value.clearRect(0, 0, w, h);
  65. for (let i = 0; i < size.value; i++) {
  66. arr[i].show();
  67. arr[i].run();
  68. }
  69. }, 30);
  70. }
  71. // 初始化
  72. function init(ctx1) {
  73. ctx.value = ctx1;
  74. start();
  75. }
  76.  
  77. // 清除画布
  78. function clearDraw() {
  79. ctx.value.clearRect(0, 0, w, h);
  80. }
  81.  
  82. // 初始化
  83. function initCanvas() {
  84. const canvas = document.querySelector("#canvasRain");
  85. ctx.value = canvas.getContext("2d");
  86. canvas.width = w;
  87. canvas.height = h;
  88. init(ctx.value);
  89. // 1-12个月的不同降雨量变化
  90. let rainArr = [
  91. { month: "1", rain: 300 },
  92. { month: "2", rain: 350 },
  93. { month: "3", rain: 400 },
  94. { month: "4", rain: 450 },
  95. { month: "5", rain: 550 },
  96. { month: "6", rain: 600 },
  97. { month: "7", rain: 1200 },
  98. { month: "8", rain: 700 },
  99. { month: "9", rain: 600 },
  100. { month: "10", rain: 460 },
  101. { month: "11", rain: 400 },
  102. { month: "12", rain: 300 },
  103. ];
  104. let i = 0;
  105. timerAll.value = setInterval(() => {
  106. size.value = rainArr[i].rain;
  107. i++;
  108. if (i == 12) i = 0;
  109. init(ctx.value); //降雨效果
  110. // 下雪效果
  111. if (i >= 2 && i <= 10) {
  112. ctxSnow.value && ctxSnow.value.clearRect(0, 0, w, h); // 清除画布重新渲染
  113. ctxSnow.value = null;
  114. } else {
  115. initSnow();
  116. }
  117. }, 2083);
  118. }
  119.  
  120. // 降雪效果
  121. function initSnow() {
  122. const canvas2 = document.querySelector("#canvasSnow");
  123. ctxSnow.value = canvas2.getContext("2d");
  124. // 设置canvas画布大小
  125. canvas2.width = w;
  126. canvas2.height = h;
  127.  
  128. const config = {
  129. number: 300, // 生成的雪花数量
  130. snowArr: [],
  131. pic: "https://www.deanhan.cn/wp-content/uploads/2017/12/snow.png", // 雪花图片
  132. };
  133. let snowImg = new Image();
  134. snowImg.src = config.pic;
  135.  
  136. for (let i = 0; i < config.number; i++) {
  137. config.snowArr.push({
  138. x: Math.random() * w, // 定义每片雪花的X轴
  139. y: Math.random() * h, // Y轴
  140. toX: Math.random(), // 雪花每一次渲染的X距离
  141. toY: Math.random() * 1 + 5, //速度
  142. size: Math.random() * 20 + 5, // 雪花的大小
  143. });
  144. }
  145.  
  146. const dropAnimation = () => {
  147. if (!!!ctxSnow.value) return;
  148. ctxSnow.value.clearRect(0, 0, w, h); // 清除画布重新渲染
  149. for (let i = 0; i < config.snowArr.length; i++) {
  150. let snow = config.snowArr[i];
  151. // ctx.beginPath(); //绘制圆形雪花 后面直接图片代替
  152. // ctx.arc(snow.x, snow.y, snow.size, 0, Math.PI * 2, true);
  153. // ctx.fillStyle = '#666';
  154. // ctx.fill();
  155. ctxSnow.value.drawImage(snowImg, snow.x, snow.y, snow.size, snow.size);
  156.  
  157. snow.x = snow.x > w ? 0 : snow.x + snow.toX; // 每调一次函数向右移动一点
  158. snow.y = snow.y > h ? 0 : snow.y + snow.toY; // 向下移动
  159. }
  160. requestAnimationFrame(dropAnimation);
  161. };
  162. requestAnimationFrame(dropAnimation);
  163. }
  164.  
  165. onMounted(() => {
  166. initCanvas();
  167. initSnow();
  168. });
  169. onBeforeUnmount(() => {
  170. if (timer.value) clearInterval(timer.value);
  171. if (timerAll.value) clearInterval(timerAll.value);
  172. clearDraw();
  173. ctxSnow.value && ctxSnow.value.clearRect(0, 0, w, h);
  174. });
  175. </script>
  176.  
  177. <style lang="scss" scoped>
  178. .canvasRainPage {
  179. width: 100%;
  180. height: 100%;
  181. background: rgba(0, 59, 109, 0.2);
  182. position: absolute;
  183. left: 0px;
  184. top: 0px;
  185. z-index: 100;
  186. pointer-events: none;
  187. #canvasRain {
  188. position: absolute;
  189. left: 0px;
  190. top: 0px;
  191. z-index: 102;
  192. }
  193. #canvasSnow {
  194. position: absolute;
  195. left: 0px;
  196. top: 0px;
  197. z-index: 101;
  198. }
  199. }
  200. </style>