Szukałem solidnego rozwiązania, które pozwoliłoby mi stworzyć mapę internetową i nałożyć wieloboki wektorowe bez ciągłego ładowania takich danych, aby umożliwić mi wyświetlanie każdego wielokąta w innym kolorze podczas zdarzenia najechania kursorem.
O ile mi wiadomo, istnieją 3 konkretne opcje osiągnięcia tego poprzez płótno, SVG, Flash.
Flash wydaje się najlepszym rozwiązaniem, gdyby działał na iPhone'ach / iPadach Apple, ponieważ zapewnia najszybszy rendering i najczystszy wyświetlacz. Płótno wydaje się drugim najlepszym wyborem, ale zajmuje BARDZO dużo czasu, jeśli na mapie są wyświetlane setki wielokątów, a renderowanie SVG zajmuje jeszcze więcej czasu.
I prawie stracił nadzieję na znalezienie rozwiązania tego problemu , ale dzisiaj natknąłem się na firmę o nazwie GISCloud http://www.giscloud.com (obecnie w wersji beta z wolnego rejestrację).
Ta firma w ramach projektu SOMEHOW opracowała niesamowity sposób renderowania setek wektorów na mapie w czasie prawie rzeczywistym. Byłem zaskoczony ich podejściem, a moje pytanie do społeczności dotyczy tego, w jaki sposób możemy powtórzyć ich podejście do użycia z istniejącymi technologiami, takimi jak ulotka, openlayery, wosk ...
Przekonaj się, oglądając to niesamowite demo: http://www.giscloud.com/map/284/africa
Upewnij się, że najedziesz myszką na którykolwiek z wielokątów na stronie i przetestujesz elementy sterujące powiększeniem, aby zobaczyć, czy te wielokąty są rzeczywiście wektorami.
Zauważyłem, że patrząc na żądania za pomocą firebuga, mapa żąda określonych plików JSON. Wygląda na to, że w zależności od poziomu / obszaru powiększenia żądanych jest wiele plików json.
Powinienem tu również wspomnieć, że gdy giscloud ładuje dane na stronie, najechanie kursorem na wektor natychmiast zmienia kolor bez tworzenia nowego żądania.
PRZYKŁADY:
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/3/3.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/5/3.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/4/4.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/3/4.json
- http://cft1.giscloud.com/t/1316509973/map284/layer1156/3/5/4.json
Zakładam, że struktura adresu URL jest zgodna ze standardową logiką usługi kafelkowania (na przykład od trzeciego do ostatniego folderu jest poziomem powiększenia ...).
W każdym razie przeanalizowałem rzeczywiste dane tych plików json i wydaje się, że logika, której używają, jest zgodna z pewnym rodzajem logiki, za pomocą której tworzą swoje wektory oparte na tych wartościach danych:
- szerokość / wysokość: określają szerokość i wysokość danych obsługiwanych w każdym żądaniu json
- piksele: tutaj definiują wartości pikseli, które, jak zakładam, w jakiś sposób odnoszą się do ogólnych współrzędnych pikseli x / y dla uogólnionych poziomów punktów? Domyślam się, że w jakiś sposób automatycznie upraszczają region w zależności od poziomu powiększenia. Zakładam, że używają współrzędnych pikseli. Wydaje mi się, że radykalnie zmniejszają rozmiar danych, które należy załadować, w porównaniu do danych z długości / długości.
- style: tutaj definiują dwie wartości css RGB. „F” reprezentuje kolor pliku wielokąta, a „S” reprezentuje kolor ramki wielokąta.
- geom: tutaj przypuszczam, że w jakiś sposób definiują konkretnie definiowanie każdego wielokąta w ładowanym kafelku, w którym takie dane są definiowane na podstawie okna kontenera mapy. Interesujące jest również to, że każdy wpis ma wartość „S”, która, jak zakładam, jest używana jako opcjonalny atrybut lub wartość łącza funkcji, a na końcu każdego wpisu znajduje się obszar, który wydaje się definiować konkretny identyfikator wektora wraz z identyfikator warstwy, który zgaduję, jest używany do połączenia danych z każdego wywoływanego żądania kafelka json.
Zakładam również, że w jakiś sposób wymyślili sposób automatycznego określania i podziału danych, które należy załadować dla każdego kafelka, w zależności od rozmiaru danych, które należy załadować dla żądanego kafelka.
Oto wyodrębniony podział jednego z tych żądań:
{"width":256,"height":256,"tile":
{"pixels":
[0,6461,-1,0,5,148,0,509,-1,10715,-1,1,-1,251,-1,1,-1,1,-1,251,-2,3,-1,255,-1,249,-2,5,-2,247,-1,509,-3,251,-1,2,-2,253,-2,252,-2,254,-1,255,-1,254,-1,255,-1,1276,-2,13,-1,233,-1,2,-1,253,-1,1,-1,255,-1,247,-1,1306,-1,1533,-1,1269,-1,1276,-1,2303,-1]},
"styles":
[{"f":"rgb(99,230,101)","s":"rgb(5,148,0)","lw":"0"}],
"geom":
[
{"s":0,"p":[4,143,5,144,3,146,1,146,2,143,4,143],"c":"layer1156_5098"},
{"s":0,"p":[-2,143,0,140,2,141,2,144,1,146,-2,144,-2,143],"c":"layer1156_5067"},
{"s":0,"p":[7,143,5,144,4,143,2,143,2,141,5,138,6,139,5,141,7,143],"c":"layer1156_5051"},
{"s":0,"p":[10,141,11,137,12,137,14,137,12,142,9,143,9,142,10,141],"c":"layer1156_5041"},
{"s":0,"p":[1,136,0,140,-2,143,-2,136,1,136],"c":"layer1156_5038"},
{"s":0,"p":[8,143,5,141,5,137,8,136,10,137,10,141,8,143],"c":"layer1156_5033"},
{"s":0,"p":[5,137,2,141,0,140,1,136,1,136,2,135,3,136,5,137],"c":"layer1156_5028"},
{"s":0,"p":[10,134,12,136,11,138,8,135,10,134],"c":"layer1156_5020"},
{"s":0,"p":[-2,133,0,136,-2,136,-2,133],"c":"layer1156_5005"},
{...}
...
]
}
Jak możemy powielać ten sam (lub podobny) typ prędkości za pomocą postgis (z którego ja również zdaje się korzystać)?
źródło
Odpowiedzi:
W przeszłości widziałem tę technikę. Wyjaśnił mi to Zain Memon (z Trulii), który pomógł mi dać wkład, gdy Michał Migurski tworzył TileStache. Zain omówił to, wyjaśniając swoje demo Trulii, które wykorzystuje tę technikę na jednym ze starszych spotkań SF GeoMeetup jakiś czas temu . W rzeczywistości, jeśli będziesz w SF w przyszłym tygodniu (to moja kiepska próba wtyczki, on to dotknie , więc nie krępuj się pojawić :)
OK, teraz wyjaśnienie.
Po pierwsze, patrzysz nieco w niewłaściwe miejsce, patrząc na powyższe pliki json.
Pozwól, że wyjaśnię (tak krótko, jak potrafię), dlaczego.
Płytki są przekazywane tak jak zwykłe renderowane kafelki, nic wielkiego, wiemy jak to zrobić, więc nie muszę tego wyjaśniać.
Jeśli sprawdzisz to w Firebug, zobaczysz, że otrzymujesz całą masę zdjęć, które wydają się puste, jak ten .
Dlaczego jest pusty? Nie jest. Piksele zawierają dane - po prostu nie są to tradycyjne widoczne dane obrazu. Używają bardzo sprytnej techniki do przekazywania danych zakodowanych w samych pikselach.
W ciągu ostatniej dekady działo się tak, że ludzie kompromitowali dane dotyczące czytelności i przenośności formatów kosztem wydajności pamięci.
Weź przykładowy przykład danych XML:
OK, ile ugryzień to przenieść? Pod warunkiem, że mamy do czynienia z utf8 (1 bajt na znak przy przetwarzaniu tej zawartości). Mamy około 176 znaków (bez liczenia tabulatorów i spacji), co sprawia, że 176 bajtów (jest to optymistyczne z różnych powodów, które pominę ze względu na prostotę). Pamiętaj, że to za 2 punkty!
Mimo to jakiś mądry tyłek, który nie rozumie, o czym on mówi, twierdzi, że „json zapewnia lepszą kompresję”.
Dobra, postawmy ten sam nonsens xml co json:
Ile bajtów tutaj? Powiedz ~ 115 znaków. Nawet trochę oszukałem i zmniejszyłem.
Powiedz, że mój obszar obejmuje 256 x 256 pikseli i że jestem na poziomie powiększenia tak wysokim, że każda funkcja jest renderowana jako jeden piksel i mam tyle funkcji, że jest pełna. Ile danych potrzebuję, aby pokazać, że 65 536 funkcji?
54 znaki (lub bajty utf - a ja nawet ignoruję inne rzeczy) na wpis „funkcja” pomnożony x 65.536 = 3538,944 lub około 3,3 MB
Myślę, że wiesz o co chodzi.
Ale w ten sposób przesyłamy dane w architekturze zorientowanej na usługi. Czytelne wzdęcia.
Co jeśli chciałbym przetransportować wszystko w systemie binarnym, który sam wymyśliłem? Powiedz, że zamiast tego zakodowałem tę informację w obrazie jednopasmowym (tj. Czarno-białym). I zdecydowałem, że 0 oznacza sprzedane, a 1 dostępne, a 2 oznacza, że nie wiem. Do licha, w 1 bajcie mam 256 opcji, których mogę użyć - i używam tylko 2 lub 3 z nich w tym przykładzie.
Jaki jest koszt tego przechowywania? 256x256x 1 (tylko jedno pasmo). 65 536 bajtów lub 0,06 MB. I to nawet nie bierze pod uwagę innych technik kompresji, które otrzymuję za darmo z kilkudziesięciu lat badań nad kompresją obrazu.
W tym momencie powinieneś zadać sobie pytanie, dlaczego ludzie nie wysyłają danych zakodowanych w formacie binarnym zamiast serializować do json? Cóż, po pierwsze, okazuje się, że javascript zajmuje dużo czasu na transport danych binarnych , dlatego ludzie nie robili tego historycznie.
Niesamowite obejście zostało wykorzystane przez niektórych ludzi, gdy pojawiły się nowe funkcje HTML5, zwłaszcza płótno . Więc co to za obejście? Okazuje się, że możesz przesyłać dane za pomocą drutu zakodowanego na czymś, co wygląda na obraz, a następnie możesz wrzucić ten obraz na płótno HTML5, które pozwala bezpośrednio manipulować pikselami ! Teraz masz sposób na przechwycenie tych danych, odkodowanie ich po stronie klienta i wygenerowanie obiektów json w kliencie.
Zatrzymaj się na chwilę i pomyśl o tym.
Masz sposób na zakodowanie ogromnej ilości znaczących danych z odniesieniami geograficznymi w wysoce skompresowanym formacie, rzędach wielkości mniejszych niż cokolwiek innego tradycyjnie wykonywanego w aplikacjach internetowych i manipulowanie nimi w javascript.
Płótno HTML nie musi nawet być używane do rysowania, służy jedynie jako binarny mechanizm dekodowania!
Właśnie o to chodzi w tych wszystkich obrazach, które widzisz w Firebug. Jeden obraz z danymi zakodowanymi dla każdego pobieranego kafelka. Są bardzo małe, ale mają znaczące dane.
Jak więc je zakodować po stronie serwera? Musisz uogólnić dane po stronie serwera i utworzyć znaczący kafelek dla każdego poziomu powiększenia, który zawiera zakodowane dane. Obecnie, aby to zrobić, musisz wdrożyć własne - gotowe rozwiązanie open source nie istnieje, ale masz wszystkie potrzebne narzędzia, aby to zrobić. PostGIS przeprowadzi uogólnienie za pomocą GEOS, TileCache może być użyty do buforowania i pomaga uruchomić generowanie kafelków. Po stronie klienta będziesz musiał użyć HTML5 Canvas, aby przekazać specjalne „fałszywe kafelki”, a następnie możesz użyć OpenLayers do stworzenia prawdziwych obiektów javascript po stronie klienta, które reprezentują wektory z efektami najechania myszką.
Jeśli potrzebujesz zakodować więcej danych, pamiętaj, że zawsze możesz generować obrazy RGBA na piksel (co daje 4 bajty na piksel lub 4 294 967 296 liczb, które możesz reprezentować na piksel ). Mogę wymyślić kilka sposobów korzystania z tego :)
Aktualizacja : Odpowiadając na pytanie QGIS poniżej.
QGIS, podobnie jak większość innych komputerowych systemów GIS , nie ma ustalonego zestawu poziomów powiększenia. Mają elastyczność powiększania w dowolnej skali i po prostu renderują. Czy mogą wyświetlać dane ze WMS lub źródeł opartych na kafelkach? Pewnie, że mogą, ale przez większość czasu są naprawdę głupi: powiększ w innym stopniu, obliczyć obwiednię, oblicz wymagane kafelki, chwyć je, pokaż im. Przez większość czasu ignorują inne rzeczy, takie jak pamięci podręczne nagłówków http, które sprawiłyby, że nie musiałyby się ponownie pobierać. Czasami implementują prosty mechanizm pamięci podręcznej (przechowuj kafelek, jeśli o to poprosisz, sprawdź kafelek, nie pytaj o niego). Ale to nie wystarczy.
Dzięki tej technice płytki i wektory muszą być ponownie przycinane na każdym poziomie powiększenia . Dlaczego? Ponieważ wektory zostały uogólnione w celu dostosowania poziomów powiększenia.
Jeśli chodzi o całą sztuczkę umieszczania kafelków na kanwie HTML5, aby uzyskać dostęp do buforów, cała ta sprawa nie jest konieczna. QGIS pozwala pisać kod w Pythonie i C ++, oba języki mają doskonałą obsługę buforów binarnych, więc to obejście jest naprawdę nieistotne dla tej platformy.
* AKTUALIZACJA 2 **:
Pojawiło się pytanie, jak stworzyć uogólnione kafelki wektorowe (krok 1 dziecka, zanim będzie można serializować wyniki w obrazy). Być może nie wyjaśniłem wystarczająco. Tilestache pozwoli Ci tworzyć skuteczne „kafelki wektorowe” danych na każdym poziomie powiększenia (ma nawet opcję, która pozwala przycinać lub nie przycinać danych, gdy przekroczy granicę kafelka). To zajmuje się rozdzielaniem wektorów na kafelki przy różnych poziomach powiększenia. Wybrałbym opcję „nie przycinaj” (ale wybierze dowolny kafelek, w którym zajmuje więcej miejsca). Następnie możesz karmić każdy wektor za pomocą opcji uogólnienia GEOS dużą liczbą, w rzeczywistości chcesz, aby był wystarczająco duży, aby polilinie i wielokąty zapadły się na siebie, ponieważ jeśli tak, możesz je usunąć z poziomu powiększenia, ponieważ na tym etapie są one bez znaczenia. Tilestache pozwala nawet pisać łatwych pytonicznych dostawców danych, w których można umieścić tę logikę. Na tym etapie możesz udostępnić je jako pliki json (tak jak robią to z niektórymi afrykańskimi próbkami map) lub jako serializowane geometrie do plików png, tak jak robią to w innych próbkach (lub Trulii), które podałem powyżej.
źródło
Bezpośrednio od dewelopera Dino Ravnic w najnowszym wpisie na liście mailingowej :
Wygląda więc na to, że po stronie klienta jest to łatwa część. To imponujące, że dane są renderowane bez buforowania.
Wspomina także o usłudze hostingowej, która może Cię zainteresować. Możesz rozważyć koszt próby odtworzenia tego z kosztem korzystania z gotowej usługi.
źródło
Jak opisałem na liście OSGeo, kluczem jest dostarczanie danych jako wektorowych płytek JSON, które mają piksele dla geometrii subpikseli i uogólnioną geometrię dla tych funkcji, które będą faktycznie widoczne na pewnym poziomie. Wydajność jest świetna, ponieważ ta technika eliminuje wszystkie niepotrzebne informacje o wektorach i pozostawia tylko te wektory, które faktycznie będą miały wizualny wpływ na mapę. Piksele mają wypełnić luki i zostać umieszczone zamiast tych wektorów subpikseli. To samo dotyczy formatu kafelków.
Po stronie zaplecza jest prawdziwy ciężki podnoszenie. Nie korzystamy z TileStache ani żadnego innego silnika map, ponieważ napisaliśmy własny, który może przy pomocy wielu optymalizacji wygenerować taką grafikę wektorową w czasie rzeczywistym.
Najpierw zaczęliśmy od dostarczania kafelków map jako plików SWF, a ostatnio po prostu włączyliśmy wyjście do JSON, abyśmy mogli używać HTML5 Canvas do renderowania grafiki. Poniżej znajduje się punkt odniesienia porównujący tego rodzaju technologię wektorową z technologią rastrową (mapnik). Dla sprawiedliwego porównania szukaj tylko w trybie CGI.
http://www.giscloud.com/blog/realtime-map-tile-rendering-benchmark-rasters-vs-vectors/
Planujemy udostępnić tę technologię jako usługę hostingu kafelków map. Chodzi o to, aby przechowywać dane geograficzne w chmurze i poprzez HTML5 dostarczać je do dowolnego klienta mapy z dużą prędkością, bez potrzeby wstępnego buforowania kafelków. Jeśli chcesz dołączyć do tej wersji beta, skontaktuj się z nami tutaj: http://www.giscloud.com/contact/
źródło
Wygląda na to, że bardzo podobne pytanie zostało ostatnio zadane na forum OSGeo Open Layers , a programiści GIS Cloud opisują swoje podejście, które jest interesującą mieszanką geometrii GeoJSON i pikseli statycznych. W rzeczywistości generują wszystkie kafelki wektorowe w locie, zamiast używać wstępnie zbudowanej pamięci podręcznej plików GeoJSON.
Esri wdrożyło podobne podejście, wykorzystując ArcGIS Server i Feature Layers , które mogą uogólniać geometrie w locie i przesyłać je przewodowo jako JSON.
Dla prostej metody, którą możesz teraz zaimplementować, możesz budować kafelki wektorowe za pomocą Tilestache (która obsługuje PostGIS ) i konsumować je w Polymaps . Polymaps używa SVG, ale wydajność jest całkiem dobra , a CSS rządzi stylem elementów mapy, więc renderowanie funkcji zależy wyłącznie od Ciebie. Oto post na blogu opisujący coś podobnego do tego, o co pytasz.
źródło
Grałem w OpenLayers przy użyciu Canvas i uzyskałem rozsądne wyniki.
Jak wspomniano w innych odpowiedziach: aby dostarczyć i pokazać wektory w locie - należy je uogólnić dla każdego poziomu powiększenia i każdego zestawu danych. Możesz także użyć kodowania polilinii Google, aby znacznie zmniejszyć rozmiar.
Użyłem prostego mechanizmu dostarczania. Każda geometria była funkcją JavaScript w odpowiedzi HTTP JavaScript. nie tak zaawansowane jak dostarczanie wektorów oparte na kafelkach, ale proste i otwarte oprogramowanie!
Nie mogłem wypróbować Google Maps v3 z Canvas, ale widziałem kilka demonstracji New York Timesa, które zrobiły na mnie wrażenie.
źródło
Nie wiem dokładnie, z którego rozwiązania korzysta ta firma (możesz je zapytać bezpośrednio), ale mam pomysł.
Kluczowym rozwiązaniem w celu poprawy szybkości przesyłania i renderowania danych wektorowych jest uogólnienie ich zgodnie z poziomem powiększenia: Przesyłanie i renderowanie przy wysokim poziomie powiększenia tysiące obiektów zaprojektowanych dla znacznie niższego poziomu powiększenia jest często bardzo czasochłonne (a także bezużyteczne, ponieważ ostateczne wyświetlanie zwykle nie jest czytelne - patrz na przykład ten obraz ). Aby to zaimplementować, Twoja baza danych serwera Postgis musi być wieloskalowa : Dla każdego poziomu powiększenia powinna istnieć jedna reprezentacja obiektu odpowiedniego dla tego poziomu powiększenia. Te różne reprezentacje mogą być obliczane automatycznie przy użyciu technik generalizacji. Ponadto dane wektorowe wysyłane przez serwer do klienta nie powinny zależeć tylko od zasięgu przestrzennego, ale także od poziomu powiększenia: serwer wysyła odpowiednie dane w zależności od poziomu powiększenia. Takie podejście jest bronione w tym doskonałym artykule :-)
źródło
Jest ciekawy artykuł, wersja demonstracyjna i kod źródłowy oprogramowania opracowanego przez Stanford Visualization Group, które używają kostki danych dla każdego kafelka w celu wizualizacji i eksploracji dużego zbioru danych geograficznych. Można go używać tylko do zbioru danych punktowych, ale może być interesującym sposobem.
http://vis.stanford.edu/papers/immens
Vizzuality ze swoją platformą CartoDB i biblioteką o nazwie Torque eksperymentuje również w jaki sposób rysować duże ilości danych.
http://cartodb.github.io/torque/
https://github.com/CartoDB/torque/tree/new_torque
źródło