炎炎夏日,快用代码下场雨
点击上方 前端瓶子君,关注公众号
回复算法,加入前端编程面试算法每日一题群
来源:北极光之夜
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总结笔记 ......等等 进我主页看更多~
最后
欢迎关注【前端瓶子君】✿✿ヽ(°▽°)ノ✿
回复「算法」,加入前端编程源码算法群,每日一道面试题(工作日),第二天瓶子君都会很认真的解答哟!
回复「交流」,吹吹水、聊聊技术、吐吐槽!
回复「阅读」,每日刷刷高质量好文!
如果这篇文章对你有帮助,「在看」是最大的支持
》》面试官也在看的算法资料《《
“在看和转发”就是最大的支持
炎炎夏日,快用代码下场雨相关推荐
- 炎炎夏日,快用代码下场雨ヽ`☂ヽ`canvas
一.先看效果(源码在最后): 哗啦啦啦 我的B站地址~效果演示更清晰 图片展示,因为图片限制5m大小,所以演示不太多: 二.实现过程(可一步一步实现): 因为雨是重点,所以中间 logo 部分就不详细 ...
- 炎炎夏日适合在屋里学习深度学习
阅读原文 摘要: 这个天气不是一般的炎热,那么相当的炎热,炎炎夏日别出去玩了,在家学习深度学习可好?没有书?没有学习材料?拿着这个资料,去你丫的鬼话吧! 一.免费书籍随意读: 1.<深度学习之美 ...
- 炎炎夏日,漂流去哪漂?评论情感分析告诉你
作者|木下瞳 来源|木下学Python 前言 炎炎夏日,在这酷暑的天气,玩水,游泳等接触水的活动成了大家都想体验的活动,以此来降低一下温度,小编也准备水上活动,去漂流,但那景点没去过,不知道好不好玩, ...
- 数据中心如何安全渡过炎炎夏日
对于我国的绝大部分地方,一年之中最难过的莫过于夏季.夏季是一年之中温度最高.湿度最大的季节,早晚温差也比较大,雨水也最多,温度波动最为频繁的季节.由于我国地广物博,由北向南划分为寒温带.中温带.暖温带 ...
- [Vue仿网易云音乐实战]炎炎夏日——放首自己喜欢的歌
前言 基于 Vue + vuex + vue-router + vue-axios +better-scroll + Stylus + px2rem 等开发的移动端音乐App,UI 界面是看着自己手机 ...
- 炎炎夏日,如何选择适合自己肤质的面膜
说到夏日,小编第一个想到的场景就是抱着冰镇的西瓜,敷着面膜,躺在沙发上追着偶像演的剧,好生惬意~在这提到面膜,相信注重护肤的小伙伴们肯定不会陌生,毕竟是一周要敷好几次的嘛. 小伙伴们也都知道,面膜的原 ...
- 如何写出让 CPU 跑得更快的代码?
作者 | 小林coding 来源 | 小林coding(ID:CodingLin) 前言 代码都是由 CPU 跑起来的,我们代码写的好与坏就决定了 CPU 的执行效率,特别是在编写计算密集型的程序,更 ...
- 炎炎夏日需要一个清凉的地 - 自制水冷系统
炎炎夏日来临了,气温是蹭蹭蹭的往上窜.整天开空调也不是个办法,电费和气温一样要蹭蹭蹭的往上窜.看有必要给自家的小鱼弄个清凉世界. 前段时间在搞亚克力小缸,看样只能把小缸的工程往后延期.优先做水冷,这样 ...
- 面试官:如何写出让 CPU 跑得更快的代码?
前言 代码都是由 CPU 跑起来的,我们代码写的好与坏就决定了 CPU 的执行效率,特别是在编写计算密集型的程序,更要注重 CPU 的执行效率,否则将会大大影响系统性能. CPU 内部嵌入了 CPU ...
最新文章
- 你有没有试过“闭上眼”使用:京东、滴滴、QQ、支付宝?
- 统一windowx和linux系统的时间
- QT的QSpinBox类的使用
- laravel+php+支付功能,laravel+微信支付源码
- Python实现普通二叉树
- html设置边框dw,Dreamweaver表格边框设置的css语法大全
- sql 除以_避免SQL除以零错误的方法
- 算法不会,尚能饭否之排序——直接插入排序(Insert sort)
- 专注企业市场 或是网盘危机的有效出路
- 【操作系统】输入输出系统(中)-思维导图
- Cause: java.sql.SQLException: Connection is read-only. Queries leading to data使用MySQL的时候遇到的问题,后续继续解决
- 图:婚庆现场管理系统-双屏版V3软件完美收工!!!
- samba服务器无法映射,ubuntu映射网络驱动器失败,以及samba服务
- 十分钟利用windows7漏洞破解开机密码
- c语言case小于,大于和小于switch语句C
- PS实战-涂抹掉原图上的文字
- 渲染性能优化之Culling 剔除
- Python实现圣诞树、打包exe过程和遇到的问题
- 【Scratch-动作模块】滑行指令
- YOYO软件使用指南
热门文章
- 硅切片切割液消泡剂轻松取而代之别的除泡方法
- 分道扬镳(DFS+剪枝+邻接表)
- 游戏服务器环境部署说明文档,游戏服务器环境安装包
- android 流量统计
- 外部程序通过COM启动AutoCAD时RPC_E_CALL_REJECTED的问题解决办法
- Android 监听U盘OTG挂载状态
- 《软件测试的艺术》高清脑图总结
- 各种素材网站大全【全部倾倒,福利倒计时-JS,HTML,游戏素材,UI,图片素材等
- 高频电子线路仿真-高频小信号谐振放大器
- matlab vlfeat hog,vlfeat-0.9.20-bin 特征提取的工具包,实现各种 ,如hog,lbp,sift. matlab 242万源代码下载- www.pudn.com...