javascript - 在 Canvas 上循环绘制图像 - 我如何优化这段代码?

标签 javascript optimization canvas drawing

我正在 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/

相关文章:

javascript - 其他语言中是否有类似的 "undefined"概念?

javascript - infowindow.close() 不与多个标记一起使用

javascript - 如何使用 Typescript 为 React 设置 Material-UI?

c - 如何在c中查看优化代码

javascript - 将图像转换为黑白的最佳 RGB 组合 "threshold"

javascript - 在javascript中逆时针排序点

java - 帮助在 Swing 中绘制自定义图形

javascript - 如何打印当前用户的地址

tensorflow - Adam 优化器真的是 RMSprop 加动量吗?如果是,为什么它没有动量参数?

php - 检查 PHP 数组是否为空的最佳方法