我有一个 JavaScript 动画,它使用 HTML 画布和“像素”操作来模拟星落效果。虽然动画有效,但我面临效率和速度问题,并且我正在寻找优化代码的方法。该动画涉及创建从屏幕顶部落下的星星,并在移动时留下像素轨迹。问题是,像素是
divs
,达到了数千。
当前JS代码:
const content = document.getElementById("bkg-content");
const background = document.getElementById("bkg");
const ctx = content.getContext("2d", { willReadFrequently: true });
let stars = [];
const maxStars = 20; // Maximum number of stars
let last_x = 0;
let next_spawn = 0;
function getX(size) {
let random = Math.random() * (window.innerWidth - size);
return last_x - size > random || random > last_x + size ? random : getX(size);
}
function createStar() {
let transparency = Math.random();
let size = transparency * 200 + 100;
let x = getX(size)
let fallingSpeed = Math.random() * 30 + 20;
next_spawn = size / fallingSpeed * 500;
last_x = x;
return {
x,
y: 0,
size,
transparency,
rotationAngle: 0,
rotationSpeed: Math.random() * 0.3 + 0.05,
rotationDirection: Math.random() < 0.5 ? 1 : -1,
fallingSpeed,
};
}
function spawnStars(count) {
for (let i = 0; i < count; i++) {
stars.push(createStar());
}
setTimeout(() => {
spawnStars(1)
}, next_spawn)
console.log(stars.length);
}
function draw() {
ctx.clearRect(0, 0, content.width, content.height);
for (let i = 0; i < stars.length; i++) {
let star = stars[i];
star.rotationAngle += star.rotationSpeed * star.rotationDirection;
star.y += star.fallingSpeed;
if (star.y > window.innerHeight + star.size / 2) {
// Remove stars that have completely passed the bottom of the screen
stars.splice(i, 1);
i--; // Adjust the loop variable since the array length has changed
} else {
ctx.save();
ctx.translate(star.x + star.size / 2, star.y);
ctx.rotate(star.rotationAngle);
// Adjust transparency based on star size
ctx.globalAlpha = star.transparency;
console.log(ctx.globalAlpha)
ctx.drawImage(starTXT, -star.size / 2, -star.size / 2, star.size, star.size);
// Reset global alpha for subsequent drawings
ctx.globalAlpha = 1;
ctx.restore();
}
}
}
function resizeCanvas() {
content.width = window.innerWidth;
content.height = window.innerHeight;
spawnStars(Math.min(maxStars, 1)); // Initially spawn one star
setInterval(() => {
createPixels()
draw()
}, 500);
}
function createPixels() {
const pixel = { size: 9, gap: 3 };
const numX = Math.floor(window.innerWidth / (pixel.size + pixel.gap));
const numY = Math.floor(window.innerHeight / (pixel.size + pixel.gap));
background.style.gridTemplateColumns = `repeat(${numX}, ${pixel.size}px)`;
background.innerHTML = ''; // clear existing pixels
for (let x = 0; x < numX; x++) {
for (let y = 0; y < numY; y++) {
const child = document.createElement("div");
child.classList.add("pixel");
background.appendChild(child);
}
}
const children = Array.from(background.getElementsByClassName("pixel"));
children.forEach((child) => {
const rect = child.getBoundingClientRect();
const { data } = ctx.getImageData(rect.left, rect.top, pixel.size, pixel.size);
const averageColor = getAverageColor(data);
const color = `rgb(${averageColor}, ${averageColor}, ${averageColor})`;
child.style.backgroundColor = color;
child.style.boxShadow = `0 0 10px ${color}`;
});
}
function getAverageColor(data) {
let sum = 0;
for (let i = 0; i < data.length; i += 4) {
sum += data[i];
}
const averageColor = sum / (data.length / 4);
return averageColor;
}
const starTXT = new Image(1600, 1600);
starTXT.src = "star.png";
starTXT.onload = resizeCanvas;
window.addEventListener('resize', resizeCanvas);
另一个问题是调整大小,以便它是最佳且快速的,代码滞后很多。有小费吗?我可以采取任何不同的方法吗?
当前的实现似乎存在性能瓶颈。我怀疑绘制函数中的循环和画布的频繁操作可能会导致速度减慢。如何优化代码以提高效率?动画速度对于流畅的用户体验至关重要。我应该遵循什么特定的技术或最佳实践来提高星坠效果的速度?我使用画布绘制星星和像素操作背景的组合。这是最佳方法,还是有可以提供更好性能的替代方法?
我已经尝试过一些基本的优化,例如使用 requestAnimationFrame 而不是 setInterval,但我正在寻找来自社区的更多见解和建议。任何有助于识别和解决代码中的性能问题的帮助将不胜感激。
抱歉,如果我的代码有任何混乱或不可读,我已经尝试了很多。
编辑:HTML 文件在下面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>...</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background-color: black;
overflow: hidden;
/* Prevent scrolling */
}
#bkg-content {
width: 100%;
height: 100%;
position: absolute;
z-index: 1;
opacity: 0%;
}
#bkg {
width: 100%;
height: 100%;
display: grid;
gap: 3px;
position: absolute;
z-index: 2;
}
.pixel {
width: 9px;
height: 9px;
}
</style>
</head>
<body>
<canvas id="bkg-content"></canvas>
<div id="bkg"></div>
<script src="./script.js"></script>
</body>
</html>
获得良好动画速度的最佳方法是通过 CSS 动画来实现,而不是尝试使用 JS 来实现。
CSS 动画的介绍有点超出了答案,所以这里是 MDN 上对该主题的介绍。
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations