HTML5 / Canvas supporta il doppio buffer?

Quello che mi piacerebbe fare è disegnare la mia grafica su un buffer e quindi essere in grado di copiarlo così com’è per la canvas in modo da poter fare animazione ed evitare lo sfarfallio. Ma non ho potuto trovare questa opzione. Qualcuno sa come posso andare su questo?

Il seguente link utile, oltre a mostrare esempi e vantaggi dell’utilizzo del doppio buffering, mostra numerosi altri suggerimenti sulle prestazioni per l’utilizzo dell’elemento canvas html5. Include collegamenti ai test di jsPerf, che aggregano i risultati dei test tra i browser in un database di Browserscope. Questo assicura che i suggerimenti sulle prestazioni siano verificati.

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

Per tua comodità, ho incluso un esempio minimo di doppio buffering efficace come descritto nell’articolo.

 // 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); 

Un metodo molto semplice consiste nell’avere due elementi canvas nella stessa posizione dello schermo e impostare la visibilità per il buffer che è necessario mostrare. Disegna il nascosto e lancia quando hai finito.

Qualche codice:

CSS:

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

Sfogliando in JS:

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

In questo codice l’array ‘Buffer []’ contiene entrambi gli oggetti canvas. Quindi quando vuoi iniziare a disegnare devi ancora ottenere il contesto:

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

I browser che ho provato gestiscono questo buffering per voi non ridipingendo la canvas finché il codice che disegna la cornice non è stato completato. Vedi anche la mailing list WHATWG: http://www.mail-archive.com/[email protected]/msg19969.html

Puoi sempre fare var canvas2 = document.createElement("canvas"); e non aggiungerlo affatto al DOM.

Dico solo perché voi ragazzi siete così ossessionati dal display:none; sembra solo più pulito per me e imita l’idea del doppio buffering in modo più accurato del semplice avere una canvas goffamente invisibile.

Più di due anni dopo:

Non è necessario implementare il doppio buffering “manualmente”. Mr. Geary ha scritto su questo nel suo libro “HTML5 Canvas” .

Per ridurre efficacemente lo sfarfallio, usa requestAnimationFrame() !

Per i non credenti, ecco un codice sfarfallio. Nota che sto cancellando esplicitamente per cancellare la cerchia precedente.

http://coderextreme.net/basketball2.html ( http://jsfiddle.net/GzSWJ/ )

   Basketball   Your browser does not support the canvas element.   

Josh ha chiesto (qualche tempo fa) di sapere come il browser “quando termina il processo di disegno” in modo da evitare lo sfarfallio. Avrei commentato direttamente al suo post ma il mio rappresentante non è abbastanza alto. Anche questa è solo la mia opinione. Non ho fatti per sostenerlo, ma mi sento abbastanza fiducioso e potrebbe essere utile per gli altri che lo leggono in futuro.

Immagino che il browser non “sappia” quando hai finito di disegnare. Ma proprio come la maggior parte dei javascript, finché il codice viene eseguito senza rinunciare al controllo del browser, il browser è essenzialmente bloccato e non può / non può aggiornare / rispondere alla sua interfaccia utente. Immagino che se si cancella la canvas e si disegna l’intero fotogramma senza rinunciare al controllo del browser, in realtà non disegnerà la tua canvas finché non hai finito.

Se si imposta una situazione in cui il rendering si estende su più chiamate setTimeout / setInterval / requestAnimationFrame, in cui si cancella il canvas in una chiamata e si disegnano elementi nell’area di disegno nelle prossime chiamate successive, ripetendo il ciclo (ad esempio) ogni 5 chiamate, I sarei disposto a scommettere che vedresti lo sfarfallio poiché la canvas verrebbe aggiornata dopo ogni chiamata.

Detto questo, non sono sicuro che mi fiderei di ciò. Siamo già al punto che javascript è compilato fino al codice macchina nativo prima dell’esecuzione (almeno questo è ciò che fa il motore V8 di Chrome da quello che ho capito). Non sarei sorpreso se non fosse passato troppo tempo prima che i browser iniziassero a lanciare i loro javascript in un thread separato dall’interfaccia utente e sincronizzare qualsiasi accesso agli elementi dell’interfaccia utente consentendo all’IU di aggiornare / rispondere durante l’esecuzione di JavaScript che non stava accedendo all’interfaccia utente. Quando / se ciò accade (e capisco che ci sono molti ostacoli da superare, come i gestori di eventi che si triggersno mentre stai ancora eseguendo altro codice), probabilmente vedremo il flicker sull’animazione della canvas che non sta usando una sorta di doppio buffering.

Personalmente, adoro l’idea di due elementi di canvas posizionati l’uno sopra l’altro e alternati che viene mostrato / disegnato su ogni fotogramma. Abbastanza poco intrusivo e probabilmente abbastanza facilmente aggiunto a un’applicazione esistente con poche righe di codice.

Non c’è sfarfallio nei browser web! Utilizzano già il buffering dbl per il loro rendering. Il motore Js eseguirà tutto il rendering prima di mostrarlo. Inoltre, il contesto salva e ripristina solo i dati della matrice di trasformazione dello stack e così via, non il contenuto del canvas stesso. Quindi, non hai bisogno o vuoi il buffering dbl!

Piuttosto che rotolare il tuo, probabilmente otterrai il miglior chilometraggio utilizzando una libreria esistente per creare animazioni JavaScript pulite e prive di sfarfallio:

Ecco un popolare: http://processingjs.org

Opera 9.10 è molto lento e mostra il processo di disegno. Se vuoi vedere un browser che non usa il doppio buffering, prova a usare Opera 9.10.

Alcune persone hanno suggerito che i browser sono in qualche modo determinanti al termine del processo di disegno, ma puoi spiegare come può funzionare? Non ho notato alcuno sfarfallio evidente in Firefox, Chrome o IE9 anche quando il disegno è lento, quindi sembra che sia quello che stanno facendo, ma il modo in cui viene realizzato è un mistero per me. Come fa il browser a sapere che sta aggiornando lo schermo poco prima che vengano eseguite ulteriori istruzioni di disegno? Pensi che lo facciano solo al momento, quindi se un intervallo di oltre 5 ms o così passa senza eseguire un’istruzione di disegno su canvas, si presuppone che possa scambiare in sicurezza i buffer?

hai bisogno di 2 tele: (nota il css z-index e position: absolute)

  Your browser does not support the canvas element.   Your browser does not support the canvas element.  

puoi notare che la prima canvas è visibile e la seconda è nascosta l’idea di disegnare sulla parte nascosta, dopo di che hidemo il visibile e rendere visibile la canvas nascosta. quando è nascosto ‘cancella la canvas nascosta

  

Nella maggior parte dei casi, non è necessario farlo, il browser implementa ciò per te. Ma non sempre utile!

Devi ancora implementarlo quando il tuo disegno è molto complicato. La maggior parte della frequenza di aggiornamento dello schermo è di circa 60 Hz, indica gli aggiornamenti dello schermo per 16 ms. Il tasso di aggiornamento del browser potrebbe avvicinarsi a questo numero. Se la tua forma ha bisogno di 100ms per essere completata, vedrai una forma incompleta. Quindi puoi implementare il doppio buffering in questa situazione.

Ho fatto un test: Clear a rect, wait for some time, then fill with some color. Se imposto il tempo a 10 ms, non vedrò lo sfarfallio. Ma se lo metto a 20ms, accade lo sfarfallio.