2012-06-22 20 views
5

Ho appena iniziato a giocare con la tela HTML5 e speravo di creare un paio di giochi con esso. Tuttavia, non appena ho iniziato a rendere le coordinate del mouse ad esso, macinato a un quasi battuta d'arresto:Ridisegnare la tela HTML5 incredibilmente lenta

http://jsfiddle.net/mnpenner/zHpgV/

Tutto quello che ho fatto è stato rendere 38 linee e del testo, dovrebbe essere in grado di gestire questo, no?

Sto facendo qualcosa di sbagliato? Mi piacerebbe essere in grado di renderizzare almeno 30 FPS, ma per qualcosa di simile mi aspetterei che sia in grado di disegnare migliaia di volte.

Oppure sto usando lo strumento sbagliato per il lavoro? WebGL è pronto per l'attività? Perché uno dovrebbe essere molto più lento dell'altro?

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(); 
 
});
<canvas id="canvas" width="570" height="570"></canvas>

risposta

7

Ecco il codice reso molto meglio.

http://jsfiddle.net/zHpgV/3/

Ecco la ripartizione delle cose che si dovrebbero prendere in considerazione il fatto che ho cambiato:

  • continua aggiunta di un percorso, invece di fermarsi e la creazione di un nuovo percorso con beginPath. Questo è di gran lunga il più grande assassino delle prestazioni qui. Si finisce con un percorso con migliaia e migliaia di segmenti di linea che non vengono mai cancellati.
  • Continuare a ripetere lo stesso percorso ripetutamente quando deve essere eseguito una sola volta, durante l'inizializzazione. Cioè, l'unica cosa che devi chiamare all'interno di render è stroke. Non è necessario chiamare ancora lineTo/moveTo, e certamente non continuamente. Nota 1
  • Accarezzare due volte per un percorso
  • Delineare all'interno di un ciclo for
  • Ridisegnare uno sfondo invece di impostare sfondo CSS
  • Impostazione del tappo linea di più e più

Nota 1 : Se si prevede di avere più di un percorso nell'applicazione, è probabile che si debbano memorizzare percorsi come questo poiché non cambiano mai. Ho un tutorial su come fare questo here.

Ovviamente, se si sta facendo tutto questo per fare solo uno sfondo, dovrebbe essere salvato come png e si dovrebbe usare un'immagine di sfondo CSS.

Come così: http://jsfiddle.net/zHpgV/4/

Poi improvvisamente la vostra routine di rendering è piuttosto piccola:

function render() { 
    c.clearRect(0, 0, scale, scale); 
    c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5); 
} 
+0

Non sapevo che i percorsi funzionassero! Penso che avere un oggetto 'path' sarebbe stato più intuitivo. Ha senso perché ora era così lento, grazie! – mpen

+3

Ora c'è un oggetto percorso nella specifica Canvas HTML5 e sarà possibile creare un Path e chiamare 'drawPath' in futuro. Ma nessun browser l'ha ancora implementato e potrebbero passare mesi prima che tu possa farne uso. Compra un giorno! –

7

Non è necessario disegnare l'intera griglia in ogni fotogramma di animazione. Mettilo su un'altra tela sottostante (è normale chiamarli "layers", ma sono solo elementi canvas separati), quindi sarai in grado di ridisegnare solo le coordinate.

<div id="canv"> 
<canvas id="bgLayer" width="500" height="500" style="z-index: 0"></canvas> 
<canvas id="fgLayer" width="500" height="500" style="z-index: 1"></canvas> 
</div> 

Ecco the example Ho giocato con tela a strati. Il tavolo disegnato sulla tela in basso, le palline sono disegnate sulla tela superiore. È solo un parco giochi, quindi c'è molto da sistemare e ottimizzare lì, ad esempio per disegnare ogni palla solo una volta su un'altra tela nascosta e usare getImageData/putImageData per migliorare le prestazioni.

Inoltre, si consiglia di utilizzare requestAnimationFrame per aggiornare l'area di disegno. Il tuo esempio si basa su ogni movimento del mouse, ma è molto più spesso necessario (quando il mouse si muove, ovviamente).

C'è un buon article sul miglioramento delle prestazioni della tela. Inoltre, c'è un ottimo SO post su questo argomento.

+0

Mi ha portato un po 'per capire letteralmente significava strato gli elementi di tela. Ho pensato che i "livelli" fossero un concetto all'interno del contesto della tela. Questa è una buona idea. Grazie per i suggerimenti! – mpen

+0

Spiacente, l'ho modificato per evitare di confondere qualcun altro. –

+1

Questi sono buoni commenti ma c'è un altro problema che non trovo in questo caso. Disegno cose molto più complesse con animazioni molto veloci senza nemmeno preoccuparmi del doppio buffering. –

9

Come ho detto nei commenti, sono rimasto sorpreso dalla lentezza di questo codice mentre disegnavo cose molto più complesse con animazioni molto veloci senza nemmeno preoccuparmi del doppio buffering.

Così ho guardato un po 'di più e ho trovato un bug come previsto.

Il problema principale è l'accumulo del percorso del disegno.

Aggiungere un c.beginPath(); ogni volta che si disegna un percorso.

Ecco uno fast rendering of the same thing, per dimostrare che ora vola.

Il disegno su tela è veloce e può essere utilizzato per le animazioni.

Problemi correlati