我正在 Canvas 元素上绘制背景图像。我使用 requestAnimationFrame 创建一个循环。在此循环中,我使用适当的坐标将图像绘制到 Canvas 上。
在 Chrome 中,动画看起来很流畅,帧率为 60 fps,但我偶尔会出现一些小故障。 Firefox 中的情况比 Chrome 中更糟糕。当我使用干净的个人资料查看它而不打开选项卡时效果会更好 - 但它仍然不完美。
以下是完整来源:http://jsbin.com/vopiw/1/edit?html,output
该函数在每一帧中都会被调用:
function draw(delta) {
totalSeconds += delta;
var vx = 100; // the background scrolls with a speed of 100 pixels/sec
var numImages = Math.ceil(canvas.width / img.width) + 1;
var xpos = totalSeconds * vx % img.width;
context.save();
context.translate(-xpos, 0);
for (var i = 0; i < numImages; i++) {
context.drawImage(img, i * img.width, 0);
}
context.restore();
}
您能发现什么可能是真正的性能缺陷吗?
到目前为止我发现了什么:
- 内存消耗略有增长,但持续增长
- 但是没有发生垃圾收集,这可能是造成故障的原因
你有什么线索吗?
最佳答案
使用该图像作为元素本身的背景图像,并使用背景位置滚动它。
不用 img
onload
直接进入代码:
(function imageLoaded() {
canvas.style.backgroundImage = 'url(...)';
canvas.style.backgroundRepeat = 'repeat-x';
draw(0);
...
然后只需更新 draw()
方法,如下所示:
// cache these
var iw = 400,
cw = canvas.width;
function draw(delta) {
totalSeconds += delta;
var vx = 100; // if always 100 just insert the value directly below
var numImages = ((cw / iw)|0) + 1; // use logic OR to remove fractions
var xpos = totalSeconds * vx % iw;
// update background position
canvas.style.backgroundPosition = (-xpos + iw) + 'px 0';
}
第二个问题是计算时间增量的方式。使用低分辨率计时器会增加不稳定性。
尝试使用内置的高分辨率计时器。幸运的是,rAF 提供了高分辨率时间戳,您可以使用它:
function loop(now) { // use argument from rAF (hi-res timestamp)
if (!looping) {
return;
}
requestAnimationFrame(loop);
var deltaSeconds = (now - lastFrameTime) * 0.001; //mul is faster than div
lastFrameTime = now;
draw(deltaSeconds);
}
<强> Modified jsbin
这将绘图操作交给了浏览器,但请记住, yield 还不止于此。原因是 drawImage()
方法本身非常快,但是您在 JavaScript 中节省了一些步骤,这是真正的瓶颈(尽管存在神话, Canvas 本身非常快)并且这些绘制操作的重复由浏览器中的内部编译代码完成。
影响流畅度的其他因素是硬件时钟和硬件功能,以及浏览器中发生的其他事情。
我还会将该 Canvas 元素放在绝对或固定位置,因为浏览器将为元素提供一个单独的位图(与 Canvas 位图无关),这可以提高 CSS 背景性能(修改后的 jsbin 中未显示)。
关于javascript - 在 Canvas 上循环绘制图像 - 我如何优化这段代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22128459/