Kawałek Kodu

Nie wszyscy chcą spędzać wakacje w jednym miejscu, bo to nie wakacje. Znajomi polecają jakieś miejscówki, ale nazwa miejscowości często nic nam nie mówi. Chcemy sprawdzić gdzie dokładnie znajduje się miejsce, zanim się tam wybierzemy. Na przyszłość będziemy wiedzieć gdzie mamy się kierować, ale już w momencie planowania możemy zaczerpnąć więcej wiedzy na temat okolicy wymarzonego celu (czytaj: czy są tanie puby).

Nominatim - "Po nazwie".

Skoro wiemy już jak korzystać z mapy elektronicznej, to możemy w naszej podróży po Leaflet.js zrobić krok dalej. Google Maps mają swoje API do geodekodowania, czyli przekształcania adresów na współrzędne, ale Open Street Map nie są gorsze. Dla nich istnieje serwis Nominatim i ten dziś wykorzystamy. Serwis znajduje się pod domeną nominatim.openstreetmap.org i mając ten adres możemy zacząć odpytywać o wyszukane lokalizacje. Nie będę kopiował dokumentacji na Wiki (na końcu podaję link), ale po krótce:

  • możemy podawać ogólne dane adresowe jako paramter q lub rozbite na szczegóły (city, street, itd.),
  • zwrotkę otrzymujemy w jednym z wybranych formatów: xml, html, json,
  • wyniki (jeśli jest kilka) są sortowane według trafności (atrybut importance w odpowiedzi), możemy ograniczać do wybranej ilości (parametr limit),
  • możemy ograniczać do obszaru (viewbox),
  • możemy wykluczać lokalizacje o wybranych id (są to wartości parametru place_id),
  • możemy wyciągać dodatkowe informacje o lokalizacji (parametr extratags), jak np. godziny otwarcia, czy można palić, adres oficjalnej strony internetowej,
  • w odpowiedzi jest informacja o licencji i takową notkę powinniśmy zawrzeć na mapie (nie wiem czy są różne licencje w zależności od obszarów lokalizacji, ale wydaje mi się, że można taką notkę zawrzeć na stałe przed uzyskaniem odpowiedzi o daną lokalizację),
  • możemy pytać maksymalnie o 1 lokalizację na sekundę przesyłając prawidłowy User-Agent.

Przykładowe zapytanie dla Warszawy: https://nominatim.openstreetmap.org/search?format=json&q=Warszawa

I zapytania z ekstratagami:
https://nominatim.openstreetmap.org/search?format=json&q=Krak%C3%B3w%20pub&extratags=1
https://nominatim.openstreetmap.org/search?format=json&q=Krak%C3%B3w%20church%20near&extratags=1

Można też szukać punkty charakterystyczne w pobliżu danego punktu (tu szkoły w okolicach ul. Piotrkowskiej w Łodzi):
https://nominatim.openstreetmap.org/search?format=json&q=school%20near%20[51.745835,19.461556]

To co nas interesuje w odpowiedzi, to oczywiście wartości lat i lon dla najbardziej trafnego punktu, czyli latitude (szerokość geograficzna) i longitude (długość geograficzna). Mając te wartości możemy w podobny sposób do Google Maps pozycjonować mapę i/lub oznaczać punkt.

No, dobra, nie ma co gadać o czymś co nie jest rocket science.

<div id="map"></div>
<form>
  <input type="text" />
  <button type="submit">Znajdź</button>
</form>

+

/* inicjujemy mapę jak
   w poprzednim wpisie
*/
const map = new L.Map(document.getElementById("map"));
const tilesUrl = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
const mapAttrib =
  'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors. Data © OpenStreetMap contributors, ODbL 1.0. <a href="https://openstreetmap.org/copyright">Copyright</a>.';

const layer = new L.TileLayer(tilesUrl, {
  minZoom: 8,
  maxZoom: 20,
  attribution: mapAttrib
});

const center = new L.LatLng(51.745835, 19.461556);
map.setView(center, 15);
const marker = L.marker(center);
marker.addTo(map);
map.addLayer(layer);

/* dodajemy obsługę
   prostego formularza
   z jednym polem na
   wpisanie adresu
*/
document.querySelector("form").addEventListener("submit", function(e) {
  e.preventDefault();
  const query = this.querySelector("input").value;
/* wysyłamy żądanie
   z wpisanym adresem
*/
  fetch(
      `https://nominatim.openstreetmap.org/search?format=json&limit=1&q=${query}`
    )
/* wiemy, że odpowiedź
   będzie w formacie JSON,
   więc ją dekodujemy
*/
    .then(resp => resp.json())
/* mają JSON pobieramy
   współrzędne pierwszej
   i jedynej (limit=1)
   lokalizacji
*/
    .then(resp => {
      if (resp.length > 0) {
        const center = new L.LatLng(resp[0].lat, resp[0].lon);
/* centrujemy mapę
   i ustawiamy marker
*/
        map.setView(center, 15);
        marker.setLatLng(center);
      }
    });
});

I działanie:

Jeśli nie znalazłeś dla siebie najlepszego miejsca, to zawsze jesteś mile widziany na tym blogu. Do przeczytania!

 

Przydatne linki:
Dokumentacja Nominatim na Wiki
"Roznosiciel ulotek", czyli o Leaflet.js i mapach S01E01.