2012-06-22 73 views
5

我刚开始玩HTML5画布,我希望能用它做几个游戏。但是,一旦我开始绘制鼠标坐标,它研磨至接近停止:重绘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(); 
 
});
<canvas id="canvas" width="570" height="570"></canvas>

回答

7

这里的代码做得更好。

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

下面是你应该考虑的事情,我改变了细分:

  • 连续增加的路径,而不是停止与beginPath闯出一条新路。这是迄今为止最大的性能杀手。你将结束一条拥有成千上万条线路的路径,永远不会被清除。
  • 当初始化时只需一次连续制作相同的路径。也就是说,你需要拨打render的唯一东西是stroke。您不需要再次致电lineTo/moveTo,当然不会持续。见注1
  • 一个路径
  • 内轻抚for循环
  • 重绘背景,而不是设置CSS背景
  • 遍地

注1设置线帽两次抚摸:如果你打算在你的应用程序中有多个路径,那么你应该缓存像这样的路径,因为它们从不改变。我有一个关于如何做到这一点的教程here

当然,如果你正在做所有这些只是做一个背景,它应该保存为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); 
} 
+0

我不知道路径起作用了!我认为有一个'path'对象会更直观。有道理,为什么现在这么慢,谢谢! – mpen

+3

HTML5 Canvas规范中现在有一个路径对象,您将能够创建路径并在将来调用'drawPath'。但没有浏览器已经实现它,它可能需要几个月才能使用它。买一天! –

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> 

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

此外,建议使用requestAnimationFrame来更新画布。你的例子用每个鼠标移动来代替,当然这需要更多的时间(当然鼠标移动的时候)。

关于提高画布性能,有一个很好的article。此外,在这个问题上有一个很好的SO post

+0

花了一段时间来弄清楚你从字面上的意思层帆布元素。我认为“图层”是画布背景下的一个概念。这是个好主意。感谢您的提示! – mpen

+0

对不起,我改变了它以避免混淆别人。 –

+1

这些都是好评,但在这种情况下我还没有找到另一个问题。我用非常快速的动画绘制更复杂的东西,甚至不用担心双缓冲。 –

9

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

所以我多了一会儿,发现了一个错误。

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

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

这里是一个fast rendering of the same thing,证明它现在苍蝇。

画布绘图快,可用于动画。