www.gmapsapi.com

Kompleksowy kurs podstaw API, po którym mapowianie nie będzie miało przed Tobą żadnych tajemnic!

Setki przykładów, kursów i poradników z kodem gotowym do skopiowania i korzystania.

Największa strona o Google Maps API w Polsce, największe źródło informacji w języku polskim.

Własna mapa w Google Maps API

Ten artykuł dotyczy API w wersji 2

« powrót do listy poradników

Google Maps API może być stosowane niezależnie od warstw mapowych, dostarczanych przez Google. Przykładowo, często poszukiwanym poradnikiem przez graczy jest możliwość stworzenia mapy w API, która zamiast prawdziwych dróg i zdjęć wyświetlać będzie na przykład teren gry, i umożliwiać opisanie go za pomocą markerów i innych dobrodziejstw Google Maps. W tym poradniku pokażę, że jest to możliwe!

W tym poradniku będę używał do przycinania i przygotowania plików programu graficznego Corel Photo-Paint - równie dobrze można użyć innego edytora grafiki, zgodnego z własnymi upodobaniami.

Wstępne omówienie

Google Maps nie przechowuje zdjęć satelitarnych w jednym pliku - zamiast tego, wszystkie zdjęcia, na wszystkich poziomach przybliżenia są w rzeczywistości podzielone na małe obrazki o wymiarach 256 na 256 pikseli. Takie wymiary ma obraz, przedstawiający cały świat na najdalszym oddaleniu. Na przybliżeniu o jeden poziom więcej świat reprezentowany jest przez 4 małe fragmenty, każdy o tych samych wymiarach 256 x 256. Na kolejnym poziomie przybliżenia świat jest reprezentowany przez 16 małych fragmentów, również o tych samych wymiarach. Google Maps numeruje obrazki, by wiedzieć, który w danym momencie wyświetlić. Kiedy oglądasz obraz mapy, API przekazuje żądanie przesłania pliku graficznego z pewnego poziomu zoom, z określoną współrzędną X i Y. Współrzędne X i Y są w rzeczywistości liczbami całkowitymi, gdzie 0 to pierwszy element. Oznacza to, że na najdalszym oddaleniu, jedyny kawałek ma współrzędne (0,0). Na kolejnym oddaleniu kawałek w górnym lewym rogu ma współrzędne (0,0), w prawym górnym (1,0), w lewym dolnym (0,1) i w prawym dolnym (1,1). Analogicznie wygląda to na kolejnych poziomach. Oto wygląd podzielonej na kawałki mapy, który będziemy musieli uzyskać:

Sposób numeracji kawałków

Z tego co napisałem wynika jedna bardzo ważna rzecz: nie każdy obraz ma odpowiednie wymiary, by mógł zostać prawidłowo podzielony na kawałki. Przede wszystkim, powinien być kwadratem, a po drugie musi mieć wymiary (w pikselach) 256x256, 512x512, 1024x1024, 2048x2048, 4096x4096 lub dowolne, w których długość boku da się zapisać jako 256*2x, gdzie x to dowolna liczba naturalna. Po odpowiednich obróbkach, mapa którą wybrałem do tego przykładu (wymiary 1750 x 1550) będzie mogła być użyta.

Przygotowanie mapy

Ten krok jest potencjalnie najtrudniejszy ze wszystkich. Wymagany jest po pierwsze obrazek w wysokiej rozdzielczości z mapą, którą chcemy wyświetlać. Im więcej poziomów zoom chcemy udostępnić oraz im głębszy ma być to zoom, tym rozdzielczość mapy powinna być wyższa. Dla celów tego poradnika wybrałem mapę z gry Grand Theft Auto: Vice City:

https://realgta.net/realgta/files/libertycitymap.gif

Jak już wcześniej pisałem, specyfika działania API wymaga, by obraz z mapą był w odpowiedniej rozdzielczości. Mapa, którą wybrałem w tym przykładzie ma rozdzielczość 1750 x 1550. W takim wypadku są dwie opcje:

  1. Przeskalować mapę do jednej z pożądanych rozdzielczości
  2. Rozszerzyć mapę o puste pole, by obrazek miał ostatecznie jedną z pożądanych rozdzielczości

Wadą pierwszego rozwiązania jest utrata jakości, a także niemożność stosowania, gdy obraz nie jest kwadratem (bo wówczas przeskalowanie go spowoduje zniekształcenia). Dla celów omówienia w tym poradniku wybrałem więc opcję mieszaną. Stworzyłem obraz o wymiarach 2048 x 2048, wypełniłem kolorem niebieskim (kolor wody) a następnie wstawiłem na niego oryginalny obraz mapy i rozciągnąłem tak, by zajmował całą szerokość 2048 pikseli. Dzięki temu zachowałem proporcje oryginału, a jednocześnie mam plik o pożądanych wymiarach:

Rozciągnięty obrazek

Kawałkowanie

W tym kroku stworzymy kawałki, by API mogło szybko ładować mapę.

Przygotowany w poprzednim kroku obrazek zapisałem jako Z3.cpt, a jego kopie jako Z2.cpt, Z1.cpt i Z0.cpt. Kopie wykorzystamy później, najpierw dokończymy edycję obrazka Z3.cpt. Będzie on odpowiadał za największe przybliżenie. Obrazek ma wymiary 2048 x 2048, co oznacza, że zmieści się w nim 8 x 8 mniejszych obrazków o wymiarach 256 x 256 px. Wybieramy narzędzie kawałkowania w Corel Photo-Paint, i klikamy na ikonkę "jednakowe kawałki". Następnie podajemy, na ile częsci ma zostać podzielony obrazek - wpisujemy 8 w pionie i 8 w poziomie.

Obrazek zostanie podzielony, musimy go jeszcze tylko wyeksportować. Klikamy w menu na Plik > Eksport dla internetu. Zaznaczamy, że mają być eksportowane jedynie obrazki, i wybieramy katalog eksportu. Po kliknięciu ZAPISZ w wybranym katalogu powinny się pojawić 64 pliki, każdy zawierający wycinek dużej mapy.

Otwieramy plik Z2.cpt. Z menu wybieramy Obrazek > Zmień rozmiar / rozdzielczość i wpisujemy skalę 50%, a następnie klikamy OK. Obrazek zostanie przeskalowany do rozdzielczości 1024 x 1024. Łatwe dzielenie mówi, że teraz w obrazku zmieszczą się już tylko 4 x 4 kawałki o wymiarach 256 x 256 pikseli. Kawałkujemy więc obrazek na 4 w pionie i 4 w poziomie, a następnie eksportujemy, analogicznie jak w poprzednim kroku.

Obrazek w pliku Z1.cpt przeskalowujemy do 25%, to jest do wymiaru 512 x 512. Analogicznie jak poprzednio, kawałkujemy go (2x2) a następnie eksportujemy.

Obrazek w pliku Z0.cpt przeskalowujemy do rozmiaru 256 x 256. Będzie to najdalsze oddalenie, jakie można będzie uzyskać na mapie. Zapisujemy obrazek pod nazwą Z0R1C1.jpg (ponieważ ma on już wymiary 256 x 256, nie ma sensu go kawałkować).

W tym momencie powinniśmy mieć 85 plików, każdy o wymiarach 256 x 256. Pliki posiadają automatyczne nazwy, nadawane przez program Corel Photo-Paint. Przykładowo, nazwa pliku Z1R3C2.jpg oznacza, że dany obrazek jest wyświetlany na poziomie przybliżenia 1, w rzędzie 3 (R - skrót od angielskiego ROW) i w kolumnie 2 (C z angielskiego COLUMN). Numerowanie kolumn i wierszy programu Corel Photo Paint zaczyna się zawsze od 1. Tę małą niezgodność z API (gdzie numeracja jest od zera) skorygujemy później.

Z https://gmapsapi.com/examples/062/mapa-vc-kawalki.zip możesz pobrać spakowane archiwum ze wszystkimi kawałkami, przygotowanymi według powyższego opisu dla wybranej przeze mnie mapy.

Skrypt

Czas zabrać się za napisanie skryptu, który wyświetli mapę. Najpierw należy stworzyć obiekt, reprezentujący zbiór praw autorskich do zdefiniowanych obszarów mapy, oraz za notę, która będzie wyświetlana:

var prawaAutorskie = new GCopyrightCollection('Mapa');
var nota = new GCopyright(1,new GLatLngBounds(new GLatLng(-90, -180),new GLatLng(90, 180)),0,"© Rockstar Games");

Pierwszym argumentem w konstruktorze GCopyrightCollection() jest wyświetlany przed prawami autorskimi prefix. Warto zwrócić uwagę na drugi i trzeci argument w konstruktorze obiektu GCopyright - odpowiadają one za zakres współrzędnych mapy. W większości przypadków najlepiej pozostawić to tak, jak w powyższej linijce, zmieniając jedynie zawartość ostatniego ciągu tekstowego.

Teraz dodajemy notę do obiektu, odpowiadającego za prawa autorskie:

prawaAutorskie.addCopyright(nota);

Najważniejszym zadaniem jest poinstruowanie API o istnieniu naszych obrazków i o ich adresie URL:

var kawalki = [new GTileLayer(prawaAutorskie,0,3)];
kawalki[0].getTileUrl = function (p,z)
{
	var zoom 	= z;
	var rzad 	= p.y + 1;
	var kolumna	= p.x + 1;
	if(zoom >= 0 & zoom <4 && rzad >0 && rzad <= Math.pow(2,zoom) && kolumna > 0 && kolumna <= Math.pow(2,zoom))
		return "https://gmapsapi.com/examples/062/mapa/Z"+zoom+"R"+rzad+"C"+kolumna+".jpg";
	else
		return '';
}

W pierwszej linijce liczba 0 oznacza minimalny, a 3 maksymalny poziom przybliżenia. Funkcja getTileUrl() będzie wywoływana przez API za każdym razem, gdy zajdzie konieczność ustalenia adresu obrazka do wyświetlenia. Pierwszy przekazywany argument mówi o współrzędnych (odpowiednio we własnościach x i y), a drugi o poziomie zoom. Mając dane te informacje, możemy skonstruować adres obrazka. Nazewnictwo kawałków, które przygotowaliśmy wygląda tak: Z{K}R{L}C{M}, gdzie {K} to poziom zoom, {L} to współrzędna Y, ale numerowana od jedynki, a {M} to współrzędna X, również numerowana od jedynki. Skorygujemy to niedociągnięcie, dodając jeden do współrzędnej przekazywanej przez API, i zwrócimy ciąg, określający URL żądanej grafiki.

Ostatni etap pracy polega na stworzeniu nowego trybu mapy:

var mapaGTA = new GMapType(kawalki, G_NORMAL_MAP.getProjection(), "Mapa", {errorMessage:"Brak obrazka"});

Ten kod tworzy nowy tryb mapy, korzystającej z projekcji domyślnej. W razie braku obrazka, zostanie wyświetlony komunikat "brak obrazka". Wszystkie powyższe rzeczy powinny znaleźć się przed inicjalizacją mapy, która powinna wyglądać mniej więcej tak:

mapa = new GMap2(document.getElementById("mapka"),{mapTypes: [mapaGTA]});
mapa.addControl(new GLargeMapControl());
mapa.setCenter(new GLatLng(5.965753671065536,61.171875),2);	

Tak stworzona aplikacja powinna elegancko wyświetlać kawałki obrazka, stwarzając pozory "ciągłości". Gratuluję, jedno z najtrudniejszych zagadnień w dziedzinie Google Maps API rozgryzione!