Einstieg in Leaflet
Matthias Scharwies
- javascript
- softwareentwicklung
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.
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 );
});
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.
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.
Dieses Beispiel im eigenen Fenster.
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)
});
Dieses Beispiel im eigenen Fenster.
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"})
});
Dieses Beispiel im eigenen Fenster.
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);
});
Dieses Beispiel im eigenen Fenster.
Autor: Jürgen Berkemeier (SELFHTML-Urgestein seit 2005)
Webseite: www.j-berkemeier.de