Matthias Scharwies: Einstieg in Leaflet

Oft möchte man auf seiner Website eine Landkarte anzeigen, z.B. um Besuchern den Weg zu zeigen, den Standort von Filialen oder Partnern zu zeigen, oder auch die Wohnorte von Mitgliedern einer Community oder eines Vereins.

Inzwischen gibt es mehrere Anbieter von interaktiven Karten, z.B. Bing Maps, Google Maps oder Open Street Map. Möchte man Karten von einem dieser Anbieter in seine Seite einbinden, benötigt man eine Schnittstelle, ein Application Programming Interface (API).

In diesem Artikel beschreibe ich, wie mit dem Leaflet API eine Karte erstellt wird, wie man auf der Karte Marker platziert und wie man auf der Karte Linien zeichnen kann. Für darüber hinaus gehende Anforderungen verweise ich auf die Leaflet-Dokumentation.

Die Beispiele laden das Leafletscript und das Leaflet-CSS von unpkg.com sowie das Kartenmaterial von OpenStreetMap, OpenStreetMapDe, OpenTopoMap und Esri. Dabei werden aus technischen Gründen Daten der Seitenbesucher, wie z.B. deren IP-Adresse, an diese Dienste übertragen. Um den Datenschutz zu wahren, werden die Besucher auf diesen Umstand hingewiesen und um Zustimmung gebeten.

Die Karte

Um Karten anzeigen zu können, benötigt man im HTML nur ein Block-Level-Element mit einer ID, z.B. ein figure, das sich hier mittels CSS-Angaben über den ganzen Viewport erstreckt.

<style>
  #map { width: 100vw; height: 100vh; margin:0; padding:0 }
</style>
<figure id="map></figure>

Zusätzlich müssen eine css-Datei und das Leaflet-API-Script eingebunden werden. Damit dieses erst nach der Zustimmung der Besucher erfolgt, werden nicht die Elemente link und script verwendet, sondern die Hilfsfunktionen loadCSS und loadScript:

// CSS laden
loadCSS("https://unpkg.com/leaflet@1.4.0/dist/leaflet.css");

// Leafletscript laden
loadScript("https://unpkg.com/leaflet@1.4.0/dist/leaflet.js", kartenScript);

In der Funktion kartenScript, die nach dem Laden des Leafletscripts aufgerufen wird, werden die Kartenelemente erstellt.

Das Leaflet-API benötigt wie auch das Google Maps API Kartenbilder im png- oder jpeg-Format. Diese Bilder werden von diversen Servern mehr oder weniger frei zur Verfügung gestellt. Dabei wird die Welt schachbrettartig mit Kartenbildern abgedeckt. In der 1. Zoomstufe hat man ein Bild, in der zweiten 4, in der dritten 16 usw.. Diese Bilder werden Tiles genannt.

Für diese Tiles muss ein Layer erstellt werden.

var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  maxZoom: 19,
  attribution: 'Map data © <a href="https://www.openstreetmap.org/" target="_blank" rel="noopener">OpenStreetMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank" rel="noopener">CC-BY-SA</a>'
});

Hierbei ist https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png ein Templatestring, bei dem zur Laufzeit die in geschweiften Klammern stehenden Angaben durch die Servernummer (s), den Zoomlevel (z) sowie die Koordinaten der Tiles (x,y) ersetzt werden. Mit dem sich so ergebenden URL können dann die Tiles vom Server geholt werden. Zusätzlich wird noch der Zoom-Bereich festgelegt und ein Copyright-String übergeben.

Um diesen Layer anzeigen zu können, muss ein Kartenbereich angelegt werden, der den Kartensatz zeigt. Mit tap: false sorgt man dafür, auch auf Smartphones und Tabletts noch scrollen zu können. Unten wird noch ein Maßstab eingeblendet.

var map = L.map('map', { layers: osm, tap: false } ) ;
L.control.scale({imperial:false}).addTo(map); // Mit metrischem Maßstab

Zum Schluss muss noch ein Kartenausschnitt gewählt werden und dann ist die Karte zu sehen:

var bounds = [ [52.6, 13.1], [52.4, 13.7] ];
map.fitBounds( bounds );

Da sich in diesem Beispiel die Kartengröße an die Viewportgröße anpasst, wird für das Ereignis "resize" ein Eventhandler notiert, der bei Größenänderung die Karte neu skaliert.

map.on("resize", function(e){
  map.fitBounds( bounds );
});

Eine einfache Karte

Dieses Beispiel im eigenen Fenster.

Diese Karte kann jetzt mit der Maus oder per Touch bewegt werden. Über die [+/-]-Schaltfläche, mit dem Scrollrad oder per Doppelklick kann der Kartenausschnitt vergrößert oder verkleinert werden.

Mehrere Karten zur Auswahl

Es können auch mehrere Kartensätze angelegt werden. Im Folgenden werden zusätzlich Layer für die deutsche Version der Open Steet Map Karte, für die Open Topo und für ein Satellitenbild erstellt.

var osmde = L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
  maxZoom: 19,
  attribution: 'Map data © <a href="https://www.openstreetmap.org/" target="_blank" rel="noopener">OpenStreetMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank" rel="noopener">CC-BY-SA</a>'
});

var opentopo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
  maxZoom: 17,
  attribution: 'Kartendaten: © OpenStreetMap-Mitwirkende, SRTM | Kartendarstellung: © <a href="https://opentopomap.org/about">OpenTopoMap</a> (CC-BY-SA)'
});

var satellit = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
  maxZoom: 18,
  attribution: 'Map data © <a href="http://www.esri.com/">Esri</a>, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});

Um zwischen den Karten wählen zu können, wird dafür ein Kontrollelement benötigt:

var baseLayers = {
  "OSM": osm,
  "OSMDE": osmde,
  "Open Topo": opentopo,
  "Satellit": satellit
};
L.control.layers(baseLayers).addTo(map);

Über den "Kartenstapel" rechts oben kann ein anderes Kartenlayout gewählt werden. Hier finden wir die Angaben aus der "baseLayers"-Definition wieder.

Eine Karte mit Kartenauswahl

Dieses Beispiel im eigenen Fenster.

Marker

Zum Markieren von Orten auf der Karte gibt es die Methode L.marker. Für einen einfachen Marker müssen dieser Methode nur die Koordinaten als Array übergeben werden:

L.marker([52.45, 13.4]).addTo(map);

Wenn bei einem Klick auf den Marker Infos angezeigt werden sollen, geht dieses mit bindPopup. Auf Wunsch kann das Infofenster schon beim Aufrufen der Karte offen sein:

L.marker([52.55, 13.4]).addTo(map).bindPopup("<b>Hello world!</b>
I am a popup.").openPopup();

Mit L.icon kann ein eigenes Icon für den Marker definiert werden, und mit on können mit dem Marker Eventhandler verknüpft werden, z.B. für click:

var logo = L.icon({
  iconUrl: 'S-Logo-vektor.svg',
  iconSize: [41, 41],
  iconAnchor: [21, 21]
});

L.marker([52.5, 13.4], {icon: logo}).addTo(map).on("click",function(event){
  console.info(event)
});

Eine Karte mit Markern

Dieses Beispiel im eigenen Fenster.

Linien

Ein weiteres Gestaltungselement sind Linien. Mit der Methode L.polyline können Linienzüge gezeichnet werden. Diese Methode benötigt als Parameter ein Array aus Arrays mit den Koordinatenpaaren, sowie u.A. Angaben zur Farbe, zur Stärke und zur Opazität der Linien. Auch Linien können mit einem Infofenster oder mit Eventhandlern verknüpft werden:

// Linie, mit Popup
L.polyline([
    [52.4, 13.7],
    [52.5, 13.7],
    [52.55, 13.6],
    [52.5, 13.5],
    [52.4, 13.5],
    [52.4, 13.7],
    [52.5, 13.5],
    [52.5, 13.7],
    [52.4, 13.5]
  ],
  {color: "red", weight: 10, opacity: 0.5}
).addTo(map).bindPopup("Das ist das Haus vom Ni-ko-laus");

// Linie mit Mouseover-Effekt
L.polyline([
    [52.45, 13.2],
    [52.55, 13.3]
  ],
  {color: "green", weight: 10, opacity: 1}
).addTo(map)
.on("mouseover", function(e) {
  e.sourceTarget.setStyle({color: "red"})
})
.on("mouseout", function(e) {
  e.sourceTarget.setStyle({color: "green"})
});

Eine Karte mit Markern und Linien

Dieses Beispiel im eigenen Fenster.

Eine Karte mit Klick-Event

Zum Schluss erhält die Karte noch einen Eventhandler, der bei Klick auf die Karte die Koordinaten in einem Popup angezeigt.

// Bei Klick auf Karte Koordinaten im Popup anzeigen
var popup = L.popup();
map.on("click", function(e) {
  popup
    .setLatLng(e.latlng)
    .setContent('<p>'+e.latlng.lat+','+e.latlng.lng+'</p>')
    .openOn(map);
});

Eine Karte mit Klickevent

Dieses Beispiel im eigenen Fenster.

über den Autor

Autor: Jürgen Berkemeier (SELFHTML-Urgestein seit 2005)
Webseite: www.j-berkemeier.de

  1. Hallo Matthias. Danke für die ausführliche Beschreibung. Gut, dass es noch einige kostenlose Alternativen zu Google Maps gibt. Marker, klar. Pop Up, auch klar. Aber warum bitte Linien ? Und muss man tatsächlich immer eine API haben??? Das bedingt doch dann auch ein entsprechendes Konto, um die API nutzen zu können, oder nicht?
  2. Linien sind ein Gestaltungselement, das man nutzen kann, aber nicht muss. Die Leaflet API ist eine kleine Bibliothek, die du selbst auf Deinem Server hostest. Der Begriff API zeigt einfach, dass es hier wie die Geolocation API eine Schnittstelle zu OpenStreetMap ist.
  3. Hallo Mathias, auch von mir ein herzliches Dankeschön. Du hast damit kurz und bündig das Wesentliche auf den Punkt gebracht. Habe etwa drei Tage verkuhhackelt weil ich nicht zuerst auf Selfhtml gesucht und Deine super Beschreibung gefunden habe. Na ja, man lernt nie aus. Wünsche Dir angenehmes Wirken und viel Spaß dabei. Schönen Gruß Heinz