Frage

Was ich möchte, ist zu tun, um meine Grafiken auf einem Puffer zeichnen und dann in der Lage sein, es zu kopieren, wie auf die Leinwand ist so ich Animation und vermeiden Sie Flackern tun können. Aber ich konnte diese Option nicht finden. Wer weiß, wie ich darüber gehen kann?

War es hilfreich?

Lösung

Die folgenden hilfreichen Link, zusätzlich zu zeigen Beispiele und Vorteile der Verwendung von Double-Buffering, zeigt einige andere Performance-Tipps für die Verwendung des HTML5-Canvas-Element. Es enthält Links zu jsPerf Tests, die aggregierte Testergebnisse in allen Browsern in eine Browserscope Datenbank. Dadurch wird sichergestellt, dass die Leistungsspitzen werden überprüft.

http://www.html5rocks.com/en/tutorials/canvas/performance/

Für Ihre Bequemlichkeit habe ich ein minimales Beispiel für eine wirksame doppelte Pufferung enthalten wie in dem Artikel beschrieben.

// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');

// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');

// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();

//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);

Andere Tipps

Eine sehr einfache Methode ist, zwei Leinwand-Elemente an der gleichen Stelle des Bildschirms und Set Sichtbarkeit für den Puffer haben, dass Sie zeigen müssen. Zeichnen Sie auf der versteckt und Flip, wenn Sie fertig sind.

Einige Code:

CSS:

canvas { border: 2px solid #000; position:absolute; top:0;left:0; 
visibility: hidden; }

Flipping in JS:

Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';

DrawingBuffer=1-DrawingBuffer;

In diesem Code das Array 'Puffer []' hält beide Leinwand-Objekte. Also, wenn Sie Sie noch starten wollen Zeichnung müssen den Kontext bekommen:

var context = Buffers[DrawingBuffer].getContext('2d');

Browser ich getestet habe alle diese Pufferung Griff für Sie nicht die Leinwand neu zu streichen, bis der Code, der den Rahmen zieht abgeschlossen hat. Siehe auch die WHATWG Mailing-Liste: http: //www.mail- archive.com/whatwg@lists.whatwg.org/msg19969.html

Sie könnten immer tun var canvas2 = document.createElement("canvas"); und fügen Sie es nicht auf das DOM überhaupt.

sagte nur, da ihr so ??mit display:none; besessen zu sein scheint es scheint nur sauberer zu mir und imitiert die Idee der doppelten Pufferung Art und Weise genauer als nur eine ungeschickt unsichtbare Leinwand hat.

Mehr als zwei Jahre später:

Es gibt keine Notwendigkeit für ‚manuell‘ Double-Buffering implementieren. Mr. Geary schrieb darüber in seinem Buch "HTML5 Canvas" .

Um effektiv zu flackern Verwendung reduzieren requestAnimationFrame() !

, fragte Josh (eine Weile zurück) darüber, wie der Browser weiß „wenn die Ziehverfahren Ende“ um zu vermeiden, flackert. Ich hätte direkt auf seinen Posten aber meine rep ist nicht hoch genug kommentiert. Auch dies ist nur meine Meinung. Ich habe keine Fakten haben, um es zu sichern, aber ich fühle mich ziemlich zuversichtlich darüber, und es kann für andere hilfreich sein, dies in Zukunft zu lesen.

ich den Browser zu raten nicht „wissen“, wenn Sie fertig Zeichnung sind. Aber genau wie die meisten JavaScript aktivieren, solange Ihr Code ausgeführt wird, ohne die Kontrolle an den Browser zu verzichten, wird der Browser im Wesentlichen gesperrt und wird nicht / kann nicht aktualisieren / reagieren auf seine UI. Ich vermute, dass, wenn Sie die Leinwand löschen und den gesamten Rahmen ziehen, ohne die Kontrolle an den Browser zu verzichten, wird es nicht tatsächlich Ihre Leinwand ziehen, bis Sie fertig sind.

Bei der Einstellung Sie eine Situation, wo Sie Ihre Rendering Spannweiten mehrere SetTimeout / setInterval / request Rufe, wenn Sie die Leinwand in einem Anruf löschen und Elemente auf der Leinwand in den nächsten Anrufe ziehen, um den Zyklus (zum Beispiel) Wiederholung alle 5 Anrufe, würde ich bereit sein, Sie flackern sehen wetten würden, da die Leinwand nach jedem Aufruf aktualisiert werden würde.

Das sagte, ich bin nicht sicher, würde ich das Vertrauen. Wir sind schon an dem Punkt, dass Javascript nativen vor der Ausführung Maschinencode unten kompiliert wird (zumindest das ist, was Chrome V8-Motor macht aus dem, was ich verstehe). Ich wäre nicht überrascht, wenn es nicht zu lang war, bevor Browser von der Benutzeroberfläche läuft ihre Javascript in einem separaten Thread gestartet und der Zugriff auf die UI-Elemente Synchronisieren ermöglicht die Benutzeroberfläche Aktualisierung / respond während die Ausführung von JavaScript, die nicht UI zugegriffen hat. Wann / wenn das passiert (und ich verstehe, dass es viele Hürden, die überwunden werden müßten, wie Event-Handler Tritte aus, während Sie noch anderen Code ausgeführt wird), werden wir wahrscheinlich sehen Flimmern auf Leinwand Animation, die nicht verwenden eine Art von double-Buffering.

Ich persönlich liebe die Idee von zwei Canvas-Elemente positioniert über aufeinander und abwechselnd die auf jedem Rahmen gezogen dargestellt / wird. Ziemlich unaufdringlich und wahrscheinlich ziemlich leicht hinzugefügt zu einer bestehenden Anwendung mit einem paar Zeilen Code.

Für die Ungläubigen, hier einige flackernde Code. Beachten Sie, dass ich Clearing explizit den vorherigen Kreis zu löschen.

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

function draw_ball(ball) {
    ctx.clearRect(0, 0, 400, 400);
    ctx.fillStyle = "#FF0000";
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, 30, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.fill();
}

var deltat = 1;
var ball = {};
ball.y = 0;
ball.x = 200;
ball.vy = 0;
ball.vx = 10;
ball.ay = 9.8;
ball.ax = 0.1;

function compute_position() {
    if (ball.y > 370 && ball.vy > 0) {
        ball.vy = -ball.vy * 84 / 86;
    }
    if (ball.x < 30) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    } else if (ball.x > 370) {
        ball.vx = -ball.vx;
        ball.ax = -ball.ax;
    }
    ball.ax = ball.ax / 2;
    ball.vx = ball.vx * 185 / 186;
    ball.y = ball.y + ball.vy * deltat + ball.ay * deltat * deltat / 2
    ball.x = ball.x + ball.vx * deltat + ball.ax * deltat * deltat / 2
    ball.vy = ball.vy + ball.ay * deltat
    ball.vx = ball.vx + ball.ax * deltat
    draw_ball(ball);
}

setInterval(compute_position, 40);
<!DOCTYPE html>
<html>
<head><title>Basketball</title></head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
</body></html>

Es gibt kein Flackern in Web-Browsern! Sie nutzen bereits dbl Pufferung für ihr Rendering. Js Motor wird alle Ihre Rendering machen, bevor es zeigt. Auch Kontext Speichern und Wiederherstellen nur stapeln transformierende Matrix Daten und solche, nicht auf die Leinwand Inhalt selbst. Also, die Sie nicht brauchen oder wollen dbl Pufferung!

Anstatt Ihre eigenen Rollen, sind Sie wahrscheinlich die beste Laufleistung gehen zu erhalten, indem eine bestehende Bibliothek zum Erstellen von sauberen und flimmerfreie JavaScript-Animation:

Hier ist ein beliebter ein: http://processingjs.org

benötigen Sie 2 Leinwand: (man beachte die CSS z-index und position: absolute)

<canvas id="layer1" width="760" height="600" style=" position:absolute; top:0;left:0; 
visibility: visible;  z-index: 0; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="layer2" width="760" height="600" style="position:absolute; top:0;left:0; 
visibility: visible;  z-index: 1; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>

Sie können feststellen, dass die erste Leinwand zu sehen ist und die zweite es die Idee, versteckt es ist auf dem versteckt zu ziehen, nachdem wir die sichtbare verstecken und die versteckte Leinwand sichtbar machen. wenn es versteckt ‚versteckte Leinwand löschen

<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");

ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;

Opera 9.10 ist sehr langsam und zeigt die Ziehverfahren. Wenn Sie noch keinen Browser doppelte Pufferung verwenden, um zu sehen, versuchen Opera 9.10 aus.

Einige Leute vorgeschlagen, dass Browser ist die Bestimmung irgendwie, wenn der Ziehvorgang endet aber können Sie erklären, wie das funktionieren kann? Ich habe keine offensichtlichen Flimmern in Firefox, Chrome bemerkt hat, oder IE9 auch wenn die Zeichnung langsam ist, so dass es scheint, wie das ist, was sie tun, aber, wie das erreicht wird, ist mir ein Rätsel. Wie würden wissen, dass der Browser immer, dass sie die Anzeige ist erfrischend kurz vor mehr Zeichnung Anweisungen ausgeführt werden sollen? Glauben Sie, dass sie nur Zeit, so dass, wenn ein Intervall von mehr als 5 ms oder so vergeht ohne eine Leinwand Zeichnung Befehl ausführt, nimmt es kann sicher Swap-Puffer?

In den meisten Fällen brauchen Sie nicht, dies zu tun, die Browser-Geräte für Sie diese. Aber nicht immer sinnvoll!

Sie haben noch diese zu implementieren, wenn Ihre Zeichnung sehr kompliziert ist. Die meisten der Update-Rate-Bildschirm ist etwa 60 Hz, es die Bildschirmaktualisierungen pro 16ms bedeutet. Die Aktualisierungsrate des Browsers kann in der Nähe von dieser Nummer. Wenn Ihre Form Notwendigkeit abgeschlossen werden 100ms, erhalten Sie eine unvollendete Form sehen. So können Sie die doppelte Pufferung in dieser Situation umsetzen können.

Ich habe einen Test gemacht: Clear a rect, wait for some time, then fill with some color. Wenn ich die Zeit auf 10 ms eingestellt, werde ich nicht Flimmern sehen. Aber wenn ich es auf 20ms gesetzt, das Flackern passiert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top