Stiftbasierte Zeichenanwendungen, die für das Web entwickelt wurden, litten lange Zeit unter Latenzproblemen, da eine Webseite Grafikupdates mit dem DOM synchronisieren muss. Bei jeder Zeichenanwendung können Latenzen von mehr als 50 Millisekunden die Hand-Augen-Koordination des Nutzers beeinträchtigen und die Anwendung erschweren.
Der desynchronized
-Hinweis für canvas.getContext()
ruft einen anderen Codepfad auf, der den üblichen DOM-Aktualisierungsmechanismus umgeht.
Stattdessen wird das zugrunde liegende System angewiesen, so viel Rendering wie möglich zu überspringen. In einigen Fällen wird der zugrunde liegende Buffer des Canvas direkt an den Displaycontroller des Bildschirms gesendet. Dadurch wird die Latenz vermieden, die durch die Verwendung der Renderer-Compositor-Warteschlange verursacht würde.
Wie gut ist das Produkt?
Wenn Sie zum Code gelangen möchten, scrollen Sie nach unten. Um die Funktion in Aktion zu sehen, benötigen Sie ein Gerät mit Touchscreen und vorzugsweise einen Eingabestift. (Auch Finger funktionieren.) Falls vorhanden, können Sie die 2D- oder WebGL-Beispiele ausprobieren. Alle anderen können sich diese Demo von Miguel Casas ansehen, einem der Entwickler, die diese Funktion implementiert haben. Öffnen Sie die Demo, drücken Sie auf „Wiedergabe“ und bewegen Sie den Schieberegler dann zufällig und schnell hin und her.
In diesem Beispiel wird ein einminütiger, 21-sekündiger Clip aus dem Kurzfilm Sintel von Durian verwendet, dem offenen Filmprojekt von Blender. In diesem Beispiel wird der Film in einem <video>
-Element wiedergegeben, dessen Inhalt gleichzeitig in einem <canvas>
-Element gerendert wird. Viele Geräte können dies ohne Tearing tun, bei Geräten mit Front-Buffer-Rendering wie ChromeOS kann es jedoch zu Tearing kommen. (Der Film ist großartig, aber herzzerreißend.
Ich war danach eine Stunde lang nicht zu gebrauchen. Ich hab dich gewarnt.)
Hinweis verwenden
Die Verwendung einer niedrigen Latenz bedeutet nicht nur, desynchronized
zu canvas.getContext()
hinzuzufügen. Ich werde die Probleme einzeln durchgehen.
Canvas erstellen
Bei einer anderen API würde ich zuerst die Funktionserkennung besprechen. Für den Hinweis desynchronized
müssen Sie zuerst den Canvas erstellen. Rufen Sie canvas.getContext()
auf und übergeben Sie ihm den neuen desynchronized
-Hinweis mit dem Wert true
.
const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
desynchronized: true,
// Other options. See below.
});
Funktionserkennung
Rufen Sie als Nächstes getContextAttributes()
an. Wenn das zurückgegebene Attributobjekt die Property desynchronized
hat, testen Sie sie.
if (ctx.getContextAttributes().desynchronized) {
console.log('Low latency canvas supported. Yay!');
} else {
console.log('Low latency canvas not supported. Boo!');
}
Flimmern vermeiden
Es gibt zwei Fälle, in denen ein Flimmern auftreten kann, wenn der Code nicht richtig programmiert ist.
Einige Browser, darunter Chrome, löschen WebGL-Canvasse zwischen Frames. Es ist möglich, dass der Displaycontroller den Puffer liest, während er leer ist, was zu einem Flimmern des angezeigten Bildes führt. Legen Sie preserveDrawingBuffer
daher auf true
fest.
const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
desynchronized: true,
preserveDrawingBuffer: true
});
Flimmern kann auch auftreten, wenn Sie den Bildschirmkontext in Ihrem eigenen Zeichencode löschen. Wenn Sie den Bildschirm löschen müssen, zeichnen Sie in einen Offscreen-Framebuffer und kopieren Sie ihn dann auf den Bildschirm.
Alpha-Kanäle
Ein halbtransparentes Canvas-Element, bei dem „alpha“ auf „wahr“ gesetzt ist, kann weiterhin desynchronisiert werden, darf aber keine anderen DOM-Elemente darüber haben.
Es kann nur einen geben.
Die Kontextattribute können nach dem ersten Aufruf von canvas.getContext()
nicht mehr geändert werden. Das war schon immer so, aber wenn Sie es noch einmal hören, können Sie Ärger vermeiden, falls Sie es nicht wissen oder vergessen haben .
Angenommen, ich erhalte einen Kontext und gebe „alpha“ als „false“ an. Später in meinem Code rufe ich canvas.getContext()
noch einmal auf, wobei „alpha“ auf „true“ gesetzt ist, wie unten dargestellt.
const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
alpha: false,
desynchronized: true,
});
//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
alpha: true,
desynchronized: true,
});
Es ist nicht offensichtlich, dass ctx1
und ctx2
dasselbe Objekt sind. Alpha ist weiterhin falsch und ein Kontext mit „alpha“ = „true“ wird nie erstellt.
Unterstützte Canvas-Typen
Der erste Parameter, der an getContext()
übergeben wird, ist contextType
. Wenn Sie mit getContext()
bereits vertraut sind, fragen Sie sich wahrscheinlich, ob neben „2d“ noch andere Kontexttypen unterstützt werden. In der folgenden Tabelle sind die Kontexttypen aufgeführt, die desynchronized
unterstützen.
contextType | Kontexttypobjekt |
---|---|
|
|
|
|
|
|
Fazit
Weitere Beispiele finden Sie in der Demo. Zusätzlich zum bereits beschriebenen Videobeispiel gibt es Beispiele für die Kontexte '2d' und 'webgl'.