Interaktive Karten mit QGIS, tippecanoe, Martin und MapLibre GL JS

3D Darstellung einer Österreich-Karte

Interaktive Karten im Web erfreuen sich heutzutage großer Beliebtheit, um diverse statistische Daten anschaulich visualisieren und analysieren zu können. Funktionen ermöglichen es, einzelne Aspekte gezielt ein- und auszublenden oder weitere Hintergrundinformationen abzurufen.

Wir beschreiben die technische Umsetzung einer interaktiven Österreich-Karte, die Bevölkerungsdaten von 2002 bis 2022 visualisiert.

Datenquellen

QGIS

QGIS ist eine umfangreiche Open-Source-Software zur Bearbeitung, Analyse und Präsentation geografischer Informationen. Die Software ermöglicht es, eigene Karten mit Symbolen und Beschriftungen zu entwerfen. Daten können aus verschiedenen Quellen importiert und kombiniert werden. Wir haben umfangreiche Möglichkeiten, die Karte zu bearbeiten und mit eigenen Ebenen zu ergänzen.

Um neue Ebenen anzulegen, ziehen wir unsere Shapefiles (.shp) aus oben genannten Quellen einfach in das QGIS-Fenster.

Screenshot QGIS

QGIS bietet die Möglichkeit, Karten direkt als mbtiles-Datei zu exportieren. Diese Funktion ist jedoch sehr eingeschränkt. Da wir es genauer wissen wollen, exportieren wir die Ebenen als einzelne GeoJSON-Dateien (rechte Maustaste über Ebene -> Export -> Objekte speichern als...). Dabei ist es wichtig, das Koordinatenbezugssystem EPSG:4326 - WGS 84 auszuwählen. Die Dateinamen sollten mit Bedacht gewählt werden. Unsere späteren Ebenen werden die selben Namen tragen (schnucki.geojson -> staatsgrenze.geojson).

Vektorkacheln mit tippecanoe erzeugen

Um für die Kartendarstellung jeweils nur die benötigten Daten nachzuladen, konvertieren wir die großen GeoJSON-Dateien unter Beibehaltung von Ebenen und Objektdaten in eine einzige .mbtiles-Vektorkacheldatei - eine SQLite-Datenbank.

Dazu nutzen wir einen aktuellen Fork des Kommandozeilentools tippecanoe (ursprünglich Mapbox).

Wir holen die Quellen und kompilieren:

apt install build-essential libsqlite3-dev zlib1g-dev git
git clone https://github.com/felt/tippecanoe.git
cd tippecanoe
make -j
make install

Einfaches Beispiel der Verwendung:

tippecanoe -o austria.mbtiles -z4 -z9 -S1 -ab staatsgrenze.geojson bezirke.geojson...

Mit -o legen wir den Output auf "austria.mbtiles" fest. Mit -z4 stellen wir die minimale Zoomstufe und mit -z9 die maximale ein. Mit -S1 können wir die Vektoren simplifizieren. Damit keine unregelmäßigen Grenzen entstehen, zieht -ab Punkte verschiedener Ebenen auf gemeinsame Koordinaten zusammen. Hintenrum füttern wir die aus QGIS exportierten geojson Dateien.

Die enorme Funktionalität von tippecanoe ist hier beschrieben.

Martin - Vector Tiles Server

Die Auslieferung der Vektorkacheln in einer virtuellen Verzeichnisstruktur (Z/X/Y) lassen wir von Martin erledigen.

Dazu laden wir die unserer Plattform entsprechende Version von der Release-Seite des Projekts herunter und entpacken das Archiv nach /opt/martin.

Wir kopieren unsere austria.mbtiles-Datei nach /opt/martin und machen Martins Binary-Datei ausführbar:

chmod +x /opt/martin/martin

Zu Testzwecken starten wir den Server:

./martin -l 0.0.0.0:4000 austria.mbtiles

Martin sollte nun in einem Browser unter http://{IP-Adresse}:4000 erreichbar sein. Unter http://{IP-Adresse}:4000/austria (= Dateiname) /Z/X/Y stehen die Kacheln bereit.

Die Konfiguration kann in einer yaml-Datei vorgenommen werden - siehe Doku.

Da wir unsere Tiles auf der Webseite über https ausliefern wollen, aktivieren wir die Apache Proxy-Module...

a2enmod proxy
a2enmod proxy_http

...leiten das Verzeichnis /vtiles auf Martin um...

<VirtualHost *:443>

  ServerName domain.org
  DocumentRoot /var/www/domain

  ProxyPass /vtiles http://127.0.0.1:4000/ retry=0
  ProxyPassReverse /vtiles http://127.0.0.1:4000/

  SSLCertificateFile /pfad/fullchain.pem
  SSLCertificateKeyFile /pfad/privkey.pem

</VirtualHost>

...starten Apache neu...

systemctl restart apache2

...und starten Martin auf localhost:

./martin -l 127.0.0.1:4000 austria.mbtiles

Unsere Österreich-Karte ist nun unter https://domain.org/vtiles/austria erreichbar.

Einrichten von Martin als Service -> /etc/systemd/system/martin.service:

[Unit]
Wants=network.target

[Service]
ExecStart=/opt/martin/martin -l 127.0.0.1:4000 /opt/martin/austria.mbtiles

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable martin
sudo systemctl start martin

MapLibre GL JS

Die Darstellung der Karte übernimmt MapLibre GL JS, ein Open-Source Community-Fork von Mapbox GL JS. Die JavaScript-Bibliothek rendert verschiedene Quellformate auf einem GPU-beschleunigten WebGL-Canvas.

Die Darstellung der Karten wird in einer Style-Spezifikation festgelegt, in der die Quellen, Ebenen und deren Aussehen definiert werden:

{
  "version": 8,
  "name": "Austria",
  "sources": {
    "austria": {
      "type": "vector",
      "tiles": [
        "https://fatvalley.at/vtiles/austria/{z}/{x}/{y}"
      ],
      "minzoom": 1,
      "maxzoom": 10
    }
  },
  "layers": [
    {
      "id": "lineLayer_Staatsgrenze",
      "source": "austria",
      "source-layer": "aborder",
      "type": "line",
      "paint": {
        "line-color": "#888888",
        "line-width": 4
      }
    },
    {
      "id": "fillLayer_Bezirke",
      "source": "austria",
      "source-layer": "bezirke_conv",
      "type": "fill",
      "paint": {
        "fill-color": "#bcc3d2"
      }
    },
    {
      "id": "lineLayer_Bezirke",
      "source": "austria",
      "source-layer": "bezirke_conv",
      "type": "line",
      "paint": {
        "line-color": "#888888",
        "line-width": 1
      }
    }
  ]
}

Hier werden aus unserer Vektor-Quelle die Staatsgrenze als Linienebene, die Bezirke einmal als Füllebene und einmal als Linienebene übereinandergelegt.

Und hier noch ein wenig JavaScript:

const map = new maplibregl.Map({
  container: 'map',
  style: mapstyle, // siehe oben - oder URL zu style.json
  minzoom: 1,
  maxzoom: 10,
  zoom: 6.4,
  // Kartenmittelpunkt
  center: [13.3458, 47.6964],
  //Festlegen der initialen Kartenränder
  bounds: [
    [9.293, 46.182], // Südwest
    [17.432, 49.095] // Nordost
  ],
  //Festlegen der maximalen Kartenränder
  maxBounds: [
    [6.759, 44.904], // Südwest
    [20.746, 50.185] // Nordost
  ],
});

map.addControl(new maplibregl.NavigationControl());

Hier die oben gezeigte .

Datenaufbereitung

Die Daten zur Anzeige können wir von der Statistik Austria Website als CSV-Datei (Comma Seperated Values) herunterladen. Für jedes Jahr stehen für jede Gemeinde die Einwohnerzahlen, gegliedert nach Alter, zur Verfügung. Insgesamt reden wir hier von ca. 7,6 Millionen eingetragenen Zeilen im CSV oder in Summe 360MB Daten. Viel zu viel, um diese in unserer Karte zu verwerten!

Um die Daten für die Anzeige auf unserer Karte verwenden zu können, müssen wir sie vereinfachen und konvertieren. Wir schreiben uns JavaScript-Funktionen, die folgende Schritte vornehmen:

Die Grundlage ist gelegt. Bitte Senf an: office@fatvalley.at