点击上方 前端瓶子君,关注公众号

回复算法,加入前端编程面试算法每日一题群

来源:北极光之夜

https://juejin.cn/post/6958698023727661092

一.先看效果(源码在最后):

我的B站地址~效果演示更清晰

图片展示,因为图片限制5m大小,所以演示不太多:

二.实现过程(可一步一步实现):

因为雨是重点,所以中间 logo 部分就不详细写了,可直接看源码~

1.定义canvas标签与设置css基本样式:

 <canvas id="canvas"></canvas>
复制代码
      *{margin: 0;padding: 0;box-sizing: border-box;}#canvas{position: fixed;background-color: rgb(0, 0, 0);z-index: -10;}
复制代码

position: fixed; 固定定位。

2. 开始js部分,获取画布与定义基本变量:

 // 获取画布var canvas = document.querySelector("#canvas");var rain = canvas.getContext('2d');// drop数组,存每个散开的小水滴信息var drop = [];// water数组,存每丝雨的信息var water = [];// 雨的数量,可自行更改var waterNum = 100;// 小水(雨)滴的重力var gravity = 1;// 鼠标在页面的初始位置var mouseX=-36,mouseY=-36;// 关于雨的角度值,值为-1到1,后面讲var direction = 0;// 这也是关于鼠标在页面位置的角度值,值为-1到1var mouseDelay = 0;// 这是画布自适应窗口大小的函数,复制即可window.onresize = resizeCanvas;function resizeCanvas() {canvas.width = window.innerWidth;canvas.height = window.innerHeight;}resizeCanvas();
复制代码

2.初始化雨:

  // 一丝雨的初始化,封装,后面好几处要调用function creatWater(){         water.push({//值为0或1,判断是否要散开水滴add:1,//随机初始水平位置x:Math.random()*3*canvas.width-canvas.width,// 随机初始垂直位置,在上面一点,这样雨能从上面下落y: Math.random()*500-500,// 随机雨的长度len: Math.random()*20+50,// 随机雨的速度speed: Math.random()*10+35,// 随机雨的随机颜色color: `rgb(255,255,255,${Math.random()*0.5})`,// 随机散开水滴数量dropNum:Math.random()*6+6})                   }// 雨数组初始化,每丝雨都来function chushi(){for (let i = 0; i < waterNum; i++) {creatWater();} }
复制代码

3.初始化雨滴:

 // 散开水滴数组初始化,x为水平位置,y为垂直位置,dropNum为数量function creatDrop (x,y,dropNum){//给drop数组添加元素for (let j = 0; j < dropNum; j++) {drop.push({// x轴位置pagex:x,// y轴位置pagey:y,// x轴移动距离dx:Math.random()*12-6,// y轴移动距离dy:Math.random()*10-20,// 半径r:Math.random()+2,//颜色color: `rgb(255,255,255,${Math.random()*0.5+0.5})`,})}}
复制代码

4.绘画每一丝雨:

 // 绘画,画雨function drawWater(){//遍历数组for (let i = 0; i < water.length; i++){let temp = water[i];// 颜色rain.strokeStyle = temp.color;// 开始路径rain.beginPath();// 开始点rain.moveTo(temp.x,temp.y);// 结束点,连线,如: 当前x位置+长度*角度值  rain.lineTo(temp.x+temp.len*direction,temp.y+temp.len);// 线宽度rain.lineWidth = 3;// 绘制rain.stroke();                            }}
复制代码

5.绘画每一个雨滴:

 // 绘画雨滴function drawDrop(){//遍历for (let i = 0; i < drop.length; i++){  let temp = drop[i];// 线宽度rain.lineWidth = 2;//颜色rain.strokeStyle = temp.color;//开始路径rain.beginPath();// 画一个随机的弧度rain.arc(temp.pagex,temp.pagey,temp.r, Math.PI , Math.random() * 2 * Math.PI);// 绘制rain.stroke();//结束路径rain.closePath();                            }}
复制代码

5. 雨信息更新,同时判断各种事件:

 //雨信息的更新function updateWater(){for (let i = 0; i < water.length; i++){// 判断雨的底部是否碰到鼠标,碰到就散开成水滴,x轴y轴与鼠标的位置绝对值在35之内则散开。if(Math.abs(mouseX-water[i].x)<35&&Math.abs(mouseY-water[i].y-water[i].len)<35){// 创建雨滴,传入x轴y轴大小与数量creatDrop(water[i].x,water[i].y+water[i].len,water[i].dropNum);// 既然水滴散开了,就清除掉这丝雨water.splice(i,1);// 重新来一丝随机的雨creatWater();}// 判断雨的底部是否超过画布底部,且add值为1if(((water[i].y+water[i].len)>=canvas.height) && water[i].add==1){// add值为0 water[i].add = 0;// 创建雨滴,传入x轴y轴大小与数量,y轴位置就为画布高即可creatDrop(water[i].x,canvas.height,water[i].dropNum);}// 判断整丝雨是否超过画布if(water[i].y>canvas.height){// 清除它water.splice(i,1);// 来个新的creatWater();}// 缓动动画原理,雨角度慢慢接近鼠标的角度direction += (mouseDelay - direction)*0.0002;           // 雨x轴位置改变water[i].x += water[i].speed*direction;//雨y轴位置改变water[i].y += water[i].speed;        }}
复制代码

6. 雨滴信息更新:

 // 雨滴信息更新function updateDrop(){for(let i=0;i<drop.length;i++){// y轴移动距离加上重力。因为dy一开是负数,所以雨滴先升后降drop[i].dy +=  gravity;    // x轴位置改变,同时它也受雨角度影响drop[i].pagex += drop[i].dx + direction*10;// y轴位置改变drop[i].pagey += drop[i].dy;//判断雨滴是否超过画布if(drop[i].pagey>canvas.height){//清除水滴drop.splice(i,1);}}}
复制代码

7.绑定鼠标事件:

 // 绑定鼠标移动事件window.addEventListener('mousemove',e=>{// 得到x轴位置mouseX = e.clientX;//得到y轴位置mouseY = e.clientY;// 雨角度值,在-1到1之间mouseDelay = (e.clientX-canvas.offsetWidth/2)/(canvas.offsetWidth/2);})// 判断鼠标离开事件window.addEventListener('mouseout',()=>{// 给个值,不会产生雨滴的值就行mouseY=canvas.height+40;})
复制代码

8.设置定时器,开始下雨动画:

// 先初始化雨数组chushi();//设置定时器,开始动画setInterval(function(){// 清除画布rain.clearRect(0,0,canvas.width,canvas.height);// 更新雨和雨滴信息updateWater();   updateDrop();// 绘画雨和雨滴drawWater();drawDrop();},20)
复制代码

三.完整代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>北极光之夜。</title><style>*{margin: 0;padding: 0;box-sizing: border-box;}#canvas{position: fixed;background-color: rgb(0, 0, 0);z-index: -10;}svg{position: absolute;top: 50%;left: 50%;transform: translate(-50%,-50%);}.txt{   font-family: 'fangsong';font-weight: 900;font-size: 80px;letter-spacing: 3px;fill: transparent;stroke: rgb(30, 134, 252); stroke-width: 1.5px;stroke-dasharray: 625;stroke-dashoffset: 625;animation: draw 2s linear infinite;text-shadow: 0 0 10px rgb(30, 134, 252),0 0 20px rgb(30, 134, 252),0 0 40px rgb(30, 134, 252),0 0 60px rgb(30, 134, 252);}@keyframes draw{0%,100%{stroke-dasharray: 625;stroke-dashoffset: 625;}45%,55%{stroke-dasharray: 652;stroke-dashoffset: 0;}}</style>
</head>
<body><svg width="500" height="200"><text x="30" y="120" class="txt">北极光之夜。</text></svg><canvas id="canvas"></canvas><script>// 获取画布var canvas = document.querySelector("#canvas");var rain = canvas.getContext('2d');// drop数组,存每个散开的小水滴信息var drop = [];// water数组,存每丝雨的信息var water = [];// 雨的数量,可自行更改var waterNum = 100;// 小水(雨)滴的重力var gravity = 1;// 鼠标在页面的初始位置var mouseX=-36,mouseY=-36;// 关于雨的角度值,值为-1到1,后面讲var direction = 0;// 这也是关于鼠标在页面位置的角度值,值为-1到1var mouseDelay = 0;// 这是画布自适应窗口大小的函数,复制即可window.onresize = resizeCanvas;function resizeCanvas() {canvas.width = window.innerWidth;canvas.height = window.innerHeight;}resizeCanvas();// 一丝雨的初始化,封装,后面好几处要调用function creatWater(){         water.push({//值为0或1,判断是否要散开水滴add:1,//随机初始水平位置x:Math.random()*3*canvas.width-canvas.width,// 随机初始垂直位置,在上面一点,这样雨能从上面下落y: Math.random()*500-500,// 随机雨的长度len: Math.random()*20+50,// 随机雨的速度speed: Math.random()*10+35,// 随机雨的随机颜色color: `rgb(255,255,255,${Math.random()*0.5})`,// 随机散开水滴数量dropNum:Math.random()*6+6})                   }// 雨数组初始化,每丝雨都来function chushi(){for (let i = 0; i < waterNum; i++) {creatWater();} }// 散开水滴数组初始化,x为水平位置,y为垂直位置,dropNum为数量function creatDrop (x,y,dropNum){//给drop数组添加元素for (let j = 0; j < dropNum; j++) {drop.push({// x轴位置pagex:x,// y轴位置pagey:y,// x轴移动距离dx:Math.random()*12-6,// y轴移动距离dy:Math.random()*10-20,// 半径r:Math.random()+2,//颜色color: `rgb(255,255,255,${Math.random()*0.5+0.5})`,})}}// 绘画,画雨function drawWater(){//遍历数组for (let i = 0; i < water.length; i++){let temp = water[i];// 颜色rain.strokeStyle = temp.color;// 开始路径rain.beginPath();// 开始点rain.moveTo(temp.x,temp.y);// 结束点,连线,如: 当前x位置+长度*角度值  rain.lineTo(temp.x+temp.len*direction,temp.y+temp.len);// 线宽度rain.lineWidth = 3;// 绘制rain.stroke();                            }}// 绘画雨滴function drawDrop(){//遍历for (let i = 0; i < drop.length; i++){  let temp = drop[i];// 线宽度rain.lineWidth = 2;//颜色rain.strokeStyle = temp.color;//开始路径rain.beginPath();// 画一个随机的弧度rain.arc(temp.pagex,temp.pagey,temp.r, Math.PI , Math.random() * 2 * Math.PI);// 绘制rain.stroke();//结束路径rain.closePath();                            }}//雨信息的更新function updateWater(){for (let i = 0; i < water.length; i++){// 判断雨的底部是否碰到鼠标,碰到就散开成水滴,x轴y轴与鼠标的位置绝对值在35之内则散开。if(Math.abs(mouseX-water[i].x)<35&&Math.abs(mouseY-water[i].y-water[i].len)<35){// 创建雨滴,传入x轴y轴大小与数量creatDrop(water[i].x,water[i].y+water[i].len,water[i].dropNum);// 既然水滴散开了,就清除掉这丝雨water.splice(i,1);// 重新来一丝随机的雨creatWater();}// 判断雨的底部是否超过画布底部,且add值为1if(((water[i].y+water[i].len)>=canvas.height) && water[i].add==1){// add值为0 water[i].add = 0;// 创建雨滴,传入x轴y轴大小与数量,y轴位置就为画布高即可creatDrop(water[i].x,canvas.height,water[i].dropNum);}// 判断整丝雨是否超过画布if(water[i].y>canvas.height){// 清除它water.splice(i,1);// 来个新的creatWater();}// 缓动动画原理,雨角度慢慢接近鼠标的角度direction += (mouseDelay - direction)*0.0002;           // 雨x轴位置改变water[i].x += water[i].speed*direction;//雨y轴位置改变water[i].y += water[i].speed;        }}// 雨滴信息更新function updateDrop(){for(let i=0;i<drop.length;i++){// y轴移动距离加上重力。因为dy一开是负数,所以雨滴先升后降drop[i].dy +=  gravity;    // x轴位置改变,同时它也受雨角度影响drop[i].pagex += drop[i].dx + direction*10;// y轴位置改变drop[i].pagey += drop[i].dy;//判断雨滴是否超过画布if(drop[i].pagey>canvas.height){//清除水滴drop.splice(i,1);}}}// 绑定鼠标移动事件window.addEventListener('mousemove',e=>{// 得到x轴位置mouseX = e.clientX;//得到y轴位置mouseY = e.clientY;// 雨角度值,在-1到1之间mouseDelay = (e.clientX-canvas.offsetWidth/2)/(canvas.offsetWidth/2);})// 判断鼠标离开事件window.addEventListener('mouseout',()=>{// 给个值,不会产生雨滴的值就行mouseY=canvas.height+40;})// 先初始化雨数组chushi();//设置定时器,开始动画setInterval(function(){// 清除画布rain.clearRect(0,0,canvas.width,canvas.height);// 更新雨和雨滴信息updateWater();   updateDrop();// 绘画雨和雨滴drawWater();drawDrop();},20)</script>
</body>
</html>
复制代码

四.总结:

看到这里了,不点个赞再走吗~

在这里插入图片描述

五.CSDN其它文章:

环绕倒影加载特效 html+css 气泡浮动背景特效 html+css 简约时钟特效 html+css+js 赛博朋克风格按钮 html+css 仿网易云官网轮播图 html+css+js 水波加载动画 html+css 导航栏滚动渐变效果 html+css+js 书本翻页 html+css 3D立体相册 html+css 霓虹灯绘画板效果 html+css+js 记一些css属性总结(一) Sass总结笔记 ......等等 进我主页看更多~

最后

欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿

回复「算法」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!

回复「交流」,吹吹水、聊聊技术、吐吐槽!

回复「阅读」,每日刷刷高质量好文!

如果这篇文章对你有帮助,「在看」是最大的支持

》》面试官也在看的算法资料《《

“在看和转发”就是最大的支持

炎炎夏日,快用代码下场雨相关推荐

  1. 炎炎夏日,快用代码下场雨ヽ`☂ヽ`canvas

    一.先看效果(源码在最后): 哗啦啦啦 我的B站地址~效果演示更清晰 图片展示,因为图片限制5m大小,所以演示不太多: 二.实现过程(可一步一步实现): 因为雨是重点,所以中间 logo 部分就不详细 ...

  2. 炎炎夏日适合在屋里学习深度学习

    阅读原文 摘要: 这个天气不是一般的炎热,那么相当的炎热,炎炎夏日别出去玩了,在家学习深度学习可好?没有书?没有学习材料?拿着这个资料,去你丫的鬼话吧! 一.免费书籍随意读: 1.<深度学习之美 ...

  3. 炎炎夏日,漂流去哪漂?评论情感分析告诉你

    作者|木下瞳 来源|木下学Python 前言 炎炎夏日,在这酷暑的天气,玩水,游泳等接触水的活动成了大家都想体验的活动,以此来降低一下温度,小编也准备水上活动,去漂流,但那景点没去过,不知道好不好玩, ...

  4. 数据中心如何安全渡过炎炎夏日

    对于我国的绝大部分地方,一年之中最难过的莫过于夏季.夏季是一年之中温度最高.湿度最大的季节,早晚温差也比较大,雨水也最多,温度波动最为频繁的季节.由于我国地广物博,由北向南划分为寒温带.中温带.暖温带 ...

  5. [Vue仿网易云音乐实战]炎炎夏日——放首自己喜欢的歌

    前言 基于 Vue + vuex + vue-router + vue-axios +better-scroll + Stylus + px2rem 等开发的移动端音乐App,UI 界面是看着自己手机 ...

  6. 炎炎夏日,如何选择适合自己肤质的面膜

    说到夏日,小编第一个想到的场景就是抱着冰镇的西瓜,敷着面膜,躺在沙发上追着偶像演的剧,好生惬意~在这提到面膜,相信注重护肤的小伙伴们肯定不会陌生,毕竟是一周要敷好几次的嘛. 小伙伴们也都知道,面膜的原 ...

  7. 如何写出让 CPU 跑得更快的代码?

    作者 | 小林coding 来源 | 小林coding(ID:CodingLin) 前言 代码都是由 CPU 跑起来的,我们代码写的好与坏就决定了 CPU 的执行效率,特别是在编写计算密集型的程序,更 ...

  8. 炎炎夏日需要一个清凉的地 - 自制水冷系统

    炎炎夏日来临了,气温是蹭蹭蹭的往上窜.整天开空调也不是个办法,电费和气温一样要蹭蹭蹭的往上窜.看有必要给自家的小鱼弄个清凉世界. 前段时间在搞亚克力小缸,看样只能把小缸的工程往后延期.优先做水冷,这样 ...

  9. 面试官:如何写出让 CPU 跑得更快的代码?

    前言 代码都是由 CPU 跑起来的,我们代码写的好与坏就决定了 CPU 的执行效率,特别是在编写计算密集型的程序,更要注重 CPU 的执行效率,否则将会大大影响系统性能. CPU 内部嵌入了 CPU ...

最新文章

  1. 你有没有试过“闭上眼”使用:京东、滴滴、QQ、支付宝?
  2. 统一windowx和linux系统的时间
  3. QT的QSpinBox类的使用
  4. laravel+php+支付功能,laravel+微信支付源码
  5. Python实现普通二叉树
  6. html设置边框dw,Dreamweaver表格边框设置的css语法大全
  7. sql 除以_避免SQL除以零错误的方法
  8. 算法不会,尚能饭否之排序——直接插入排序(Insert sort)
  9. 专注企业市场 或是网盘危机的有效出路
  10. 【操作系统】输入输出系统(中)-思维导图
  11. Cause: java.sql.SQLException: Connection is read-only. Queries leading to data使用MySQL的时候遇到的问题,后续继续解决
  12. 图:婚庆现场管理系统-双屏版V3软件完美收工!!!
  13. samba服务器无法映射,ubuntu映射网络驱动器失败,以及samba服务
  14. 十分钟利用windows7漏洞破解开机密码
  15. c语言case小于,大于和小于switch语句C
  16. PS实战-涂抹掉原图上的文字
  17. 渲染性能优化之Culling 剔除
  18. Python实现圣诞树、打包exe过程和遇到的问题
  19. 【Scratch-动作模块】滑行指令
  20. YOYO软件使用指南

热门文章

  1. 硅切片切割液消泡剂轻松取而代之别的除泡方法
  2. 分道扬镳(DFS+剪枝+邻接表)
  3. 游戏服务器环境部署说明文档,游戏服务器环境安装包
  4. android 流量统计
  5. 外部程序通过COM启动AutoCAD时RPC_E_CALL_REJECTED的问题解决办法
  6. Android 监听U盘OTG挂载状态
  7. 《软件测试的艺术》高清脑图总结
  8. 各种素材网站大全【全部倾倒,福利倒计时-JS,HTML,游戏素材,UI,图片素材等
  9. 高频电子线路仿真-高频小信号谐振放大器
  10. matlab vlfeat hog,vlfeat-0.9.20-bin 特征提取的工具包,实现各种 ,如hog,lbp,sift. matlab 242万源代码下载- www.pudn.com...