在线演示
See the Pen Canvas Particle Demo by pdslly (@pdslly) on CodePen.
参考代码
const mycan = document.getElementById("mycan");
const ctx = mycan.getContext("2d");
const { clientLeft, clientTop } = mycan;
let { innerWidth, innerHeight } = window;
let adjustX = innerWidth / 100;
let adjustY = innerHeight / 200;
mycan.width = innerWidth;
mycan.height = innerHeight;
ctx.font = "bold 20px Verdana";
ctx.fillText("IFRONT", 0, 30);
const data = ctx.getImageData(0, 0, mycan.width, 100);
let particleArray = [];
const mouse = {
x: null,
y: null,
radius: 150,
};
window.addEventListener("mousemove", function ({ x, y }) {
mouse.x = x + clientLeft;
mouse.y = y + clientTop;
});
class Particle {
constructor(x, y) {
this.x = this.baseX = x;
this.y = this.baseY = y;
this.size = 3;
this.density = Math.random() * 30 + 1;
}
draw() {
const { x, y, size } = this;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
}
update() {
const { x, y, size, density, baseX, baseY } = this;
const { x: mx, y: my, radius } = mouse;
const dx = mx - x;
const dy = my - y;
const distance = Math.sqrt(dx * dx + dy * dy);
const forceDirX = dx / distance;
const forceDirY = dy / distance;
const force = Math.max(0, (radius - distance) / radius);
if (distance < size + radius) {
const dirX = forceDirX * force * density;
const dirY = forceDirY * force * density;
this.x -= dirX;
this.y -= dirY;
} else {
if (x !== baseX) {
this.x -= (x - baseX) / 10;
}
if (y !== baseY) {
this.y -= (y - baseY) / 10;
}
}
}
}
function init() {
particleArray = [];
for (let x = 0, w = data.width; x < w; x++) {
for (let y = 0, h = data.height; y < h; y++) {
if (data.data[y * 4 * w + x * 4 + 3] > 128) {
let posX = x + adjustX;
let posY = y + adjustY;
particleArray.push(new Particle(posX * 15, posY * 15));
}
}
}
}
function animate() {
ctx.clearRect(0, 0, innerWidth, innerHeight);
connect();
for (const particle of particleArray) {
particle.update();
particle.draw();
}
requestAnimationFrame(animate);
}
function connect() {
const len = particleArray.length;
for (let a = 0; a < len; a++) {
for (let b = 0; b < len; b++) {
const C_DISTANCE = 2500;
let { x: ax, y: ay } = particleArray[a];
let { x: bx, y: by } = particleArray[b];
let opacityValue = 1;
let weight = 255;
let disX = ax - bx;
let disY = ay - by;
let distance = disX * disX + disY * disY;
let { x: mx, y: my, radius } = mouse;
if (distance < C_DISTANCE) {
opacityValue = 1 - distance / C_DISTANCE;
let dx = mx - ax;
let dy = my - ay;
let mDis = Math.sqrt(dx * dx + dy * dy);
if (mDis < radius / 2) weight = 0;
else if (mDis < radius - 50) weight = 140;
else if (mDis < radius + 20) weight = 210;
ctx.strokeStyle = `rgba(255,255,${weight},${opacityValue})`;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(ax, ay);
ctx.lineTo(bx, by);
ctx.stroke();
}
}
}
}
window.addEventListener("resize", function () {
let { innerWidth, innerHeight } = window;
mycan.width = innerWidth;
mycan.height = innerHeight;
adjustX = innerWidth / 200;
adjustY = innerHeight / 200;
ctx.clearRect(0, 0, innerWidth, innerHeight);
init();
});
init();
animate();