Szybkie i responsywne interaktywne wykresy / wykresy: SVG, Canvas, inne?

114

Próbuję wybrać odpowiednią technologię do aktualizacji projektu, która w zasadzie renderuje tysiące punktów na powiększalnym, przesuwalnym wykresie. Obecna implementacja przy użyciu Protovis jest gorsza. Sprawdź to tutaj:

http://www.planethunters.org/classify

Po całkowitym oddaleniu jest około 2000 punktów. Spróbuj użyć uchwytów na dole, aby nieco powiększyć, i przeciągnij, aby przesuwać. Zobaczysz, że jest dość niestabilny, a zużycie procesora prawdopodobnie wzrasta do 100% na jednym rdzeniu, chyba że masz naprawdę szybki komputer. Każda zmiana w obszarze ostrości wywołuje przerysowanie do protovis, które jest cholernie wolne i jest gorsze, gdy rysuje się więcej punktów.

Chciałbym dokonać pewnych aktualizacji interfejsu, a także zmienić podstawową technologię wizualizacji, aby była bardziej responsywna podczas animacji i interakcji. Z poniższego artykułu wynika, że ​​można wybrać między inną biblioteką opartą na SVG lub biblioteką opartą na płótnie:

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

d3.js , który wyrósł z Protovis, jest oparty na SVG i ma być lepszy w renderowaniu animacji . Jednak mam wątpliwości, o ile lepszy i jaki jest jego sufit wydajności. Z tego powodu rozważam również bardziej kompletny przegląd przy użyciu biblioteki opartej na płótnie, takiej jak KineticJS . Zanim jednak zajdę zbyt daleko w stosowanie tego czy innego podejścia, chciałbym usłyszeć od kogoś, kto wykonał podobną aplikację internetową z tak dużą ilością danych i uzyskać jego opinię.

Najważniejsza jest wydajność, z drugorzędnym naciskiem na łatwość dodawania innych funkcji interakcji i programowania animacji. Prawdopodobnie nie będzie więcej niż 2000 punktów naraz, z tymi małymi słupkami błędów na każdym z nich. Powiększanie, pomniejszanie i przesuwanie musi być płynne. Jeśli najnowsze biblioteki SVG są w tym przyzwoite, być może łatwość korzystania z d3 przeważy nad zwiększoną konfiguracją dla KineticJS itp. Ale jeśli jest ogromna przewaga wydajności w używaniu płótna, szczególnie dla ludzi z wolniejszymi komputerami, to ja zdecydowanie wolałby iść tą drogą.

Przykład aplikacji stworzonej przez NYTimes, która używa SVG, ale nadal animuje się w akceptowalny sposób płynnie: http://www.nytimes.com/interactive/2012/05/17/business/dealbook/how-the-facebook-offering-compares.html . Gdybym mógł uzyskać taką wydajność i nie musiałbym pisać własnego kodu do rysowania na płótnie, prawdopodobnie wybrałbym SVG.

Zauważyłem, że niektórzy użytkownicy używali hybrydy manipulacji d3.js połączonej z renderowaniem na płótnie . Jednak nie mogę znaleźć dużo dokumentacji na ten temat w Internecie ani skontaktować się z operatorem tego postu. Jeśli ktoś ma jakieś doświadczenie w realizacji tego rodzaju implementacji DOM-to-Canvas ( demonstracja , kod ), również chciałbym poznać Twoją opinię. Wydaje się, że jest to dobra hybryda możliwości manipulowania danymi i posiadania niestandardowej kontroli nad ich renderowaniem (a tym samym wydajnością), ale zastanawiam się, czy konieczność ładowania wszystkiego do DOM nadal będzie spowalniać.

Wiem, że istnieją pytania podobne do tego, ale żadne z nich nie dotyczy dokładnie tego samego. Dzięki za pomoc.

Kontynuacja : implementacja, z której korzystałem, znajduje się na https://github.com/zooniverse/LightCurves

Andrew Mao
źródło
„Najważniejsza jest wydajność, z drugorzędnym naciskiem na łatwość dodawania innych interakcji” +1 dla płótna
philipp,
Pytanie brzmi, czy SVG jest wystarczające w większości przeglądarek dla 2k punktów + inne elementy wykresu? Jeśli tak, a powolność wynika po prostu ze słabości Protovis, to wolałbym pozostać przy SVG.
Andrew Mao,
1
Mike Bostock już udzielił dobrej odpowiedzi. Dodatkowe informacje można znaleźć w tych dwóch zasobach: stackoverflow.com/questions/5882716/html5-canvas-vs-svg-vs-div/ ... blogs.msdn.com/b/ie/archive/2011/04/22 /…
Ümit
8
Kontynuacja: zaimplementowałem to z hybrydowym podejściem SVG / płótno, w którym SVG zajmuje się osiami i liniami siatki, a płótno może renderować kropki niezwykle szybko. Jest super szybki!
Andrew Mao,

Odpowiedzi:

183

Na szczęście narysowanie 2000 okręgów jest dość łatwym przykładem do przetestowania. Oto cztery możliwe implementacje, po dwie z Canvas i SVG:

W tych przykładach wykorzystano zachowanie zoomu D3 do implementacji powiększania i przesuwania. Oprócz tego, czy okręgi są renderowane w formacie Canvas czy SVG, inna ważna różnica dotyczy tego, czy używasz powiększania geometrycznego czy semantycznego .

Powiększanie geometryczne oznacza, że ​​zastosujesz pojedynczą transformację do całej rzutni: po powiększeniu okręgi stają się większe. Kontrastowe powiększanie semantyczne oznacza, że ​​stosujesz transformacje do każdego okręgu osobno: po powiększeniu okręgi zachowują ten sam rozmiar, ale się rozchodzą. Planethunters.org używa obecnie semantycznego powiększania, ale warto rozważyć inne przypadki.

Powiększanie geometryczne upraszcza implementację: raz zastosujesz przesunięcie i skalowanie, a następnie wszystkie okręgi zostaną ponownie renderowane. Implementacja SVG jest szczególnie prosta, ponieważ aktualizuje pojedynczy atrybut „transform”. Wydajność obu przykładów przybliżania geometrycznego wydaje się więcej niż wystarczająca. W przypadku powiększania semantycznego zauważysz, że D3 jest znacznie szybszy niż Protovis. Dzieje się tak, ponieważ wykonuje dużo mniej pracy przy każdym zdarzeniu powiększenia. (Wersja Protovis musi ponownie obliczyć wszystkie atrybuty wszystkich elementów.) Semantyczne powiększanie oparte na kanwie jest nieco bardziej błyskawiczne niż SVG, ale semantyczne powiększanie SVG nadal jest responsywne.

Jednak nie ma magicznej kuli dla wydajności, a te cztery możliwe podejścia nie obejmują całej przestrzeni możliwości. Na przykład można połączyć powiększanie geometryczne i semantyczne, używając podejścia geometrycznego do przesuwania (aktualizacja atrybutu „transform”) i przerysowując tylko pojedyncze okręgi podczas powiększania. Prawdopodobnie możesz nawet połączyć jedną lub więcej z tych technik z transformacjami CSS3, aby dodać trochę przyspieszenia sprzętowego (jak w przykładzie hierarchicznego łączenia brzegów ), chociaż może to być trudne do wdrożenia i może powodować artefakty wizualne.

Mimo to, moim osobistym preferencją jest zachowanie jak największej ilości plików SVG i używanie Canvas tylko jako „wewnętrznej pętli”, gdy wąskim gardłem jest renderowanie . SVG ma tak wiele udogodnień dla rozwoju - takich jak CSS, łączenia danych i inspektor elementów - że często przedwczesna optymalizacja jest rozpoczynana od Canvas. Połączenie Canvas z SVG, jak w połączonej wizualizacji Facebook IPO, jest elastycznym sposobem na zachowanie większości tych udogodnień przy jednoczesnym zachowaniu najlepszej wydajności. Użyłem tej techniki również w Cubism.js , gdzie specjalny przypadek wizualizacji szeregów czasowych dobrze nadaje się do buforowania bitmap.

Jak pokazują te przykłady, możesz używać D3 z Canvas, nawet jeśli części D3 są specyficzne dla SVG. Zobacz także ten wykres ukierunkowany na siłę i ten przykład wykrywania kolizji .

mbostock
źródło
Wow, to była niesamowita odpowiedź i od samego mistrza wizualizacji! Myślę, że musiałbym trzymać się semantycznego powiększania, a na moim komputerze renderowanie oparte na płótnie jest znacznie szybsze niż wersja SVG podczas przesuwania / powiększania (może to mieć związek z implementacją przeglądarki?). To, co powiedziałeś o używaniu SVG z kanwą jako wewnętrzną pętlą, jest dokładnie tym, co chciałem potwierdzić, a przykłady kodu to tylko słodki bonus. Dzięki wielkie!
Andrew Mao,
Właśnie pomyślałem, aby wypróbować przykłady semantycznego powiększania w różnych przeglądarkach: Chrome, obie dość szybkie, nie potrafię odróżnić; IE: SVG nieco wolniej; Firefox (ostatni komentarz): SVG działa bardzo wolno w porównaniu do płótna. Myślę, że to też trochę komplikuje decyzję, ale sprawia, że ​​renderowanie płótna jest bezpiecznym wyborem. Jeszcze jedno pytanie: czy używanie KineticJS zamiast płótna bezpośrednio wpłynie znacząco na wydajność?
Andrew Mao,
1
Andrew, trochę spóźniony, ale oto moje doświadczenie z FF: Nadrabia zaległości. Kiedyś uruchamiałem przejścia SVG FF 15 i D3 szybko zaczęły się spowalniać. Ale każda nowa wersja była znacznie szybsza. Teraz jestem na wersji beta FF 18 i jest szybszy w porównaniu do 17. Nie jestem pewien, czy jest tak gładki jak chrom.
user2503795
@AndrewMao Cześć Andrew, natrafiłem na sytuację, w której wydaje się, że wąskim gardłem jest renderowanie. Muszę przesunąć i powiększyć niektóre punkty i około 6000 krzywej ścieżki. stackoverflow.com/questions/17907769/svg-path-rendering-speed/… Ale nie do końca rozumiem Bostocka, kiedy powiedział „trzymaj jak najwięcej w SVG i używaj Canvas tylko do„ wewnętrznej pętli ”. spojrzałem jednak na cztery przykłady… Czy możesz rzucić mi trochę światła?
kakacii
@kakacii czy transformacja jest równie powolna we wszystkich przeglądarkach? Jeśli tak, powiedziałbym, że albo używasz złego kodu, albo przekroczyłeś granice renderowania w przeglądarce. Jeśli mógłbyś wysłać kod, być może będę mógł pomóc. mbostock odnosił się do używania SVG ze względu na prostotę manipulacji i płótna tylko w razie potrzeby, ponieważ kodowanie jest bardziej skomplikowane. Jednak biblioteki takie jak KineticJS do pewnego stopnia to uprościły.
Andrew Mao,
8

Myślę, że w twoim przypadku decyzja między płótnem a svg nie przypomina decyzji między »jazdą na koniu« lub »porsche«. Dla mnie to bardziej decyzja o kolorze auta.

Pozwól mi wyjaśnić: Zakładając, że w oparciu o ramy działania

  • narysuj gwiazdę,
  • dodaj gwiazdkę i
  • usunąć gwiazdkę

zajmuje liniowy czas. Tak więc, jeśli twoja decyzja dotycząca frameworka była dobra, jest trochę szybsza, w przeciwnym razie nieco wolniejsza.

Jeśli przyjmiesz założenie, że framework jest po prostu szybki, to staje się całkowicie oczywiste, że brak wydajności jest spowodowany dużą ilością gwiazdek, a obsługa ich jest czymś, czego żaden framework nie może dla ciebie zrobić, przynajmniej nie wiem o tym.

Chcę powiedzieć, że podstawa problemu prowadzi do podstawowego problemu geometrii obliczeniowej, a mianowicie: przeszukiwania zakresów i kolejnego z grafiki komputerowej: poziomu szczegółowości .

Aby rozwiązać problem z wydajnością, musisz zaimplementować dobry preprocesor, który jest w stanie bardzo szybko znaleźć gwiazdy do wyświetlenia i być może jest w stanie skupić gwiazdy, które są blisko siebie, w zależności od powiększenia. Jedyną rzeczą, która zapewnia żywy i szybki widok, jest utrzymywanie jak najniższej liczby gwiazd do narysowania.

Jak powiedziałeś, najważniejsza jest wydajność, niż zwykle używałbym płótna, ponieważ działa bez operacji DOM. Oferuje również możliwość korzystania z webGL, co znacznie zwiększa wydajność graficzną.

BTW: czy sprawdziłeś paper.js ? Używa płótna, ale emuluje grafikę wektorową.

PS: W tej książce można znaleźć bardzo szczegółowe omówienie grafiki w Internecie, technologii, zalet i wad płótna, SVG i DHTML.

philipp
źródło
7

Niedawno pracowałem nad pulpitem nawigacyjnym działającym niemal w czasie rzeczywistym (odświeżanie co 5 sekund) i zdecydowałem się użyć wykresów renderujących się za pomocą kanwy.

Wypróbowaliśmy Highcharts (biblioteka wykresów JavaScript oparta na SVG) i CanvasJS (biblioteka wykresów JavaScript oparta na płótnie). Chociaż Highcharts jest fantastycznym interfejsem API do tworzenia wykresów i oferuje znacznie więcej funkcji, zdecydowaliśmy się użyć CanvasJS.

Musieliśmy wyświetlić co najmniej 15 minut danych na wykres (z możliwością wybrania zakresu maksymalnie dwóch godzin).

Tak więc przez 15 minut: 900 punktów (punkt danych na sekundę) x2 (wykres liniowy i słupkowy) x4 wykresy = łącznie 7200 punktów.

Używając profilera Chrome, z CanvasJS pamięć nigdy nie przekroczyła 30 MB, podczas gdy użycie pamięci Highcharts przekroczyło 600 MB.

Również z czasem odświeżania wynoszącym 5 sekund, renderowanie CanvasJS było bardziej responsywne niż Highcharts.

Użyliśmy jednego timera (setInterval 5 sekund), aby wykonać 4 wywołania interfejsu API REST w celu pobrania danych z serwera zaplecza, który łączył się z Elasticsearch. Każdy wykres aktualizowany po odebraniu danych przez JQuery.post ().

To powiedziawszy, w przypadku raportów offline wybrałbym Highcharts, ponieważ jest to bardziej elastyczny interfejs API.

Istnieją również wykresy Zing, które twierdzą, że używają SVG lub Canvas, ale ich nie oglądały.

Canvas należy wziąć pod uwagę, gdy wydajność jest naprawdę krytyczna. SVG dla elastyczności. Nie chodzi o to, że frameworki kanwy nie są elastyczne, ale frameworowi kanwy potrzeba dużo więcej pracy, aby uzyskać taką samą funkcjonalność jak framework svg.

user432024
źródło
3

Warto również zajrzeć do Meteor Charts, który jest oparty na szybkim frameworku KineticJS: http://meteorcharts.com/

Eric Rowell
źródło
0

Odkryłem również, że kiedy drukujemy do pliku PDF stronę z grafiką SVG, wynikowy plik PDF nadal zawiera obraz wektorowy, a jeśli drukujesz stronę z grafiką Canvas, obraz w wynikowym pliku PDF jest rasteryzowany.

ostrokach
źródło