30 sty 2020

Jak do Open Street Map i Leaflet dodać routing - OSRM

Jak do Open Street Map i Leaflet dodać routing - OSRM
Słowo się rzekło, a więc o to krótki wpis o tym jak podłączyć ruting do OSM.
Będziemy opierać się o OSRM Open Source Routing Machine oraz skorzystamy z pluginu Leaflet Routing Machine.

Na wstępie uprzedzę że przykład może nie działać za każdym razem, będę używać nominatim.openstreetmap.org w wersji demo. W związku z tym pod każdym kodem będę zamieszczał "print screen" 😉

Nie jest to także opis instalacji środowiska, maszyny z bazą danych. Taki opis możecie znaleźć tutaj osrm backend, a jeżeli komuś się zamarzyło postawienie takiej maszyny u siebie lokalnie niech najpierw przeczyta ten opis disk and memory requirements 😉

Mapy OSM OpenStreetMap to tylko "kafelki" nie ma tam rutingu. Za ruting odpowiada osobna maszyna, którą sami stawiamy lub używamy tych dostępnych darmowych czy płatnych.

Najpierw zaczynamy pod podstawowego przykładu, samo wyświetlenie trasy wraz z opisem. Do html należy dodać style leaflet.css, leaflet-routing-machine.css oraz js leaflet.js, leaflet-routing-machine.js a także kawałek naszego kodu.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Leaflet Routing Machine Example</title>
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css" />
  <link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.css" />
  <style>
    html,
    body {
      height: 100%;
      margin: 0;
    }

    #map {
      width: 100%;
      height: 100%;
    }
  </style>
</head>
<body>
  <div id="map" class="map"></div>
  <script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet.js"></script>
  <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script>

  <script>
    let map = L.map('map');

    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}{r}.png', {
      attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    L.Routing.control({
      waypoints: [
        L.latLng(52.228, 21.008),
        L.latLng(52.231, 21.015)
      ]
    }).addTo(map);
  </script>

Jak widać kod nie jest skomplikowany wystarczy tylko 6 linijek kodu aby pojawiła się mapa.

L.Routing.control({
  waypoints: [
    L.latLng(52.228, 21.008),
    L.latLng(52.231, 21.015)
  ]
}).addTo(map);

Do kodu możemy dodać kilka przydatnych opcji:

let map = L.map('map');

L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}{r}.png', {
  attribution: '© OpenStreetMap contributors'
}).addTo(map);

L.Routing.control({
  waypoints: [
    L.latLng(52.228, 21.008),
    L.latLng(52.231, 21.015)
  ],

  // wskazówki serwowane w naszym języku,
  language: 'pl',

  // możliwość przesuwania drogi, 
  routeWhileDragging: true,

  // pokazuje alternatywne trasy oczywiście jeśli takie istnieją
  showAlternatives: true,
  
  // kolorowanie trasy
  altLineOptions: {
    styles: [
      {color: 'black', opacity: 0.15, weight: 9},
      {color: 'white', opacity: 0.8, weight: 6},
      {color: 'blue', opacity: 0.5, weight: 2}
    ]
  }
}).addTo(map);

Oczywiście opcji jest o wiele więcej, ale to już dla zainteresowanych leaflet-routing-machine api

Brakuje obecnie czegoś najważniejszego, a mianowicie formularzy z wyborem punktu A i B.
Do tego należy pobrać i umieścić u siebie Control.Geocoder, a także zmodyfikować nasz kod.

let map = L.map('map');

window.lrmConfig = {
  //    serviceUrl: 'https://api.mapbox.com/directions/v5',
  //    profile: 'mapbox/driving',
};

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

let control = L.Routing.control(L.extend(window.lrmConfig, {
  waypoints: [
    L.latLng(52.228, 21.008),
    L.latLng(52.231, 21.015)
  ],

  language: 'pl',
  geocoder: L.Control.Geocoder.nominatim(),
  routeWhileDragging: true,
  reverseWaypoints: true,
  showAlternatives: true,
  altLineOptions: {
    styles: [
      {color: 'black', opacity: 0.15, weight: 9},
      {color: 'white', opacity: 0.8, weight: 6},
      {color: 'blue', opacity: 0.5, weight: 2}
    ]
  }
})).addTo(map);

L.Routing.errorControl(control).addTo(map);

window.lrmConfig obiekt ten odpowiada za adres URL usługi routera. W związku z tym że nominatim jest ustawiony jako defaultowy ten obiekt zostawiamy pusty.
W kodzie pojawił się też jeden element, odpowiada za wywołanie usługi geocoder: L.Control.Geocoder.nominatim()

Więcej informacji możecie znaleźć na tej stornie leaflet-routing-machine

Dobra czas na małe podsumowanie

Nie jest to google maps i raczej nigdy nie będzie. Częstym rozwiązaniem stosowanym przez programistów jest otwieranie osobnej strony z rutingiem googlowym. Wiem że to dziwnie wygląda ale jeżeli potrzebuje się bardziej rozbudowanego wyglądu to nie ma opcji.
Jeżeli zaś wystarczy pokazać trasę z punktu A do punktu B to jak najbardziej można to wykorzystać.

Na plus:

  • darmowe ale też można podpiąć płatne serwery

Na minus:

  • czasami działa czasami nie, mówię o wersji nominatim
  • w porównaniu do google maps to taka wersja archaiczna, brak transportu, dróg pieszych, rowerowych czy samolotu
  • niestety ale jeżeli chcesz mieć własny serwer z rutingiem to jest dodatkowy koszt

Powiązane artykuły:

Alternatywa dla google maps – Open Street Map oraz Leaflet
Użycie GeoJson z Leaflet
Dodawanie, przesuwanie i kasowanie markerów – Leaflet
Centrowanie mapy uwzględniając szerokość diva – fitBounds leaflet
Jak dodać kolorowe markery w postaci svg oraz legendę do map z leaflet