重绘HTML5画布非常慢

mpe*_*pen 4 html5 canvas

我刚刚开始玩HTML5画布,我希望能用它制作一些游戏.但是,一旦我开始将鼠标坐标渲染到它,它就会磨成近乎停顿的状态:

http://jsfiddle.net/mnpenner/zHpgV/

我所做的只是呈现38行和一些文本,它应该能够处理,不是吗?

难道我做错了什么?我希望能够以至少30 FPS渲染,但对于这样的东西,我希望它能够绘制1000次.

或者我只是使用错误的工具来完成工作?WebGL是否可以胜任这项任务?为什么一个比另一个慢得多?

String.prototype.format = function() {
    var args = arguments;
    return this.replace(/\{(\d+)\}/g, function(m, n) {
        return args[n];
    });
};
var $canvas = $('#canvas');
var c = $canvas[0].getContext('2d');
var scale = 20;
var xMult = $canvas.width() / scale;
var yMult = $canvas.height() / scale;
var mouseX = 0;
var mouseY = 0;
c.scale(xMult, yMult);
c.lineWidth = 1 / scale;
c.font = '1pt Calibri';

function render() {
    c.fillStyle = '#dcb25c';
    c.fillRect(0, 0, scale, scale);
    c.fillStyle = '#544423';
    c.lineCap = 'square';
    for (var i = 0; i <= 19; ++i) {
        var j = 0.5 + i;
        c.moveTo(j, 0.5);
        c.lineTo(j, 19.5);
        c.stroke();
        c.moveTo(0.5, j);
        c.lineTo(19.5, j);
        c.stroke();
    }
    c.fillStyle = '#ffffff';
    c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5);
}
render();
$canvas.mousemove(function(e) {
    mouseX = e.clientX;
    mouseY = e.clientY;
    render();
});
Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas" width="570" height="570"></canvas>
Run Code Online (Sandbox Code Playgroud)

Den*_*ret 9

正如我在评论中所说,我对这段代码的缓慢感到惊讶,因为我用非常快的动画绘制了更复杂的东西,甚至没有打扰双缓冲.

所以我看了一点,发现了一个预期的错误.

主要问题是绘图路径的积累.

c.beginPath();每次绘制一条路径时添加一个.

是对同一件事快速渲染,以证明它现在过得很快.

绘图画布速度快,可用于动画.


Sim*_*ris 8

这里的代码做得更好.

http://jsfiddle.net/zHpgV/3/

以下是我改变后应该考虑的事项的细分:

  • 连续添加到路径而不是停止并创建新路径beginPath.这是迄今为止最大的性能杀手.你最终会得到一条路径,里面有成千上万的线路段,永远不会被清除.
  • 在初始化时只需要进行一次连续不断地制作相同的路径.也就是说,你唯一需要调用的renderstroke.你不需要再打电话lineTo/moveTo,当然不是连续打电话.见注1.
  • 一条路径抚摸两次
  • 在for循环中抚摸
  • 重绘背景而不是设置CSS背景
  • 一遍又一遍地设置线帽

注意1:如果您计划在应用程序中有多个路径,那么您应该缓存这样的路径,因为它们永远不会更改.我有一个如何在这里做的教程.

当然,如果你正在做所有这些只是制作背景,它应该保存为png,你应该使用CSS背景图像.

像这样:http://jsfiddle.net/zHpgV/4/

然后突然你的渲染例程相当小:

function render() {
    c.clearRect(0, 0, scale, scale);
    c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5);
}
Run Code Online (Sandbox Code Playgroud)

  • HTML5 Canvas规范中现在有一个路径对象,您将来可以创建一个Path并调用`drawPath`.但是还没有浏览器实现它,可能需要几个月的时间才能使用它.有一天买! (3认同)

Art*_*lev 7

您不必在每个动画帧中绘制整个网格.将它放在另一个底层画布上(通常将它们称为"图层",但它们只是单独的画布元素),因此您只能重绘坐标.

<div id="canv">
 <canvas id="bgLayer" width="500" height="500" style="z-index: 0"></canvas>
 <canvas id="fgLayer"  width="500" height="500" style="z-index: 1"></canvas>
</div>
Run Code Online (Sandbox Code Playgroud)

这是我一直在玩分层画布的例子.在底部画布上绘制的表格,球在顶部画布上绘制.它只是一个游乐场,因此有很多需要修复和优化的地方,例如在另一个隐藏的画布上只绘制一次球,并使用getImageData/putImageData来提高性能.

此外,建议使用requestAnimationFrame更新画布.你的例子取而代之的是每次鼠标移动,这需要更多时间(当鼠标移动时).

一篇关于提高画布性能的好文章.此外,关于这个主题还有很多SO帖子.