Leaflet Maps

Manuell eingebunden - ohne zusätzliche Contao-Extension.

Ausgehend von: Tipp von Franko im Contao-Forum

Weitere Quellen:

  1. Leaflet-Dokumentation
  2. Selfhtml - Einstieg in Leaflet
  3. https://kau-boys.de/4653/webentwicklung/verwende-marker-auf-deinem-eigenen-bild-mit-leaflet

Längengrad und Breitengrad herausfinden:

  • Mit dem Koordinaten Picker - das geht direkt hier - einfach Doppelklick auf die Karte
    Der Picker kann in der Datei files/js/leafletmap.js deaktiviert werden.
  • https://www.laengengrad-breitengrad.de/
  • oder auch mit Geojson, das noch weitere Funktionen bietet.

Es werden verschiedene Kartenlayer definiert, die rechts oben mit dem Layer-Icon aktiviert werden:

  • OSM Straßenkarte
  • topographische Karte
  • Satellit

und ein Fullscreen Plugin wird eingebaut.

Howto

Download Leaflet Library
Leaflet herunterladen und z.B. nach files/leaflet entpacken - Ordner veröffentlichen.

Für die Fullscreen Darstellung gibt es unter anderen z.B. dieses Plugin:
Download Fullscreen Plugin für Openstreetmap von Codeworld
Das Plugin herunterladen und nach files/leaflet/fullscreen entpacken.

Zunächst etwas CSS (SCSS)

  • Leaflet und das Fullscreen Plugin bringen jeweils eigene CSS Dateien mit, die im weiter unten stehenden Template eingebunden werden.
  • Da ich aber einige Selektoren ändern möchte, überschreibe ich diese in meinem eigenen CSS:
  • Wichtig ist eine Höhenangabe im .leaflet-container, weil sonst die Karte nicht angezeigt wird.

Hinweis: Folgende CSS Anweisungen gelten speziell für diese Website. Darum nicht einfach kopieren sondern nur als Idee für das eigene CSS nutzen.

// _leaflet_map.scss

// osmblocker oveleon-cookiebar
.osmblocker {
	width: calc(100% - 2*var(--marg));
	margin: 0 auto;
}
.button.osm {
	margin: 0 var(--marg);
}

// map
#map {
	margin-bottom: var(--margin-bottom);
}

.leaflet-container {
	z-index: var(--zindex-leaflet);
	height: calc(90vh - 50px);
	max-height: 700px;
	width: calc(100% - var(--marg));
	margin: 0 auto;
	background: var(--white);
	font-family: var(--font-default) !important;
	font-size: 1.3rem !important;
	@include respond-above(md) {
		height: 80vh;
		max-width: 1800px;
	}
	/* hr im Leaflet-popup */
	hr {
		margin: 5px 0;
	}
}
.leaflet-control,
.leaflet-bottom, 
.leaflet-top {
	z-index: var(--zindex-leaflet);
}

.leaflet-top {
	bottom: 3rem !important;
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
	background: var(--white);
	width: auto;
}

.leaflet-popup-content {
	p {margin: 0 !important;}
}

/* Stellt die Karten in Grautönen dar
.leaflet-tile-pane { 
 	-webkit-filter: grayscale(100%); 
 	filter: grayscale(100%); 
} 
*/

Zwei Javascript-Dateien anlegen

und in files/js speichern:

  1. files/js/osmblocker.js
    für die Anbindung an die oveleon/contao-cookiebar
  2. files/js/leafletmap.js
    für die Darstellung der Karten
// files/js/osmblocker.js
document.addEventListener("DOMContentLoaded", function() {
	cookiebar.addModule(6, initializeLeaflet, {
		selector: '#map',
		message: '<div class="osmblocker bg blue block"><p class="h3">Hier soll eine Karte gezeigt werden</p><p>Für die Kartendarstellungen nutzen wir fremde Dienste, die von externen Servern geladen werden. Dafür benötigen wir Ihre Zustimmung.<br>Sie können in den <a href="javascript:cookiebar.show(true);" title="Cookie-Settings" class="linkshield">Cookie Einstellungen</a> die Details einsehen und dort auch die Zustimmung jederzeit wieder ändern.</p></div>',
		button: {
			show: true,
			text: 'Zustimmen und Karte ansehen.',
			classes: 'button osm'
		}
	});
});

Anbindung an die Oveleon Cookiebar Extension

Auf die Oveleon Cookiebar gehe ich hier nicht näher ein, dafür gibt es bereits mehrere Threads im Contao-Forum.

Im Zusammenhang mit der OSM Karte ist wichtig, dass ganz oben in der files/js/osmblocker.js bei

cookiebar.addModule(6, initializeLeaflet, {...

die ID des entsprechenden Oveleon-Cookiebar-Eintrages steht. Hier in meinem Fall ist das die ID 6.

// files/js/leafletmap.js
function initializeLeaflet() {
	// Layer definieren
	var osm = L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
		'attribution': 'Kartendaten &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
		maxZoom: 19,
		useCache: true
	});
	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('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
		maxZoom: 18,
		attribution: 'Map data © <a href="https://www.esri.com/">Esri</a>, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
	});
	
	var map = L.map('map', { 
		layers: osm, 
		tap: false,
		fullscreenControl: true,
	});
	L.control.scale({imperial:false}).addTo(map); // imperial:false zeigt nur den metrischen Maßstab

	var baseLayers = {
		"OpenStreetMap": osm,
		"OpenTopoMap": opentopo,
		"Satellit": satellit
	};
	L.control.layers(baseLayers).addTo(map);
			
	// Kartenausschnitt festlegen
	var bounds = [ [47.50013976186046,9.732603475826199], [47.513192289950354,9.757662053958269] ];
	map.fitBounds( bounds );
	// Zentriert die Marker on resize
	// map.on("resize", function(e){
		// map.fitBounds( bounds );
	// });

	// Position von Markericon, etc. festlegen -->  
	var customIcon = L.Icon.extend({
		options: {
		shadowUrl: 'files/leaflet/images/marker-shadow.png',
		iconSize:    [25, 45],
		iconAnchor:  [12, 45],
		popupAnchor: [1, -43],
		tooltipAnchor: [16, -28],
		shadowSize:  [41, 45]
		}
	})
	// eigene Marker Icons festlegen	
	var blackIcon = new customIcon({ iconUrl: 'files/theme/design/marker/marker-black.png', iconRetinaUrl: 'files/theme/design/marker/marker-black-2x.png' })
	var blueIcon = new customIcon({ iconUrl: 'files/theme/design/marker/marker-blue.png', iconRetinaUrl: 'files/theme/design/marker/marker-blue-2x.png' })
	var redIcon = new customIcon({ iconUrl: 'files/theme/design/marker/marker-red.png', iconRetinaUrl: 'files/theme/design/marker/marker-red-2x.png' })
	var orangeIcon = new customIcon({ iconUrl: 'files/theme/design/marker/marker-orange.png', iconRetinaUrl: 'files/theme/design/marker/marker-orange-2x.png' })

	// mehrere Marker mit Popup in Karte einfügen --> 
	// wenn die Marker eine url haben, steht der Link im Popup
	// wenn die Marker kein spezielles Icon zugewiesen haben, wird das StandardIcon(blau) angezeigt 
	var myMarker = [
		{
			'name': 'Seebühne Bregenz',
			'latlng': [47.50572190274721, 9.738092422485353],
			'url': 'https://bregenzerfestspiele.com',
			'icon': redIcon,
		},
		{
			'name': 'Hafen Bregenz',
			'latlng': [47.506782927165574, 9.747180506246696],
		},
		{
			'name': 'Vorarlberger Landestheater',
			'latlng': [47.5046782514231, 9.747147560119629],
			'url': 'https://landestheater.org',
			'icon': orangeIcon,
		},
	];
	
	myMarker.map( mrk => {
		let marker = L.marker( mrk.latlng, { title: mrk.name }  );
		if ( mrk.icon && mrk.icon !== '' ) {
			marker = L.marker( mrk.latlng, { title: mrk.name,icon: mrk.icon }  );
		}
		if ( mrk.url !== undefined ) {
			marker.bindPopup(mrk.name+'<br><a class="linkextern" target="_blank" href="'+mrk.url+'">'+mrk.url+'</a>');
		} else {
			marker.bindPopup(mrk);
		}
		marker.addTo( map );
	} );

	// Koordinaten Picker
	// zum Deaktivieren einfach auskommentieren
	var popup = L.popup();
	map.on("dblclick", function(e) {
	  popup
		.setLatLng(e.latlng)
		.setContent('<p class="h5">Koordinaten Picker</p><hr><p>'+e.latlng.lat+', '+e.latlng.lng+'<hr>Kann in leafletmap.js deaktiviert werden!</p>')
		.openOn(map);
	});	
}

Twig-Template erstellen

Nachfolgenden Code als openstreetmap.html.twig im Ordner templates/content_element/html/ speichern.

In diesem Template werden alle Dateien zusammengeführt.

Wichtig dabei:

  • anders lautende Template-Namen müssen in der config/config.yaml der Cookiebar unter der Rubik iframe_types mitgeteilt werden (nur den Namen - ohne Suffix - eintragen). Siehe das Beispiel weiter unten.
  • Evtl. auch die Pfade zu den css und js - Dateien anpassen,
    ebenso die Pfade zum Fullscreen Plugin Control.FullScreen.css und Control.FullScreen.js

templates/content_element/html/openstreetmap.html.twig

{# templates/content_element/html/openstreetmap.html.twig #}
{% extends "@Contao/content_element/html.html.twig" %}

{#
  ** Add changes to the base template here. **

  Hint: Try adjusting blocks and attributes instead of
  overwriting the whole template. This way your version
  can remain compatible with future changes to the base
  template as well as adjustments made by extensions.

  Currently available blocks:
    "editor_view", "html"
#}

{% block html %}
   {{ parent() }}
   {# OSM Blocker einbinden #}
	<script src="files/js/osmblocker.js"></script>
	
	{# Leaflet einbinden #}
	<link rel="stylesheet" href="files/leaflet/leaflet.css">
	<script src="files/leaflet/leaflet.js"></script>
	{# Fullscreen einbinden #}
	<link rel="stylesheet" href="files/leaflet/fullscreen/Control.FullScreen.css" />
	<script src="files/leaflet/fullscreen/Control.FullScreen.js"></script>

	{# eigene Karte einbinden #}
	<script src="files/js/leafletmap.js"></script>
{% endblock %}

config/config.yaml

// config/config.yaml
contao_cookiebar:
    iframe_types:
        openstreetmap:
            - andererTemplatename

Karte in Contao ausgeben

Ein HTML-Element mit folgendem Inhalt anlegen und für die Ausgabe das angelegte openstreetmap-Template zuweisen:

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