注:本博文代码基于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部分

这里主要用到的形状就是CircleLine。先引入这两个组件:

['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

本作品採用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

ZRender实现粒子网格动画实战的更多相关文章

  1. 3D Grid Effect – 使用 CSS3 制作网格动画效果

    今天我们想与大家分享一个小的动画概念.这个梦幻般的效果是在马库斯·埃克特的原型应用程序里发现的​​.实现的基本思路是对网格项目进行 3D 旋转,扩展成全屏,并呈现内容.我们试图模仿应用程序的行为,因此 ...

  2. cocos2d-x 网格动画深入分析

    转自:http://www.2cto.com/kf/201212/179828.html 在TestCpp中的EffectsTest示例中展示了一些屏幕特效,它是将屏幕划分为多个格子,并对这些格子进行 ...

  3. iOS CAEmitterLayer 实现粒子发射动画效果

    iOS CAEmitterLayer 实现粒子发射动画效果 效果图 代码已上传 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo 动 ...

  4. 基于HTML5/CSS3图片网格动画特效

    现在HTML5技术可以让网页上的图片变得非常神奇,各种各样的HTML5图片动画特效让你眼花缭乱.今天要分享的这款HTML5图片网格动画特效就非常炫酷.图片缩略图按网格的布局一行行排列,你只需点击按钮即 ...

  5. iOS自定义转场动画实战讲解

    iOS自定义转场动画实战讲解   转场动画这事,说简单也简单,可以通过presentViewController:animated:completion:和dismissViewControllerA ...

  6. Android Animation动画实战(二):从屏幕底部弹出PopupWindow

    在这篇文章之前,我已经陆陆续续写了几篇博客,介绍了Android Animation是如何使用的,有还不明白的,可以点击查看: 1. Android Animation动画详解(一): 补间动画 2. ...

  7. Android 属性动画实战

    什么是属性动画? 属性动画可以通过直接更改 View 的属性来实现 View 动画.例如: 通过不断的更改 View 的坐标来实现让 View 移动的效果: 通过不断的更改 View 的背景来实现让 ...

  8. Android Animation动画实战(一): 从布局动画引入ListView滑动时,每一Item项的显示动画

    前言: 之前,我已经写了两篇博文,给大家介绍了Android的基础动画是如何实现的,如果还不清楚的,可以点击查看:Android Animation动画详解(一): 补间动画 及 Android An ...

  9. Frame动画实战

    Android动画分为Tween动画和Frame动画,Tween动画主要包括图片的放大缩小.旋转.透明度变化.移动等等操作:Frame动画则简单得多了,就是把一张张的图片连续播放产生动画效果. 本节主 ...

随机推荐

  1. Map 中的EntrySet() ,Map的遍历

      我们循环Map时一般用到EntrySet(),EntrySet() 返回的时Set集合(Set<Map.Entry<K, V>>). 那么这里的有Map.Entry< ...

  2. 商城商品购买数量增减的完美JS效果

    近期在开发一个地方O2O租书项目,使用ASP.NET MVC技术,其中在图书详情页,用户可以输入借阅的数量,这里使用了js来控制数量的增减和校验. 数量一定是数字 点击增减按钮的时候要能自动加1或减1 ...

  3. 用最优方法从LinkedList列表中删除重复元素

    用运行速度最优的方法从LinkedList列表里删除重复的元素,例如A->B->BB->B->C,返回A->B->BB->C. 考试的时候没完全想明白,考完又 ...

  4. 求和为s的连续正数序列

    输入一个正数是s,打印出所有和为s的连续正数序列(至少含有两个数).例如输入15,由于1+2+3+4+5=4+5+6==7+8=15,所有结果打印出3个序列1-5,4-6,7-8. 代码如下: voi ...

  5. BZOJ3884 上帝与集合的正确用法 【欧拉定理】

    题目 对于100%的数据,T<=1000,p<=10^7 题解 来捉这道神题 欧拉定理的一般形式: \[a^{m} \equiv a^{m \mod \varphi(p) + [m \ge ...

  6. BZOJ2141&洛谷1975 排队 【线段树套treap】

    题目 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和. 红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别,排 ...

  7. ionic2实战-使用Chart.js

    前言 Chart.js官网 Chart.js中文文档 安装Chart.js 执行cnpm install typings -g,全局安装Typings 执行typings search chart.j ...

  8. Java代码添加背景音乐

    太心塞!弄了很久才终于把Java添加背景音乐实现了.不过还是很Happy! 这次介绍的办法,是只要一打开Java Application,便可直接听到背景音乐.代码保存,方便以后再次利用. packa ...

  9. .NET中如何有效的使用Cache

    原文发布时间为:2009-09-30 -- 来源于本人的百度文章 [由搬家工具导入]   Cache 即高速缓存 ,我想很多人对他的第一印象一定像我一样,感觉他一定能提高系统得性能和运行速度。   C ...

  10. 解决Navicat 报错:1130-host ... is not allowed to connect to this MySql server,MySQL不允许从远程访问的方法

    1. 改表法. 可能是你的帐号不允许从远程登陆,只能在localhost.这个时候只要在localhost的那台电脑,登入mysql后,更改 "mysql" 数据库里的 " ...