javascript - 如何优化大画布动画
问题描述
我有一个大画布动画,是从 codepen 中获取的。问题是它有时运行有点慢。这就是为什么我想知道如何优化此动画以使其运行更顺畅?我想要尽可能多的提示,如果您可以更改代码中的任何内容来帮助我,我将不胜感激。
$(window).on("load", function() {
(function() {
var requestAnimationFrame =
window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
window.requestAnimationFrame = requestAnimationFrame;
})();
// Terrain stuff.
var background = document.getElementById("bgCanvas"),
bgCtx = background.getContext("2d"),
width = 1920,
height = 1080;
if (height < 400) {
height = 400;
}
background.width = width;
background.height = height;
function Terrain(options) {
options = options || {};
this.terrain = document.createElement("canvas");
this.terCtx = this.terrain.getContext("2d");
this.scrollDelay = options.scrollDelay || 90;
this.lastScroll = new Date().getTime();
this.terrain.width = width;
this.terrain.height = height;
this.fillStyle = options.fillStyle || "#191D4C";
this.mHeight = options.mHeight || height;
// generate
this.points = [];
var displacement = options.displacement || 140,
power = Math.pow(2, Math.ceil(Math.log(width) / Math.log(2)));
// set the start height and end height for the terrain
this.points[0] = this.mHeight; //(this.mHeight - (Math.random() * this.mHeight / 2)) - displacement;
this.points[power] = this.points[0];
// create the rest of the points
for (var i = 1; i < power; i *= 2) {
for (var j = power / i / 2; j < power; j += power / i) {
this.points[j] =
(this.points[j - power / i / 2] + this.points[j + power / i / 2]) /
2 +
Math.floor(Math.random() * -displacement + displacement);
}
displacement *= 0.6;
}
document.body.appendChild(this.terrain);
}
Terrain.prototype.update = function() {
// draw the terrain
this.terCtx.clearRect(0, 0, width, height);
this.terCtx.fillStyle = this.fillStyle;
if (new Date().getTime() > this.lastScroll + this.scrollDelay) {
this.lastScroll = new Date().getTime();
this.points.push(this.points.shift());
}
this.terCtx.beginPath();
for (var i = 0; i <= width; i++) {
if (i === 0) {
this.terCtx.moveTo(0, this.points[0]);
} else if (this.points[i] !== undefined) {
this.terCtx.lineTo(i, this.points[i]);
}
}
this.terCtx.lineTo(width, this.terrain.height);
this.terCtx.lineTo(0, this.terrain.height);
this.terCtx.lineTo(0, this.points[0]);
this.terCtx.fill();
};
// Second canvas used for the stars
bgCtx.fillStyle = "#05004c";
bgCtx.fillRect(0, 0, width, height);
// stars
function Star(options) {
this.size = Math.random() * 2;
this.speed = Math.random() * 0.05;
this.x = options.x;
this.y = options.y;
}
Star.prototype.reset = function() {
this.size = Math.random() * 2;
this.speed = Math.random() * 0.05;
this.x = width;
this.y = Math.random() * height;
};
Star.prototype.update = function() {
this.x -= this.speed;
if (this.x < 0) {
this.reset();
} else {
bgCtx.fillRect(this.x, this.y, this.size, this.size);
}
};
function ShootingStar() {
this.reset();
}
ShootingStar.prototype.reset = function() {
this.x = Math.random() * width;
this.y = 0;
this.len = Math.random() * 80 + 10;
this.speed = Math.random() * 10 + 6;
this.size = Math.random() * 1 + 0.1;
// this is used so the shooting stars arent constant
this.waitTime = new Date().getTime() + Math.random() * 3000 + 500;
this.active = false;
};
ShootingStar.prototype.update = function() {
if (this.active) {
this.x -= this.speed;
this.y += this.speed;
if (this.x < 0 || this.y >= height) {
this.reset();
} else {
bgCtx.lineWidth = this.size;
bgCtx.beginPath();
bgCtx.moveTo(this.x, this.y);
bgCtx.lineTo(this.x + this.len, this.y - this.len);
bgCtx.stroke();
}
} else {
if (this.waitTime < new Date().getTime()) {
this.active = true;
}
}
};
var entities = [];
// init the stars
for (var i = 0; i < height; i++) {
entities.push(
new Star({
x: Math.random() * width,
y: Math.random() * height
})
);
}
// Add 2 shooting stars that just cycle.
entities.push(new ShootingStar());
entities.push(new ShootingStar());
entities.push(new Terrain({ mHeight: height / 2 - 120 }));
entities.push(
new Terrain({
displacement: 120,
scrollDelay: 50,
fillStyle: "rgb(17,20,40)",
mHeight: height / 2 - 60
})
);
entities.push(
new Terrain({
displacement: 100,
scrollDelay: 20,
fillStyle: "rgb(10,10,5)",
mHeight: height / 2
})
);
//animate background
function animate() {
bgCtx.fillStyle = "#110E19";
bgCtx.fillRect(0, 0, width, height);
bgCtx.fillStyle = "#ffffff";
bgCtx.strokeStyle = "#ffffff";
var entLen = entities.length;
while (entLen--) {
entities[entLen].update();
}
requestAnimationFrame(animate);
}
animate();
});
编辑:当我说慢时,我的意思是动画断断续续且不流畅
解决方案
我很确定这是你的Terrain#update
。特别是你的循环
Terrain.prototype.update = function() {
for (var i = 0; i <= width; i++) {
if (i === 0) {
this.terCtx.moveTo(0, this.points[0]);
} else if (this.points[i] !== undefined) {
this.terCtx.lineTo(i, this.points[i]);
}
}
你有width = 1920
,所以每个update
循环将循环 1920 次,每秒 60 个循环,用于 3 个元素。1920 * 60 * 3 = 每秒约 230,000 次迭代。尝试增加for
循环中的间隔,看看是否有帮助
for (var i = 0; i <= width; i += 3) { // or maybe an even higher interval
编辑:再看一点之后,您似乎也在Star
屏幕上绘制了 1000 个对象。您可能需要考虑降低该数字。你会用这个让每个人的电脑着火!
推荐阅读
- javascript - 从字符串时区获取时间(javascript)
- r - Rstudio 发布文件到 rpubs 没有外部浏览器和登录页面弹出
- python-3.x - Django没有从静态目录加载样式文件
- rust - 如何使用引号在 proc_macro 中插入函数参数标识符?
- swift - 从自定义标题单元格内的视图控制器更改按钮图像
- javascript - JS 函数中的 Word Press PHP ACF Snippets
- pandas - 如何在熊猫数据透视表上添加列(多列)
- r - 仅在 r 中自动将日期时间数据的格式转换为日期
- python - 回归模型在训练时间上给出了 nan 或 inf?
- c++ - 反转字符串中的单词,我不知道为什么会得到这个输出