Neuzeichnen HTML5-canvas-unglaublich langsam
Ich habe gerade angefangen zu spielen mit dem HTML5-canvas und ich hatte gehofft, ein paar Spiele mit ihm. Jedoch sobald ich begann, Rendern die Koordinaten der Maus, um es, es gemahlen zu einem in der Nähe halt:
http://jsfiddle.net/mnpenner/zHpgV/
Alles, was ich Tat, war render 38 Linien und text, es sollte in der Lage sein, damit umzugehen, nicht?
Mache ich etwas falsch? Ich möchte in der Lage sein zu Rendern mindestens 30 FPS, aber für so etwas würde ich erwarten, dass es in der Lage sein zu ziehen, 1000 mal.
Oder bin ich einfach nur mit dem falschen Werkzeug für den job? Ist WebGL für die Aufgabe? Warum sollte man so viel langsamer als die anderen?
JS:
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();
});
HTML:
<canvas id="canvas" width="570" height="570"></canvas>
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier ist der code viel besser.
http://jsfiddle.net/zHpgV/3/
Hier ist eine Auflistung der Dinge, die Sie berücksichtigen sollten, dass ich geändert:
beginPath
. Dies ist mit Abstand der größte performance-killer hier. Sie sind am Ende mit einem Pfad mit tausenden von line-segements, dass wird nie geklärt.render
iststroke
. Sie brauchen nicht zu rufenlineTo/moveTo
immer wieder, und schon gar nicht kontinuierlich. Siehe Anmerkung 1.Hinweis 1: Wenn Sie planen, mehr als einen Pfad in Ihrer Anwendung dann sollten Sie wahrscheinlich die cache-Pfade wie diese, da Sie sich nie ändern. Ich habe ein tutorial, wie zu tun, dass hier.
Natürlich wenn Sie all dies tun, einfach nur ein hintergrund, er sollte gespeichert werden als png-und Sie sollten mit einem CSS hintergrund Bild.
Etwa so: http://jsfiddle.net/zHpgV/4/
Dann plötzlich Ihre render-routine ist eher klein:
path
Objekt gewesen wäre intuitiver. Sinnvoll ist, warum es so langsam war, jetzt aber, danke!drawPath
in die Zukunft. Aber kein browser implementiert hat, ist es noch nicht und es kann Monate, bevor Sie in der Lage sein, es zu nutzen. Kaufen eines Tages!Wie gesagt in den Kommentaren, ich war überrascht von der Langsamkeit dieser code wie ich zeichne viel viel mehr komplexe Dinge mit sehr schnellen Animationen, ohne sich die Mühe über die doppelte Pufferung.
So, ich sah ein wenig mehr und einen Fehler gefunden als erwartet.
Das Hauptproblem ist die Ansammlung von der Zeichnung Weg.
Hinzufügen
c.beginPath();
jedes mal, wenn Sie zeichnen einen Pfad.Hier ein schnelles rendering von der gleichen Sache, um zu beweisen, es fliegt jetzt.
Leinwand Zeichnung ist schnell und kann verwendet werden, für die Animationen.
Sie nicht haben, um zu zeichnen das gesamte raster in jedes Animations-frame. Legen Sie es auf einem anderen zugrunde liegenden Leinwand (es ist üblich, von "Schichten", aber Sie sind nur einzelne canvas-Elemente), so dass Sie werde in der Lage sein, neu zu zeichnen, koordiniert nur.
Hier ist das Beispiel Spiele ich schon mit layered Leinwand. Die Tabelle gezogen, die auf der Unterseite der Leinwand, die Kugeln sind gezogen, die auf der oberen Leinwand. Es ist nur ein Spielplatz, es gibt also eine Menge zu reparieren und zu optimieren, gibt es, zum Beispiel zu zeichnen, jeden ball nur einmal auf eine andere versteckte Leinwand und verwenden getImageData/putImageData um die Leistung zu verbessern.
Außerdem ist es empfohlen, zu verwenden requestAnimationFrame zum aktualisieren der Leinwand. Dein Beispiel zieht auf jede Bewegung der Maus statt, das ist viel mehr oft dann benötigt, (wenn die Maus bewegt natürlich).
Es ist eine gute Artikel auf die Verbesserung Leinwand-performance. Auch gibt es eine große SO ein post zu diesem Thema.