Wprowadzenie

Omówienie mechanizmu Geocoding jest trzecim wpisem dotyczącym Google Maps. W pierwszym z nich dokonaliśmy odpowiedniej konfiguracji, wygenerowaliśmy klucz oraz zaznaczyliśmy na mapie przykładową lokalizację.

Kolejny wpis to wykorzystanie mechanizmu geolokalizacji oraz śledzenie na żywo naszej lokalizaji wraz z zaznaczeniem jej na mapie. Przydatne w przypadku aplikacji takich jak Uber czy Bolt.

W trakcie mojego następnego projektu „po godzinach" natknąłem się na kolejny problem. Potrzebuję utworzyć mapę w stylu tej znanej z Airbnb. Zarejestrowani użytkownicy podają swoje dane adresowe (nie są widoczne) a te muszą zostać naniesione na mapę i dynamicznie odświeżane w momencie zmiany kryteriów wyszukiwania. W tym artykule omówimy problemy konfiguracyjne, które napotkamy oraz naniesiemy na mapę kilka lokalizacji na bazie prawdziwnych danych adresowch.

Geocoding

Z uwagi na zmianę polityki Google korzystanie z map nie jest już takie proste. Wprowadzane zmiany wymagają odpowiedniej konfiguracji płatności, aby uniknąć wyświetlania map w poniższy sposób: GeocodingAPI: włączanie API W poprzenich wpisach posługiwaliśmy się taką mapą na potrzebny (jedynie) naszego artykułu. Tym razem musimy podpiąć płatności ponieważ chcąc wywołać odpowiedni kod możemy zobaczyć taki komunikat w oknie konsoli naszej przeglądarki: GoogleAPI: błąd konsoli

Jako potwierdzenie tej wiadomości warto przejść na oficjalną stronę – tam również zobaczymy odpowiedni komunikat: GeocodingAPI: klucz i płatności

Nie jest to jednak tak straszne jak się wydaje. Google każdego miesiąca przyznaje nam limit 200$ na wykorzystanie – na potrzeby programistyczne i małych projektów wystarczy bez żadnych problemów.

Konfiguracja

Pierwszą wymaganą od nas rzeczą jest posiadanie odpowiedniego klucza API - jeżeli jeszcze nie posiadacie zapraszam do pierwszego z serii wpisu: ASP.NET Core – Google Maps API

Kolejny krok to włącznie Geocoding API - w przeciwnym wypadku będziemy dostawać w konsoli poniższy błąd: GeocodingAPI: włączanie API

Przechodzimy do naszego konta Google Cloud Platform przy pomocy adresu: Google Cloud Platform Console
W kolejnym kroku wykorzystujemy panel wyszukiwania wpisując Geocoding API. Efektem jest przeniesienie na ekran konfiguracji wyglądający następująco: GeocodingAPI: włączanie usługi

Wystarczy włączyć interfejs a powyższy błąd nie będzie się już pojawiał. Przed nami ostatni etap konfiguracji, podpięcie konta w celu konfiguracji płatności z zaznaczeniem limitu, którego nie chcemy przekroczyć – wykorzystamy jedynie 200$ comiesięcznego limitu dostępnego po konfiguracji konta.

Płatności

Podpięcie płatności nie jest procesem skompikowanym. Czasami można pogubić się w mnogości opcji ale mam nadzieje, że będziecie w stanie przejść przez kolejne etapy bez żadnych problemów (praktycznie każdy krok to osobny zrzut ektanu). Na pierwszym etapie musimy przejść do swojego konta Google Cloud Platform wybierając ‘Panel informacyjny’ w celu podpięcia płatności: GeocodingAPI: dodawanie płatności W następnym kroku dodamy konto rozliczeniowe dla wybranego projektu: GeocodingAPI: dodawanie płatności Pamiętajcie, że w ramach jednego konta możemy posiadać wiele projektów, które będą korzystały z limitu płatności w wysokości 200$. Następnego etapu nie będę pokazywał publicznie – dane wrażliwe. Niestety, karty takie jak Revolut nie są obsługiwane. Po poprawnej weryfikacji naszej karty możemy zobaczyć poniższy komunikat: GeocodingAPI: potwierdzenie Możecie zobaczyć, że dodatkowo dostałem 300$ - jest to promocja dla nowych klientów w celu wypróbowania różnych usług. Po zamknięciu okna dialogowego zobaczycie „ekran powitalny" platformy z interesującą nas sekcją Pricing for Maps, Routes, and Places: Google Cloud Platform: strona główna Przechodzimy dalej klikając: GET STARTED.
Pojawi się kolejne okno pozwalające na włączenie platformy Google Maps: Google Cloud Platform: włączenie najwazniejszych usług Przez kolejne kroki przechodzimy wybierając odpowiednie „parametry" z list rozwijalnych: Google Clod Platform: konfiguracja Przeszliśmy przez wszystkie kroki, jesteśmy gotowi do rozpoczęcia pracy. Boicie się, że limit 200$ to za mało? Takie środki(w skali miesiąca) pozwalają nam na poniższe:

  • do 28 000 darmowych załadowań map dynamicznych (mapy, które po otwarciu pozostają interaktywne i gotowe na nasze interakcje) lub
  • do 100 000 darmowych odsłon map statycznych (mapy, które są obrazkiem, zrzutem ekranu) lub
  • do 40 00 darmowych zapytań związanych z wyznaczeniem kierunku lub
  • do 40 000 darmowych zapytań związanych z geolokalizacją
Jak widzicie...nawet na potrzeby działających projektów (we wczesnej fazie) są to wartości wystarczające. Co jeżeli jednak boicie się, że przekroczycie ten limit? Zapraszam do następnej sekcji.

Google Maps za darmo

Jak upewnić się, że nie przekroczymy budżetu 200$? Możemy skorzystać z funkcjonalności jaką jest zarządzanie budżetami. Otwieramy główny panel znajdujący się pod adresem https://console.cloud.google.com a następnie z panelu po lewej wybieramy sekcję Płatności. Zostaniemy przekierowani na dashboard: Google Cloud Platform: dashboard Z tego miejsca wybieramy z panelu po lewej stronie Budżet i alerty.
Tworzymy budżet przechodząc przez 3 proste kroki wg. poniższego schematu: Google Cloud Platform: tworzenie budżetu

Jest jeszcze drugi sposób jeżeli chcemy zredukować prawdopodobieństwo przekroczenia limitu. Przechodząc przez ustawienia poszczególnych interfejsów możemy ustawić limity indywidualne. Możemy np. ustawić dzienny limit zapytań do danego API: Google Cloud Platform: limit wywołań API

Konfiguracja została zakończona. Jako potwierdzenie, że wszystko przebiegło pomyślnie odwołamy się do poprzedniego artykułu celem sprawdzenia kilku zapytań do API.

Uruchomienie aplikacji bez odpowiedniej konfiguracji konta: Google API: brak konfiguracji konta Uruchomienie aplikacji z użyciem nowego klucza API i podpiętymi płatnościami (mała rzecz a naprawdę cieszy): Google API: poprawna konfiguracja

Geolokalizacja

Cały proces konfiguracji jest już za nami – wszystko działa poprawnie. Możemy przejść do właściwej implementacji naszych wymagań. W pierwszym kroku spróbujemy przekonwertować nazwę miasta na współrzędne geograficzne i zaznaczyć daną lokalizację na mapie.

Kod JavaScript oraz zapytanie do Geocoding API pozwolą nam na wyświetlenie długości i szerokości geograficznej. Jeżeli wszystko przebiegnie pomyślnie w oknie przeglądarki zobaczymy stosowany komunikat:

$(document).ready(function () {

        var geocoder = new google.maps.Geocoder();
        var address = "Gdynia";

        // Używamy GeocodingAPI w celu zmiany adresu na dane geograficzne
        // Długość i szerokość geograficzna pozwalają na zaznacznie 'lokalizacji' na mapie
        geocoder.geocode({ 'address': address }, function (results, status) {

            if (status == google.maps.GeocoderStatus.OK) {
                var latitude = results[0].geometry.location.lat();
                var longitude = results[0].geometry.location.lng();
                alert("szerokosc: " + latitude + "\ndlugosc: " + longitude);
            } else {
                debugger;
                console.log(results);
            }
        });

    });
Podstawowe wywołanie działa bez problemów. Pamiętajcie, żeby po konfiguracji platności oraz klucza odczekać conajmniej 10 minut – jest to wymagany czas na odświeżenie danych po stronie Google.

W następnym kroku zaznaczymy daną lokalizację na mapie. W tym celu musimy nieco zmodyfikować nasz kod interfejsu użytkownika oraz dodać kilka linii kodu HTML:

<script type="text/javascript">

    $(document).ready(function () {

        var geocoder = new google.maps.Geocoder();
        var address = "Gdynia";

        // Używamy GeocodingAPI w celu zmiany adresu na dane geograficzne
        // Długość i szerokość geograficzną pozwalają na zaznacznie 'lokalizacji' na mapie
        geocoder.geocode({ 'address': address }, function (results, status) {

            if (status == google.maps.GeocoderStatus.OK) {
                var latitude = results[0].geometry.location.lat();
                var longitude = results[0].geometry.location.lng();
                //alert("szerokosc: " + latitude + "\ndlugosc: " + longitude);

                // tworzymy instancję nowej mapy z odpowiednim powiększeniem, punktem centralnym i typem mapy:
                // typy map: roadmap, satellite, hybrid oraz terrain
                // punkty startowe to pierwszy element kolekcji
                var map = new google.maps.Map(document.getElementById('map'), {
                    zoom: 14,
                    center: { lat: latitude, lng: longitude },
                    mapTypeId: 'terrain'
                });


                // Na nasza mapę naniesiemy teraz naszą "lokalizację"
                var gdynia = { lat: latitude, lng: longitude };

                var marker = new google.maps.Marker({ position: gdynia, map: map });

            } else {
                debugger;
                console.log(results);
            }
        });

    });
</script>
<style>
    /* Zawsze ustawiaj wysokość mapy w sposób jawny, aby określić (tym samym) rozmiar kontenera div */
    #map {
        height: 100%;
        width: 100%;
        position: static !important;
    }
</style>

<div id="map"></div>

<script src="https://maps.googleapis.com/maps/api/js?key=PODAJ_SWOJ_KLUCZ_DOSTEPU_GOOGLE_MAPS">
</script>

A efekt naszej implementacji prezentuje się w poniższy sposób: Google Maps API: Gdynia

Został nam ostani krok. Spróbujemy na mapie zaznaczyć 10 różnych lokalizacji, które będą stanowiły punkt wyjściowy do przygotowania wyszukiwarki bazującej na tej znanej z Airbnb. Ponownie musimy wprowadzić kilka istotnych zmian w naszej implementacji. Poniżej kod wraz z komentarzami:

<script type="text/javascript">

    $(document).ready(function () {

        var geocoder = new google.maps.Geocoder();

        // Definiujemy tablicę przykładowych adresów na terenie Warszawy
        var addressess = [
            "Warszawa, Widawska 45",
            "Warszawa, Sokołowska 6",
            "Warszawa, Elekecyjna 81",
            "Warszawa, Czardasza 14",
            "Warszawa, Fińska 33",
            "Warszawa, Drużynowa 8",
            "Warszawa, Argentyńska 141",
            "Warszawa, Pratulińska 14",
            "Warszawa, Dojazdowa 145",
            "Warszawa, Margerytki 28"
        ];

        // Centralnym punktem na naszej mapie będzie Warszawa
        var city = "Warszawa";

        // Używamy GeocodingAPI w celu zmiany adresu na dane geograficzne
        // Długość i szerokość geograficzną pozwalają na zaznacznie 'lokalizacji' na mapie
        geocoder.geocode({ 'address': city }, function (results, status) {

            if (status == google.maps.GeocoderStatus.OK) {
                var latitude = results[0].geometry.location.lat();
                var longitude = results[0].geometry.location.lng();

                // tworzymy instancję nowej mapy z odpowiednim powiększeniem, punktem centralnym i typem mapy:
                // typy map: roadmap, satellite, hybrid oraz terrain
                var map = new google.maps.Map(document.getElementById('map'), {
                    zoom: 12,
                    center: { lat: latitude, lng: longitude },
                    mapTypeId: 'terrain'
                });

                // Musimy dokonać iteracji po zdefiniowanych adresach celem uzyskać współrzędnych geograficznych
                for (i = 0; i < addressess.length; i++) {
                    geocoder.geocode({ 'address': addressess[i] }, function (results, status) {
                        if (status == google.maps.GeocoderStatus.OK) {
                            var latitude = results[0].geometry.location.lat();
                            var longitude = results[0].geometry.location.lng();

                            var cordinates = { lat: latitude, lng: longitude };
                            var marker = new google.maps.Marker({ position: cordinates, map: map });
                        } else {
                            console.log(status);
                        }
                    });
                }


            } else {
                debugger;
                console.log(status);
            }
        });

    });
</script>
A po uruchomieniu aplikacji możemy zobaczyć poniższy rezultat: Google API: mapa warszawy

Interaktywne markery

Nie miałem pomysłu jak nazwać ten nagłówek. Jeżeli chcemu uzyskać więcej szczegółów dotyczących wskazanej lokalizacji możemy wykorzystać tzw. InfoWindow. Pozwalają nam na wyświetlenie dodatkowych informacji, jak np. adres czy współrzędne geograficzne zaznaczone na mapie. Wprowadzimy nieznacze modyfikacje w naszym kodzie, dodamy jedną funkcję, aby poprawić czytelność całej implementacji:

<script type="text/javascript">

    // Metoda dokonująca zmiany adresu na współrzędne geograficzne
    function Geocode(address, map, iterator) {

        var geocoder = new google.maps.Geocoder();
        var infowindow = new google.maps.InfoWindow();

        geocoder.geocode({ 'address': address }, function (results, status, i) {
            if (status == google.maps.GeocoderStatus.OK) {

                // szerokość i długość geograficzna
                var latitude = results[0].geometry.location.lat();
                var longitude = results[0].geometry.location.lng();

                var cordinates = { lat: latitude, lng: longitude };
                // definicja znacznika
                var marker = new google.maps.Marker({ position: cordinates, map: map });

                // zdarzenie definicujące InfoWindow zawierające adres zaznaczonej lokalizacji
                google.maps.event.addListener(marker, 'click', (function (marker) {
                    return function () {
                        infowindow.setContent(address);
                        infowindow.open(map, marker);
                    }
                })(marker, i));
            } else {
                console.log(status);
            }
        });
    }

    $(document).ready(function () {

        var geocoder = new google.maps.Geocoder();

        // Definiujemy tablicę przykładowych adresów na terenie Warszawy
        var addressess = [
            "Warszawa, Widawska 45",
            "Warszawa, Sokołowska 6",
            "Warszawa, Elekecyjna 81",
            "Warszawa, Czardasza 14",
            "Warszawa, Fińska 33",
            "Warszawa, Drużynowa 8",
            "Warszawa, Argentyńska 141",
            "Warszawa, Pratulińska 14",
            "Warszawa, Dojazdowa 145",
            "Warszawa, Margerytki 28"
        ];

        // Centralnym punktem na naszej mapie będzie Warszawa
        var city = "Warszawa";

        // Używamy GeocodingAPI w celu zmiany adresu na dane geograficzne
        // Długość i szerokość geograficzną pozwalają na zaznacznie 'lokalizacji' na mapie
        geocoder.geocode({ 'address': city }, function (results, status) {

            if (status == google.maps.GeocoderStatus.OK) {
                var latitude = results[0].geometry.location.lat();
                var longitude = results[0].geometry.location.lng();

                // tworzymy instancję nowej mapy z odpowiednim powiększeniem, punktem centralnym i typem mapy:
                // typy map: roadmap, satellite, hybrid oraz terrain
                var map = new google.maps.Map(document.getElementById('map'), {
                    zoom: 12,
                    center: { lat: latitude, lng: longitude },
                    mapTypeId: 'terrain'
                });

                // Musimy dokonać iteracji po zdefiniowanych adresach celem uzyskania współrzędnych geograficznych
                for (var i = 0; i < addressess.length; i++) {
                    var specifcAddress = addressess[i];
                    console.log("outside", i);

                    // Każdy adres zostanie przetworzony przez funkcję Geocode
                    Geocode(addressess[i], map, i);
                }
            } else {
                debugger;
                console.log(status);
            }
        });

    });
</script>
A tak wygląda rezultat naszej implementacji po wskazaniu kilku znaczników: Info window dla google maps

Podsumowanie

Mam nadzieję, że przygotowany wpis wyczerpuje temat związany z mechanizmem geolokalizacji. Przeszliśmy przez niezbędą konfigurację, dodaliśmy i opisaliśmy wszystkie przeszkody napotkane po drodze. W efekcie byliśmy w stanie zaznaczyć na mapie przykładowe adresy nie dysponując współrzędnymi geograficznymi, które potrzebne są do poprawnego rozlokowania znaczników na mapie.