16 cze 2020

Użycie GeoJson z Leaflet

Wracamy do serii artykułów w których opisuję różne użycia Leaflet. Dzisiaj poruszymy temat GeoJson.

GeoJson jest to nic innego jak plik JSON, który reprezentuje cechy geograficzne. Nie posiada on formalnych standardów, może reprezentować punty, adresy i lokalizacje, kraje, prowincje i wiele innych elementów. Zerknijcie na wpis w wiki


Poniżej przykład pliku geojson:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "place"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              16.54541015625,
              49.724479188712984
            ],
            [
              24.01611328125,
              49.724479188712984
            ],
            [
              24.01611328125,
              53.74871079689897
            ],
            [
              16.54541015625,
              53.74871079689897
            ],
            [
              16.54541015625,
              49.724479188712984
            ]
          ]
        ]
      }
    }
  ]
}

Naszym przykładem będzie pokazanie Polski z podziałem na województwa. Po najechaniu na poszczególne województwo otworzy się popup z województwem do tego zmienimy kolor poligonu. Dodamy także do lewego rogu pole w którym również pojawi się nazwa województwa w które kliknęliśmy bądź najechaliśmy na nie myszką.
Zaczynamy od podstawowego HTML.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>simple map</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.js"></script>
    <style>
      body {
        padding: 0;
        margin: 0;
        position: relative;
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
      }

      html,
      body,
      #map {
        height: 100%;
      }

      /* style dla naszego województwa */
      .marker-position {
        position: absolute;
        bottom: 0;
        left: 0;
        z-index: 999;
        padding: 10px;
        font-weight: 700;
        background-color: #fff;
      }
    </style>
  </head>
  <body>
    <!-- w to miejsce będziemy dodawać nazwę województwa -->
    <div class="marker-position">Click/hover on polygon</div>
    <!-- miejsce dla naszej mapy -->
    <div id="map"></div>
    <script src="script.js"></script>
  </body>
</html>

Teraz przejdźmy do js.
Najprostszym sposobem jest dodanie L.geoJSON(data).addTo(map);

fetch('./plik-geojson') // może to być plik, lub adres pod którym jest plik
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    // przekazujemy do metody nasze dane
    // i pokazujemy na mapie
    L.geoJSON(data).addTo(map);
  });

Ale oczywiście to zbyt łatwe, rozszerzymy ten przykład o to co pisaliśmy wcześniej.
Poniżej nasz główny kod js.

// konfiguracja mapy
let config = {
  minZoom: 4,
  maxZomm: 18
};
// powiększenie, od którego rozpocznie się powiększenie mapy
const zoom = 7;
// współrzędne
const lat = 51.918904;
const lon = 19.1343786;

// wywołanie mapy
const map = L.map("map", config).setView([lat, lon], zoom);

// Służy do ładowania i wyświetlania warstw kafelków na mapie
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
  attribution:
    '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// dodatkowa funkcja dodająca nazwę województwa
// do div w lewym dolnym rogu
function addTextToDiv(text) {
  const markerPlace = document.querySelector(".marker-position");
  markerPlace.textContent = text;
}

// pokazujmy województwo
function getVoivodeshipName(feature, layer) {
  // sprawdzmy czy properties oraz properties.name istnieje
  if (feature.properties && feature.properties.name) {
    // otwieramy popup z nazwa wojwództwa
    layer.bindPopup(feature.properties.name);
  }
}

// pobranie pliku z danymi przez fetch
// oczywiście można to zrobić przez $.ajax, axios itd.
fetch("https://raw.githubusercontent.com/codeforamerica/click_that_hood/master/public/data/poland.geojson")
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {

    var layer = new L.GeoJSON(data, {

      // metoda wywołana tylko raz
      onEachFeature: function (feature, layer) {

        // zdarzenie na mouseover
        layer.on("mouseover", function (e) {

          // 
          getVoivodeshipName(feature, layer);

          // pokaż województwo
          addTextToDiv(feature.properties.name);

          // otworzenie popup z nazwą województwa
          this.openPopup();

          // style
          this.setStyle({
            fillColor: "#eb4034",
            weight: 2,
            color: "#eb4034",
            fillOpacity: 0.7
          });
        });

        // zdarzenie na mouseout
        layer.on("mouseout", function () {

          // zamknięcie popup z nazwą województwa
          this.closePopup();

          // style
          this.setStyle({
            fillColor: "#3388ff",
            weight: 2,
            color: "#3388ff",
            fillOpacity: 0.2
          });

        });

        // zdarzenie na kliknięcie
        layer.on("click", function () {
          // dodając nazwę prowincji do widocznego div
          addTextToDiv(feature.properties.name);
        });

      }
    }).addTo(map); // dodanie layer do mapy
  });

Poniżej działająca przykład.

See the Pen
geoJson leaflet
by Greg (@Tomik23)
on CodePen.

To tak naprawdę wszystko. Pliki GeoJSON w zależności od ilości szczegółów mogą sporo "ważyć". Do testów można sobie samemu przygotować plik z koordynatami, polecam tą stronę geojson.io.
Więcej o GeoJSON przeczytasz na leafletjs.com

Powiązane artykuły:

Alternatywa dla google maps – Open Street Map oraz Leaflet
Jak do Open Street Map i Leaflet dodać routing – OSRM
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