HTML5 Canvas vs. SVG vs. div

476

Was ist der beste Ansatz, um Elemente im laufenden Betrieb zu erstellen und sie bewegen zu können? Angenommen, ich möchte ein Rechteck, einen Kreis und ein Polygon erstellen und dann diese Objekte auswählen und verschieben.

Ich verstehe, dass HTML5 drei Elemente bietet, die dies ermöglichen können: svg , canvas und div . Für was ich tun möchte, welches dieser Elemente bietet die beste Leistung?

Um diese Ansätze zu vergleichen, habe ich mir überlegt, drei visuell identische Webseiten zu erstellen, die jeweils eine Kopf-, Fuß-, Widget- und Textinhalt enthalten. Das Widget auf der ersten Seite wird vollständig mit dem canvasElement erstellt, das zweite vollständig mit dem svgElement und das dritte vollständig mit dem einfachen divElement HTML und CSS.

verdy
quelle
13
Das könnte Sie interessieren: Gedanken darüber, wann Canvas und SVG verwendet werden sollen .
Robertc
1
Für diejenigen unter Ihnen, die neu in dieser Theologie sind, behandelt dieses Video sowohl SVG als auch Canvas und andere Details darüber, wie dies in HTML5 integriert wird.
Paulo Bueno
12
Kurze Antwort: Canvas ist für MS Paint wie SVG für MS Powerpoint. Leinwand ist Raster, SVG ist vektoriell.
GetFree
2
Sehr geehrter Leser, nehmen Sie alle Vergleiche und Aussagen hier mit einem Körnchen Salz und sehen Sie sich das Datum der Beiträge und Kommentare an. Die Zeiten haben sich geändert und werden sich ändern. Die relative Leistung und sogar die Optionen, die Sie haben, werden sich ändern. ZB wurden die meisten Antworten geschrieben, als es kein WebGL gab, was definitiv eine Alternative ist - es wird auch in ein paar Jahren veraltet sein, aber ab heute kann es sehr relevant sein.
Sebastian
@Sebastian was würdest du heute empfehlen? Gibt es einen Vorteil von SVG bei Verwendung von DIVs, wenn Sie eine Basisgröße (z. B. 1280 x 800) angeben und bereit sind, Elemente manuell im Code zu skalieren oder ständig Prozentsätze zu verwenden?
Crashalot

Antworten:

563

Die kurze Antwort:

SVG wäre für Sie einfacher , da die Auswahl und das Verschieben bereits integriert sind. SVG-Objekte sind DOM-Objekte, daher verfügen sie über "Klick" -Handler usw.

DIVs sind in Ordnung, aber klobig und haben eine schreckliche Leistungsbelastung bei großen Zahlen.

Canvas bietet zweifellos die beste Leistung, Sie müssen jedoch alle Konzepte des verwalteten Status (Objektauswahl usw.) selbst implementieren oder eine Bibliothek verwenden.


Die lange Antwort:

HTML5 Canvas ist einfach eine Zeichenfläche für eine Bitmap. Sie haben sich eingerichtet, um zu zeichnen (z. B. mit Farbe und Linienstärke), das Ding zu zeichnen, und dann hat die Leinwand keine Kenntnis von diesem Ding: Es weiß nicht, wo es ist oder was es ist, das Sie gerade gezeichnet haben, es ist nur Pixel. Wenn Sie Rechtecke zeichnen und sie verschieben oder auswählbar sein möchten, müssen Sie all dies von Grund auf neu codieren, einschließlich des Codes, um sich daran zu erinnern, dass Sie sie gezeichnet haben.

SVG hingegen muss Verweise auf jedes Objekt enthalten, das es rendert. Jedes von Ihnen erstellte SVG / VML-Element ist ein echtes Element im DOM. Standardmäßig können Sie die von Ihnen erstellten Elemente viel besser verfolgen und den Umgang mit Mausereignissen standardmäßig vereinfachen. Bei einer großen Anzahl von Objekten wird dies jedoch erheblich verlangsamt

Diese SVG-DOM-Referenzen bedeuten, dass ein Teil der Arbeit im Umgang mit den von Ihnen gezeichneten Dingen für Sie erledigt wird. Und SVG ist schneller beim Rendern wirklich großer Objekte, aber langsamer beim Rendern vieler Objekte.

Ein Spiel wäre in Canvas wahrscheinlich schneller. Ein riesiges Kartenprogramm wäre in SVG wahrscheinlich schneller. Wenn Sie Canvas verwenden möchten, habe ich einige Tutorials, um bewegliche Objekte hier zum Laufen zu bringen .

Canvas ist besser für schnellere Dinge und umfangreiche Bitmap-Manipulationen (wie Animationen) geeignet, benötigt jedoch mehr Code, wenn Sie viel Interaktivität wünschen.

Ich habe eine Reihe von Zahlen für von HTML DIV erstellte Zeichnungen im Vergleich zu von Canvas erstellten Zeichnungen ausgeführt. Ich könnte einen großen Beitrag über die Vorteile der einzelnen Tests verfassen, aber ich werde einige der relevanten Ergebnisse meiner Tests angeben, die für Ihre spezifische Anwendung zu berücksichtigen sind:

Ich habe Canvas- und HTML-DIV-Testseiten erstellt, beide hatten bewegliche "Knoten". Canvas-Knoten waren Objekte, die ich in Javascript erstellt und verfolgt habe. HTML-Knoten waren bewegliche Divs.

Ich habe jedem meiner beiden Tests 100.000 Knoten hinzugefügt. Sie haben ganz anders gespielt:

Das Laden der Registerkarte "HTML-Test" hat ewig gedauert (etwas weniger als 5 Minuten, Chrome hat darum gebeten, die Seite beim ersten Mal zu beenden). Der Task-Manager von Chrome gibt an, dass die Registerkarte 168 MB belegt. Es nimmt 12-13% CPU-Zeit in Anspruch, wenn ich es betrachte, 0%, wenn ich es nicht betrachte.

Die Registerkarte Canvas wird in einer Sekunde geladen und nimmt 30 MB ein. Außerdem nimmt es die ganze Zeit 13% der CPU-Zeit in Anspruch, unabhängig davon, ob man es sich ansieht oder nicht. (2013 bearbeiten: Sie haben das größtenteils behoben)

Das Ziehen auf der HTML-Seite ist reibungsloser, was vom Design erwartet wird, da das aktuelle Setup im Canvas-Test ALLES alle 30 Millisekunden neu zeichnet. Dafür gibt es für Canvas zahlreiche Optimierungen. (Die Ungültigmachung der Zeichenfläche ist am einfachsten, auch das Ausschneiden von Regionen, das selektive Neuzeichnen usw. hängt nur davon ab, wie sehr Sie sich für die Implementierung interessieren.)

Es besteht kein Zweifel, dass Canvas bei der Objektmanipulation schneller sein kann als die Divs in diesem einfachen Test und natürlich viel schneller in der Ladezeit. Das Zeichnen / Laden ist in Canvas schneller und bietet auch viel mehr Raum für Optimierungen (dh das Ausschließen von Dingen außerhalb des Bildschirms ist sehr einfach).

Fazit:

  • SVG ist wahrscheinlich besser für Anwendungen und Apps mit wenigen Elementen (weniger als 1000? Kommt wirklich darauf an)
  • Canvas ist besser für Tausende von Objekten und sorgfältige Manipulationen geeignet, aber es wird viel mehr Code (oder eine Bibliothek) benötigt, um es in Betrieb zu nehmen.
  • HTML-Divs sind klobig und nicht skalierbar. Das Erstellen eines Kreises ist nur mit abgerundeten Ecken möglich. Das Erstellen komplexer Formen ist möglich, umfasst jedoch Hunderte winziger, pixelweiter Divs. Wahnsinn folgt.
Simon Sarris
quelle
4
Die Kuchenbibliothek ist ein weiteres Beispiel für bewegliche Objekte und Animationen mit Objekten auf einer Leinwand
SiggyF
Falsch: P divs können skaliert werden, wenn der Browser eine hw-beschleunigte CSS-Engine verwendet, CSS-Grafik ist anders und neben Canvas und SVG ist CSS-Grafik / Div-Grafik genau dann die richtige Wahl, wenn Sie nicht nur eine kleine Überlagerung übertreiben müssen: P.
ShrekOverflow
In Bezug auf DIVs können Sie, wenn Sie Kreise / spezielle Formen erstellen möchten und das Bild / Sprite nicht zu gegebener Zeit ändern möchten, einfach ein PNG erstellen und es als background-image... verwenden. In SVG / Canvas
luiges90
4
Was ist, wenn Sie ein interaktives Kartenspiel erstellen? : p
Anthony
Dies wurde mit (nicht verschachtelten) DIVs und CSS 3D-Transformationen erstellt, daher würde ich sagen, dass DIVs überhaupt nicht langsam sind: youtube.com/watch?v=fzBC20B5dsk
Erik Kaplun
39

Um dies hinzuzufügen, habe ich eine Diagrammanwendung erstellt und zunächst mit Canvas begonnen. Das Diagramm besteht aus vielen Knoten, und sie können ziemlich groß werden. Der Benutzer kann Elemente im Diagramm verschieben.

Was ich fand, war, dass auf meinem Mac SVG für sehr große Bilder überlegen ist. Ich habe ein MacBook Pro 2013 13 "Retina, und es läuft die Geige unten ziemlich gut. Das Bild ist 6000x6000 Pixel groß und hat 1000 Objekte. Eine ähnliche Konstruktion auf Leinwand war für mich unmöglich zu animieren, als der Benutzer Objekte in der Retina herumzog Diagramm.

Auf modernen Displays müssen Sie auch unterschiedliche Auflösungen berücksichtigen, und hier bietet Ihnen SVG all dies kostenlos an.

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

Vollbild: 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);
knut
quelle
2
Wir haben uns auch für SVG entschieden, nachdem wir verzweifelt versucht hatten, Canvas dazu zu bringen, für uns zu arbeiten. Wir haben ein sehr großes Diagramm und SVG war bei weitem das effizienteste. Außerdem ist die automatische Skalierung auf Retina-Bildschirmen ein enormer Bonus.
Fijjit
knut und @Fijjit haben Sie in Betracht gezogen, DIVs anstelle von SVG zu verwenden? Wenn Sie eine Basisgröße (z. B. 1280 x 800) angeben, können Sie DIVs nicht manuell skalieren, damit sie so scharf wie SVG aussehen? danke für Ihre Hilfe!
Crashalot
24

Die Unterschiede zwischen SVG und Canvas zu kennen, wäre hilfreich bei der Auswahl des richtigen.

Segeltuch

SVG

  • Auflösung unabhängig
  • Unterstützung für Event-Handler
  • Am besten geeignet für Anwendungen mit großen Rendering-Bereichen (Google Maps)
  • Langsames Rendern, wenn es komplex ist (alles, was das DOM häufig verwendet, ist langsam)
  • Nicht für Spieleanwendungen geeignet
Leo die vier
quelle
8
Warum sagen die Leute, dass Canvas von der Auflösung abhängt? Ich verstehe, dass die Bitmap nach dem Rendern nicht mehr gut skaliert werden kann. Sie können jedoch Änderungen der Auflösungsgröße neu zeichnen. Wie ist diese Auflösung also nicht unabhängig?
Alex Bollbach
@AlexBollbach - Canvas ist auflösungsabhängig, da Sie die Auflösung berücksichtigen müssen, um gute Ergebnisse zu erzielen. Bei SVG ist Ihnen die Auflösung egal. Viel Glück beim Erhalten nicht zackiger Linien auf einem 2400DPI-Drucker und einem Canvas-basierten Rendering. Kein Problem mit SVG.
Sebastian
18

Ich stimme den Schlussfolgerungen von Simon Sarris zu:

Ich habe einige Visualisierungen in Protovis (SVG) mit Processingjs (Canvas) verglichen, die> 2000 Punkte anzeigen, und Processingjs ist viel schneller als Protovis.

Das Behandeln von Ereignissen mit SVG ist natürlich viel einfacher, da Sie sie an die Objekte anhängen können. In Canvas müssen Sie dies manuell tun (Mausposition überprüfen usw.), aber für eine einfache Interaktion sollte es nicht schwierig sein.

Es gibt auch die Bibliothek dojo.gfx des Dojo-Toolkits. Es bietet eine Abstraktionsschicht und Sie können den Renderer angeben (SVG, Canvas, Silverlight). Das könnte auch eine praktikable Wahl sein, obwohl ich nicht weiß, wie viel Overhead die zusätzliche Abstraktionsschicht hinzufügt, aber es erleichtert das Codieren von Interaktionen und Animationen und ist rendererunabhängig.

Hier einige interessante Benchmarks:

Ümit
quelle
17

Nur meine 2 Cent bezüglich der Divs Option.

Famous / Infamous und SamsaraJS (und möglicherweise andere) verwenden absolut positionierte nicht verschachtelte Divs (mit nicht trivialem HTML / CSS-Inhalt), kombiniert mit Matrix2d / Matrix3d ​​für die Positionierung und 2D / 3D-Transformationen, und erzielen auf moderater mobiler Hardware stabile 60 FPS Also würde ich dagegen argumentieren, dass Divs eine langsame Option sind.

Auf Youtube und anderswo gibt es zahlreiche Bildschirmaufnahmen von hochleistungsfähigen 2D / 3D-Inhalten, die im Browser ausgeführt werden. Alles ist ein DOM-Element, auf dem Sie das Element mit 60 FPS überprüfen können (gemischt mit WebGL für bestimmte Effekte, jedoch nicht für das Hauptteil des Renderings).

Erik Kaplun
quelle
14

Obwohl die meisten der oben genannten Antworten immer noch zutreffend sind, denke ich, dass sie ein Update verdienen:

Im Laufe der Jahre hat sich die Leistung von SVG erheblich verbessert, und jetzt gibt es hardwarebeschleunigte CSS-Übergänge und -Animationen für SVG , die überhaupt nicht von der JavaScript-Leistung abhängen. Natürlich hat sich auch die JavaScript-Leistung und damit die Leistung von Canvas verbessert, aber nicht so sehr, wie SVG verbessert wurde. Außerdem gibt es ein "neues Kind" auf dem Block, das heutzutage in fast allen Browsern verfügbar ist, und das ist WebGL . Um die gleichen Wörter zu verwenden, die Simon oben verwendet hat: Es schlägt sowohl Canvas als auch SVG zweifellos. Dies bedeutet jedoch nicht, dass es sich um die Go-to-Technologie handeln sollte, da es ein Biest ist, mit dem man arbeiten kann, und es ist nur in ganz bestimmten Anwendungsfällen schneller.

Meiner Meinung nach bietet SVG für die meisten Anwendungsfälle heute das beste Verhältnis von Leistung zu Benutzerfreundlichkeit. Visualisierungen müssen sehr komplex (in Bezug auf die Anzahl der Elemente) und gleichzeitig sehr einfach (pro Element) sein, damit Canvas und noch mehr WebGL wirklich glänzen.

In dieser Antwort auf eine ähnliche Frage gebe ich weitere Details an, warum ich denke, dass die Kombination aller drei Technologien manchmal die beste Option ist, die Sie haben.

Sebastian
quelle
Unix-Benutzer sollten beachten, dass die Hardwarebeschleunigung sowohl in Firefox als auch in Chromium standardmäßig deaktiviert ist, was Mitte 2019 immer noch der Fall ist.
NVRM
@NVRM - Hier geht es um die Hardwarebeschleunigung von CSS und SVG, nicht um die Videodecodierung. AFAIK der erstere ist seit Jahren verfügbar: Überprüfen Sie die Ausgabe von Chrom: // GPU
Sebastian
layers.acceleration.force-enabledIn Firefox geht es nicht um Videodecodierung. Es ist eine bekannte Tatsache. Wenn fertig, sind Schleifen mit requestAnimationFrame eine andere Ebene, die viel mehr Neuanstriche ermöglicht. Über Video überhaupt nicht.
NVRM
@NVRM - Können Sie bitte Links zu FF- und Chromium-Fehlern für diese GPU-Probleme unter Linux bereitstellen? Beachten Sie auch, dass ich mich mit "hardwarebeschleunigt" nicht nur auf die GPU-Beschleunigung bezog, sondern auch auf Multithread-Compositing und Animationen, z. B. das Laden von Spinnern, die sich weiter drehen, während kein JavaScript ausgeführt wird oder während JS ausgeführt wird. Dies ist mit Canvas unmöglich und im Vergleich zu reinem "JavaScript" ist es tatsächlich eine Art Hardwarebeschleunigung (Multithreading), die definitiv in Chrome und FF auf allen Plattformen verfügbar ist. Vielen Dank!
Sebastian
1
Um die aktuelle Situation zusammenzufassen: Funktioniert für mich auf Chrome und Chromium. Unter Linux. Im Jahr 2019. In allen Fällen habe ich ohne spezielle Konfiguration getestet. Firefox / Mozilla arbeitet daran für Linux , aber das Rendern außerhalb des Prozesses ist auch für FF nichts Neues und funktioniert mit SVG, CSS usw. immer besser als mit Canvas.
Sebastian
13

Für Ihre Zwecke empfehle ich die Verwendung von SVG, da DOM-Ereignisse wie Maushandhabung, einschließlich Drag & Drop, enthalten sind, Sie kein eigenes Neuzeichnen implementieren müssen und den Status von nicht verfolgen müssen Ihre Objekte. Verwenden Sie Canvas, wenn Sie Bitmap-Bilder bearbeiten müssen, und verwenden Sie ein reguläres div, wenn Sie in HTML erstellte Inhalte bearbeiten möchten. In Bezug auf die Leistung werden Sie feststellen, dass moderne Browser jetzt alle drei beschleunigen, aber dass die Leinwand bisher die größte Aufmerksamkeit erhalten hat. Auf der anderen Seite ist es entscheidend, wie gut Sie Ihr Javascript schreiben, um die bestmögliche Leistung mit Canvas zu erzielen. Daher würde ich weiterhin die Verwendung von SVG empfehlen.

Gaurav
quelle
1
Die Verwendung von einfachem HTML ist in Kombination mit CSS-Bildern am leistungsfähigsten.
Raynos
16
@ Raynos: Quelle?
Janus Troelsen
3

Während des Googelns finde ich eine gute Erklärung zur Verwendung und Komprimierung von SVG und Canvas unter http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Ich hoffe es hilft:

  • SVG verwendet wie HTML beibehaltenes Rendering : Wenn wir ein Rechteck auf dem Bildschirm zeichnen möchten, verwenden wir deklarativ ein Element in unserem DOM. Der Browser zeichnet dann ein Rechteck, erstellt jedoch auch ein speicherinternes SVGRectElement- Objekt, das das Rechteck darstellt. Dieses Objekt bleibt für uns zur Manipulation erhalten - es bleibt erhalten. Wir können ihm im Laufe der Zeit verschiedene Positionen und Größen zuweisen. Wir können auch Ereignis-Listener anhängen, um sie interaktiv zu gestalten.
  • Canvas verwendet sofortiges Rendern : Wenn wir ein Rechteck zeichnen , rendert der Browser sofort ein Rechteck auf dem Bildschirm, aber es wird niemals ein "Rechteckobjekt" geben, das es darstellt. Es gibt nur ein paar Pixel im Canvas-Puffer. Wir können das Rechteck nicht verschieben. Wir können nur ein anderes Rechteck zeichnen. Wir können nicht auf Klicks oder andere Ereignisse im Rechteck reagieren. Wir können nur auf Ereignisse auf der gesamten Leinwand reagieren .

Canvas ist also eine niedrigere, restriktivere API als SVG. Aber das hat eine Kehrseite: Mit Canvas können Sie mit der gleichen Menge an Ressourcen mehr erreichen. Da der Browser nicht das speicherinterne Objektdiagramm aller von uns gezeichneten Objekte erstellen und verwalten muss, benötigt er weniger Speicher und Rechenressourcen, um dieselbe visuelle Szene zu zeichnen. Wenn Sie eine sehr große und komplexe Visualisierung zeichnen möchten, ist Canvas möglicherweise Ihr Ticket.

Alireza Fattahi
quelle