HTML5 Canvas vs. SVG vs. div

476

Jakie jest najlepsze podejście do tworzenia elementów w locie i możliwości ich przenoszenia? Załóżmy na przykład, że chcę utworzyć prostokąt, okrąg i wielokąt, a następnie wybrać te obiekty i przesunąć je.

Rozumiem, że HTML5 zapewnia trzy elementy, które mogą to umożliwić: svg , canvas i div . Co chcę zrobić, który z tych elementów zapewni najlepszą wydajność?

Aby porównać te podejścia, zastanawiałem się nad stworzeniem trzech wizualnie identycznych stron internetowych, z których każda zawiera nagłówek, stopkę, widżet i treść tekstową. Widżet na pierwszej stronie zostałby utworzony w całości z canvaselementem, drugi w całości z svgelementem, a trzeci z prostym divelementem, HTML i CSS.

verdy
źródło
13
Może Cię to zainteresować: Myśli o tym, kiedy używać Canvas i SVG .
robertc
1
Dla tych z was, którzy są nowi w tej technologii, ten film zawiera zarówno SVG, jak i Canvas oraz inne szczegóły na temat tego, jak to się integruje na HTML5.
Paulo Bueno,
12
Krótka odpowiedź: płótno jest do MS Paint jak SVG do MS Powerpoint. Płótno jest rastrowe, SVG jest wektorowe.
GetFree,
2
Drogi czytelniku: weź wszystkie porównania i stwierdzenia z odrobiną soli i spójrz na datę postów i komentarzy. Czasy się zmieniły i zmienią się. Względna wydajność, a nawet dostępne opcje ulegną zmianie. Np. Większość odpowiedzi napisano, gdy nie było WebGL, co zdecydowanie jest alternatywą - za kilka lat będzie również nieaktualne, ale na dzień dzisiejszy może być bardzo istotne.
Sebastian,
@Sebastian, który poleciłbyś dzisiaj? jeśli dany rozmiar podstawowy (np. 1280 x 800) i jeśli chcesz ręcznie skalować elementy w kodzie lub cały czas używać wartości procentowych, to czy SVG ma przewagę nad korzystaniem z DIV?
Crashalot

Odpowiedzi:

563

Krótka odpowiedź:

SVG byłoby łatwiejsze dla Ciebie , ponieważ zaznaczanie i przenoszenie jest już wbudowane. Obiekty SVG są obiektami DOM, więc mają procedury obsługi „klikania” itp.

DIV są w porządku, ale niezgrabne i mają okropne wyniki ładowania przy dużej liczbie.

Canvas ma najlepszą wydajność, ale musisz samodzielnie wdrożyć wszystkie koncepcje stanu zarządzanego (wybór obiektu itp.) Lub użyć biblioteki.


Długa odpowiedź:

HTML5 Canvas to po prostu powierzchnia do rysowania mapy bitowej. Ustawiłeś rysować (powiedz z kolorem i grubością linii), narysuj tę rzecz, a następnie Płótno nie ma o tym żadnej wiedzy: nie wie, gdzie to jest ani co jest właśnie narysowane, to jest tylko piksele. Jeśli chcesz narysować prostokąty i pozwolić im się poruszać lub wybierać, musisz zakodować wszystko od zera, w tym kod, aby pamiętać, że je narysowałeś.

Z drugiej strony SVG musi utrzymywać odniesienia do każdego renderowanego obiektu. Każdy tworzony element SVG / VML jest prawdziwym elementem w DOM. Domyślnie pozwala to na znacznie lepsze śledzenie tworzonych elementów i sprawia, że ​​radzenie sobie z takimi rzeczami jak zdarzenia myszy jest łatwiejsze, ale znacznie spowalnia, gdy istnieje duża liczba obiektów

Te odniesienia do SVG DOM oznaczają, że część pracy związanej z rysowaniem rzeczy jest zrobiona za Ciebie. A SVG jest szybszy podczas renderowania naprawdę dużych obiektów, ale wolniejszy podczas renderowania wielu obiektów.

Gra byłaby prawdopodobnie szybsza w Canvas. Ogromny program mapowy byłby prawdopodobnie szybszy w SVG. Jeśli chcesz korzystać z Canvas, mam tutaj tutoriale na temat uruchamiania ruchomych obiektów i uruchamiania ich tutaj .

Płótno byłoby lepsze do szybszych rzeczy i ciężkich operacji bitmapowych (takich jak animacja), ale zajmie więcej kodu, jeśli chcesz dużo interaktywności.

Znalazłem wiele liczb na rysunku wykonanym w HTML DIV w porównaniu do rysunku na płótnie. Mógłbym napisać ogromny post o zaletach każdego z nich, ale podam kilka istotnych wyników moich testów do rozważenia dla konkretnego zastosowania:

Zrobiłem strony testowe Canvas i HTML DIV, obie miały ruchome „węzły”. Węzły Canvas to obiekty, które utworzyłem i które śledziłem w Javascript. Węzły HTML były ruchomymi divami.

Dodałem 100 000 węzłów do każdego z moich dwóch testów. Wystąpili zupełnie inaczej:

Załadowanie karty testowej HTML trwało wieczność (czas trwania nieco poniżej 5 minut, Chrome poprosił o zabicie strony za pierwszym razem). Menedżer zadań Chrome twierdzi, że karta zajmuje 168 MB. Zajmuje to 12–13% czasu procesora, gdy na niego patrzę, 0%, gdy nie patrzę.

Karta Canvas ładowana jest w ciągu jednej sekundy i zajmuje 30 MB. Zajmuje również 13% czasu procesora przez cały czas, niezależnie od tego, czy ktoś na to patrzy. (Edycja 2013: Naprawiono to głównie)

Przeciąganie na stronie HTML jest płynniejsze, czego oczekuje projekt, ponieważ obecna konfiguracja polega na przerysowaniu WSZYSTKO co 30 milisekund w teście Canvas. W tym celu można zoptymalizować Canvas. (najłatwiejsze jest unieważnienie obszaru roboczego, także wycinanie regionów, wybiórcze przerysowywanie itp. zależy tylko od tego, jak bardzo chcesz się wdrożyć)

Nie ma wątpliwości, że Canvas może być szybszy w manipulowaniu obiektami, ponieważ div w tym prostym teście, i oczywiście znacznie szybciej w czasie ładowania. Rysowanie / ładowanie jest szybsze w kanwie i ma również znacznie więcej miejsca na optymalizacje (tj. Wykluczanie rzeczy, które są poza ekranem, jest bardzo łatwe).

Wniosek:

  • SVG jest prawdopodobnie lepszy dla aplikacji i aplikacji z kilkoma elementami (mniej niż 1000? Zależy naprawdę)
  • Płótno jest lepsze dla tysięcy obiektów i starannej manipulacji, ale potrzeba dużo więcej kodu (lub biblioteki), aby zdjąć go z ziemi.
  • Divy HTML są nieporęczne i nie skalują się, dzięki czemu okrąg jest możliwy tylko z zaokrąglonymi narożnikami, dzięki czemu możliwe są złożone kształty, ale obejmują setki małych div o szerokości piksela. Następuje szaleństwo.
Simon Sarris
źródło
4
Ciasto biblioteka jest kolejnym przykładem robi ruchome obiekty i animacje z obiektów na płótnie
SiggyF
Źle: P div może skalować się, jeśli przeglądarka używa silnika CSS z przyspieszeniem hw, grafika css jest inna, a oprócz Canvas i SVG są tutaj właściwym wyborem, grafika CSS / div jest tylko wtedy, gdy nie musisz przesadzać z małą nakładką: P
ShrekOverflow,
Jeśli chodzi o DIV, jeśli chcesz tworzyć koła / kształty specjalne i nie zamierzasz z background-image
czasem
4
Co jeśli tworzysz interaktywną grę mapową? : p
Anthony
Zostało to utworzone przy użyciu (nie zagnieżdżonych) DIV i transformacji CSS 3D, więc powiedziałbym, że DIV wcale nie są wolne: youtube.com/watch?v=fzBC20B5dsk
Erik Kaplun
39

Aby dodać do tego, robiłem aplikację diagramu i początkowo zacząłem od canvas. Schemat składa się z wielu węzłów i mogą one być dość duże. Użytkownik może przeciągać elementy na diagramie.

Odkryłem, że na moim komputerze Mac, w przypadku bardzo dużych obrazów, SVG jest lepszy. Mam MacBooka Pro 2013 13 "Retina, która dość dobrze biegnie pod skrzynką. Obraz ma wymiary 6000 x 6000 pikseli i zawiera 1000 obiektów. Podobna konstrukcja płótna była dla mnie niemożliwa do animacji, gdy użytkownik przeciągał obiekty w diagram.

Na nowoczesnych wyświetlaczach musisz również uwzględnić różne rozdzielczości, a tutaj SVG daje to wszystko za darmo.

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

Pełny ekran: 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
źródło
2
My też zdecydowaliśmy się na SVG po desperackich próbach zmuszenia Canvas do pracy dla nas. Mamy bardzo duży schemat, a SVG był zdecydowanie najbardziej wydajny, a automatyczne skalowanie na ekranach siatkówki jest ogromną zaletą.
Fijjit,
knut i @Fijjit, czy rozważałeś użycie DIV zamiast SVG? gdyby podano rozmiar podstawowy (np. 1280 x 800), czy nie można ręcznie skalować DIV, aby wyglądały tak ostro jak SVG? dzięki za pomoc!
Crashalot
24

Znajomość różnic między SVG a Canvas byłaby pomocna w wyborze właściwego.

Brezentowy

SVG

  • Rozdzielczość niezależna
  • Wsparcie dla programów obsługi zdarzeń
  • Najlepiej nadaje się do aplikacji z dużymi obszarami renderowania (Google Maps)
  • Powolne renderowanie, jeśli jest złożone (wszystko, co często korzysta z DOM, będzie wolne)
  • Nie nadaje się do aplikacji gier
Leo The Four
źródło
8
dlaczego ludzie mówią, że płótno zależy od rozdzielczości? Rozumiem, że po renderowaniu bitmapa nie skaluje się ładnie. ale możesz przerysować zmiany rozdzielczości, więc dlaczego ta rozdzielczość nie jest niezależna?
Alex Bollbach,
@AlexBollbach - Płótno jest zależne od rozdzielczości, ponieważ musisz wziąć (zależnie) od rozdzielczości, aby uzyskać dobre wyniki. Z SVG nie przejmujesz się rozdzielczością. Powodzenia w uzyskiwaniu nieostrych linii na drukarce 2400 DPI i renderowaniu na podstawie Canvas. Nie ma problemu z SVG.
Sebastian,
18

Zgadzam się z wnioskami Simona Sarrisa:

Porównałem niektóre wizualizacje w Protovis (SVG) do Processingjs (Canvas), które wyświetlają> 2000 punktów, a przetwarzanie js jest znacznie szybsze niż protovis.

Obsługa zdarzeń za pomocą SVG jest oczywiście o wiele łatwiejsza, ponieważ możesz dołączyć je do obiektów. W Canvas musisz to zrobić ręcznie (sprawdź pozycję myszy itp.), Ale dla prostej interakcji nie powinno to być trudne.

Istnieje również dojo.gfx biblioteka zestawu narzędzi dojo. Zapewnia warstwę abstrakcji i można określić moduł renderujący (SVG, Canvas, Silverlight). Może to być również realny wybór, chociaż nie wiem, ile narzutu dodaje dodatkowa warstwa abstrakcji, ale ułatwia kodowanie interakcji i animacji i jest niezależny od renderera.

Oto kilka interesujących punktów odniesienia:

Ümit
źródło
17

Tylko moje 2 centy dotyczące opcji div.

Famous / Infamous i SamsaraJS (i ewentualnie inni) używają absolutnie pozycjonowanych, nie zagnieżdżonych div (z nietrywialnymi treściami HTML / CSS), w połączeniu z matrix2d / matrix3d ​​do pozycjonowania i transformacji 2D / 3D, i osiągają stabilny 60 FPS na umiarkowanym mobilnym sprzęcie , więc argumentowałbym przeciwko temu, by divs było opcją powolną.

Istnieje wiele nagrań ekranu na Youtube i innych miejscach, z wydajnymi materiałami 2D / 3D uruchomionymi w przeglądarce, przy czym wszystko jest elementem DOM, na którym można sprawdzić element , przy 60 klatkach na sekundę (zmieszane z WebGL dla pewnych efektów, ale nie dla główna część renderowania).

Erik Kaplun
źródło
14

Chociaż w większości powyższych odpowiedzi jest trochę prawdy, myślę, że zasługują one na aktualizację:

Przez lata wydajność SVG znacznie się poprawiła, a teraz dostępne są przyspieszane sprzętowo przejścia CSS i animacje SVG, które wcale nie zależą od wydajności JavaScript. Oczywiście poprawiła się także wydajność JavaScript, a wraz z nią wydajność Canvas, ale nie tak bardzo, jak poprawiła się SVG. Jest też „nowy dzieciak” na bloku, który jest obecnie dostępny w prawie wszystkich przeglądarkach i to jest WebGL . Aby użyć tych samych słów, których Simon użył powyżej: bije zarówno Canvas, jak i SVG . Nie oznacza to jednak, że powinna to być technologia, ponieważ jest to bestia do pracy i jest szybsza tylko w bardzo szczególnych przypadkach użycia.

IMHO dla większości dzisiejszych przypadków użycia, SVG zapewnia najlepszy stosunek wydajności do użyteczności. Wizualizacje muszą być naprawdę złożone (pod względem liczby elementów) i jednocześnie bardzo proste (na element), aby Canvas i jeszcze bardziej WebGL naprawdę świeciły.

W tej odpowiedzi na podobne pytanie podaję więcej szczegółów, dlaczego uważam, że połączenie wszystkich trzech technologii jest czasami najlepszą opcją, jaką masz.

Sebastian
źródło
Użytkownicy systemów uniksowych powinni pamiętać, że przyspieszenie sprzętowe jest domyślnie wyłączone zarówno w przeglądarce Firefox, jak i Chromium, co nadal jest prawdą w połowie 2019 r.
NVRM
@NVRM - dotyczy przyspieszania sprzętowego CSS i SVG, a nie dekodowania wideo. AFAIK ten pierwszy jest dostępny od lat: Sprawdź dane wyjściowe chrome: // gpu
Sebastian
layers.acceleration.force-enabledw Firefoksie nie chodzi o dekodowanie wideo. To dobrze znany fakt. Po wykonaniu pętli za pomocą requestAnimationFrame jest inny poziom, pozwalający na znacznie więcej odświeżeń. W ogóle nie chodzi o wideo.
NVRM,
@NVRM - czy możesz podać linki do błędów FF i Chromium dla tych problemów z GPU w Linuksie? Zauważ też, że przez „przyspieszenie sprzętowe” miałem na myśli nie tylko przyspieszenie GPU, ale także wielowątkowe kompozycje i animacje, takie jak np. Ładowanie spinnerów, które obracają się, gdy JavaScript nie jest uruchomiony lub podczas wykonywania JS. Jest to niemożliwe w przypadku Canvas, a w porównaniu z czystym „JavaScript” jest to rzeczywiście pewnego rodzaju przyspieszenie sprzętowe (wielowątkowość), które jest zdecydowanie dostępne w Chrome i FF na wszystkich platformach. Dzięki!
Sebastian,
1
Podsumowując obecną sytuację: Działa dla mnie w Chrome i Chromium. W systemie Linux. W 2019 roku. We wszystkich przypadkach testowałem bez specjalnej konfiguracji. Firefox / Mozilla działa na tym systemie Linux , jednak renderowanie poza procesem nie jest niczym nowym dla FF i zawsze będzie działać lepiej z SVG, CSS itp. Niż dla Canvas.
Sebastian,
13

Do swoich celów zalecam używanie SVG, ponieważ otrzymujesz zdarzenia DOM, takie jak obsługa myszy, w tym przeciąganie i upuszczanie, nie musisz implementować własnego przerysowywania i nie musisz śledzić stanu twoje przedmioty. Użyj Canvas, gdy musisz manipulować obrazami bitmapowymi, i zwykłego div, jeśli chcesz manipulować materiałami utworzonymi w HTML. Jeśli chodzi o wydajność, przekonasz się, że współczesne przeglądarki przyspieszają teraz wszystkie trzy, ale do tej pory największą uwagę przyciągnęło płótno. Z drugiej strony to, jak dobrze piszesz javascript, ma kluczowe znaczenie dla uzyskania jak największej wydajności z płótnem, więc nadal polecam używanie SVG.

Gauraw
źródło
1
W rzeczywistości użycie zwykłego HTML jest najbardziej wydajne w połączeniu z obrazami CSS.
Raynos
16
@Raynos: Źródło?
Janus Troelsen
3

Podczas wyszukiwania w Google znajduję dobre wyjaśnienie dotyczące używania i kompresji SVG i Canvas na stronie http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Mam nadzieję, że to pomoże:

  • SVG, podobnie jak HTML, wykorzystuje zachowane renderowanie : kiedy chcemy narysować prostokąt na ekranie, deklaratywnie używamy elementu w naszym DOM. Przeglądarka narysuje następnie prostokąt, ale utworzy również w pamięci obiekt SVGRectElement, który reprezentuje prostokąt. Ten przedmiot jest czymś, co pozostaje do zmanipulowania - zostaje zachowane. Z czasem możemy mu przypisywać różne pozycje i rozmiary. Możemy również dołączyć detektory zdarzeń, aby były interaktywne.
  • Płótno korzysta z natychmiastowego renderowania : kiedy narysujemy prostokąt , przeglądarka natychmiast renderuje prostokąt na ekranie, ale nigdy nie będzie żadnego „obiektu prostokąta”, który go reprezentuje. W buforze płótna jest tylko kilka pikseli. Nie możemy przesunąć prostokąta. Możemy narysować tylko inny prostokąt. Nie możemy reagować na kliknięcia lub inne zdarzenia w prostokącie. Możemy reagować tylko na wydarzenia na całym płótnie .

Płótno jest bardziej restrykcyjnym interfejsem API niższego poziomu niż SVG. Ale jest też druga strona tego, że z płótnem możesz zrobić więcej przy tej samej ilości zasobów. Ponieważ przeglądarka nie musi tworzyć i utrzymywać wykresu obiektów w pamięci dla wszystkich narysowanych przez nas obiektów, potrzebuje mniej zasobów pamięci i zasobów obliczeniowych, aby narysować tę samą scenę wizualną. Jeśli masz do rysowania bardzo dużą i złożoną wizualizację, Canvas może być Twoim biletem.

Alireza Fattahi
źródło