我有一个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);
字符串
另一个问题是重复,所以它是最佳的和快速的,代码滞后很多。任何提示?任何不同的方法,我可以采取?
the result I aimed for
目前的实现似乎存在性能瓶颈。我怀疑draw函数中的循环和画布的频繁操作可能会导致速度变慢。我如何优化代码以提高效率?动画速度对于流畅的用户体验至关重要。我应该遵循哪些特定的技术或最佳实践来提高星落效果的速度?我使用画布绘制星星和像素操作背景的组合。这是最佳的方法,或者有其他方法可以提供更好的性能?
我已经尝试了一些基本的优化,比如使用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>
型
2条答案
按热度按时间aydmsdu91#
获得良好动画速度的最佳方法是通过CSS Animation来实现,而不是尝试使用JS。
CSS动画的介绍有点超出了SO答案,所以这里是MDN上的主题介绍。
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animations/Using_CSS_animations
ppcbkaq52#
好吧,我做到了。
事实是你的代码并不是那么低效!它非常好。只是有两个问题:
createPixels
函数外提取childrens
数组来纠正这个问题。setInterval
回调是如此之高。这是通过使用requestAnimationFrame
没有延迟纠正的。看看这个:https://jsfiddle.net/b7pv152w/
代码,供其他用户参考,可以在下面找到:
个字符