你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
神奇的canvas——点与线绘制的绚丽动画效果
立即下载
用AI写一个
该例子支持:好用才打赏哦
现在下载学习
发布时间:2017-09-08
427人
|
浏览:12845次
|
收藏
|
分享
技术:canvas
运行环境:浏览器
概述
用CANVAS实现的点与线绘制的绚丽动画效果,挺好用。
详细
## 前言 之前在某网站上看到了一个canvas绘制的动画效果,虽然组成的元素很简单,只有点和线,但是视觉效果却非常炫丽,当下就非常想自己把他实现一遍。因为工作原因这个想法搁置了一段时间,前不久忽然想起来,就抽空完成了这个demo,下面是demo的截图,想要看动态效果的小伙伴可以戳旁边的链接:[canvas绘制绚丽的点线动画效果](http://demo.cxstore.top/free-dots/index.html) >运行效果图  下面就简单介绍一下完成这个demo的思路 ## 需要掌握的基础知识 1. canvas绘制点与线的api 2. 理解JavaScript中“类” ## 需求分析 1. 点**随机**产生并向**随机**方向以**随机**的速度匀速移动 2. 未点击时,点的总数保持不变;点击时在**点击的位置**产生数个新的点 3. 点与点之间在一定距离内有细线连接 4. 鼠标在画面中移动时,能够与其他点产生互动 ## 编写代码(文章末尾有源码) ### 点的实现 由于在整个demo中需要使用到大量的点,所以使用一个*Dot类*来负责产生点的实例以及这个点的所有行为 ``` // 声明一个Dot对象 var Dots = function () { this.canvas; // canvas节点 this.ctx; // canvas绘图上下文 this.x; // 横向坐标 this.y; // 纵向坐标 this.r; // dot半径 this.sx; // 单位时间水平移动距离 this.sy; // 单位时间纵向移动距离 }; ``` Dot的原型链中需要有一下两个方法:init() 与 update() ``` Dots.prototype = { init: function(){...}, update: function(){...} } ``` *init()* Dots实例的初始化方法,在canvas中绘制一个点,并确定这个Dots实例移动的方向与速度(由sx与sy决定,即确定sx与sy的值) *update()* 更新dot的位置,通过不断调用其的update方法,使其产生运动的效果,并且判断dot所处的位置是否已经超出canvas的边界,若超出则调用其init()方法,使其重生在canvas内 **如何绘制一个点?** 点的本质是一个实心圆,所以绘制一个点就是绘制一个填充了颜色的圆 ``` this.ctx.beginPath(); // 开启绘制路径 this.ctx.arc(this.x, this.y, this.r, 0, 2*Math.PI); // 绘制圆 参数依次为 圆的横坐标/纵坐标/半径/绘制圆的起始位置/绘制圆的弧度大小 this.ctx.fillStyle = "rgba(255,255,255,.8)"; // 设置填充颜色 this.ctx.fill(); // 填充颜色 this.ctx.closePath(); // 关闭绘制路径 ``` ### 让点移动起来 如果让你实现一个动画,你可能会想到通过定时器setTimeout或者setInterval的方式来实现,时间设定越短动画也就越流畅,但是使用定时器会有这么几个问题出现: 1. 当有耗时任务时,定时器任务会等待耗时任务结束,js引擎空闲时再去执行 2. 当设定时间非常短时,可能会出现掉帧现象,产生动画不连贯的感受 那么有什么方法可以解决这个问题呢?答案是使用全局函数requestAnimFrame() requestAnimFrame的字面意思是“请求动画帧”,作用是根据GPU的渲染频率来执行方法内的js代码,这样就不会出现上面使用定时器而导致的两个可能的问题 ``` // dot移动效果 function animateUpdate() { dot.update(); // 更新dot的当前位置 requestAnimFrame(animateUpdate); } requestAnimFrame(animateUpdate); ``` ### 绘制点与点之间的连线 将产生的点存放在一个数组中,就得到了一个当前所有点实例的集合,通过for循环的嵌套,将数组中的每个点进行两两比较,当点与点之间的距离达到预先设置的临界值时,即可绘制连线 **如何绘制一条线?** ``` ctx.beginPath(); // 开启绘制路径 ctx.moveTo(x, y); // 设置线的起始位置 ctx.lineTo(dx, dy); // 设置线的结束位置 ctx.strokeStyle = 'rgb(255,255,255)'; // 设置绘制线条的颜色 ctx.strokeWidth = 1; // 设置绘制线条的宽度 ctx.stroke(); // 绘制 ctx.closePath(); // 关闭绘制路径 ``` **如何实现线条的淡入淡出效果?** 设置reba颜色值可实现带透明度的颜色,透明度的计算方式为,(临界值距离 - 实际距离) / 临界值距离,这样就可以实现两点距离越远线条颜色越淡。再通过动画不停渲染,就可以造成视觉上淡入淡出的效果 ``` ctx.strokeStyle = 'rgba(255,255,255,'+(dotsDistance-s)/dotsDistance+')'; ``` ### 实现鼠标交互 添加点击事件 click 事件监听器,当点击时实例化多个Dots对象,并将其添加到上文保存点的数组中,这样既可将新产生的点与原有的点产生联系。需要注意的是,产生点的位置应该为点击的位置,由于demo中的canvas是全屏显示的,所以只需要获取鼠标点的pageX / pageY,如果canvas并非全屏,则需要获取到的点产生的位置应该是相对于canvas的位置,而不能直接使用pageX / pageY, 并且需要判断是否在canvas内,如果不在则不产生新点 ``` document.addEventListener('click', createDot); // 添加点击事件 function createDot(e) { // 点击事件方法 var tx = e.pageX, ty = e.pageY; // 获取点击位置 if ((tx > 0 && tx < width) && (ty > 0 && ty < height)) { // 判断是都在canvas内 width和height为canvas宽高 for (var i = 0; i < 5; i ++) { var dot = new Dots(); dotsArr.push(dot); dot.init(canvas, tx, ty); } // 循环创建5个点 并添加到数组中 } }; ``` **如何实现鼠标在canvas中移动的交互效果?** 首先添加 mousemove 的事件监听器,其他步骤与上面点击的代码相同,唯一不同的是,确定点击在canvas内后不能创建新的点。现在为Dots对象添加一个新的原型链方法mouseDot()用于更新需要跟踪鼠标移动的点的位置 ``` mouseDot: function (x, y) { this.x = x * 2; this.y = y * 2; // 这里的2是屏幕的devicePixelRatio 是一个全局熟悉 在retain屏幕下 devicePixelRatio=2 标识浏览器会用两个像素点去绘制原先的一个像素 这样会导致绘图不清晰 之后会专门写一篇关于这个问题的文章 感兴趣的小伙伴可以持续关注 this.ctx.beginPath(); this.ctx.arc(this.x, this.y, this.r + 0.5, 0, 2*Math.PI); this.ctx.fillStyle = "rgba(255,0,0,.8)"; this.ctx.fill(); this.ctx.closePath(); } ``` ``` document.addEventListener('mousemove', moveDot); function moveDot(e) { var tx = e.pageX, ty = e.pageY; if ((tx > 0 && tx < width) && (ty > 0 && ty < height)) { dot.mouseDot(tx, ty); // 更新跟踪点的位置 小伙伴们可以思考一下这里的dot对于的是dotsArr中的哪一个点 } }; ``` ### 性能优化 以上就是canvas实现绚丽点线效果的基本思路啦!但是还有一个问题需要优化,看过demo的小伙伴可能已经发现了,刚开始不断点击的时候会不断产生点,但是当点的数量到达一定程度的时候就会发现:不管怎么点击,画面中的点的数量基本保持不变 其实在之前看到的网站上,点的数量是可以无上限增加的。但是点的数量不断增加会严重消耗性能,导致动画效果卡顿严重,无法直视,同时点太多也十分的不美观,于是demo就对这一情况做了优化: **当点的数量增加到预设的最大值时,每新增一个点,就会舍弃掉点数组中最先添加进去的点** 至于是如何实现的,小伙伴们可以在源码中寻找答案哦! ## 代码结构图 > 文件结构类别如下 
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
23
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
次、
2
例子数量
756
帮助
27
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
神奇的canvas——点与线绘制的绚丽动画效果
神奇的canvas——巧用 canvas 为图片添加水印