2012-06-22 80 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,證明它現在蒼蠅。

畫布繪圖快,可用於動畫。