Grafici / grafici interattivi veloci e reattivi: SVG, Canvas, altro?


114

Sto cercando di scegliere la tecnologia giusta da utilizzare per aggiornare un progetto che fondamentalmente rende migliaia di punti in un grafico zoomabile e pannabile. L'attuale implementazione, utilizzando Protovis, è sottoperformante. Controllalo qui:

http://www.planethunters.org/classify

Ci sono circa 2000 punti quando si rimpicciolisce completamente. Prova a utilizzare le maniglie in basso per ingrandire un po 'e trascinalo per eseguire la panoramica. Vedrai che è piuttosto instabile e l'utilizzo della CPU probabilmente sale al 100% su un core a meno che tu non abbia un computer molto veloce. Ogni modifica all'area di messa a fuoco chiama un ridisegno di protovis che è dannatamente lento ed è peggiore con più punti disegnati.

Vorrei apportare alcuni aggiornamenti all'interfaccia e cambiare la tecnologia di visualizzazione sottostante per essere più reattiva con l'animazione e l'interazione. Dal seguente articolo, sembra che la scelta sia tra un'altra libreria basata su SVG o una basata su tela:

http://www.sitepoint.com/how-to-choose-between-canvas-and-svg/

d3.js , che è nato da Protovis, è basato su SVG e dovrebbe essere migliore nel rendering delle animazioni . Tuttavia, sono dubbioso su quanto sia migliore e quale sia il suo limite di prestazioni. Per questo motivo, sto anche valutando una revisione più completa utilizzando una libreria basata su tela come KineticJS . Tuttavia, prima di arrivare troppo lontano nell'usare un approccio o un altro, mi piacerebbe sentire qualcuno che ha fatto un'applicazione web simile con così tanti dati e ottenere la sua opinione.

La cosa più importante sono le prestazioni, con un focus secondario sulla facilità di aggiungere altre funzionalità di interazione e programmare l'animazione. Probabilmente non ci saranno più di 2000 punti contemporaneamente, con quelle piccole barre di errore su ciascuno. Lo zoom avanti, indietro e la panoramica devono essere fluidi. Se le librerie SVG più recenti sono decenti in questo, allora forse la facilità d'uso di d3 supererà la maggiore configurazione per KineticJS, ecc. Ma se c'è un enorme vantaggio in termini di prestazioni nell'usare una tela, specialmente per le persone con computer più lenti, allora io preferirei decisamente andare in quel modo.

Esempio di app creata dal NYTimes che utilizza SVG, ma si anima ancora in modo accettabile e fluido: http://www.nytimes.com/interactive/2012/05/17/business/dealbook/how-the-facebook-offering-compares.html . Se riesco a ottenere quella performance e non devo scrivere il mio codice di disegno su tela, probabilmente sceglierei SVG.

Ho notato che alcuni utenti hanno utilizzato un ibrido di manipolazione d3.js combinato con il rendering su tela . Tuttavia, non riesco a trovare molta documentazione su questo in linea o entrare in contatto con l'OP di quel post. Se qualcuno ha esperienza con questo tipo di implementazione DOM-to-Canvas ( demo , codice ), mi piacerebbe sentire anche la tua opinione. Sembra essere un buon ibrido tra essere in grado di manipolare i dati e avere un controllo personalizzato su come renderli (e quindi sulle prestazioni), ma mi chiedo se dover caricare tutto nel DOM rallenterà ancora le cose.

So che ci sono alcune domande esistenti simili a questa, ma nessuna chiede esattamente la stessa cosa. Grazie per l'aiuto.

Follow-up : l'implementazione che ho finito per utilizzare è su https://github.com/zooniverse/LightCurves


"La cosa più importante è la performance, con un focus secondario sulla facilità di aggiungere altre interazioni" +1 per canvas
philipp

La domanda è: SVG è sufficiente sulla maggior parte dei browser per 2k punti + altri elementi del grafico? Se è così, e la lentezza è dovuta solo ai punti deboli di protovis, preferirei restare con SVG.
Andrew Mao

1
Mike Bostock ha già dato una buona risposta. Per alcune informazioni aggiuntive è possibile controllare queste due risorse: stackoverflow.com/questions/5882716/html5-canvas-vs-svg-vs-div/... blogs.msdn.com/b/ie/archive/2011/04/22 /…
Ümit

8
Follow-up: ho implementato questo con un approccio ibrido SVG / tela, in cui SVG si prende cura degli assi e delle linee della griglia e la tela può rendere i punti estremamente rapidamente. È super veloce!
Andrew Mao,

Risposte:


183

Fortunatamente, disegnare 2000 cerchi è un esempio abbastanza facile da testare. Quindi ecco quattro possibili implementazioni, due ciascuna di Canvas e SVG:

Questi esempi utilizzano il comportamento dello zoom di D3 per implementare lo zoom e la panoramica. A prescindere dal fatto che i cerchi siano renderizzati in Canvas o SVG, l'altra differenza principale è se usi lo zoom geometrico o semantico .

Lo zoom geometrico significa applicare una singola trasformazione all'intera finestra: quando si ingrandisce, i cerchi diventano più grandi. Lo zoom semantico in contrasto significa che si applicano le trasformazioni a ciascun cerchio individualmente: quando si ingrandisce, i cerchi rimangono della stessa dimensione ma si allargano. Planethunters.org attualmente utilizza lo zoom semantico, ma potrebbe essere utile considerare altri casi.

Lo zoom geometrico semplifica l'implementazione: si applica una traslazione e scala una volta, quindi viene eseguito nuovamente il rendering di tutti i cerchi. L'implementazione SVG è particolarmente semplice, aggiornando un singolo attributo "transform". Le prestazioni di entrambi gli esempi di zoom geometrico sembrano più che adeguate. Per lo zoom semantico, noterai che D3 è significativamente più veloce di Protovis. Questo perché sta facendo molto meno lavoro per ogni evento di zoom. (La versione di Protovis deve ricalcolare tutti gli attributi su tutti gli elementi.) Lo zoom semantico basato su Canvas è un po 'più veloce di SVG, ma lo zoom semantico SVG sembra comunque reattivo.

Eppure non esiste una bacchetta magica per le prestazioni e questi quattro possibili approcci non iniziano a coprire l'intero spazio delle possibilità. Ad esempio, è possibile combinare lo zoom geometrico e semantico, utilizzando l'approccio geometrico per la panoramica (aggiornando l'attributo "trasformazione") e ridisegnando solo i singoli cerchi durante lo zoom. Probabilmente potresti anche combinare una o più di queste tecniche con trasformazioni CSS3 per aggiungere un po 'di accelerazione hardware (come nell'esempio di raggruppamento edge gerarchico ), sebbene ciò possa essere difficile da implementare e potrebbe introdurre artefatti visivi.

Tuttavia, la mia preferenza personale è quella di mantenere il più possibile in SVG, e usare Canvas solo per il "ciclo interno" quando il rendering è il collo di bottiglia . SVG ha così tante comodità per lo sviluppo, come CSS, data-join e ispettore degli elementi, che spesso è un'ottimizzazione prematura iniziare con Canvas. La combinazione di Canvas con SVG, come nella visualizzazione IPO di Facebook che hai collegato, è un modo flessibile per mantenere la maggior parte di queste comodità pur ottenendo le migliori prestazioni. Ho anche usato questa tecnica in Cubism.js , dove il caso speciale della visualizzazione di serie temporali si presta bene alla memorizzazione nella cache bitmap.

Come mostrano questi esempi, puoi usare D3 con Canvas, anche se parti di D3 sono specifiche di SVG. Vedi anche questo grafico diretto alla forza e questo esempio di rilevamento delle collisioni .


Wow, questa è stata una risposta fantastica, e dal maestro della visualizzazione in persona! Penso che dovrei attenermi allo zoom semantico e sul mio computer, il renderizzatore basato su tela è molto più veloce della versione SVG durante il panning / zoom (potrebbe avere a che fare con l'implementazione del browser?). Quello che hai detto sull'uso di SVG con canvas come loop interno è esattamente quello che stavo cercando di confermare, e gli esempi di codice sono solo un dolce bonus. Grazie mille!
Andrew Mao

Ho solo pensato di provare gli esempi di zoom semantico su diversi browser: Chrome, entrambi abbastanza veloci, non posso dire la differenza; IE: SVG leggermente più lento; Firefox (ultimo commento): SVG è molto lento rispetto a Canvas. Immagino che questo complichi anche un po 'la decisione, ma rende il rendering della tela una scelta sicura. Un'altra domanda: l'utilizzo di KineticJS invece del canvas influirà in modo significativo sulle prestazioni?
Andrew Mao

1
Andrew, un po 'in ritardo ma ecco la mia esperienza con FF: sta recuperando terreno. Eseguivo le transizioni SVG FF 15 e D3 rapidamente iniziando a rallentare. Ma ogni nuova versione è diventata sostanzialmente più veloce. Ora sono su FF 18 beta ed è veloce rispetto a 17. Non sono sicuro che sia liscio come il cromo.
user2503795

@AndrewMao Ciao Andrew, mi imbatto in una situazione in cui sembra che il rendering sia il collo di bottiglia. Ho bisogno di fare una panoramica e zoomare alcuni punti e circa 6000 curve. stackoverflow.com/questions/17907769/svg-path-rendering-speed/… Ma non capisco bene Bostock quando ha detto "mantieni quanto più possibile in SVG e usa Canvas solo per il" loop interno "" Ho ha guardato i quattro esempi però .. Potresti farmi un po 'di luce?
kakacii

@kakacii la trasformazione è altrettanto lenta in tutti i browser? Se è così, direi che stai usando il codice sbagliato o hai raggiunto i limiti del rendering del browser. Se potessi pubblicare del codice, potrei essere in grado di aiutarti. mbostock si riferiva all'utilizzo di SVG per semplicità di manipolazione e canvas solo se necessario poiché è più complicato da codificare. Tuttavia, biblioteche come KineticJS lo hanno in qualche modo semplificato.
Andrew Mao

8

Penso che nel tuo caso la decisione tra canvas e svg non sia come una decisione tra »andare a cavallo« o guidare una »Porsche«. Per me è più simile alla decisione sul colore delle auto.

Mi spiego: supponendo che, in base al quadro le operazioni

  • disegna una stella,
  • aggiungi una stella e
  • rimuovere una stella

prendere tempo lineare. Quindi, se la tua decisione del framework è stata buona, è un po 'più veloce, altrimenti un po' più lenta.

Se continui a presumere che il framework sia solo veloce, diventa del tutto ovvio che la mancanza di prestazioni è causata dall'elevata quantità di stelle e gestirle è qualcosa che nessuno dei framework può fare per te, almeno non lo so a questo proposito.

Quello che voglio dire è che la base del problema porta a un problema di base della geometria computazionale, vale a dire: la ricerca della distanza e un altro della grafica computerizzata: il livello di dettaglio .

Per risolvere il tuo problema di prestazioni devi implementare un buon preprocessore che sia in grado di trovare molto velocemente quali stelle visualizzare ed è forse in grado di raggruppare stelle vicine tra loro, a seconda dello zoom. L'unica cosa che mantiene la tua vista vivida e veloce è mantenere il numero di stelle da disegnare il più basso possibile.

Come hai affermato, la cosa più importante sono le prestazioni, di quanto tenderei a usare canvas, perché funziona senza operazioni DOM. Offre anche l'opportunità di utilizzare webGL, cosa che aumenta molto le prestazioni grafiche.

BTW: hai controllato paper.js ? Utilizza la tela, ma emula la grafica vettoriale.

PS: In questo libro puoi trovare una discussione molto dettagliata sulla grafica sul web, le tecnologie, i pro e i contro di canvas, SVG e DHTML.


7

Di recente ho lavorato su un dashboard quasi in tempo reale (aggiornamento ogni 5 secondi) e ho scelto di utilizzare grafici che eseguono il rendering utilizzando la tela.

Abbiamo provato Highcharts (libreria di grafici JavaScript basata su SVG) e CanvasJS (libreria di grafici JavaScript basata su tela). Sebbene Highcharts sia una fantastica API per la creazione di grafici e offra molte più funzionalità, abbiamo deciso di utilizzare CanvasJS.

Avevamo bisogno di visualizzare almeno 15 minuti di dati per grafico (con la possibilità di scegliere un intervallo di massimo due ore).

Quindi per 15 minuti: 900 punti (punto dati al secondo) x2 (grafico a linee e barre combinate) x4 grafici = 7200 punti totali.

Utilizzando Chrome Profiler, con CanvasJS la memoria non ha mai superato i 30 MB mentre con Highcharts l'utilizzo della memoria ha superato i 600 MB.

Inoltre, con un tempo di aggiornamento di 5 secondi, il rendering di CanvasJS è risultato più reattivo di Highcharts.

Abbiamo utilizzato un timer (setInterval 5 secondi) per effettuare 4 chiamate API REST per estrarre i dati dal server back-end connesso a Elasticsearch. Ogni grafico aggiornato man mano che i dati vengono ricevuti da JQuery.post ().

Detto questo, per i rapporti offline preferirei Highcharts poiché è API più flessibile.

Ci sono anche grafici Zing che affermano di utilizzare SVG o Canvas ma non li hanno guardati.

La tela dovrebbe essere considerata quando le prestazioni sono davvero critiche. SVG per flessibilità. Non che i framework canvas non siano flessibili, ma ci vuole più lavoro per il framework canvas per ottenere le stesse funzionalità di un framework svg.



0

Ho anche trovato quando stampiamo in PDF una pagina con grafica SVG, il PDF risultante contiene ancora un'immagine basata su vettore, mentre se stampi una pagina con grafica Canvas, l'immagine nel file PDF risultante viene rasterizzata.

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.