particles = [];
for (let i = 0; i < opts.particleAmount; i++){
particles.push( new Particle() );
}
window.requestAnimationFrame(loop);
}
在調(diào)用 loop 函數(shù)之前, setup 函數(shù)會創(chuàng)建一個由一系列粒子組成的 粒子 數(shù)組,這里使用 requestionAnimationFrame 來創(chuàng)建循環(huán)動畫。
loop 函數(shù)看起來是這個樣子的:
function loop(){
window.requestAnimationFrame(loop);
drawArea.clearRect(0,0,w,h);
for (let i = 0; i < particles.length; i++){
particles[i].update();
particles[i].draw();
}
}
loop 函數(shù)會清除 canvas 畫布,更新每個粒子的位置,然后再繪制粒子;這里使用requestAnimationFrame() 來刷新、創(chuàng)建動畫。
設(shè)置了相關(guān)常量、變量,并初始化了 resizeReset 函數(shù)后,調(diào)用 setup 函數(shù)開始運行動畫:
const canvasBody = document.getElementById("canvas"),
drawArea = canvasBody.getContext("2d");
let delay = 200, tid;
resizeReset();
setup();
到了這一步,動畫看起來就是一系列點在 canvas 畫布里面來回移動:
動畫效果可以去 CodePen 上查看Dudley Storey ( @dudleystorey )的 《使用HTML5的canvas創(chuàng)建動態(tài)點動畫》 。
為了創(chuàng)建網(wǎng)狀結(jié)構(gòu),我們需要增加一點代碼。
創(chuàng)建線條
為了繪制線條, loop() 函數(shù)需要添加些代碼,變成下面這個樣子:
function loop(){
window.requestAnimationFrame(loop);
drawArea.clearRect(0,0,w,h);
for (let i = 0; i < particles.length; i++){
particles[i].update();
particles[i].draw();
}
for (let i = 0; i < particles.length; i++){
linkPoints(particles[i], particles);
}
}
每個粒子都會調(diào)用 linkPoints 函數(shù),這個函數(shù)會調(diào)用 checkDistance 函數(shù):
let checkDistance = function(x1, y1, x2, y2){
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
};
checkDistance 函數(shù)決定了每個點與點之間的距離;如果距離小于 checkDistance,那么線條的 透明度 就會被設(shè)置成大于0,并且線條會在匹配的點之間重新繪制。
在繼續(xù)之前,先分解下 rgb 顏色 :
`let rgb = opts.lineColor.match(/\d+/g);``
linkPoints 函數(shù)用來檢測每一個點相對于剩下其他點的距離(等同于函數(shù)的"hubs"參數(shù)),然后使用 模板字面量 按照相應(yīng)的 透明度 來繪制線條:
let linkPoints = function(point1, hubs){
for (let i = 0; i < hubs.length; i++) {
let distance = checkDistance(point1.x, point1.y, hubs[i].x, hubs[i].y);
let opacity = 1 - distance / opts.linkRadius;
if (opacity > 0) {
drawArea.lineWidth = 0.5;
drawArea.strokeStyle = `rgba(${rgb[0]}, ${rgb[1]}, ${rgb[2]}, ${opacity})`;
drawArea.beginPath();
drawArea.moveTo(point1.x, point1.y);
drawArea.lineTo(hubs[i].x, hubs[i].y);
drawArea.closePath();
drawArea.stroke();
}
}
}
結(jié)論
使用ES6是非常高效的,我也鼓勵你在腳本上去嘗試各個設(shè)置選項。
需要指出的是:如果添加過多的點和/或過多的連接距離(連接距離會創(chuàng)建過多的線條),動畫也會扛不住。當(dāng)視口變窄時最好降低粒子的運動速度:粒子的尺寸越小,在愈加狹窄空間內(nèi)的移動速度貌似會越快。