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.

Wczytanie najbliżej położonych punktów

Ten artykuł dotyczy API w wersji 2

« powrót do listy poradników

Często pojawiającym problemem przy okazji bardziej złożonych aplikacji jest możliwość wyświetlenia z bazy tylko tych markerów, które zawarte są w pewnej odległości od dowolnego miejsca. Jest to bardzo praktyczne, oto krótka lista rzeczy, które można dzięki temu osiągnąć:

  • wyszukiwanie kontaktów lub firm w pewnym rejonie
  • wyświetlanie lokalów oddalonych najmniej od klikniętego punktu
  • analogicznie, wyświetlanie lokalów oddalonych najmniej od pewnego adresu (w połączeniu z usługą geokodowania)
  • i wiele innych

W tym poradniku do znalezienia najbliższych markerów została użyta tabela w bazie MySql i odpowiednio skierowane do niej zapytanie.

Konstrukcja tabeli

W celu zaprezentowania funkcjonalności liczenia odległości, potrzebna będzie tabela w bazie danych. Poniższe zapytanie stworzy tabelę, posiadającą pola id (klucz główny), nazwa, adres, lat i lng (współrzędne geograficzne):

CREATE TABLE `PoznajGoogleMaps_markery` (
  `id` int(11) NOT NULL auto_increment,
  `nazwa` varchar(50) NOT NULL,
  `adres` varchar(100) NOT NULL,
  `lat` float(10,6) NOT NULL,
  `lng` float(10,6) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1

Wstawienie danych do tabeli

Teraz potrzebujemy dane. Najprawdopodobniej w chwili czytania posiadasz już jakiś swój zestaw danych, dla celu tego przykładu posłużę się bazą lokalizacji pizzeri, znalezioną w gąszczu stron dokumentacji Google. Kopię pliku CSV znajdziesz pod tym adresem:

http://gmapsapi.com/download/przykladowe_dane_pizzerie.csv

W pliku tym separatorem jest przecinek. W programie phpMyAdmin istnieje opcja importowania danych z pliku CSV, dla stworzonej przed chwilą tabeli należy podać poniższe wartości:

parametry importu pliku CSV

Po zaimportowaniu pozostaje sprawdzenie zawartości tabeli. Wszystko wydaje się być w porządku:

dane w tabeli

Zapytanie SQL

Zapytanie SQL, pozwalające znaleźć odległość między dwoma punktami w układzie geograficznym z uwzględnieniem kulistości Ziemii nie jest proste. Przyjmując, że:

  • X1 oznacza długość geograficzną pierwszego z punktów
  • X2 oznacza długość geograficzną drugiego z punktów
  • Y1 oznacza szerokość geograficzną pierwszego z punktów
  • Y2 oznacza szerokość geograficzną drugiego z punktów

oraz że odległość ma zostać wyrażona w kilometrach poprawny jest następujący wzór:

odległość(km) = 6371 * acos( cos(Y1) * cos(Y2 ) * cos(X2 - X1) + sin(Y1 ) * sin(Y2))

Ten wzór można wykorzystać na wiele sposobów, między innymi na znalezienie odległości lokalu zapisanego w tabeli od pewnego konkretnego miejsca.

Trzymając się nazewnictwa, jakie zostało podane przy tworzeniu tabeli, wyświetlenie wszystkich punktów w bazie wraz z ich odległościami od punktu o współrzędnych (37,-122) wyglądać będzie następująco:

SELECT id, nazwa, adres, ( 6371 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS dystans
FROM PoznajGoogleMaps_markery;

Wywołanie zapytania da następujący efekt:

wyniki zapytania

Działa idealnie. Aby posortować dane, należy dodać do zapytania SQL fragment ORDER BY dystans:

SELECT id, nazwa, adres, ( 6371 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS dystans
FROM PoznajGoogleMaps_markery
ORDER BY dystans

Aby dodatkowo ograniczyć maksymalną liczbę wyników do np. 20, należy jeszcze dopisać LIMIT 0,20:

SELECT id, nazwa, adres, ( 6371 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS dystans
FROM PoznajGoogleMaps_markery
ORDER BY dystans
LIMIT 0,20

A jak ograniczyć się jedynie do lokalizacji, oddalonych o nie więcej niż X kilometrów? Należy użyć konstrukcji HAVING dystans <= X:

SELECT id, nazwa, adres, ( 6371 * acos( cos( radians(37) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * sin( radians( lat ) ) ) ) AS dystans
FROM PoznajGoogleMaps_markery
HAVING dystans <= 20
ORDER BY dystans
LIMIT 0,20

Uwaga, HAVING i WHERE nie są zamienne - użycie WHERE wygeneruje błąd, ponieważ w tabeli nie istnieje fizycznie pole o nazwie "dystans"! Dopiero po jego obliczeniu możemy za pomocą HAVING sprawdzać jego wartość.

Zadanie zapytania i wygenerowanie pliku XML z danymi wynikowymi

Plik dane.php zawiera skrypt, generujący wyniki zapytania w XMLu. W celu wygenerowania rezultatów, należy uruchomić go z parametrami lat i lon przypisując im odpowiednio szerokość i długość geograficzną punktu, od którego będzie liczona odległość. Opcjonalnie można również zmienić długość promienia oraz maksymalną liczbę zwracanych wyników:

$lat = (float) $_GET['lat'];
$lng = (float) $_GET['lng'];

if($_GET['promien'])
	$promien = (float) $_GET['promien'];
else
	$promien = 50;
	
if($_GET['ilosc'])
	$ilosc = (int) $_GET['ilosc'];
else
	$ilosc = 20;

/* ... wycięty fragment ... */	

mysql_query("SET NAMES 'UTF8';");

$zapytanie = sprintf("SELECT id, lat, lng, nazwa, adres, ( 6371 * acos( cos( radians(%f) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(%f) ) + sin( radians(%f) ) * sin( radians( lat ) ) ) ) AS  dystans FROM PoznajGoogleMaps_markery HAVING dystans < %f ORDER BY dystans ASC LIMIT 0,%d;",$lat,$lng,$lat,$promien,$ilosc);
$pobierz = mysql_query($zapytanie);

print "\n<dane>\n";

while($dane = mysql_fetch_array($pobierz))
{
	printf("\t<marker lat=\"%f\" lon=\"%f\" nazwa=\"%s\" adres=\"%s\" dystans=\"%.4f\" />\n",$dane['lat'],$dane['lng'],htmlspecialchars($dane['nazwa']),htmlspecialchars($dane['adres']),$dane['dystans']);
}

print "</dane>";

Pełny kod skryptu dostępny jest tutaj: http://gmapsapi.com/examples/055/dane.php.txt

Skrypt, wywołany z następującymi parametrami: ?lat=37&lng=-122&ilosc=10&promien=40 da następujący rezultat. Świetnie! Czas zaprogramować aplikację po stronie klienta.

Przykładowa aplikacja

W aplikacji tej użytkownik będzie mógł kliknąć myszą na mapie - gdy to zrobi, skrypt wczyta dane lokalów, znajdujących się w promieniu 40 kilometrów od klikniętego punktu, i wyświetli je na mapie. W celu uatrakcyjnienia przykładu, skrypt pozwala również na:

  • dodanie klikalnych linków do markerów w pasku bocznym
  • wyświetlenie napisu "ŁADOWANIE" w trakcie wczytywania danych
  • po wczytaniu markerów mapa zostanie wycentrowana tak, by wszystkie markery były widoczne bez konieczności przesuwania

Przykład jest kompilacją różnych wcześniejszych przykładów:

Oto efekt: przykład 1pokaż kod przykładu

Zaznaczanie obszaru wokół

W kolejnym przykładzie dodano okrąg o promieniu 20 km, który pokazuje się po kliknięciu. Ułatwia on wyobrażenie o tym, w jakim obszarze poszukiwane są markery. Polecam samodzielną analizę funkcji rysujOkrag(): przykład 2pokaż kod przykładu

Polecane artykuły

Dodaj stronę do ulubionego serwisu społecznościowego

Oto, co najczęściej czytają internauci, którzy przeczytali ten artykuł:

Dodawanie znaczników na mapę

API v2

Kurs podstaw cz. II: Podstawowe informacje na temat wstawiania markerów (znaczników)


Dodawanie markerów przez użytkownika

API v2

Poradnik pokazuje, w jaki sposób stworzyć formularz, pozwalający na dodawanie markerów


Popularne, darmowe ikony dla markerów

API v2

Kurs podstaw cz. IV: Lista darmowych ikon do wykorzystania w Twojej aplikacji mapowej


Kategorie markerów i polilinii

API v2

Stwórz markery/polilinie w kilku kategoriach, a następnie ukrywaj i pokazuj wybrane kategorie