Schnelle und reaktionsschnelle interaktive Diagramme / Grafiken: SVG, Canvas, andere?

114

Ich versuche, die richtige Technologie für die Aktualisierung eines Projekts auszuwählen, das im Grunde Tausende von Punkten in einem zoombaren, pannbaren Diagramm wiedergibt. Die aktuelle Implementierung mit Protovis ist unterdurchschnittlich. Schau es dir hier an:

http://www.planethunters.org/classify

Bei vollständiger Verkleinerung gibt es ungefähr 2000 Punkte. Versuchen Sie, mit den Griffen unten etwas zu zoomen, und ziehen Sie es, um es zu schwenken. Sie werden sehen, dass es ziemlich abgehackt ist und Ihre CPU-Auslastung auf einem Kern wahrscheinlich bis zu 100% steigt, es sei denn, Sie haben einen wirklich schnellen Computer. Jede Änderung des Fokusbereichs führt zu einer Neuzeichnung von Protovis, die verdammt langsam ist und mit mehr gezogenen Punkten schlechter ist.

Ich möchte einige Aktualisierungen an der Benutzeroberfläche vornehmen und die zugrunde liegende Visualisierungstechnologie ändern, um schneller auf Animation und Interaktion reagieren zu können. Aus dem folgenden Artikel geht hervor, dass Sie zwischen einer anderen SVG-basierten Bibliothek und einer Canvas-basierten Bibliothek wählen können:

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

d3.js , das aus Protovis hervorgegangen ist, basiert auf SVG und soll Animationen besser rendern können . Ich bin jedoch zweifelhaft, wie viel besser und wie hoch die Leistungsobergrenze ist. Aus diesem Grund erwäge ich auch eine umfassendere Überarbeitung mit einer Canvas-basierten Bibliothek wie KineticJS . Bevor ich mich jedoch zu weit mit dem einen oder anderen Ansatz befasse, würde ich gerne von jemandem hören, der eine ähnliche Webanwendung mit so vielen Daten erstellt hat, und seine Meinung einholen.

Das Wichtigste ist die Leistung, wobei der Schwerpunkt auf der einfachen Hinzufügung anderer Interaktionsfunktionen und der Programmierung der Animation liegt. Es wird wahrscheinlich nicht mehr als 2000 Punkte auf einmal geben, mit diesen kleinen Fehlerbalken auf jedem. Das Vergrößern, Verkleinern und Schwenken muss reibungslos sein. Wenn die neuesten SVG-Bibliotheken diesbezüglich anständig sind, überwiegt möglicherweise die einfache Verwendung von d3 das erhöhte Setup für KineticJS usw. Wenn die Verwendung einer Zeichenfläche jedoch einen enormen Leistungsvorteil bietet, insbesondere für Benutzer mit langsameren Computern, dann ich würde definitiv lieber diesen Weg gehen.

Beispiel für eine App von NYTimes, die SVG verwendet, aber dennoch akzeptabel reibungslos animiert: http://www.nytimes.com/interactive/2012/05/17/business/dealbook/how-the-facebook-offering-compares.html . Wenn ich diese Leistung erzielen kann und keinen eigenen Canvas-Zeichencode schreiben muss, würde ich mich wahrscheinlich für SVG entscheiden.

Ich habe festgestellt, dass einige Benutzer eine Mischung aus d3.js-Manipulation und Canvas-Rendering verwendet haben . Ich kann jedoch online nicht viel Dokumentation finden oder mich mit dem OP dieses Beitrags in Verbindung setzen. Wenn jemand Erfahrung mit dieser Art der Implementierung von DOM-to-Canvas ( Demo , Code ) hat, würde ich gerne auch von Ihnen hören. Es scheint eine gute Mischung aus der Möglichkeit zu sein, Daten zu manipulieren und die benutzerdefinierte Kontrolle über das Rendern (und damit die Leistung) zu haben, aber ich frage mich, ob das Laden von allem in das DOM die Dinge immer noch verlangsamen wird.

Ich weiß, dass es einige Fragen gibt, die dieser ähnlich sind, aber keine von ihnen stellt genau das Gleiche. Danke für Ihre Hilfe.

Follow-up : Die Implementierung, die ich letztendlich verwendet habe, befindet sich unter https://github.com/zooniverse/LightCurves

Andrew Mao
quelle
"Das Wichtigste ist die Leistung, mit einem sekundären Fokus auf die Leichtigkeit, andere Interaktionen hinzuzufügen" +1 für Leinwand
Philipp
Die Frage ist, reicht SVG in den meisten Browsern für 2k Punkte + andere Diagrammelemente aus? Wenn ja, und die Langsamkeit ist nur auf Schwächen in Protovis zurückzuführen, dann würde ich lieber bei SVG bleiben.
Andrew Mao
1
Mike Bostock gab bereits eine gute Antwort. Weitere Informationen
Ümit
8
Follow-up: Ich habe dies mit einem hybriden SVG / Canvas-Ansatz implementiert, bei dem sich das SVG um Achsen und Gitterlinien kümmert und das Canvas die Punkte außerordentlich schnell rendern kann. Es ist super schnell!
Andrew Mao

Antworten:

183

Glücklicherweise ist das Zeichnen von 2000 Kreisen ein ziemlich einfaches Beispiel zum Testen. Hier sind also vier mögliche Implementierungen, jeweils zwei von Canvas und SVG:

Diese Beispiele verwenden D3 Zoomverhalten zu implementieren Zoomen und Schwenken. Abgesehen davon, ob die Kreise in Canvas oder SVG gerendert werden, besteht der andere Hauptunterschied darin, ob Sie geometrisches oder semantisches Zoomen verwenden.

Geometrisches Zoomen bedeutet, dass Sie eine einzelne Transformation auf das gesamte Ansichtsfenster anwenden: Wenn Sie hineinzoomen, werden die Kreise größer. Semantisches Zoomen im Kontrast bedeutet, dass Sie Transformationen auf jeden Kreis einzeln anwenden: Wenn Sie hineinzoomen, bleiben die Kreise gleich groß, aber sie breiten sich aus. Planethunters.org verwendet derzeit semantisches Zoomen, es kann jedoch nützlich sein, andere Fälle zu berücksichtigen.

Das geometrische Zoomen vereinfacht die Implementierung: Sie wenden einmal eine Übersetzung und Skalierung an, und dann werden alle Kreise neu gerendert. Die SVG-Implementierung ist besonders einfach und aktualisiert ein einzelnes "Transformations" -Attribut. Die Leistung beider Beispiele für geometrisches Zoomen ist mehr als ausreichend. Beim semantischen Zoomen werden Sie feststellen, dass D3 erheblich schneller als Protovis ist. Dies liegt daran, dass für jedes Zoomereignis viel weniger Arbeit erforderlich ist. (Die Protovis-Version muss alle Attribute für alle Elemente neu berechnen.) Das Canvas-basierte semantische Zoomen ist etwas flotter als SVG, aber das semantische SVG-Zoomen reagiert immer noch.

Es gibt jedoch kein Wundermittel für die Leistung, und diese vier möglichen Ansätze decken nicht den gesamten Bereich der Möglichkeiten ab. Sie können beispielsweise geometrisches und semantisches Zoomen kombinieren, indem Sie den geometrischen Ansatz zum Schwenken (Aktualisieren des Attributs "Transformieren") verwenden und nur einzelne Kreise beim Zoomen neu zeichnen. Sie könnten wahrscheinlich sogar eine oder mehrere dieser Techniken mit CSS3-Transformationen kombinieren, um eine gewisse Hardwarebeschleunigung hinzuzufügen (wie im Beispiel für die hierarchische Kantenbündelung ). Dies kann jedoch schwierig zu implementieren sein und visuelle Artefakte verursachen.

Meine persönliche Präferenz ist es jedoch , so viel wie möglich in SVG zu behalten und Canvas nur für die "innere Schleife" zu verwenden, wenn das Rendern der Engpass ist . SVG bietet so viele Entwicklungsmöglichkeiten wie CSS, Datenverknüpfungen und den Elementinspektor, dass es häufig eine vorzeitige Optimierung ist, mit Canvas zu beginnen. Die Kombination von Canvas mit SVG, wie in der von Ihnen verlinkten Facebook-IPO-Visualisierung, ist eine flexible Möglichkeit, die meisten dieser Annehmlichkeiten beizubehalten und gleichzeitig die beste Leistung zu erzielen. Ich habe diese Technik auch in Cubism.js verwendet , wo sich der Spezialfall der Zeitreihenvisualisierung gut für das Bitmap-Caching eignet.

Wie diese Beispiele zeigen, können Sie D3 mit Canvas verwenden, obwohl Teile von D3 SVG-spezifisch sind. Siehe auch dieses kraftgerichtete Diagramm und dieses Beispiel für die Kollisionserkennung .

mbostock
quelle
Wow, das war eine großartige Antwort und vom Meister der Visualisierung selbst! Ich denke, ich müsste mich an das semantische Zoomen halten, und auf meinem Computer ist der Canvas-basierte Renderer beim Schwenken / Zoomen viel schneller als die SVG-Version (möglicherweise mit der Browser-Implementierung zu tun?). Was Sie über die Verwendung von SVG mit Canvas als innere Schleife gesagt haben, wollte ich genau bestätigen, und die Codebeispiele sind nur ein süßer Bonus. Vielen Dank!
Andrew Mao
Ich hatte gerade den Gedanken, die Beispiele für das semantische Zoomen in verschiedenen Browsern auszuprobieren: Chrome, beide ziemlich schnell, ich kann den Unterschied nicht erkennen; IE: SVG etwas langsamer; Firefox (letzter Kommentar): SVG ist im Vergleich zu Canvas hella langsam. Ich denke, das erschwert die Entscheidung auch ein wenig, macht aber das Rendern von Leinwand zu einer sicheren Wahl. Noch eine Frage: Wird die Verwendung von KineticJS anstelle von Canvas die Leistung erheblich beeinträchtigen?
Andrew Mao
1
Andrew, etwas spät, aber hier ist meine Erfahrung mit FF: Es holt auf. Ich habe früher FF 15- und D3-SVG-Übergänge ausgeführt, die schnell langsam wurden. Aber jede neue Version wurde wesentlich schneller. Jetzt bin ich auf FF 18 Beta und es ist schnell im Vergleich zu 17. Ich bin mir nicht sicher, ob es so glatt wie Chrom ist.
user2503795
@ AndrewMao Hallo Andrew, ich stoße auf eine Situation, in der das Rendern der Engpass zu sein scheint. Ich muss einige Punkte und ungefähr 6000 Kurvenpfade schwenken und zoomen. stackoverflow.com/questions/17907769/svg-path-rendering-speed/… Aber ich verstehe Bostock nicht ganz, als er sagte " Behalte so viel in SVG wie möglich und verwende Canvas nur für die" innere Schleife ", die ich habe Sieh dir die vier Beispiele an. Könntest du mir etwas Licht ins Dunkel bringen?
Kakacii
@kakacii ist die Transformation in allen Browsern gleich langsam? Wenn ja, würde ich sagen, dass Sie entweder den falschen Code verwenden oder die Grenzen des Browser-Renderings erreicht haben. Wenn Sie einen Code posten könnten, könnte ich Ihnen vielleicht helfen. mbostock bezog sich auf die Verwendung von SVG, um die Manipulation und die Zeichenfläche nur bei Bedarf zu vereinfachen, da das Codieren komplizierter ist. Bibliotheken wie KineticJS haben dies jedoch teilweise vereinfacht.
Andrew Mao
8

Ich denke, dass in Ihrem Fall die Entscheidung zwischen Canvas und SVG nicht wie eine Entscheidung zwischen »Reiten« oder »Porsche« ist. Für mich ist es eher die Entscheidung über die Farbe des Autos.

Lassen Sie mich erklären: Angenommen, basierend auf dem Rahmen der Operationen

  • zeichne einen Stern,
  • füge einen Stern hinzu und
  • entferne einen Stern

nimm lineare Zeit. Wenn Sie sich also für das Framework entschieden haben, ist es etwas schneller, ansonsten etwas langsamer.

Wenn Sie weiterhin davon ausgehen, dass das Framework nur schnell ist, wird es völlig offensichtlich, dass der Mangel an Leistung durch die hohe Anzahl von Sternen verursacht wird und der Umgang mit ihnen etwas ist, das keines der Frameworks für Sie tun kann, zumindest weiß ich es nicht darüber.

Was ich sagen möchte, ist, dass die Basis des Problems zu einem Grundproblem der Rechengeometrie führt, nämlich: Bereichssuche und ein anderes Problem der Computergrafik: Detaillierungsgrad .

Um Ihr Leistungsproblem zu lösen, müssen Sie einen guten Präprozessor implementieren, der sehr schnell findet, welche Sterne angezeigt werden sollen, und möglicherweise in der Lage ist, Sterne zu gruppieren, die je nach Zoom nahe beieinander liegen. Das einzige, was Ihre Sicht lebendig und schnell hält, ist, die Anzahl der zu zeichnenden Sterne so gering wie möglich zu halten.

Wie Sie sagten, ist das Wichtigste die Leistung, als ich normalerweise Canvas verwenden würde, da es ohne DOM-Operationen funktioniert. Es bietet auch die Möglichkeit, webGL zu verwenden, was die Grafikleistung erheblich steigert.

Übrigens: Hast du nachgesehen? Haben paper.js ? Es verwendet Canvas, emuliert jedoch Vektorgrafiken.

PS: In diesem Buch finden Sie eine sehr detaillierte Diskussion über Grafiken im Web, die Technologien, Vor- und Nachteile von Canvas, SVG und DHTML.

philipp
quelle
7

Ich habe kürzlich an einem Echtzeit-Dashboard gearbeitet (alle 5 Sekunden aktualisieren) und mich für die Verwendung von Diagrammen entschieden, die mit Canvas gerendert werden.

Wir haben Highcharts (SVG-basierte JavaScript-Diagrammbibliothek) und CanvasJS (Canvas-basierte JavaScript-Diagrammbibliothek) ausprobiert. Obwohl Highcharts eine fantastische Diagramm-API ist und viel mehr Funktionen bietet, haben wir uns für CanvasJS entschieden.

Wir mussten mindestens 15 Minuten Daten pro Diagramm anzeigen (mit der Option, einen Bereich von maximal zwei Stunden auszuwählen).

Also für 15 Minuten: 900 Punkte (Datenpunkt pro Sekunde) x2 (Linien- und Balkenkombinationsdiagramm) x4 Diagramme = insgesamt 7200 Punkte.

Bei Verwendung von Chrome Profiler wurde bei CanvasJS der Speicher nie über 30 MB überschritten, während bei Highcharts die Speichernutzung 600 MB überstieg.

Auch mit einer Aktualisierungszeit von 5 Sekunden reagierte das CanvasJS-Rendering viel schneller als Highcharts.

Wir haben einen Timer (setInterval 5 Sekunden) verwendet, um 4 REST-API-Aufrufe durchzuführen, um die Daten vom Back-End-Server abzurufen, der mit Elasticsearch verbunden ist. Jedes als Daten aktualisierte Diagramm wird von JQuery.post () empfangen.

Das heißt, für Offline-Berichte würde ich mich für Highcharts entscheiden, da es eine flexiblere API ist.

Es gibt auch Zing-Diagramme, die behaupten, entweder SVG oder Canvas zu verwenden, sie aber nicht angesehen haben.

Canvas sollte in Betracht gezogen werden, wenn die Leistung wirklich kritisch ist. SVG für Flexibilität. Nicht dass Canvas-Frameworks nicht flexibel sind, aber das Canvas-Framework benötigt viel mehr Arbeit, um die gleiche Funktionalität wie ein SVG-Framework zu erhalten.

user432024
quelle
3

Könnte auch in Meteor Charts schauen, die auf dem überschnellen KineticJS-Framework basieren: http://meteorcharts.com/

Eric Rowell
quelle
0

Ich habe auch festgestellt, dass beim Drucken einer Seite mit SVG-Grafiken als PDF das resultierende PDF immer noch ein vektorbasiertes Bild enthält. Wenn Sie eine Seite mit Canvas-Grafiken drucken, wird das Bild in der resultierenden PDF-Datei gerastert.

ostrokach
quelle