canvas粒子动画之404(即拿即用)
class Grain {
constructor(params = {}) {
this.params = params;
this.createCav(params.el);
this.init();
window.addEventListener("resize", () => {
clearInterval(this.play);
this.throttle(this.init)();
});
}
throttle(fn, interval = 300) {
let canRun = null;
return () => {
if (canRun) clearTimeout(canRun);
canRun = setTimeout(() => {
fn.call(this);
}, interval);
};
}
init() {
const imgData = this.drawText();
this.drawSpot(imgData);
this.play = setInterval(() => {
this.moveAnimate();
}, 80);
}
drawText() {
this.node.cav.width = this.el.offsetWidth;
this.node.cav.height = this.el.offsetHeight;
const { ctx, cav } = this.node;
ctx.clearRect(0, 0, cav.width, cav.height);
const text = String(this.params.text) || "404 not found";
ctx.beginPath();
const fontSize = cav.width / Math.abs(text.length - 6) > 200 ? 200 : cav.width / (text.length - 6);
ctx.font = `bold ${fontSize}px serif`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, cav.width / 2, cav.height / 2);
ctx.closePath();
return ctx.getImageData(0, 0, cav.width, cav.height);
}
drawSpot(imgData) {
const arr = [];
const { data, width, height } = imgData;
const row = height;
const col = width;
for (let i = 0; i < row; i++) {
for (let j = 0; j < col; j++) {
const index = i * col * 4 + (j * 4 + 3);
if (data[index] !== 0) {
arr.push({
x: j,
y: i,
color: [data[index - 3], data[index - 2], data[index - 1], data[index]]
});
}
}
}
this.drawGrain(arr);
}
drawGrain(arr) {
this.imgData = [];
let i = 0;
const { ctx, cav } = this.node;
ctx.beginPath();
ctx.clearRect(0, 0, cav.width, cav.height);
ctx.closePath();
arr.forEach(item => {
i += 1;
if (i === 12) {
this.imgData.push({
...item,
r: Math.floor(Math.random() * 8),
offsetX: item.x,
offsetY: item.y,
translate: Math.random() * 1,
row: true,
col: true
});
i = 0;
}
});
}
createCav(el) {
this.el = el || document.body;
const canvas = document.createElement("canvas");
this.el.setAttribute("style", "position: relative; background: #1d8bf1 ");
canvas.setAttribute("style", "position: absolute; left: 0; top: 0");
this.el.appendChild(canvas);
this.node = {
cav: canvas,
ctx: canvas.getContext("2d")
};
}
moveAnimate() {
const { ctx } = this.node;
this.clearCanvas();
this.imgData.forEach(item => {
const translate = Math.random() * 2;
if (item.col) {
item.offsetY += translate;
if (item.offsetY > item.y + 2) item.col = false;
} else {
item.offsetY -= translate;
if (item.offsetX > item.x + 2) item.col = true;
}
if (item.row) {
item.offsetX += translate;
if (item.offsetX > item.x + 2) item.row = false;
} else {
item.offsetX -= translate;
if (item.offsetX < item.x - 2) item.row = true;
}
ctx.beginPath();
ctx.fillStyle = "rgb(255,255,255,0.5)";
ctx.arc(item.offsetX, item.offsetY, item.r, 0, 2 * Math.PI);
ctx.fill();
ctx.closePath();
});
}
clearCanvas() {
const { ctx, cav } = this.node;
ctx.beginPath();
ctx.clearRect(0, 0, cav.width, cav.height);
ctx.closePath();
}
}
new Grain({ text: "love you" });