HTML5 Canvas vs. SVG vs. div


476

Qual è l'approccio migliore per creare elementi al volo e poterli spostare? Ad esempio, supponiamo che io voglia creare un rettangolo, un cerchio e un poligono, quindi selezionare quegli oggetti e spostarli.

Capisco che HTML5 fornisce tre elementi che possono renderlo possibile: svg , canvas e div . Per quello che voglio fare, quale di questi elementi fornirà le migliori prestazioni?

Per confrontare questi approcci, stavo pensando di creare tre pagine Web visivamente identiche, ognuna con un'intestazione, piè di pagina, widget e contenuto testuale. Il widget nella prima pagina verrebbe creato interamente con l' canvaselemento, il secondo interamente con l' svgelemento e il terzo con l' divelemento semplice , HTML e CSS.


13
Potresti trovare questo interessante: pensieri su quando usare Canvas e SVG .
Robert

1
Per quelli che non conoscono questa tecnologia, questo video copre sia SVG che Canvas e altri dettagli su come si integra su html5.
Paulo Bueno,

12
Risposta breve: Canvas è per MS Paint come SVG per MS Powerpoint. La tela è raster, SVG è vettoriale.
GetFree

2
Caro lettore: prendi tutti i confronti e le dichiarazioni qui con un granello di sale e guarda la data dei post e dei commenti. I tempi sono cambiati e cambieranno. Le prestazioni relative e anche le opzioni disponibili cambieranno. Ad esempio, la maggior parte delle risposte sono state scritte quando non c'era WebGL, il che è sicuramente un'alternativa - sarà obsoleto anche tra qualche anno, ma ad oggi potrebbe essere molto rilevante.
Sebastian,

@Sebastian quale consiglieresti oggi? se viene data una dimensione di base (ad es. 1280x800) e se sei disposto a ridimensionare manualmente gli elementi nel codice o utilizzare le percentuali continuamente, c'è un vantaggio di SVG nell'uso dei DIV?
Crashalot,

Risposte:


563

La breve risposta:

SVG sarebbe più facile per te, dal momento che la selezione e lo spostamento è già incorporato. Gli oggetti SVG sono oggetti DOM, quindi hanno gestori "click", ecc.

I DIV sono ok ma goffi e hanno prestazioni terribili che si caricano su grandi numeri.

Canvas offre le migliori prestazioni a mani basse, ma è necessario implementare tutti i concetti di stato gestito (selezione degli oggetti, ecc.) O utilizzare una libreria.


La lunga risposta:

HTML5 Canvas è semplicemente una superficie di disegno per una bitmap. Ti prepari per disegnare (dì con uno spessore di colore e linea), disegna quella cosa, e quindi la tela non ha conoscenza di quella cosa: non sa dove sia o cosa abbia appena disegnato, è solo pixel. Se vuoi disegnare rettangoli e farli spostare o essere selezionabili, devi codificare tutto da zero, incluso il codice per ricordare che li hai disegnati.

SVG d'altra parte deve mantenere i riferimenti a ciascun oggetto che esso esegue il rendering. Ogni elemento SVG / VML che crei è un elemento reale nel DOM. Per impostazione predefinita, questo ti consente di tenere traccia molto migliore degli elementi che crei e semplifica la gestione di cose come gli eventi del mouse, ma rallenta in modo significativo quando ci sono molti oggetti

Quei riferimenti SVG DOM significano che parte del footwork della gestione delle cose che disegni è fatto per te. E SVG è più veloce nel rendering di oggetti molto grandi , ma più lento nel rendering di molti oggetti.

Un gioco sarebbe probabilmente più veloce in Canvas. Un enorme programma cartografico sarebbe probabilmente più veloce in SVG. Se vuoi usare Canvas, ho alcuni tutorial su come mettere in funzione oggetti mobili e farli funzionare qui .

Canvas sarebbe meglio per cose più veloci e manipolazione bitmap pesante (come l'animazione), ma richiederebbe più codice se si desidera molta interattività.

Ho eseguito un sacco di numeri sul disegno HTML DIV rispetto al disegno su tela. Potrei fare un enorme post sui vantaggi di ciascuno, ma fornirò alcuni dei risultati rilevanti dei miei test da considerare per la tua specifica applicazione:

Ho realizzato pagine di prova DIV Canvas e HTML, entrambe con "nodi" mobili. I nodi di tela erano oggetti che ho creato e tenuto traccia di in Javascript. I nodi HTML erano div mobili.

Ho aggiunto 100.000 nodi a ciascuno dei miei due test. Si sono esibiti in modo abbastanza diverso:

Il caricamento della scheda del test HTML ha richiesto un'eternità (a tempo leggermente inferiore a 5 minuti, Chrome ha chiesto di chiudere la pagina la prima volta). Il task manager di Chrome afferma che la scheda occupa 168 MB. Richiede il 12-13% di tempo CPU quando lo guardo, lo 0% quando non lo guardo.

La scheda Canvas viene caricata in un secondo e occupa 30 MB. Inoltre, occupa sempre il 13% del tempo della CPU, indipendentemente dal fatto che uno lo stia osservando o meno. (Modifica del 2013: l'hanno risolto principalmente)

Il trascinamento sulla pagina HTML è più fluido, come previsto dal progetto, poiché l'impostazione corrente prevede di ridisegnare TUTTO ogni 30 millisecondi nel test Canvas. Ci sono molte ottimizzazioni per Canvas per questo. (l'invalidazione della tela è la più semplice, anche le aree di ritaglio, il ridisegno selettivo, ecc. dipende solo da quanto hai voglia di implementare)

Non c'è dubbio che potresti rendere Canvas più veloce nella manipolazione degli oggetti come i div in quel semplice test, e ovviamente molto più veloce nel tempo di caricamento. Disegnare / caricare è più veloce in Canvas e ha anche molto più spazio per le ottimizzazioni (cioè escludere cose che sono fuori dallo schermo è molto semplice).

Conclusione:

  • SVG è probabilmente migliore per applicazioni e app con pochi elementi (meno di 1000? Dipende davvero)
  • La tela è migliore per migliaia di oggetti e un'attenta manipolazione, ma è necessario molto più codice (o una libreria) per farlo decollare.
  • I div HTML sono ingombranti e non si ridimensionano, creare un cerchio è possibile solo con angoli arrotondati, creare forme complesse è possibile ma coinvolge centinaia di minuscoli div piccoli pixel. Ne consegue la follia.

4
La libreria Cake è un altro esempio di realizzazione di oggetti mobili e animazioni con oggetti su una tela
SiggyF,

Sbagliato: i div di P possono ridimensionarsi se il browser utilizza un motore CSS con accelerazione hw, l'arte css è diversa e oltre a Canvas e SVG sono la scelta corretta qui, l'arte CSS / arte div è proprio quando non è necessario sovraccaricare solo un piccolo overlay: P
ShrekOverflow,

Per quanto riguarda i DIV, se vuoi creare cerchi / forme speciali e non cambierà la sua immagine / sprite a tempo debito, puoi semplicemente creare un PNG e usarlo come background-image... Sebbene tu possa fare cose simili in SVG / Canvas
luiges90

4
Cosa succede se si sta creando un gioco con mappe interattive? : p
Anthony,

Questo è stato creato utilizzando DIV (non nidificati) e trasformazioni 3D CSS, quindi direi che i DIV non sono affatto lenti: youtube.com/watch?v=fzBC20B5dsk
Erik Kaplun

39

Per aggiungere a questo, ho fatto un'applicazione diagramma, e inizialmente ho iniziato con tela. Il diagramma è composto da molti nodi e possono diventare piuttosto grandi. L'utente può trascinare elementi nel diagramma intorno.

Quello che ho scoperto è che sul mio Mac, per immagini molto grandi, SVG è superiore. Ho un MacBook Pro 2013 13 "Retina, e scorre abbastanza bene il violino sotto. L'immagine è 6000x6000 pixel e ha 1000 oggetti. Una struttura simile in tela era impossibile da animare per me quando l'utente stava trascinando oggetti nella diagramma.

Sui display moderni devi anche tenere conto di risoluzioni diverse, e qui SVG ti offre tutto questo gratuitamente.

Fiddle: http://jsfiddle.net/knutsi/PUcr8/16/

Schermo intero: http://jsfiddle.net/knutsi/PUcr8/16/embedded/result/

var wiggle_factor = 0.0;
nodes = [];

// create svg:
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute('style', 'border: 1px solid black');
svg.setAttribute('width', '6000');
svg.setAttribute('height', '6000');

svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink",
    "http://www.w3.org/1999/xlink");

document.body.appendChild(svg);


function makeNode(wiggle) {
    var node = document.createElementNS("http://www.w3.org/2000/svg", "g");
    var node_x = (Math.random() * 6000);
    var node_y = (Math.random() * 6000);
    node.setAttribute("transform", "translate(" + node_x + ", " + node_y +")");

    // circle:
    var circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    circ.setAttribute( "id","cir")
    circ.setAttribute( "cx", 0 + "px")
    circ.setAttribute( "cy", 0 + "px")
    circ.setAttribute( "r","100px");
    circ.setAttribute('fill', 'red');
    circ.setAttribute('pointer-events', 'inherit')

    // text:
    var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.textContent = "This is a test! ÅÆØ";

    node.appendChild(circ);
    node.appendChild(text);

    node.x = node_x;
    node.y = node_y;

    if(wiggle)
        nodes.push(node)
    return node;
}

// populate with 1000 nodes:
for(var i = 0; i < 1000; i++) {
    var node = makeNode(true);
    svg.appendChild(node);
}

// make one mapped to mouse:
var bnode = makeNode(false);
svg.appendChild(bnode);

document.body.onmousemove=function(event){
    bnode.setAttribute("transform","translate(" +
        (event.clientX + window.pageXOffset) + ", " +
        (event.clientY + window.pageYOffset) +")");
};

setInterval(function() {
    wiggle_factor += 1/60;
    nodes.forEach(function(node) {

        node.setAttribute("transform", "translate(" 
                          + (Math.sin(wiggle_factor) * 200 + node.x) 
                          + ", " 
                          + (Math.sin(wiggle_factor) * 200 + node.y) 
                          + ")");        
    })
},1000/60);

2
Abbiamo deciso anche di SVG, dopo aver cercato disperatamente di far funzionare Canvas per noi. Abbiamo un diagramma molto grande e SVG era di gran lunga il più efficiente, inoltre il ridimensionamento automatico sugli schermi della retina è un vantaggio enorme.
Fijjit,

knut e @Fijjit hai preso in considerazione l'utilizzo di DIV invece di SVG? se le dimensioni di base (ad es. 1280x800) non potessero ridimensionare manualmente i DIV in modo che appaiano nitidi come SVG? Grazie per l'aiuto!
Crashalot,

24

Conoscere le differenze tra SVG e Canvas sarebbe utile per selezionare quello giusto.

Tela

SVG

  • Risoluzione indipendente
  • Supporto per gestori di eventi
  • Ideale per applicazioni con aree di rendering di grandi dimensioni (Google Maps)
  • Rendering lento se complesso (tutto ciò che usa molto il DOM sarà lento)
  • Non adatto per l'applicazione di gioco

8
perché la gente dice che Canvas è dipendente dalla risoluzione? capisco che una volta che la bitmap è stata renderizzata non si ridimensiona bene. ma puoi ridisegnare le modifiche alle dimensioni della risoluzione, quindi in che modo tale risoluzione non è indipendente?
Alex Bollbach,

@AlexBollbach - Canvas dipende dalla risoluzione, perché è necessario tenere conto (dipendere) dalla risoluzione per ottenere buoni risultati. Con SVG non ti interessa la risoluzione. Buona fortuna con l'ottenimento di linee non jaggy su una stampante 2400 DPI e un rendering basato su Canvas. Nessun problema con SVG.
Sebastian,

18

Concordo con le conclusioni di Simon Sarris:

Ho confrontato alcune visualizzazioni in Protovis (SVG) con Processingjs (Canvas) che visualizzano> 2000 punti e processingjs è molto più veloce di protovis.

La gestione degli eventi con SVG è ovviamente molto più semplice perché è possibile collegarli agli oggetti. In Canvas devi farlo manualmente (controlla la posizione del mouse, ecc.) Ma per una semplice interazione non dovrebbe essere difficile.

C'è anche la libreria dojo.gfx del dojo toolkit. Fornisce un livello di astrazione ed è possibile specificare il renderer (SVG, Canvas, Silverlight). Potrebbe anche essere una scelta praticabile, anche se non so quanto sovraccarico aggiunga il livello di astrazione aggiuntivo, ma semplifica la codifica delle interazioni e delle animazioni ed è indipendente dal renderer.

Ecco alcuni benchmark interessanti:


17

Solo i miei 2 centesimi per quanto riguarda l'opzione div.

Famous / Infamous e SamsaraJS (e forse altri) utilizzano div non posizionati assolutamente nidificati (con contenuto HTML / CSS non banale), combinati con matrix2d / matrix3d ​​per il posizionamento e trasformazioni 2D / 3D, e raggiungono un 60FPS stabile su hardware mobile moderato , quindi direi che divs è un'opzione lenta.

Ci sono molte registrazioni di schermate su Youtube e altrove, roba 2D / 3D ad alte prestazioni in esecuzione nel browser con tutto ciò che è un elemento DOM su cui puoi ispezionare Element , a 60FPS (mescolato con WebGL per alcuni effetti, ma non per il parte principale del rendering).


14

Mentre c'è ancora un po 'di verità nella maggior parte delle risposte sopra, penso che meritino un aggiornamento:

Nel corso degli anni le prestazioni di SVG sono migliorate molto e ora ci sono transizioni e animazioni CSS con accelerazione hardware per SVG che non dipendono affatto dalle prestazioni JavaScript. Naturalmente anche le prestazioni di JavaScript sono migliorate e con esse le prestazioni di Canvas, ma non tanto quanto SVG è stato migliorato. Inoltre c'è un "nuovo figlio" sul blocco che è disponibile in quasi tutti i browser oggi e che è WebGL . Per usare le stesse parole usate da Simon in precedenza: batte entrambe le mani su Canvas e SVG . Questo non significa che dovrebbe essere la tecnologia ideale, poiché è una bestia con cui lavorare ed è solo più veloce in casi d'uso molto specifici.

IMHO per la maggior parte dei casi d'uso oggi, SVG offre il miglior rapporto prestazioni / usabilità. Le visualizzazioni devono essere davvero complesse (rispetto al numero di elementi) e allo stesso tempo molto semplici (per elemento) in modo che Canvas e ancor più WebGL brillino davvero.

In questa risposta a una domanda simile sto fornendo maggiori dettagli, perché penso che la combinazione di tutte e tre le tecnologie a volte sia l'opzione migliore che hai.


Gli utenti Unix dovrebbero tenere presente che l'accelerazione hardware è disabilitata per impostazione predefinita su Firefox e Chromium, ancora vera a metà 2019.
NVRM

@NVRM: si tratta dell'accelerazione hardware di CSS e SVG, non della decodifica video. AFAIK il primo è disponibile da anni: controlla l'output di chrome: // gpu
Sebastian

layers.acceleration.force-enabledin Firefox non si tratta di decodifica video. È un fatto ben noto. Al termine, i cicli che utilizzano requestAnimationFrame sono di un altro livello, consentendo così un numero maggiore di ridisegni. Non riguarda affatto i video.
NVRM

@NVRM: puoi fornire collegamenti a bug FF e Chromium per questi problemi con la GPU su Linux, per favore? Inoltre, per "accelerazione hardware" non mi riferivo solo all'accelerazione della GPU, ma anche al compositing e alle animazioni multi-thread, come ad esempio il caricamento di spinner che continuano a girare mentre JavaScript non è in esecuzione o mentre JS è in esecuzione. Questo è impossibile con Canvas e rispetto al puro "JavaScript" è davvero una sorta di accelerazione hardware (multi-threading) che è sicuramente disponibile in Chrome e FF su tutte le piattaforme. Grazie!
Sebastian

1
Per riassumere la situazione attuale: funziona per me su Chrome e Chromium. Su Linux. Nel 2019. In tutti i casi ho provato senza una configurazione speciale. Firefox / Mozilla ci sta lavorando per Linux , tuttavia il rendering fuori processo non è una novità per FF, e funzionerà sempre meglio con SVG, CSS, ecc. Di quanto non possa fare per Canvas.
Sebastian,

13

Per i tuoi scopi, ti consiglio di utilizzare SVG, poiché ottieni eventi DOM, come la gestione del mouse, incluso il trascinamento della selezione, inclusi, non devi implementare il tuo nuovo disegno e non devi tenere traccia dello stato di i tuoi oggetti. Usa Canvas quando devi fare manipolazione di immagini bitmap e usa un div regolare quando vuoi manipolare cose create in HTML. Per quanto riguarda le prestazioni, scoprirai che i browser moderni stanno accelerando tutti e tre, ma che la tela ha ricevuto finora la massima attenzione. D'altra parte, quanto bene scrivi il tuo javascript è fondamentale per ottenere il massimo delle prestazioni con canvas, quindi ti consiglio comunque di usare SVG.


1
In realtà l'utilizzo di HTML semplice è il più efficace in combinazione con immagini CSS.
Raynos,

16
@Raynos: Source?
Janus Troelsen,

3

Mentre cerco su google trovo una buona spiegazione sull'uso e la compressione di SVG e Canvas su http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Spero che sia d'aiuto:

  • SVG, come l'HTML, utilizza il rendering conservato : quando vogliamo disegnare un rettangolo sullo schermo, utilizziamo in modo dichiarativo un elemento nel nostro DOM. Il browser disegna quindi un rettangolo, ma crea anche un oggetto SVGRectElement in memoria che rappresenta il rettangolo. Questo oggetto è qualcosa che ci consente di manipolare: viene mantenuto. Possiamo assegnargli diverse posizioni e dimensioni nel tempo. Possiamo anche collegare listener di eventi per renderlo interattivo.
  • Canvas utilizza il rendering immediato : quando disegniamo un rettangolo , il browser rende immediatamente un rettangolo sullo schermo, ma non ci sarà mai alcun "oggetto rettangolo" che lo rappresenti. C'è solo un mucchio di pixel nel buffer dell'area di disegno. Non possiamo spostare il rettangolo. Possiamo solo disegnare un altro rettangolo. Non possiamo rispondere a clic o altri eventi sul rettangolo. Possiamo solo rispondere agli eventi sull'intera tela .

Quindi canvas è un'API più restrittiva e di basso livello rispetto a SVG. Ma c'è un rovescio della medaglia in questo, che è che con la tela puoi fare di più con la stessa quantità di risorse. Poiché il browser non deve creare e mantenere il grafico degli oggetti in memoria di tutte le cose che abbiamo disegnato, ha bisogno di meno memoria e risorse di calcolo per disegnare la stessa scena visiva. Se hai una visualizzazione molto ampia e complessa da disegnare, Canvas potrebbe essere il tuo biglietto.

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.