Le applicazioni di disegno basate su stilo create per il web soffrono da tempo di problemi di latenza perché una pagina web deve sincronizzare gli aggiornamenti grafici con il DOM. In qualsiasi applicazione di disegno, latenze superiori a 50 millisecondi possono interferire con la coordinazione mano-occhio di un utente, rendendo difficile l'utilizzo delle applicazioni.
L'opzione desynchronized
per canvas.getContext()
richiama un percorso di codice diverso che aggira il solitamente meccanismo di aggiornamento DOM.
Il suggerimento indica invece al sistema sottostante di saltare il maggior numero possibile di operazioni di composizione e, in alcuni casi, il buffer sottostante della tela viene inviato direttamente al controller del display dello schermo. In questo modo viene eliminata la latenza che verrebbe causata dall'utilizzo della coda del compositore del renderer.
Qual è la tua valutazione?
Se vuoi passare al codice, scorri verso l'alto. Per provarlo, hai bisogno di un dispositivo con un touchscreen e preferibilmente uno stilo. (funzionano anche le dita). Se ne hai uno, prova i sample 2d o webgl. Per gli altri, guarda questa demo di Miguel Casas, uno degli ingegneri che ha implementato questa funzionalità. Apri la demo, premi Riproduci, quindi muovi il cursore avanti e indietro in modo casuale e veloce.
Questo esempio utilizza un clip di un minuto e ventuno secondi dello short film Sintel di Durian, il progetto cinematografico open source di Blender. In questo esempio, il filmato viene riprodotto in un elemento <video>
i cui contenuti vengono visualizzati contemporaneamente in un elemento <canvas>
. Molti dispositivi possono farlo senza tearing, anche se i dispositivi con rendering del buffer anteriore, ad esempio ChromeOS, potrebbero presentare tearing. Il film è fantastico, ma straziante.
Non ho potuto fare nulla per un'ora dopo averlo visto. Io ti ho messo in guardia.
Utilizzo dell'indizio
L'utilizzo di una latenza bassa non si limita all'aggiunta di desynchronized
a
canvas.getContext()
. Esaminerò i problemi uno alla volta.
Crea il canvas
In un'altra API parlerei prima del rilevamento delle funzionalità. Per il suggerimento desynchronized
devi prima creare la tela. Chiama canvas.getContext()
e passagli il nuovo desynchronized
suggerimento con un valore di true
.
const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
desynchronized: true,
// Other options. See below.
});
Rilevamento di funzionalità
Quindi chiama getContextAttributes()
. Se l'oggetto degli attributi restituito ha una proprietà desynchronized
, testalo.
if (ctx.getContextAttributes().desynchronized) {
console.log('Low latency canvas supported. Yay!');
} else {
console.log('Low latency canvas not supported. Boo!');
}
Evitare lo sfarfallio
Esistono due casi in cui puoi causare sfarfallio se non scrivi il codice correttamente.
Alcuni browser, tra cui Chrome, cancellano i canvas WebGL tra un frame e l'altro. È possibile che il controller del display legga il buffer mentre è vuoto, causando sfarfallio dell'immagine disegnata. Per evitare questo problema, imposta
preserveDrawingBuffer
su true
.
const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
desynchronized: true,
preserveDrawingBuffer: true
});
Il tremolio può verificarsi anche quando cancelli il contesto dello schermo nel codice di disegno. Se devi cancellare, disegna in un framebuffer offscreen e poi copialo sullo schermo.
Canali alfa
Un elemento canvas traslucido, in cui alpha è impostato su true, può comunque essere disattivato, ma non deve avere altri elementi DOM sopra.
Può esserci un solo
Non puoi modificare gli attributi del contesto dopo la prima chiamata a
canvas.getContext()
. Questo è sempre stato vero, ma ripeterlo potrebbe farti risparmiare un po' di frustrazione se non lo sai o lo hai dimenticato .
Ad esempio, supponiamo di ottenere un contesto e di specificare alpha come false, quindi
in un punto successivo del codice chiamo canvas.getContext()
una seconda volta con alpha
impostato su true come mostrato di seguito.
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,
});
Non è ovvio che ctx1
e ctx2
siano lo stesso oggetto. Alfa è ancora false e un
contesto con alfa uguale a true non viene mai creato.
Tipi di tela supportati
Il primo parametro passato a getContext()
è contextType
. Se hai già familiarità con getContext()
, ti starai chiedendo se sono supportati tipi di contesto diversi da "2d". La tabella seguente mostra i tipi di contesto che supportano desynchronized
.
contextType | Oggetto tipo di contesto |
---|---|
|
|
|
|
|
|
Conclusione
Se vuoi vedere altri esempi, dai un'occhiata ai Sample. Oltre all'esempio video già descritto, sono disponibili esempi che mostrano i contesti '2d' e 'webgl'.