Zum Inhalt springen

Vectortiles

Vektor-Kacheln und Raster-Kacheln sind zwei Methoden zur Darstellung von Karten im Web.

Vektor-Kacheln enthalten geografische Daten in Form von Vektoren wie Punkten, Linien und Polygonen, die clientseitig gerendert werden. Dies ermöglicht flexible Anpassungen des Kartendesigns, scharfe Darstellung bei allen Zoomstufen und oft kleinere Datenmengen, da nur die Geometrie übertragen wird. Allerdings erfordert das Rendering mehr Rechenleistung auf dem Client-Gerät und eine komplexere Erstellung und Wartung der Dienste.

Raster-Kacheln sind vorgerenderte Kartenbilder, die in bestimmten Zoomstufen auf Servern gespeichert und an den Client gesendet werden. Sie benötigen weniger Rechenleistung, sind weit verbreitet und einfach zu integrieren. Allerdings können sie bei unterschiedlichen Zoomstufen unscharf werden, haben oft größere Dateigrößen und sind weniger flexibel, da Änderungen im Kartenstil neue vorgerenderte Kacheln erfordern.

Bei den Tools zur Anzeige dieser Kacheln zeigen sich ebenfalls Unterschiede. Leaflet unterstützt sowohl Raster- als auch Vektor-Kacheln, ist jedoch stärker auf Raster-Kacheln ausgerichtet und bietet eine einfachere Integration dieser Art. Die Einbindung von Vektor-Kacheln in Leaflet1 erfordert zusätzliche Plugins. MapLibre ist speziell für die Verwendung von Vektor-Kacheln optimiert und ermöglicht es, deren Vorteile voll auszuschöpfen, einschließlich dynamischer Anpassungen des Kartenstils und effizientem Client-seitigem Rendering für bessere Darstellung und Interaktivität.

Hier geht es nun um Vektor-Tiles.

Vectortiles

Tilemaker und Tilekiln sind zwei Tools zur Erstellung von Vektor-Kacheln, die sich in Funktionalität, Einsatzbereich und Arbeitsweise unterscheiden.

Tilemaker ist ein einfach zu bedienendes Tool, das aus OpenStreetMap (OSM)-Daten Vektor-Kacheln erstellt. Es verarbeitet OSM-Daten im PBF-Format direkt in Vektor-Kacheln. Die Konfiguration erfolgt über eine JSON-Datei. Tilemaker ist leicht zu installieren und zu nutzen, ideal für statische Kachelsets, die nicht häufig aktualisiert werden müssen. Eine Datenbank ist nicht erforderlich. Minütliche Aktualisierungen sind nicht möglich.

Tilekiln ist ein Tool, das auf Flexibilität und Performance ausgelegt ist. Es kann mit verschiedenen Datenquellen wie PostGIS und GeoJSON arbeiten. Die Konfiguration erfolgt über YAML-Dateien. Tilekiln benötigt eine Datenbank wie PostGIS und ist für häufige, sogar minütliche Aktualisierungen geeignet.

Ich habe beide unter Ubuntu 24.04 angeschaut.

Tilemaker

Wenn eine digitale Karte in einer Webanwendung angezeigt wird, verwenden Webentwickler in der Regel Online-Dienste. Für viele Anwendungen ist dies jedoch nicht erforderlich. Es ist gar nicht so kompliziert, selbst Karten zu erstellen und sie auf dem eigenen Webspace zu hosten. Frei verfügbare Daten von OpenStreetmap und Open-Source-Tools unterstützen beim Erstellen von individuellen Vektor-Kacheln für eine Website. Problematisch ist in meinen Augen lediglich die Datenmenge. Aber meist ist es nicht erforderlich die ganze Welt in der Karte aufzunehmen.

Das Hosting des gesamten Planeten erfordert erhebliche Mengen an Speicherplatz. Im Mai 2024 liegt die Dateigröße bei 75 GB.

In diesem Kapitel zeige, wie ich eine Karten mit Daten von OpenStreetmap und Tilemaker für die spanische Region Murcia auf meinem lokalen Rechner erstellt habe.

Erstellen eines regionalen Openstreetmap-Daten-Exports

Die Bounding Box[] von Murcia ist bbox=-1.8982,38.7055,-0.6868,37.3503.

  • Nordwestlicher Punkt (oben links): 38.7055° N, -1.8982° W und
  • Südöstlicher Punkt (unten rechts): 37.3503° N, -0.6868° W.

Ein praktisches Werkzeug zum bestimmen der Bounding-Box-Koordinaten ist calc[].

Als erstes benötigen wir die Openstreetmap-Daten zur Erstellung der Karte. Wenn man einen begrenzten Bereich anzeigen mag, ist es nicht erforderlich, die Daten vom ganzen Planeten herunterzuladen. Es reicht ein Export der Daten der Region, die wir anzeigen möchten. Verschiedene Anbieter, halten aktuelle vorgefertigte Exporte zum Download bereit. Die GeoFabrik[] ist einer von diesen. Beachte dabei jedoch, dass wir, wenn wir eine Region exportieren möchten, eigentlich einen rechteckigen Export wünschen. Wir möchten also auch einige Teile rund um die Grenze mit einbeziehen. Die Exporte der Geofabrik werden um die Grenzen der Region herum extrahiert und die angrenzenden Bereiche erscheinen als graue Flächen, wenn wir die Karte auf einem rechteckigen Bereich anzeigen. Und dann ist es nicht selten so, dass genaue der Bereich, den man anzeigen möchte, nicht als Export zur Verfügung steht. Deshalb basteln wir uns die genaue Grenze selbst zurecht.

Terminal window
mkdir ~/data
cd ~/data
wget https://download.geofabrik.de/europe/spain-latest.osm.pbf

Wir können einen rechteckigen Ausschnitt aus einer größeren Region generieren, beispielsweise aus Spanien ein Rechteck, in das Murcia passt. Den Ausschnitt erstelle ich mit dem Werkzeug Osmium[]. Wir laden also zunächst die Daten zu dem umgebenden Gebiet von der GeoFabrik herunter, in unserem Fall das Land Spanien. Der nächste Schritt besteht darin, den Begrenzungsrahmen der Region zu bestimmen, die wir extrahieren möchten. In unserem Fall Murcia.

Achtung. Manchmal reicht der nächstgrößere Export nicht aus. Beispiel: Weil Rheinland-Pfalz am westlichen Rand von Deutschland liegt, muss ich Europa als größere Datenquelle wählen, damit es tatsächlich rechteckig wird.

Die von mir gewählte Begrenzung ist bbox=-1.8982,38.7055,-0.6868,37.3503[].

Unter Ubuntu installiere ich das Tool Osmium via:

Terminal window
~$ sudo apt-get install osmium-tool
[sudo] password for astrid:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
libboost-program-options1.83.0
The following NEW packages will be installed:
libboost-program-options1.83.0 osmium-tool
0 upgraded, 2 newly installed, 0 to remove and 5 not upgraded.
Need to get 902 kB of archives.
After this operation, 3,982 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://de.archive.ubuntu.com/ubuntu noble/main amd64 libboost-program-options1.83.0 amd64 1.83.0-2.1ubuntu3 [320 kB]
Get:2 http://de.archive.ubuntu.com/ubuntu noble/universe amd64 osmium-tool amd64 1.16.0-1build1 [582 kB]
Fetched 902 kB in 8s (120 kB/s)
Selecting previously unselected package libboost-program-options1.83.0:amd64.
(Reading database ... 148486 files and directories currently installed.)
Preparing to unpack .../libboost-program-options1.83.0_1.83.0-2.1ubuntu3_amd64.deb ...
Unpacking libboost-program-options1.83.0:amd64 (1.83.0-2.1ubuntu3) ...
Selecting previously unselected package osmium-tool.
Preparing to unpack .../osmium-tool_1.16.0-1build1_amd64.deb ...
Unpacking osmium-tool (1.16.0-1build1) ...
Setting up libboost-program-options1.83.0:amd64 (1.83.0-2.1ubuntu3) ...
Setting up osmium-tool (1.16.0-1build1) ...
Processing triggers for libc-bin (2.39-0ubuntu8.1) ...
Processing triggers for man-db (2.12.0-4build2) ...

Dann erstelle ich den regionalen Export für Murcia:

Terminal window
$ osmium extract --bbox=-1.8982,38.7055,-0.6868,37.3503 --set-bounds --strategy=smart spain-latest.osm.pbf --output murcia.osm.pbf

Für das deutsche Bundesland Rheinland-Pfalz sähe der Befehl wie folgt aus:

Terminal window
$ osmium extract --bbox=6.1173598760,48.9662745077,8.5084754437,50.9404435711 --set-bounds --strategy=smart europe-latest.osm.pbf --output rlp.osm.pbf

Am Ende verfüge ich über die Daten zur Erstellung eines rechteckigen Ausschnitts der von mir gewünschten Region in der Datei murcia.osm.pbf. Diese kann ich zum selbst erstellen der Vector-Tiles zum selbsthosten weiterbearbeiten.

Erzeugen der Vector-Tiles

Der nächste Schritt ist die Erstellung der Vektorkacheln aus dem regionalen Export. Hierfür verwende ich Tilemaker[].

Vorher installiere ich die notwendigen Pakete[].

Terminal window
sudo apt install build-essential libboost-dev libboost-filesystem-dev libboost-iostreams-dev libboost-program-options-dev libboost-system-dev liblua5.1-0-dev libshp-dev libsqlite3-dev rapidjson-dev zlib1g-dev git lua5.1 apache2
Terminal window
~$ git clone https://github.com/systemed/tilemaker.git
Cloning into 'tilemaker'...
remote: Enumerating objects: 5801, done.
remote: Counting objects: 100% (2263/2263), done.
remote: Compressing objects: 100% (704/704), done.
remote: Total 5801 (delta 1832), reused 1651 (delta 1514), pack-reused 3538
Receiving objects: 100% (5801/5801), 42.46 MiB | 474.00 KiB/s, done.
Resolving deltas: 100% (3175/3175), done.

Danach kompiliere und installiere ich Tilemaker via make und sudo make install.

Terminal window
$ cd tilemaker
$ make
...
$ sudo make install
Using lua
- Lua language version 5.1
- include path is -I/usr/include/lua5.1
- library path is -llua5.1
install -m 0755 -d /usr/local/bin/
install -m 0755 tilemaker /usr/local/bin/
install -m 0755 tilemaker-server /usr/local/bin/

Daten aus internationalen Gewässern und Küstengebieten oder Daten von National Earth ergänzen die Daten. Openstreetmap stellt die Coastlines auf der Website osmdata.openstreetmap.de zur Verfügung.

Terminal window
$ cd ~/data
$ wget https://osmdata.openstreetmap.de/download/water-polygons-split-4326.zip

National Earth[^] bietet Downloadmöglichkeiten über ihre Website[^] an. Besorge dir hier die Daten zu ne_10m_urban_areas, ne_10m_glaciated_areas und ne_10m_antarctic_ice_shelves_polys.

Terminal window
$ cd ~/data
$ wget https://naciscdn.org/naturalearth/10m/physical/ne_10m_antarctic_ice_shelves_polys.zip
$ wget https://naciscdn.org/naturalearth/10m/cultural/ne_10m_urban_areas.zip
$ wget https://naciscdn.org/naturalearth/10m/physical/ne_10m_glaciated_areas.zip

Lege Unterverzeichnisse mit den Namen landcover und coastline an und endpacke die Daten hier. Unter Umständen gibt es ein Skript, das dies für dich erledigt.

Terminal window
$ cd ~/tilemaker
$ mkdir coastline
$ cd coastline
$ unzip ~/data/water-polygons-split-4326.zip
$ cd ~/tilemaker
$ mkdir ~/tilemaker/landcover
$ mkdir ~/tilemaker/landcover/ne_10m_antarctic_ice_shelves_polys
$ mkdir ~/tilemaker/landcover/ne_10m_glaciated_areas
$ mkdir ~/tilemaker/landcover/ne_10m_urban_areas
$ cd ~/tilemaker/landcover/ne_10m_antarctic_ice_shelves_polys
$ unzip ~/data/ne_10m_antarctic_ice_shelves_polys.zip
$ cd ~/tilemaker/landcover/ne_10m_glaciated_areas
$ unzip ~/data/ne_10m_glaciated_areas.zip
$ cd ~/tilemaker/landcover/ne_10m_urban_areas
$ unzip ~/data/ne_10m_urban_areas.zip

Innerhalb von tilemaker sind nun die folgendenden Daten hinzugekommen. Falls dir die Daten nicht wichtig sind, kannst du auch ohne diese weiter arbeiten. Dir wird lediglich bei der Erstellung der Vector-Kacheln gemeldet, dass die Daten fehlen und natürlich fehlen diese in den Vectorkacheln.

Terminal window
.../tilemaker/coastline$ ll
total 12
drwxrwxr-x 3 astrid astrid 4096 May 19 20:46 ./
drwxrwxr-x 12 astrid astrid 4096 May 19 20:46 ../
drwxrwxr-x 2 astrid astrid 4096 May 19 20:46 water-polygons-split-4326/
./water-polygons-split-4326:
total 1164348
drwxrwxr-x 2 astrid astrid 4096 May 19 20:46 ./
drwxrwxr-x 3 astrid astrid 4096 May 19 20:46 ../
-rw-r--r-- 1 astrid astrid 836 May 19 06:05 README.txt
-rw-r--r-- 1 astrid astrid 6 May 19 04:54 water_polygons.cpg
-rw-r--r-- 1 astrid astrid 1013786 May 19 04:54 water_polygons.dbf
-rw-r--r-- 1 astrid astrid 145 May 19 04:50 water_polygons.prj
-rw-r--r-- 1 astrid astrid 1190819048 May 19 04:54 water_polygons.shp
-rw-r--r-- 1 astrid astrid 426916 May 19 04:54 water_polygons.shx
.../tilemaker/landcover$ ll
insgesamt 20
drwxrwxr-x 5 youruser youruser 4096 Nov 24 19:25 ./
drwxrwxr-x 12 youruser youruser 4096 Nov 20 12:23 ../
drwxrwxrwx 2 youruser youruser 4096 Nov 24 19:25 ne_10m_antarctic_ice_shelves_polys/
drwxrwxrwx 2 youruser youruser 4096 Nov 19 19:26 ne_10m_glaciated_areas/
drwxrwxrwx 2 youruser youruser 4096 Nov 19 19:01 ne_10m_urban_areas/
~/tilemaker/landcover$ ll -R
.:
total 20
drwxrwxr-x 5 astrid astrid 4096 May 19 20:57 ./
drwxrwxr-x 13 astrid astrid 4096 May 19 20:49 ../
drwxrwxr-x 2 astrid astrid 4096 May 19 20:57 ne_10m_antarctic_ice_shelves_polys/
drwxrwxr-x 2 astrid astrid 4096 May 19 20:57 ne_10m_glaciated_areas/
drwxrwxr-x 2 astrid astrid 4096 May 19 20:57 ne_10m_urban_areas/
./ne_10m_antarctic_ice_shelves_polys:
total 432
drwxrwxr-x 2 astrid astrid 4096 May 19 20:57 ./
drwxrwxr-x 5 astrid astrid 4096 May 19 20:57 ../
-rw-r--r-- 1 astrid astrid 5 Aug 12 2017 ne_10m_antarctic_ice_shelves_polys.cpg
-rw-r--r-- 1 astrid astrid 28336 Jul 30 2017 ne_10m_antarctic_ice_shelves_polys.dbf
-rw-r--r-- 1 astrid astrid 143 Jul 30 2017 ne_10m_antarctic_ice_shelves_polys.prj
-rw-r--r-- 1 astrid astrid 23872 May 21 2018 ne_10m_antarctic_ice_shelves_polys.README.html
-rw-r--r-- 1 astrid astrid 364308 Jul 6 2017 ne_10m_antarctic_ice_shelves_polys.shp
-rw-r--r-- 1 astrid astrid 1372 Jul 6 2017 ne_10m_antarctic_ice_shelves_polys.shx
-rw-r--r-- 1 astrid astrid 7 May 21 2018 ne_10m_antarctic_ice_shelves_polys.VERSION.txt
./ne_10m_glaciated_areas:
total 4204
drwxrwxr-x 2 astrid astrid 4096 May 19 20:57 ./
drwxrwxr-x 5 astrid astrid 4096 May 19 20:57 ../
-rw-r--r-- 1 astrid astrid 5 Aug 12 2017 ne_10m_glaciated_areas.cpg
-rw-r--r-- 1 astrid astrid 300067 Jul 30 2017 ne_10m_glaciated_areas.dbf
-rw-r--r-- 1 astrid astrid 143 Jul 30 2017 ne_10m_glaciated_areas.prj
-rw-r--r-- 1 astrid astrid 22479 May 21 2018 ne_10m_glaciated_areas.README.html
-rw-r--r-- 1 astrid astrid 3938340 Jul 8 2017 ne_10m_glaciated_areas.shp
-rw-r--r-- 1 astrid astrid 15188 Jul 8 2017 ne_10m_glaciated_areas.shx
-rw-r--r-- 1 astrid astrid 7 May 21 2018 ne_10m_glaciated_areas.VERSION.txt
./ne_10m_urban_areas:
total 19744
drwxrwxr-x 2 astrid astrid 4096 May 19 20:57 ./
drwxrwxr-x 5 astrid astrid 4096 May 19 20:57 ../
-rw-r--r-- 1 astrid astrid 5 Aug 13 2017 ne_10m_urban_areas.cpg
-rw-r--r-- 1 astrid astrid 950401 Aug 13 2017 ne_10m_urban_areas.dbf
-rw-r--r-- 1 astrid astrid 147 Aug 13 2017 ne_10m_urban_areas.prj
-rw-r--r-- 1 astrid astrid 23671 May 21 2018 ne_10m_urban_areas.README.html
-rw-r--r-- 1 astrid astrid 19119748 Aug 13 2017 ne_10m_urban_areas.shp
-rw-r--r-- 1 astrid astrid 95124 Aug 13 2017 ne_10m_urban_areas.shx
-rw-r--r-- 1 astrid astrid 7 May 21 2018 ne_10m_urban_areas.VERSION.txt

Jetzt habe ich alles Notwendige und erstelle die Vector-Tiles für die Karte mithilfe von Tilemaker. Als erstes verschaffe ich mir einen Überblick über die Optionen:

Terminal window
$ tilemaker --help
tilemaker v3.0.0
Convert OpenStreetMap .pbf files into vector tiles
Available options:
--help show help message
--input arg source .osm.pbf file
--output arg target directory or .mbtiles/.pmtiles file
--bbox arg bounding box to use if input file does not have
a bbox header set, example:
minlon,minlat,maxlon,maxlat
--merge merge with existing .mbtiles (overwrites
otherwise)
--config arg (=config.json) config JSON file
--process arg (=process.lua) tag-processing Lua file
--verbose verbose error output
--skip-integrity don't enforce way/node integrity
--log-tile-timings log how long each tile takes
Performance options:
--store arg temporary storage for node/ways/relations data
--fast prefer speed at the expense of memory
--compact use faster data structure for node lookups
NOTE: This requires the input to be renumbered
(osmium renumber)
--no-compress-nodes store nodes uncompressed
--no-compress-ways store ways uncompressed
--materialize-geometries materialize geometries; uses more memory
--shard-stores use an alternate reading/writing strategy for
low-memory machines
--threads arg (=0) number of threads (automatically detected if 0)
Ausgabeoptionen

Wenn du deine Karten mit Tilemaker generierst, gibt es zwei Ausgabeoptionen: directory und mbtiles/pmtiles.

Directory

Mit Tilemaker ist es möglich, die Kacheldateien als einzelne Dateien in ein Verzeichnis zu generieren.

Achte darauf, in der Konfigurations-Datei "compress": mit "none" zu belegen. In diesem Beispiel ist dies die Datei config-openmaptiles.json!

Möchtest du alle pbf-Dateien einzeln in ein Verzeichnis erstellen? Dann reicht es aus, im Parameter Output keine Endung zu verwenden. --output rlp.mbtiles packt beispielsweise alle pbf-Dateien in die Datei rlp.mbtiles. --output rlp legt alle pbf-Dateien einzeln im Verzeichnis rlp an.

Terminal window
$ cd ~/tilemaker
$ tilemaker --input ~/data/murcia.osm.pbf --output murcia --process ./resources/process-openmaptiles.lua --config ./resources/config-openmaptiles.json

Wenn die Konvertierung abgeschlossen ist und alles fehlerfrei verlief steht am Ende

Terminal window
Filled the tileset with good things at murcia

In diesem Beispiel werden die Dateien im Verzeichnis murcia erzeugt. In diesem Verzeichnis gibt es eine Reihe von Verzeichnissen und eine Datei namens metadata.json.

Terminal window
~/tilemaker/murcia$ ll
total 72
drwxrwxr-x 17 astrid astrid 4096 May 19 21:09 ./
drwxrwxr-x 14 astrid astrid 4096 May 19 21:10 ../
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 0/
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 1/
drwxrwxr-x 8 astrid astrid 4096 May 19 21:09 10/
drwxrwxr-x 12 astrid astrid 4096 May 19 21:09 11/
drwxrwxr-x 22 astrid astrid 4096 May 19 21:09 12/
drwxrwxr-x 42 astrid astrid 4096 May 19 21:09 13/
drwxrwxr-x 81 astrid astrid 4096 May 19 21:09 14/
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 2/
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 3/
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 4/
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 5/
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 6/
drwxrwxr-x 3 astrid astrid 4096 May 19 21:09 7/
drwxrwxr-x 4 astrid astrid 4096 May 19 21:09 8/
drwxrwxr-x 5 astrid astrid 4096 May 19 21:09 9/
-rw-rw-r-- 1 astrid astrid 2508 May 19 21:09 metadata.json

Falls du so wie ich vor hast, die Vector Tiles später nicht als eine mbtiles-Datei anzubieten, sondern in ein Verzeichnis entpacken möchtest, ist es wichtig in der Datei config-openmaptiles.json die Eigenschaft "compress": mit "none" zu belegen! Außerdem muss die URL angepasst werden.

resources/config-openmaptiles.json
{
"layers": {
"place": { "minzoom": 0, "maxzoom": 14 },
...
...
"mountain_peak": { "minzoom": 11, "maxzoom": 14 }
},
"settings": {
"minzoom": 0,
"maxzoom": 14,
"basezoom": 14,
"include_ids": false,
"combine_below": 14,
"name": "Tilemaker to OpenMapTiles schema",
"version": "3.0",
"description": "Tile config based on OpenMapTiles schema",
"compress": "none",
"filemetadata": {
"tilejson": "2.0.0",
"scheme": "xyz",
"type": "baselayer",
"format": "pbf",
"tiles": ["https://localhost/murcia/{z}/{x}/{y}.pbf"]
}
}
}
mbtiles

Die mbtiles-Datei ist eine sqlite3-Datenbank, die von serverseitigen Skriptsprachen wie PHP LUA oder NodeJs gelesen werden kann. Tileserver öffnen diese Datei und lesen die Kacheldaten aus, sobald der Client sie anfordert.

Terminal window
$ cd ~/tilemaker
$ tilemaker --input ~/data/murcia.osm.pbf --output murcia.mbtiles --process ./resources/process-openmaptiles.lua --config ./resources/config-openmaptiles.json

Wenn die Konvertierung abgeschlossen ist und alles fehlerfrei verlief steht am Ende

Terminal window
Filled the tileset with good things at murcia.mbtiles

Die mbtiles-Datei findet man im Tilemaker-Verzeichnis

Terminal window
~/tilemaker$ ls -l
...
-rw-r--r-- 1 astrid astrid 51118080 May 19 21:11 murcia.mbtiles
...

Hosting der Vector-Tiles

Dateien in Verzeichn

Wenn wir die Daten in ein Verzeichnis exportiert haben, können wir die Vectortiles über einen Webserver anbieten.

Für den lokalen Test installiere ich Apache.

Terminal window
sudo apt install apache2

Ob der Webserver fehlerfrei läuft, überprüfe ich via Browser mit der Adresse localhost. Hier wird mir die HTML-Datei /var/www/html/index.html angezeigt.

Ansicht der Default Apache Website im Browser.

Falls es Probleme mit dem Webserver gibt, sind folgende Befehle hilfreich.

Terminal window
$ sudo systemctl status apache2
$ sudo systemctl enable apache2
$ sudo systemctl restart apache2

Nun erstelle ich eine HTHML-Website, die eine Karte anzeigt.

Terminal window
sudo nano /var/www/html/map.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Display a map on a webpage</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js'></script>
<link href='https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css' rel='stylesheet' />
</head>
<body>
<div id='map' style='width: 800px; height: 800px;'></div>
<script>
var map = new maplibregl.Map({
container: 'map',
style: 'style.json',
center: [1, 37],
zoom: 15
});
map.fitBounds([[-1.8982,37.350300000000007],[2.2250738585072014e-308,38.7]]);
map.addControl(new maplibregl.NavigationControl());
</script>
</body>
</html>

Im nächsten Schritt kopiere ich die Vector-Tiles in das Webserver-Verzeichnis.

Terminal window
sudo cp -R ~/tilemaker/murcia /var/www/html/

Die Vector-Tiles beinhalten vereinfacht ausgedrückt lediglich Punkte, Striche und Formen. Diese müssen gestaltet werden. Schriften, Farben, Symbole und Linienstärken sind beispielsweise individuell möglich. Ich greife hier auf Stil-Vorlagen zurück, welche der interne Tilemaker-Server zur Verfügung stellt und kopiere diese auf meinen Test-Webserver.

Terminal window
sudo cp -R ~/tilemaker/server/static/fonts /var/www/html/
sudo cp -R ~/tilemaker/server/static/style.json /var/www/html/

Die style.json Datei muss angepasst werden:

Terminal window
sudo nano style.json

Für mein Beispiel tausche ich

...
"url": "http://localhost:8080/spec.json"
...
"glyphs": "http://localhost:8080/fonts/{fontstack}/{range}.pbf",
...

gegen

...
"url": "http://localhost/murcia/metadata.json"
...
"glyphs": "http://localhost/fonts/{fontstack}/{range}.pbf",
...

aus.

Nun ist alles fertig und die URL http://localhost/map.html zeigt mir die Karte an.

Ansicht der Karte im Browser unter Adresse http://localhost/map.html auf dem lokalen Apache Webserver.

Hinweis: Wenn du das Beispiel geändert hast, um einen anderen Bereich zu zeigen, musst du die Koordinaten an allen Stellen ändern.

Wenn du selbst einen individuellen Stile anlegen magst, ist Maputnik eine gute Anlaufstelle.

Mbtiles

Falls du alle Vector-Tiles in eine einzelne Mbtiles-Datei gepackt hast, ist ein Test der Tiles mit Tilemaker einfach.

Terminal window
~/tilemaker$ cd ~/tilemaker/server
~/tilemaker/server$ tilemaker-server ~/tilemaker/murcia.mbtiles
Starting local server on port 8080

Ein Aufruf von http://localhost:8080/ im lokalen Browser zeigt die Karte. Diese beinhalte Werkzeugen zum Überprüfen der Eigenschaften der einzelnen Objekte in den Vector-Tiles.

Ansicht der Karte im integrierten Tilemaker Server.

MBTiles entpacken

Du hast gesehen: Es ist möglich die von Tilemaker generierte mbtile-Datei anzusehen, nämlich via integriertem Server. Dies ist für eine Entwicklungsumgebung praktisch. Performanter ist es allerdings, die Vector-Tiles direkt von einem statischen Webserver zu laden. Nebenbei ist die Handhabung von großen Dateien in bestimmten Umgebungen problematisch. Beispielsweise sind besondere Schritte notwendig, um eine Demo[] auf github.io zu veröffentlichen, wenn sich eine Datei mit mehr als 100 MB im Paket befindet.

Wie schon erwähnt, kannst du mit Tilemaker einzelne pbf-Dateien in einem Verzeichnis anlegen. In meinem Workaround bevorzuge ich es, mit mbtiles-Dateien zu arbeiten und die zum Veröffentlichen vorgesehene Datei am Ende zu entpacken. Hierfür gibt es das Werkzeug mbutil.

Installiere mbutil und Python und verschaffe dir einen Überblick über die Optionen von mbutil.

Terminal window
cd ~
git clone https://github.com/mapbox/mbutil.git
sudo apt-get install python3 python-is-python3
cd mbutil/
./mb-util -h

Die Datei ~/tilemaker/murcia.mbtiles entpacke ich via

Terminal window
~/mbutil/mb-util ~/tilemaker/murcia.mbtiles ~/tilemaker/murciadir --image_format=pbf

Nun verfüge ich über Vector-Tiles in entpackter Form und kann sie analog zum vorhergehenden Kapitel auf einem Webserver selbst hosten.

Zur Erinnerung: Entpackt dürfen die Tiles nicht komprimiert sein! Beim Erstellen der mbtiles-Datei muss "compress": "none" in der Konfiguration von Tilemaker aktiviert gewesen sein.

Tilekiln

Tilekiln[] umfasst verschiedene Werkzeuge zur Erzeugung und Bereitstellung von Mapbox Vector Tiles (MVTs). Eine PostgreSQL + PostGIS Datenbank dient als Datenquelle und die Funktion ST_AsMVT wird zur Erzeugung und Visualisierung der MVTs verwendet.

Postgresql-Datenbank

Ich installiere die erforderliche Software. Dabei baue ich auf der zuvor beschriebenen Tilemaker Installation auf.

Terminal window
sudo apt update
sudo apt upgrade
sudo apt install postgresql postgresql-contrib postgis postgresql-16-postgis-3 postgresql-16-postgis-3-scripts osm2pgsql curl python3-venv gdal-bin

Pgadmin[] kann ich leider erst später installieren, weil es zur Zeit noch nicht in Ubuntu 24.04 unterstützt wird (https://stackoverflow.com/posts/62699398/revisions).

Node.js wird standardmäßig mit der Version 18 unter Ubuntu 24.04 installiert, welche für die Sprites nicht ausreichend ist. Deshalb verwende ich nvm um die Node.js Version 20 zu installieren.

Terminal window
wget -q -O- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
. ~/.bashrc
nvm install 20

Stil Spirit

Spirit[] ist ein allgemeiner Kartenstil für OpenStreetMap-Daten und Vektor-Kacheln. Zusätzlich unterstützt die Software optional Shortbread-Schema-Vektorkacheln. Ich kopiere als erstes die Software via Git, lade Sprites via npm und eine Vorlage für osm2pgsql.

Terminal window
cd ~
git clone https://github.com/pnorman/spirit.git
cd spirit
npm install @unvt/charites @basemaps/sprites
cd ~
git clone https://github.com/osm2pgsql-dev/osm2pgsql-themepark.git
export LUA_PATH="$HOME/osm2pgsql-themepark/lua/?.lua;;"

Ich befolge weiter die Anleitung[] zur Installation des Stils und installiere tilekiln in einem venv.

Terminal window
cd ~
python3 -m venv venv
~/venv/bin/pip install tilekiln

Daten

Als erstes vergebe ich dem Postgresql-Datenbank-Benutzer postgres ein Passwort. Standarmäßig ist das leer. Mir ist es schön öfter passiert, dass dies Probleme machte. Beispielsweise bei der Anmeldung in Pgadmin.

Terminal window
$ sudo -u postgres psql postgres
postgres=# alter user postgres with password 'geheim';
ALTER ROLE
postgres=# exit

Dann berechtige ich meinen Linux-User, lege eine Datenbank an und aktiviere PostGIS

Terminal window
$ sudo -u postgres createuser -s $USER
$ createdb spirit
$ psql -d spirit -c 'CREATE EXTENSION postgis;'
CREATE EXTENSION

Nun besorge ich mir Openstreetmap Daten von der Geofabrik. Zum Testen reicht ein kleiner Bereich. Ich entscheide mich für die spanische Region Murcia.

Terminal window
mkdir ~/data
cd ~/data
wget https://download.geofabrik.de/europe/spain/murcia-latest.osm.pbf

Zuletzt lese ich die Openstreet-Daten der Datei murcia-latest.osm.pbf via osm2pgsql in die Postgresql-Datenbank ein.

Terminal window
cd ~/spirit
osm2pgsql --output flex --style spirit.lua -d spirit ~/data/murcia-latest.osm.pbf
scripts/get-external-data.py

Der Fehler ERROR: Failed to execute Lua function 'osm2pgsql.process_node': [string "./themes/spirit/topics/places.lua"]:40: unknown field 'as_point' stack traceback könnte bei älteren Installationen auftrauchen. Er weißt darauf hin, dass die osm2pgsql-Version nicht auf dem neuesten Stand ist.

Serve

Der Befehl tilekiln serve dev ... startet einen Server, der Kacheln (Tiles) live rendert, ohne sie zwischenzuspeichern. Dabei wird eine tilejson-Adresse unter /<id>/tilejson.json eingerichtet. /tilejson.json leitet auf diese tilejson-Adresse weiter. Im Spirit-Repository gibt es zwei Styles: spirit.yaml mit der ID v1 und shortbread.yaml mit der ID shortbread_v1.

Terminal window
cd ~/spirit
../venv/bin/tilekiln serve dev --config spirit.yaml --source-dbname spirit
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started parent process [24228]
INFO: Started server process [24233]
INFO: Waiting for application startup.
INFO: Started server process [24234]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Application startup complete.

Nun ist es möglich, die Style-Datei für die Vector-Tiles im Browser aufzurufen. In unserem Beispiel über die Adresse http://127.0.0.1:8000/v1/tilejson.json. Bei mir sieht diese wie folgt aus:

{
"attribution": "<a href=\"https://www.openstreetmap.org/copyright\">\u00a9 OpenStreetMap</a> contributors",
"center": [
0,
0,
4
],
"maxzoom": 15,
"minzoom": 0,
"name": "Street Spirit",
"scheme": "xyz",
"tilejson": "3.0.0",
"tiles": [
"http://127.0.0.1:8000/v1/{z}/{x}/{y}.mvt"
],
"vector_layers": [
{
"description": "Administrative boundaries",
"fields": {},
"id": "admin",
"maxzoom": 15,
"minzoom": 4
},
{
"description": "Administrative area names",
"fields": {},
"id": "admin-names",
"maxzoom": 14,
"minzoom": 0
},
{
"description": "Building polygons",
"fields": {},
"id": "buildings",
"maxzoom": 15,
"minzoom": 13
},
{
"description": "Building names",
"fields": {},
"id": "building-names",
"maxzoom": 15,
"minzoom": 15
},
{
"description": "Ocean and water polygons",
"fields": {},
"id": "water",
"maxzoom": 15,
"minzoom": 0
},
{
"description": "Water linestrings",
"fields": {
"name": "Name of waterway",
"waterway": "Type of waterway"
},
"id": "water-lines",
"maxzoom": 15,
"minzoom": 8
},
{
"description": "Names for water bodies",
"fields": {
"name": "Name of water body"
},
"id": "water-names",
"maxzoom": 15,
"minzoom": 8
},
{
"description": "Linear road features",
"fields": {
"highway": "Type of highway"
},
"id": "roads",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Linear railway features",
"fields": {
"highway": "Type of highway"
},
"id": "railways",
"maxzoom": 15,
"minzoom": 12
},
{
"description": "Runways and other aeroways",
"fields": {},
"id": "aeroways",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Transit-oriented points",
"fields": {
"mode": "Mode of transportation",
"station": "If the point is a station or stop"
},
"id": "transit-points",
"maxzoom": 15,
"minzoom": 12
},
{
"description": "Various types of landuse",
"fields": {
"landuse": "Type of landuse"
},
"id": "landuse",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Various types of landuse",
"fields": {
"landuse": "Type of landuse",
"name": "Name of landuse",
"way_area": "Area in square meters in web mercator"
},
"id": "landuse-names",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Various types of educational areas",
"fields": {
"landuse": "Type of landuse"
},
"id": "education",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Names of educational facilities",
"fields": {
"education": "Type of landuse",
"name": "Name of education"
},
"id": "education-names",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Parks and other leisure areas",
"fields": {},
"id": "leisure",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Parks and other leisure area names",
"fields": {
"way_area": "Area in square meters in web mercator"
},
"id": "leisure-names",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Populated places",
"fields": {},
"id": "settlements",
"maxzoom": 15,
"minzoom": 8
},
{
"description": "vegetation areas",
"fields": {
"vegetation": "Type of vegetation. One of wood, heath, scrub, wetland, or grass",
"wetland": "Wetland tag, if the object is a wetland"
},
"id": "vegetation",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "vegetation names",
"fields": {
"vegetation": "Type of vegetation. One of wood, heath, scrub, wetland, or grass",
"wetland": "Wetland tag, if the object is a wetland"
},
"id": "vegetation-names",
"maxzoom": 15,
"minzoom": 10
},
{
"description": "Food-related POIs",
"fields": {
"name": "Name of food POI"
},
"id": "food",
"maxzoom": 15,
"minzoom": 15
}
]
}
Stil, Glyphen und Sprites

Um die Punkte, Striche und Formen in den Vektorkacheln darzustellen, benötigt man Glyphen und Sprites (also Schriftarten und Icons/Symbole), sowie einen Stil.

Glyphen

Die Schriften NotoSans-Regular und NotoSans-Bold werden für den Spirit-Stil benötigt und aktuell unter https://pnorman.dev.openstreetmap.org/spirit/fonts/{fontstack}/{range}.pbf zur Verfügung gestellt.

Wer andere Schriftarten verwenden möchte findet unter versatiles-fonts ein Beispiel für die Umsetzung. Weiterhin ist es mir wichtig, die Schriften auf dem eigenen Server bereizustellen. Für das Ausprobieren ist dieser Workaround jedoch super.

Sprites

Das Spirit-GitHub-Repository enthält ein Verzeichnis namens sprites, das acht .svg-Dateien mit Standard-Icons enthält. Diese Icons müssen zu einer einzigen Rasterbilddatei zusammengeführt und bereitgestellt werden. Für Entwicklungs- und Testzwecke empfiehlt die Spirit-Installationsanleitung die Verwendung des Basemaps-sprites Node-Pakets (Teil von Basemaps) in Kombination mit einem einfachen Python-HTTP-Webserver.

Wir hatten die Sprites zuvor schon via npm install @unvt/charites @basemaps/sprites installiert.

Öffne nun ein anderes Kommandozeilenfenster und wechsele ins Verzeichnis spirit um den Befehl node_modules/.bin/basemaps-sprites sprites && python3 serve.pyaufzurufen. Unter der Adresse http://127.0.0.1:8081/ findest du nun die Sprites die wir zuvor installiert haben.

Terminal window
cd ~/spirit
~/spirit$ node_modules/.bin/basemaps-sprites sprites && python3 serve.py
Write 7 sprites to sprites { ratio: 1 }
Write 7 sprites to sprites@2x { ratio: 2 }
Done
Serving HTTP on 127.0.0.1 port 8081 (http://127.0.0.1:8081/) ...
Stil

Schließlich muss der Spirit-Stil bereitgestellt werden. Die Spirit-Installationsanleitung empfiehlt Charites, ein Kommandozeilen-Tool zum Schreiben, Bearbeiten und Bereitstellen von Vektor-Kartenstilen. Die Installation via npm install @unvt/charites @basemaps/sprites erfolgte bereits.

Wiederum in einem anderen Kommandozeilen-Fenster rufen ich den Befehl zum hosten des Spirit-Stil unter http://localhost:8080/.

Terminal window
cd ~/spirit
~/spirit$ node_modules/.bin/charites serve style.yaml
Provider: default
Loading your style: /home/astrid/spirit/style.yaml
Your map is running on http://localhost:8080/

Nun erscheint unter der Adresse http://localhost:8080/#13.5/37.5981/-0.99064 die Ansicht der Region Murcia auf der Karte im Browser.

Ansicht Region Murcia auf der Karte im Tilekiln-Server.

Um zu überprüfen, ob auch Änderungen funktioniert, ändere ich einen Stil. Zum Beispiel ändere ich in der Datei /home/astrid/spirit/style/transit-points.yaml die icon-size des mit 3 - Standard ist 1. Der Bahnhof in Cartagena sollte auf der Karte danach größer angezeigt werden.

id: transit-points
source: spirit
source-layer: transit-points
type: symbol
layout:
icon-image: airport
icon-allow-overlap: true
text-optional: true
text-field: '{name}'
text-font: !!inc/file style/inc/regular-font.yaml
text-size: 12
text-offset: [0, 0.4]
text-anchor: top
paint:
text-color: '#003c77'
text-halo-width: 1
text-halo-color: white

Ansicht Region Murcia auf der Karte im Tilekiln-Server, wobei als Bahnhof ein Flugplatz angezeigt wird.

Was noch fehlt, sind Aktualisierungen. Wir haben Openstreetmap-Daten in die Datenbank eingelesen. Diese sind bisher statisch. Das heißt, sie ändern sich nicht, wenn zur Openstreetmap-Datenbank neue Inhalte hinzugefügt oder bestehende geändert werden. Außerdem fehlt noch eine einfache Möglichkeit, die Vector-Tiles an Gegebenheiten anzupassen. Letzteres ist etwas, was bei dem ich gerne Hilfestellungen hätte. Ich habe das Gefühl, dass ich jedes Mal das Rad neu erfinde.

Footnotes

  1. leafletjs.com

Impressum

Astrid Günther
Sonnenhang 23
56729 Kehrig
Germany
E-Mail: info At astrid-guenther.de

Ich freu mich über Anfragen zu den von mir hier beschriebenen Themen und beantworte diese zeitnah!

Datenschutz

Ich erhebe oder speichere keine personenbezogenen Daten über diese Website. Um den Aufruf dieser Seite zu ermöglichen, speichert der Internet-Provider einige Daten in Server-Log-Files, die ein Browser automatisch weiterleitet: Browsertyp und Browserversion, verwendetes Betriebssystem, Referrer URL, Hostname des zugreifenden Rechners, Uhrzeit der Serveranfrage, IP-Adresse. Die Grundlage für die Datenverarbeitung ist Art. 6 Abs. 1 DSGVO, der die Verarbeitung von Daten zur Erfüllung eines Vertrags oder vorvertraglicher Maßnahmen erlaubt.