ZRender实现粒子网格动画实战
来源:互联网 发布:电车难题知乎 编辑:程序博客网 时间:2024/05/16 07:26
注:本博文代码基于ZRender 3.4.3版本开发,对应版本库地址:ZRender 库。
效果
实现分析
通过上面显示的效果图,可以看出,这种效果就是在Canvas中生成多个可移动的点,然后根据点之间的距离来确定是否连线,思路比较简单。
实现问题:
- 保持Canvas 100%显示
- resize时,自动调节Canvas尺寸和内部变量
- 生成圆点
- 实现圆点的移动,及边界处理
- 实现原点的直线连接
Canvas设置
html:
<canvas id="main"></canvas>
css:
#main{ position: absolute; //用于100%填充 left:0; top:0; background: #000; z-index: -1; //方便做背景层使用 }
ZRender部分
这里主要用到的形状就是Circle
和Line
,先引入这两个组件:
['zrender', 'zrender/graphic/shape/Circle', 'zrender/graphic/shape/Line'], function(zrender, Circle, Line){}
设置全局及配置项用到的变量
var winH = window.innerHeight; //同步页面宽、高var winW = window.innerWidth; //同步页面宽、高var opts = { //可配置参数 background: '#000', //Canvas背景色 paricalRadius: 2, //粒子半径 paricalColor: 'rgb(0, 255, 0)', //粒子颜色 lineColor: 'rgb(0, 255, 0)', //连线颜色 joinLineDis: 300, //粒子间连线的要求距离 particalAmount: 30, //生成的粒子数量 speed: 1, //粒子速度};var tid; //setTimeout id,防抖处理var particals = []; //用于存储partical对象
初始化ZRender
var zr= zrender.init(main, {width: winW, height: winH});zr.dom.style.backgroundColor = opts.background; //设置背景色
窗口 resize 处理
window.addEventListener('resize', function(){ clearTimeout(tid); var tid = setTimeout(function(){ //防抖处理 winW = zr.dom.width = window.innerWidth; winH = zr.dom.height = window.innerHeight; zr.refresh(); }, 300); //这里设置了300ms的防抖间隔}, false);
效果:
创建粒子类 Partical
总结一下这个类,需要以下属性:
- 坐标位置 x, y
- 粒子速度
- 粒子移动角度
- 粒子颜色
- 粒子半径
- 粒子的角度方向变量
- 粒子的ZRender形状实例
方法:
- 更新位置坐标
- 划线
这边直接用ES6的语法来创建类:
class Partical {}
构造器:
constructor(){ this.lines = [], //用于存储连线 //粒子坐标初始化 this.x = winW * Math.random(); this.y = winH * Math.random(); this.speed = opts.speed + Math.random(); //这个random可不加,主要是为了制作不同的速度的 this.angle = ~~(360 * Math.random()); this.color = opts.paricalColor; this.radius = opts.paricalRadius + Math.random(); this.vector = { x: this.speed * Math.cos(this.angle), y: this.speed * Math.sin(this.angle), } this.element = new Circle({ shape: { cx: this.x, cy: this.y, r: this.radius, }, style: { fill: this.color, } });};
更新位置坐标方法:
updatePosition(){ //边界判断 if(this.x >= winW || this.x <= 0){ this.vector.x *= -1; } if(this.y >= winH || this.y <= 0){ this.vector.y *= -1; } if(this.x > winW){ this.x = winW; } if(this.x < 0){ this.x = 0; } if(this.y > winH){ this.y = winH; } if(this.y < 0){ this.y = 0; } //更新位置坐标 this.x += this.vector.x; this.y += this.vector.y; //更新形状坐标 this.element.shape.cx = this.x; this.element.shape.cy = this.y; this.element.dirty();};
划线方法:
drawLines(){ //清空lines,用于重绘线 for(let i = 0; i < this.lines.length; i ++){ let l = this.lines[i]; zr.remove(l); //删除形状 l = null; //并解除绑定 } this.lines = []; //删除后,清空数组 //遍历各个点之间的距离 for(let i = 0; i < particals.length; i ++){ let p = particals[i]; //勾股定理,获取两点之间的距离 let distance = Math.sqrt(Math.pow(this.x - p.x, 2) + Math.pow(this.y - p.y, 2)); if(distance <= opts.joinLineDis && distance > 0){ let opacity = 1 - distance / opts.joinLineDis; //根据距离大小来设置透明度 let color = opts.lineColor.match(/\d+/g); //因为这里要用到透明度,所以需要重新组合rgba,先把各个颜色值取到数组中 let l = new Line({ shape: { x1: this.x, y1: this.y, x2: p.x, y2: p.y, }, style: { stroke: 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + opacity + ')', //组建颜色 fill: null }, }); this.lines.push(l); //存入lines zr.add(l); //加入ZRender Storage中 } };}
目前所有核心部分已完成,现在来初始化它:
var init = function(){ for (let i = 0; i < opts.particalAmount; i++) { let p = new Partical(); particals.push(p); // 把粒子实例 存入particals中,方便后面操作 zr.add(p.element); //加入 ZRender Storage中 }};
效果:
开始动画函数,让粒子动起来,并生成连接线:
function loop(){ for(let i = 0; i < particals.length; i ++){ let p = particals[i]; p.updatePosition(); //更新位置 p.drawLines(); //绘制线段 } window.requestAnimationFrame(loop);};
最终效果:
全部代码
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <script src="./esl.js"></script> <style> #main{ position: absolute; left:0; top:0; background: #000; z-index: -1; } </style></head><body> <canvas id="main"></canvas><script>require.config({ packages:[ { name: 'zrender', location: './src', main: 'zrender', }, ],});require(['zrender', 'zrender/graphic/shape/Circle', 'zrender/graphic/shape/Line'], function(zrender, Circle, Line){ /* * 作者:王乐平 * 博客:http://blog.csdn.net/lecepin/ */ //-----全局var-----{ var winH = window.innerHeight; var winW = window.innerWidth; var opts = { background: '#000', //Canvas背景色 paricalRadius: 2, paricalColor: 'rgb(0, 255, 0)', lineColor: 'rgb(0, 255, 0)', joinLineDis: 300, particalAmount: 30, speed: 1, }; var tid; //setTimeout id,防抖处理 var particals = []; //用于存储partical对象 //-----------------} var zr = zrender.init(main, {width: winW, height: winH}); zr.dom.style.backgroundColor = opts.background; window.addEventListener('resize', function(){ clearTimeout(tid); var tid = setTimeout(function(){ winW = zr.dom.width = window.innerWidth; winH = zr.dom.height = window.innerHeight; zr.refresh(); }, 300); //这里设置了300ms的防抖间隔 }, false); class Partical { constructor(){ this.lines = [], //用于存储连线 //粒子坐标初始化 this.x = winW * Math.random(); this.y = winH * Math.random(); this.speed = opts.speed + Math.random(); //这个random可不加,主要是为了制作不同的速度的 this.angle = ~~(360 * Math.random()); this.color = opts.paricalColor; this.radius = opts.paricalRadius + Math.random(); this.vector = { x: this.speed * Math.cos(this.angle), y: this.speed * Math.sin(this.angle), } this.element = new Circle({ shape: { cx: this.x, cy: this.y, r: this.radius, }, style: { fill: this.color, } }); }; updatePosition(){ if(this.x >= winW || this.x <= 0){ this.vector.x *= -1; } if(this.y >= winH || this.y <= 0){ this.vector.y *= -1; } if(this.x > winW){ this.x = winW; } if(this.x < 0){ this.x = 0; } if(this.y > winH){ this.y = winH; } if(this.y < 0){ this.y = 0; } this.x += this.vector.x; this.y += this.vector.y; this.element.shape.cx = this.x; this.element.shape.cy = this.y; this.element.dirty(); }; drawLines(){ //清空lines for(let i = 0; i < this.lines.length; i ++){ let l = this.lines[i]; zr.remove(l); l = null; } this.lines = []; //遍历各个点之间的距离 for(let i = 0; i < particals.length; i ++){ let p = particals[i]; //勾股定理 let distance = Math.sqrt(Math.pow(this.x - p.x, 2) + Math.pow(this.y - p.y, 2)); if(distance <= opts.joinLineDis && distance > 0){ let opacity = 1 - distance / opts.joinLineDis; let color = opts.lineColor.match(/\d+/g); let l = new Line({ shape: { x1: this.x, y1: this.y, x2: p.x, y2: p.y, }, style: { stroke: 'rgba(' + color[0] + ',' + color[1] + ',' + color[2] + ',' + opacity + ')', fill: null }, }); this.lines.push(l); zr.add(l); } }; } } var init = function(){ for (let i = 0; i < opts.particalAmount; i++) { let p = new Partical(); particals.push(p); zr.add(p.element); } }; function loop(){ for(let i = 0; i < particals.length; i ++){ let p = particals[i]; p.updatePosition(); p.drawLines(); } window.requestAnimationFrame(loop); }; init(); loop();});</script></body></html>
博客名称:王乐平博客
CSDN博客地址:http://blog.csdn.net/lecepin
2 0
- ZRender实现粒子网格动画实战
- 粒子动画实现
- canvas动画之二 -- 创建动态粒子网格动画
- canvas动画之二 -- 创建动态粒子网格动画
- 使用HTML5 Canvas创建动态粒子网格动画
- 使用animator实现粒子动画效果
- FLIP 动画实现多维网格的过渡
- 粒子动画
- 粒子动画
- 粒子动画
- 网格动画
- 如何制作网格粒子发射器
- Unity3D中暂停时的动画及粒子效果实现
- 用CAEmitterLayer实现粒子动画飘雪花效果
- Unity3D中暂停时的动画及粒子效果实现
- android使用粒子动画实现炊烟袅袅的效果
- android 手摸手教你用 Canvas 实现简单粒子动画
- 分享一个酷炫的粒子动画实现
- 【算法作业9】LeetCode 455. Assign Cookies
- Quartz定时执行程序
- javaScript定义类或者对象
- 事务管理基本概念【了解】
- GetLastError函数封装显示具体错误信息
- ZRender实现粒子网格动画实战
- Android 碎片(Fragment)
- 在linux下用gcc查看代码的【预处理】,【编译】,【汇编】和【链接】
- 微信小程序---页面生命周期
- HDU
- BZOJ4872 [Shoi2017]分手是祝愿
- springMVC两种方式实现多文件上传
- git切换分支前stash的用法
- 更改mysql字符集utf8至utf8mb4