Verwende Marker auf deinem eigenen Bild mit Leaflet

In den letzten beiden Blogbeiträgen haben wir PHP-Code zum Geocoding geschrieben. Diese Woche möchte ich euch zeigen, wie ihr etwas ähnliches Leaflet umsetzen könnt, einer bekannten JavaScript-Bibliothek zum Erstellen von Karten. Da es auch eine Funktion zum Hinzufügen eigener Bild-Layer hat, werden wir dies nutzen, um erneut unsere Karte zu erstellen.

Mit Leaflet loslegen

Wenn man Leaflet verwendet, dann muss man erst einmal ein wenig (externes) CSS und JavaScript laden. Ihr könnt mehr dazu im Quick Start Guide nachlesen, aber im Grunde braucht ihr die folgenden Dinge:

 <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
     integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
     crossorigin=""/>

 <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
     integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
     crossorigin=""></script>

<div id="leaflet-map"></div>

Neben dem CSS und JS braucht ihr noch einen Container, den die Map verwenden wird. Ihr könnt auch ein paar Styles angeben, aber dazu kommen wir gleich.

Die Karte aufsetzen

Wie auch in unseren vorherigen Beispielen werden wir erneut eine Deutschlandkarte verwenden, mit einer spezifischen Größe und Grenzen. Diese müssen wir auch bei Leaflet angeben:

// Create the map object.
const map = L.map( 'leaflet-map', {
    center: [ 51.1642, 10.4541 ],
    maxZoom: 10,
    zoomDelta: 1,
    zoomSnap: 0,
    scrollWheelZoom: false,
    trackResize: true,
    attributionControl: false,
} );

// Define the image overlay and its boundaries.L.marker([52.5162746,13.3777041]).addTo(map);
const imageUrl = './ammap-germany-low.svg';
const imageBounds = [
    [ 55.051693, 5.864765 ],
    [ 47.269299, 15.043380 ],
];

// Add the overlay to the map.
L.imageOverlay( imageUrl, imageBounds ).addTo( map );

// Automatically zoom the map to the boundaries.
map.fitBounds( imageBounds );

Zuerst erstellen wir das map Objekt mit einer Basis-Konfiguration. Dann definieren wir die Bildquelle und die Grenzen als GPS-Koordinaten, bevor wir sie schließlich zur Karte hinzufügen. Im letzten Schritt stellen wir sicher, dass das Bild in den Container eingepasst wird.

Der Container sollte eine gute Größe haben, um die Karte darzustellen und auch deren Seitenverhältnis. Wir verwenden einfach die SVG-Größe in unserem CSS:

#leaflet-map {
    width: 585.506px;
    height: 791.999px;
    background: white;
    max-width: 100%;
    max-height: 100%;
}

Es muss nicht so exakt angegeben werden und ihr könnt auch einen Container wählen, der größer/kleiner als das SVG ist.

Hinzufügen der Marker zur Karte

Nachdem wir nun die Karte haben, stellt sich die Frage, wie wir die Marker hinzufügen. Nun, da wir eine Karten-Bibliothek verwenden, ist das sehr einfach. Für einen Marker auf das Brandenburger Tor brauchen wir nur eine Zeile:

L.marker([52.5162746,13.3777041]).addTo(map);

Das ist wirklich alles! Keine Transformation von GPS zu Pixel-Koordinaten mehr. Das wird alles von Leaflet erledigt. Wir bekommen dann das folgende Ergebnis (nur ein Screenshot):

© ammap.com | SVG map of Germany (low detail), verwendet mit Leaflet, verändert durch Bernhard Kau, CC BY-NC 4.0

Der einzige Nachteil ist, dass Leaflet standardmäßig nur die EPSG:3857 Projektion (Web Mercator) unterstützt. Wenn ihr eine andere Projektion benötigt, dann gibt es aber eine PROJ Erweiterung: Proj4Leaflet.

Hinzufügen aller Landeshauptstädte zur Deutschlandkarte

Vermutlich möchtet ihr auf eurer Karte nicht nur einen einzelnen Marker darstellen. Fügen wir also ein paar mehr Marker hinzu. Ich habe hierzu eine Liste aller 16 Landeshauptstädte gemacht:

var capitals = [
    {
        'state': 'BB', 'name': 'Potsdam', 
        'lat': 52.4009309, 'lng': 13.0591397,
        'url': 'https://de.wikipedia.org/wiki/Potsdam'
    },
    {
        'state': 'BE', 'name': 'Berlin', 
        'lat': 52.5170365, 'lng': 13.3888599,
        'url': 'https://de.wikipedia.org/wiki/Berlin'
    },
    {
        'state': 'BW', 'name': 'Stuttgart', 
        'lat': 48.7784485, 'lng': 9.1800132,
        'url': 'https://de.wikipedia.org/wiki/Stuttgart'
    },
    {
        'state': 'BY', 'name': 'München', 
        'lat': 48.1371079, 'lng': 11.5753822,
        'url': 'https://de.wikipedia.org/wiki/München'
    },
    {
        'state': 'HB', 'name': 'Bremen', 
        'lat': 53.0758196, 'lng': 8.8071646,
        'url': 'https://de.wikipedia.org/wiki/Bremen'
    },
    {
        'state': 'HE', 'name': 'Wiesbaden', 
        'lat': 50.0820384, 'lng': 8.2416556,
        'url': 'https://de.wikipedia.org/wiki/Wiesbaden'
    },
    {
        'state': 'HH', 'name': 'Hamburg', 
        'lat': 53.550341, 'lng': 10.000654,
        'url': 'https://de.wikipedia.org/wiki/Hamburg'
    },
    {
        'state': 'MV', 'name': 'Schwerin', 
        'lat': 53.6288297, 'lng': 11.4148038,
        'url': 'https://de.wikipedia.org/wiki/Schwerin'
    },
    {
        'state': 'NI', 'name': 'Hannover', 
        'lat': 52.3744779, 'lng': 52.3744779,
        'url': 'https://de.wikipedia.org/wiki/Hannover'
    },
    {
        'state': 'NW', 'name': 'Düsseldorf', 
        'lat': 51.2254018, 'lng': 6.7763137,
        'url': 'https://de.wikipedia.org/wiki/Düsseldorf'
    },
    {
        'state': 'RP', 'name': 'Mainz', 
        'lat': 50.0012314, 'lng': 8.2762513,
        'url': 'https://de.wikipedia.org/wiki/Mainz'
    },
    {
        'state': 'SH', 'name': 'Kiel', 
        'lat': 54.3227085, 'lng': 10.135555,
        'url': 'https://de.wikipedia.org/wiki/Kiel'
    },
    {
        'state': 'SL', 'name': 'Saarbrücken', 
        'lat': 49.234362, 'lng': 6.996379,
        'url': 'https://de.wikipedia.org/wiki/Saarbrücken'
    },
    {
        'state': 'SN', 'name': 'Dresden', 
        'lat': 51.0493286, 'lng': 13.7381437,
        'url': 'https://de.wikipedia.org/wiki/Dresden'
    },
    {
        'state': 'ST', 'name': 'Magdeburg', 
        'lat': 52.1315889, 'lng': 11.6399609,
        'url': 'https://de.wikipedia.org/wiki/Magdeburg'
    },
    {
        'state': 'TH', 'name': 'Erfurt', 
        'lat': 50.9777974, 'lng': 11.0287364,
        'url': 'https://de.wikipedia.org/wiki/Erfurt'
    },
];

Ähnlich zum Beispiel aus den anderen beiden Blogbeiträgen möchten wir diese Marker auch verlinken. Ich habe hierzu einfach die Links zur deutschen Wikipedia verwendet. Ein Marker kann verschiedene Event-Handler bekommen. Wir verwenden hier den onclick Handler. Das Hinzufügen aller Marker wird dann mit diesem Code umgesetzt:

capitals.map( city => {
    let marker = L.marker( [ city.lat, city.lng ], { title: city.name } );
    marker.on( 'click', function () {
        window.location = city.url;
    } );
    marker.addTo( map );
} );

Das liefert uns das folgende Ergebnis (beim Hover über einen Marker erscheint zusätzlich der Name der Stadt als Titel):

© ammap.com | SVG map of Germany (low detail), verwendet mit Leaflet, verändert durch Bernhard Kau, CC BY-NC 4.0

Standardmäßig können wir in die Karte reinzoomen, aber auch raus. Das ist für ein Bild-Overlay in der Regel nicht optimal. Wenn wir rein und wieder rauszoomen, wollen wir die Karte wieder im Container zentrieren. Beides kann mit folgendem Code erreicht werden, den ich bei den Karten verwendet habe:

// Set the current min zoom to the zoom level after init.
map.setMinZoom( map.getZoom() );

// Re-center the map when zoomed to minZoom level.
map.on( 'zoomend', function () {
    if ( map.getZoom() === map.getMinZoom() ) {
        map.fitBounds( imageBounds );
    }
} );

Fazit

In den letzten drei Blogbeiträgen habt ihr gelernt, wie ihr mit euren eigenen Bildern individuelle Karten erstellen könnt. Wenn ihr nur eine statische Map braucht, dann ist der PHP-Ansatz wohl der beste. Wenn ihr allerdings eine interaktive Karte, ähnlich wie Google Maps (mit Zoomen, etc.) benötigt, dann wollt ihr vielleicht eher Leaflet verwenden.

Falls ihr auch diesen Code wieder selbst testen wollte, dann findet ihr eine lauffähige Version in einem neuen Branch auf GitHub. Ich habe dort alles in einer einzelnen HTML-Datei kombiniert, ihr könnte es aber natürlich auch auf mehrere Dateien aufteilen, z.B. in einem WordPress Theme/Plugin.

Ich habe noch eine Idee für einen „Bonus-Blogbeitrag“ in dieser Serie, aber vielleicht gibt es noch ein weiteres Thema zu interaktiven und individuellen Karten. ☺️

Veröffentlicht von

Bernhard ist fest angestellter Webentwickler, entwickelt in seiner Freizeit Plugins, schreibt in seinem Blog über WordPress und andere Themen, treibt sich gerne bei den WP Meetups in Berlin und Potsdam herum und läuft nach Feierabend den ein oder anderen Halbmarathon.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert