最近几年,辨识度最高的虚拟图案之一也许就是上面你所看到的这种动画形式了;我不确定这种动画形式是否有学名,这里我姑且称之为 动态粒子网格动画(dynamic point mesh animation) 。本例中的动画是基于这种动画形式的变种,灵感来自于Daniel Mayovskiy 之前的作品。
通常,这类动画被放置于其他内容之后,所以在该例中,将 的大小设置为与视口相同的大小:
样式如下:
body {
background: #222;
margin: 0rem;
min-height: 100vh;
}
#canvas {
position: absolute;
display: block;
top: 0;
left: 0;
z-index: -1;
}
这段代码的Codepen版本 在动画的顶部放置了一些文本,并为文本添加了些许结构和样式。
为了确保 能够铺满视口,页面末尾的第一部分 JavaScript 代码是一个缩放函数:
let resizeReset = function() {
w = canvasBody.width = window.innerWidth;
h = canvasBody.height = window.innerHeight;
}
创建点集
opts 是一个 对象 ,包含一系列属性,默认属性如下:
const opts = {
particleColor: "rgb(200,200,200)",
lineColor: "rgb(200,200,200)",
particleAmount: 40,
defaultSpeed: 1,
variantSpeed: 1,
defaultRadius: 2,
variantRadius: 2,
linkRadius: 200,
}
变量 variantSpeed 和 variantRadiut 用来增加点的尺寸大小和移动速度的 随机性 , linkRadius 表示点与点要连成线必须要靠近的距离范围。
元素可以被缩放,这样就会导致粒子会碰触到浏览器窗口的边缘。脚本一加载, resizeReset() 函数就会被调用,但是需要延迟或“去抖”,以便在页面其余部分的操作期间不会减慢脚本的运行:
let delay = 200, tid;
window.addEventListener("resize", function(){
deBouncer();
});
let deBouncer = function() {
clearTimeout(tid);
tid = setTimeout(function() {
resizeReset();
}, delay);
};
生成每个点(each of the dots)的 粒子 对象是一个比较庞大的函数:
Particle = function(xPos, yPos){
this.x = Math.random() * w;
this.y = Math.random() * h;
this.speed = opts.defaultSpeed + Math.random() * opts.variantSpeed;
this.directionAngle = Math.floor(Math.random() * 360);
this.color = opts.particleColor;
this.radius = opts.defaultRadius + Math.random() * opts. variantRadius;
this.vector = {
x: Math.cos(this.directionAngle) * this.speed,
y: Math.sin(this.directionAngle) * this.speed
};
this.update = function(){
this.border();
this.x += this.vector.x;
this.y += this.vector.y;
};
this.border = function(){
if (this.x >= w || this.x <= 0) {
this.vector.x *= -1;
}
if (this.y >= h || this.y <= 0) {
this.vector.y *= -1;
}
if (this.x > w) this.x = w;
if (this.y > h) this.y = h;
if (this.x < 0) this.x = 0;
if (this.y < 0) this.y = 0;
};
this.draw = function(){
drawArea.beginPath();
drawArea.arc(this.x, this.y, this.radius, 0, Math.PI*2);
drawArea.closePath();
drawArea.fillStyle = this.color;
drawArea.fill();
};
};
在脚本的上下文中, this 指代的是每个创建出来的 粒子 :
每个粒子的初始速度和角度是随机生成的,粒子的颜色通过相关的设置选项来确定。
this.vector 用来存储粒子的 移动方向 :如果 this.vector.x 为 1 ,则粒子向右 运动;如果是 -1 ,则粒子向 左 移动。同样,如果 this.vector.y 为 负,则粒子向 上 移动,如果为 正 ,则粒子向 下 移动。
this.update 用来更新每个粒子 下一个位置 的坐标。首先,进行边缘检测;如果粒子的移动超出了canvas的尺寸,则将方向向量乘以 -1 产生 反向 的运动方向。
窗口缩放可能会引起粒子超出边界,如此一来 边缘检测 函数就捕捉不到了,所以就需要一系列的 if 语句来检测这种情况,将粒子的位置重置为当前canvas的边界。
最后一步,将这些点绘制到画布上。
我们需要进行下面的操作来使粒子运动起来:
function setup(){