html5 - canvas element - Più livelli


176

Senza alcuna libreria di estensioni, è possibile avere più livelli nello stesso elemento canvas?

Quindi, se eseguo un clearRect sul livello superiore, non cancellerà quello inferiore?

Grazie.


potresti dare un'occhiata a radikalfx.com/2009/10/16/canvas-collage . usa una sorta di tecnica a "strati".
Matteo,

2
guarda questo ... html5.litten.com/using-multiple-html5-canvases-as-layers questo ti aiuterà a risolvere il problema in modo corretto
Dakshika,

@Dakshika Grazie per quel link, ha spiegato un problema che ho avuto usando la tela qualche anno fa che una biblioteca si è presa cura di me.
Fering

Risposte:


267

No, tuttavia, potresti <canvas>sovrapporre più elementi uno sopra l'altro e realizzare qualcosa di simile.

<div style="position: relative;">
 <canvas id="layer1" width="100" height="100" 
   style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
 <canvas id="layer2" width="100" height="100" 
   style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
</div>

Disegna il tuo primo livello sulla layer1tela e il secondo livello sulla layer2tela. Quindi quando sei clearRectsul livello superiore, tutto ciò che è sulla tela inferiore verrà mostrato.


c'è un modo per nascondere / nascondere un livello .. in modo tale da poter nascondere layer1 e mostrare layer2 e viceversa quando richiesto .. ??
Zaraki,

4
Potresti nasconderlo con CSS - cioè display: none;. O semplicemente cancella la tela, se non è super costoso ridisegnarla di nuovo quando dovrebbe essere mostrato il livello.
jimr,

I valori assegnati a 'left' e 'top' devono essere '0px', non '0'.
Bryan Green,

6
@BryanGreen Non è vero. "Tuttavia, per lunghezze zero l'identificatore dell'unità è facoltativo (ovvero può essere sintatticamente rappresentato come <numero> 0)." w3.org/TR/css3-values/#lengths
xehpuk

Posso controllare il tipo di composizione per più aree di disegno?
ziyuang,

40

Correlato a questo:

Se hai qualcosa sulla tua tela e vuoi disegnare qualcosa sul retro - puoi farlo cambiando l'impostazione context.globalCompositeOperation su 'destination-over' - e poi riportalo a 'source-over' quando ' fatto.

   var context = document.getElementById('cvs').getContext('2d');

    // Draw a red square
    context.fillStyle = 'red';
    context.fillRect(50,50,100,100);



    // Change the globalCompositeOperation to destination-over so that anything
    // that is drawn on to the canvas from this point on is drawn at the back
    // of what's already on the canvas
    context.globalCompositeOperation = 'destination-over';



    // Draw a big yellow rectangle
    context.fillStyle = 'yellow';
    context.fillRect(0,0,600,250);


    // Now return the globalCompositeOperation to source-over and draw a
    // blue rectangle
    context.globalCompositeOperation = 'source-over';

    // Draw a blue rectangle
    context.fillStyle = 'blue';
    context.fillRect(75,75,100,100);
<canvas id="cvs" />


sì, va bene ma in caso di cancellazione, come richiesto. questo cancellerà entrambi gli strati parallelamente. che di nuovo non è corretto.
Pardeep Jain,

27

È possibile creare più canvaselementi senza aggiungerli al documento. Questi saranno i tuoi livelli :

Quindi fai quello che vuoi con loro e alla fine rendi il loro contenuto nell'ordine corretto nell'area di destinazione usando drawImagesu context.

Esempio:

/* using canvas from DOM */
var domCanvas = document.getElementById('some-canvas');
var domContext = domCanvas.getContext('2d');
domContext.fillRect(50,50,150,50);

/* virtual canvase 1 - not appended to the DOM */
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(50,50,150,150);

/* virtual canvase 2 - not appended to the DOM */    
var canvas2 = document.createElement('canvas')
var ctx2 = canvas2.getContext('2d');
ctx2.fillStyle = 'yellow';
ctx2.fillRect(50,50,100,50)

/* render virtual canvases on DOM canvas */
domContext.drawImage(canvas, 0, 0, 200, 200);
domContext.drawImage(canvas2, 0, 0, 200, 200);

Ed ecco alcuni codici: https://codepen.io/anon/pen/mQWMMW


4
@SCLeo hai detto che "Performance killer. Circa ~ 10 volte più lento" è completamente sbagliato. A seconda dei casi d'uso, utilizzare un singolo canvas DOM e renderizzare i canvas offscreen è più veloce che impilare il canvas in DOM. L'errore comune è l'analisi comparativa delle chiamate di rendering, le chiamate di disegno su tela possono essere cronometrate, il rendering DOM è al di fuori del contesto Javascripts e non può essere cronometrato. Il risultato è che la tela sovrapposta DOM non ottiene il rendering di composizione (eseguito da DOM) incluso nel benchmark ..
Blindman67

@ Blindman67 So cosa intendi. Dai un'occhiata a questo benchmark: jsfiddle.net/9a9L8k7k/1 . In caso di incomprensione, ci sono tre tele, la tela 1 (ctx1) è una vera tela. Canvas 2 (ctx2) e canvas 3 (ctx) sono fuori schermo. L'immagine è stata precedentemente renderizzata su ctx3. Nel test 1 di questo benchmark, eseguo il rendering diretto di ctx3 su ctx1. Nel test 2, eseguo il rendering di ctx3 su ctx2 e quindi ctx2 in ctx1. Il test 2 è 30 volte più lento del test 1 sul mio computer. Ecco perché dico che usare una tela intermedia è molto più lento.
SCLeo,

@ Blindman67 Il trucco della tela fuori schermo funziona solo quando la tela fuori schermo è statica. L'uso di tele dinamiche danneggerà notevolmente le prestazioni. (Ancora una volta, quello che sto cercando di dire è che la tela dinamica fuori schermo è estremamente lenta, quindi presumibilmente questa tecnica (falsi strati con più tele fuori schermo) non sarà desiderabile)
SCLeo

@ Blindman67 IMPORTANTE: l'indirizzo del benchmark è https://jsfiddle.net/9a9L8k7k/3 , dimentico di salvare dopo la modifica e Stack Overflow non mi permette più di cambiare il commento precedente ...
SCLeo

4
@ Blindman67 Mi dispiace, è un mio errore. Ho testato e ho scoperto che l'utilizzo di più tele fuori schermo è molto fluido. Non sono ancora sicuro del motivo per cui quel benchmark dimostra che l'utilizzo della tela fuori schermo è così lento.
SCLeo,

6

Anch'io stavo avendo lo stesso problema, mentre io ho più elementi canvas con position: absolute fa il lavoro, se vuoi salvare l'output in un'immagine, non funzionerà.

Quindi sono andato avanti e ho creato un semplice "sistema" di stratificazione per codificare come se ogni livello avesse il proprio codice, ma tutto viene reso nello stesso elemento.

https://github.com/federicojacobi/layeredCanvas

Ho intenzione di aggiungere funzionalità extra, ma per ora lo farà.

Puoi fare più funzioni e chiamarle per "fingere" i livelli.


Questo è perfetto
Nadir,

4

Potresti anche dare un'occhiata a http://www.concretejs.com che è un framework di tela Html5 moderno, leggero, che consente il rilevamento di hit, la stratificazione e molte altre cose periferiche. Puoi fare cose del genere:

var wrapper = new Concrete.Wrapper({
  width: 500,
  height: 300,
  container: el
});

var layer1 = new Concrete.Layer();
var layer2 = new Concrete.Layer();

wrapper.add(layer1).add(layer2);

// draw stuff
layer1.sceneCanvas.context.fillStyle = 'red';
layer1.sceneCanvas.context.fillRect(0, 0, 100, 100);

// reorder layers
layer1.moveUp();

// destroy a layer
layer1.destroy();

In che modo quei livelli finiranno nel DOM? Ognuno accessibile tramite CSS?
Garavani,

0

Comprendo che la Q non desidera utilizzare una libreria, ma la offrirò per altri provenienti da ricerche su Google. @EricRowell ha menzionato un buon plugin, ma c'è anche un altro plugin che puoi provare, html2canvas .

Nel nostro caso stiamo usando PNG trasparenti a strati con z-indexcome widget "Product Builder". Html2canvas ha funzionato brillantemente per ridurre la pila senza spingere le immagini, né usando complessità, soluzioni alternative e la tela "non reattiva" stessa. Non siamo riusciti a farlo in modo uniforme / sano con la tela alla vaniglia + JS.

Primo utilizzo z-indexsu div assoluti per generare contenuto a strati all'interno di un wrapper posizionato relativo. Quindi reindirizzare il wrapper attraverso html2canvas per ottenere un'area di rendering, che può essere lasciata così com'è o prodotta come immagine in modo che un client possa salvarla.


Se hai immagini più pesanti, ci vorrà del tempo per convertire HTML in canvas, abbiamo dovuto allontanarci da questo solo perché il rendering ha richiesto molto tempo.
Vilius,

@Vilius sì, buona chiamata per le immagini pesanti / grandi. Abbiamo cercato di attenerci a 300K o meno di immagini con non più di 4 livelli, altrimenti i clienti colpiti dalle risorse avrebbero sentito il bruciore durante il download dell'immagine compostata finale. Curioso, cosa ti sei trasferito in quel tempo ridotto?
Dhaupin,

Bene, abbiamo fatto un grosso errore usando gli elementi html per disegnare qualcosa in primo luogo. Poiché la nostra API ha restituito x, y, larghezza e altezza, siamo passati a jscanavs per disegnare l'immagine invece di usare elementi html. Intendiamoci, abbiamo avuto un paio di problemi con la rotazione (i punti di partenza erano un po 'imbarazzanti e imprevedibili) e applicando le immagini usando dimensioni specifiche, ma alla fine tutto è stato risolto. Abbiamo anche scoperto che la nostra applicazione di elaborazione delle immagini stava esaurendo molte risorse, quindi ci siamo allontanati anche da quello.
Vilius,

0

ma il livello 02 coprirà tutti i disegni nel livello 01. L'ho usato per mostrare il disegno in entrambi i livelli. usa (background-color: transparent;) nello stile.

    <div style="position: relative;"> 
      <canvas id="lay01" width="500" height="500" style="position: absolute; left: 0; top: 0; z-index: 0; background-color: transparent;">
      </canvas> 
      <canvas id="lay02" width="500" height="500" style="position: absolute; left: 0; top: 0; z-index: 1; background-color: transparent;">
      </canvas>
</div>

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.