Schritt für Schritt: OpenStreetMap Karte ohne Erweiterung
Es exisitieren zahlreiche Erweiterungen zum Thema für Contao [1,2,3,4].
Diese bieten einfache Integration und umfangreiche Funktionen zur Kartendarstellung.
In den meisten Fällen benötigt man wahrscheinlich lediglich eine einfache Karte mit einem Marker.
Dies könnte man auch mit Contao Bordmitteln ohne Erweiterung realisieren - Daher ...
Zur Umsetzung helfen aktuelle JS-Frameworks wie z.B.: Leaflet o. OpenLayers.
Die Frameworks selbst stellen kein Kartenmaterial zur Verfügung. Dazu werden Kartenanbieter wie Google-Maps, OpenStreetMap, mapbox usw. herangezogen.
Manche sind kostenfrei, manche nicht. Einige bieten eine eigene API und/oder erfordern Anmeldung sowie API-Keys zur Nutzung.
Die folgenden Beispiele nutzen das Leaflet-Framework zusammen mit OpenStreetMap (deutsche Karte).
Die Leaflet Tutorials [5] bieten einen übersichtlichen Einstieg.
Das Framework ist gut dokumentiert [6] und im Netz finden sich zahlreiche weitere Hilfenstellungen.
Getestet habe ich lokal noch mit Contao 4.8.x - sollte aber auch mit der 4.9.x funktionieren.
[1] con4gis/maps
[2] netzmacht/contao-leaflet-maps
[3] chrmue/cm_membermaps
[4] delahaye/dlh_googlemaps
[5] Leaflet Tutorials
[6] Leaflet Dokumentation
OpenStreetMap Karte mit Marker und eigenem Icon
Zur Umsetzung in Contao nutzen wir:
- jQuery: Muss im Seitenlayout aktiviert werden
- Contao Inhaltselement vom Typ "HTML"
- Eigenes Template für das obige Inhaltselement
Zunächst laden wir die aktuelle Leaflet Version (z.Zeit v1.6.0)
herunter und speichern diese in einem bel. Verzeichnis unterhalb von Contao "files" ab.
Benötigt werden hier die Dateien "leaflet.css" und "leaflet.js".
Vorgehensweise:
- Erstellt ein neues Template basierend auf "ce_html.html5" und benennt es z.B. "ce_html_map.html5".
- Erstellt ein neues Inhaltselement vom Typ "HTML" und wählt hier obiges Template "ce_html_map.html5" aus.
Im Inhaltselement selbst trägt man folgendes ein:
HTML-Code:
<div id="MYMAP" class="block" style="height:80vh"></div>
Hinweis:
Die CSS-Angabe "height" (in px o. vh) ist zwingend erforderlich!
Zur Demo hier inline eingetragen. Kann aber auch über ein externes CSS-Stylesheet gesetzt werden.
Die CSS-ID "MYMAP" ist beliebig muss aber im folgenden Template entsprechend lauten.
Im Template trägt man folgendes ein:
Code:
<link rel="stylesheet" href="/files/MeinPfadZurDatei/leaflet.css"/>
<script src="/files/MeinPfadZurDatei/leaflet.js"></script>
<?= $this->html ?>
<script>
function createMap(){
// container CSS-ID
const mapCssId = 'MYMAP';
// coordinates
const latitude = 51.492789;
const longitude = 7.451879;
const latLng = L.latLng(latitude, longitude);
const zoomDefault = 15;
const zoomMin = 8;
const zoomMax = 18;
const myMarkerIconURL = '/files/MeinPfadZurDatei/marker-icon.png'; // marker icon path
const myMarkerHtmlInfo = '<b>Signal Iduna Park</b><br>Borussia Dortmund'; // marker popup info
// Custom Marker Icon
var myMarkerIcon = new L.icon({
iconUrl: myMarkerIconURL,
iconSize: [25, 41], // size of the icon
iconAnchor: [12, 41], // point of the icon which will correspond to marker's location
popupAnchor: [0, -30] // point from which the popup should open relative to the iconAnchor
});
// create marker
var myMarker = new L.marker(latLng, {icon: myMarkerIcon}).bindPopup(myMarkerHtmlInfo);
// add layer(s) to group
var myGroup = new L.featureGroup([myMarker]);
// map tiles provider - see for example https://leaflet-extras.github.io/leaflet-providers/preview/
var mapProvider =
new L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
attribution: '©<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
// initiate map
var map = new L.Map(mapCssId, {
minZoom: zoomMin,
maxZoom: zoomMax,
scrollWheelZoom: false,
fadeAnimation: false,
layers: [mapProvider, myGroup]
});
map.setView(latLng, zoomDefault); // show map and center to coordinates
myMarker.openPopup(); // optional open Marker Popup
// on resize ...
map.on("resize", function(e){
map.setView(latLng, zoomDefault); // ... center back to marker
});
}
(function($){
$(document).ready(function(){
createMap();
});
})(jQuery);
</script>
Alle obigen Einträge a la MeinPfadZurDatei bitte mit den tatsächlichen Pfadangaben ersetzen!
Die Kommentare helfen hoffentlich.
Die Variablen dienen nur der Übersicht.
Setzt man anstelle der Variablen die Werte und entfernt die Kommentare bleiben nur wenige Zeilen übrig.
Einbindung der Leaflet Dateien:
Im Beispiel wurden die Dateien "leaflet.css" und "leaflet.js" (Reihenfolge beachten!) direkt gesetzt.
Man kann diese aber auch über die Contao Mittel a la
$GLOBALS['TL_CSS'][] = '...' und $GLOBALS['TL_JAVASCRIPT'][] = '...' einfügen lassen.
Marker Icon:
Das Beispiel bezieht sich auf das Standard Leaflet Marker-Icon "marker-icon.png" (befindet sich im Leaflet Verzeichnis).
Wenn man hier ein anderes, eigenes Icon nutzen möchte müssen die Angaben "iconSize", "iconAnchor" u. "popupAnchor" entsprechend angepasst werden.
GEO-Koordinaten:
Im Beispiel werden die GEO-Koordinaten für das BVB-Stadion in Dortmund gesetzt :-).
Für "latitude" und "longitude" dann die passenden Werte der jeweiligen Adresse (s.u.) eintragen.
Davon abgesehen kann man mit den Werten "zoomMin", "zoomMax" (normalerweise von 0 bis 20) und "zoomDefault" spielen.
Ansonsten müssen zukünftig lediglich die Werte für "latitude" und "longitude" im Template geändert werden.
Das Ergenbnis:
Abhängig von der Containter "height" Angabe erhalten Sie eine Kartendarstellung mit der entsprechenden Zoom-Stufe ("zoomDefault").
Neben den Copyright Infos erhalten Sie Zoom-Buttons zur Kontrolle des Zooms (begrentzt durch Angabe von "zoomMin" und "zoomMax").
Zitat:
GEO-Koordinaten manuell ermitteln:
Es gibt zahlreiche Möglichkeiten diese GEO-Daten anhand einer Adresse zu ermitteln. Am einfachsten:
- Adresse mit Google-Maps suchen
- Dann RechtsKlick auf den Ergebnis-Marker und Auswahl "Was ist hier"
- Die entsprechenden Koordinaten werden dann angezeigt
Umsetzung mit einer GeoJSON Datei
Mit den obigen Beispielen könnte man ein o. mehrere Layer (Marker etc.) setzen.
Eine Alternative hierzu wäre die Nutzung einer GeoJSON Datei. Hierbei werden die Karten-Inhalte quasi ausgelagert.
Folgendes Beispiel für das Template:
Code:
<link rel="stylesheet" href="/files/MeinPfadZurDatei/leaflet.css"/>
<script src="/files/MeinPfadZurDatei/leaflet.js"></script>
<?= $this->html ?>
<script>
function createMap(){
// container CSS-ID
const mapCssId = 'MYMAP';
var fileGeoData = '/files/MeinPfadZurDatei/mymapdata.geojson';
const zoomDefault = 15;
const zoomMin = 8;
const zoomMax = 18;
const myMarkerIconURL = '/files/MeinPfadZurDatei/marker-icon.png'; // marker icon path
const myMarkerHtmlInfo = '<b>Signal Iduna Park</b><br>Borussia Dortmund'; // marker popup info
// Custom Marker Icon
var myMarkerIcon = new L.icon({
iconUrl: myMarkerIconURL,
iconSize: [25, 41], // size of the icon
iconAnchor: [12, 41], // point of the icon which will correspond to marker's location
popupAnchor: [0, -30] // point from which the popup should open relative to the iconAnchor
});
// map tiles provider - see for example https://leaflet-extras.github.io/leaflet-providers/preview/
var mapProvider =
new L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', {
attribution: '©<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
// initiate map
var map = new L.Map(mapCssId, {
minZoom: zoomMin,
maxZoom: zoomMax,
scrollWheelZoom: false,
fadeAnimation: false,
layers: [mapProvider]
});
// create feature content
function getEachFeature(feature, layer){
var popupContent = "";
if (feature.properties && feature.properties.name && feature.properties.info) {
popupContent += "<b>" + feature.properties.name + "</b><br>" +
feature.properties.info;
}
layer.bindPopup(popupContent);
};
// read .geojson file and fetch all feature properties
$.getJSON(fileGeoData, function(data){
locations = L.geoJson(data, {
// fetch all features
onEachFeature: getEachFeature, pointToLayer: function(feature, latlng){
return L.marker(latlng, {icon: myMarkerIcon}); // create marker
}
});
map.fitBounds(locations.getBounds(), {padding: [50,50]}); // fit map with optional padding (takes into account the map maxZoom value)
locations.addTo(map);
function openMarkerPopup(id){
locations.eachLayer(function(feature){
if(feature.feature.properties.id==id){
feature.openPopup();
}
});
}
// optional open a specific marker popup from feature ID property
openMarkerPopup(10);
});
// on resize ...
map.on("resize", function(e){
map.fitBounds(locations.getBounds(), {padding: [50,50]}); // with optional padding
});
}
(function($){
$(document).ready(function(){
createMap();
});
})(jQuery);
</script>
Ersetzt auch hier wieder zunächst alle MeinPfadZurDatei Einträge mit den tatsächlichen Pfadangaben!
Scheint etwas komplizierter - Aber lediglich die Variable "fileGeoData" (s.u.) ist hier relevant.
Über jquery lesen wir die json Datei ein ($.getJSON ...) und in der Funktion (getEachFeature()) werden die eigentlichen Karten features verarbeitet.
Weiteres zur eigentlichen json Datei s.u..
Nützliche Leaflet PlugIns
Das beliebte Leaflet-Framework kann man mit PlugIn's erweitern.
Eine kleine Übersicht findet sich hier: https://leafletjs.com/plugins.html
Beispiele:
https://github.com/Leaflet/Leaflet.fullscreen
Erweitert die Karten Controls mit einem FullScreen-Button/Ansicht.
https://github.com/Zverik/leaflet-grayscale
Manche Kartenanbieter verfügen über SW/Graustufen Tiles.
Mit diesem PlugIn kann man bel. Karten in Graustufen anzeigen lassen.
https://github.com/Leaflet/Leaflet.markercluster
Wenn man wirklich viele Marker nutzt werden hierüber, abhängig vom Zoom-Level,
mehrere Marker übersichtlich zusammengefasst und dargestellt.
3D-Ansichten:
Auch hierzu gibt es zahlreiche Möglichkeiten. Eine wäre https://osmbuildings.org/.
Auch in Kombination mit Leaflet: https://osmbuildings.org/documentation/leaflet/