Processwire - Leaflet Map Marker Modul

Aus Wikizone
Wechseln zu: Navigation, Suche

Siehe auch

https://processwire.com/talk/topic/9745-module-leaflet-map/?page=5 (Forum)
https://github.com/gmclelland/FieldtypeLeafletMapMarker/blob/PW3/InputfieldLeafletMapMarker.module (Fork)
https://leafletjs.com/ (Leaflet Hauptseite)
https://leaflet-extras.github.io/leaflet-providers/preview/index.html (Karten Provider)
https://github.com/Leaflet/Leaflet.markercluster (Doku für Cluster Modul)
https://github.com/leaflet-extras/leaflet-providers

Überblick

Wird aus Zeitgründen vom Entwickler nicht sehr aktiv weitergepflegt. Allerdings gibt es ordentlichen Support im Forum und ein paar Forks auf Github.

Man kann für spezielle Anforderungen auch nur das Feld im Backend nutzen und Leaflet im Frontend selbst aufsetzen bzw. eigene Skripte nutzen. Das JavaScript für die Frontendausgabe im Modul findet man in:

MarkupLeafletMap.js (JavaScript für Frontend-Ausgabe)
MarkupLeafletMap.module (Inline JS für Frontend ) 

Quickstart

  • Benötigt die Konfiguration von $additionalHeaderData. Das ist einfach ein String der in _init.php angelegt und im Header eingebunden wird. Damit lassen sich Zusätzliche Daten per Template rendern.
  • Feldname im Backend ist hier map_leaflet
  • Achtung Bug (V2.8.1): Immer den Geocoder auf der Seite benutzen. Die Standarddaten aus der Feldkonfiguration werden nicht richtig übernommen (Adressfeld) und es gibt Ausgabefehler.

Beispiel

$map = wire('modules')->get('MarkupLeafletMap');
$additionalHeaderData = $map->getLeafletMapHeaderLines();
$mapMarkup = $map->render($page, 'map_leaflet ,array('markerColour' => 'green'));

$content .= '
  <div class="content_bottom">
    <!-- Button GM -->
    <div class="gmroute" style="z-index: 30001;position: relative;height: 24px;right: 20px;top: 40px;">
      <a class="gmroute-link" href="https://www.google.de/maps/dir//Lange+Str.+9+D-72829+Engstingen" target="_blank" style="float: right;">Route planen</a>
    </div>
    <!-- Map -->
    <div class="col span_12">'.$mapMarkup.'</div>
  </div>';

Daten manuell auslesen und verarbeiten

Einfaches Beispiel das auch bei AJAX Seiten funktioniert und einen Button zur Google Maps Wegbeschreibung enthält.

// If AJAX put this in _init.php else uncomment next two lines
// $map = wire('modules')->get('MarkupLeafletMap');
// $additionalHeaderData = $map->getLeafletMapHeaderLines();

$myAdress = $page->map_leaflet->address;	// outputs the address you entered
$myLat = $page->map_leaflet->lat; 		// outputs the latitude
$myLng = $page->map_leaflet->lng; 		// outputs the longitude
$myZoom = $page->map_leaflet->zoom;		// outputs the zoom level

$mapMarkup = "
<div id='mleafletmap1'style='height:400px;'></div>
<script>
var mleafletmap1 = new jsMarkupLeafletMap();
 mleafletmap1.setOption('zoom', $myZoom);
  mleafletmap1.init('mleafletmap1', $myLat, $myLng, 'OpenStreetMap.Mapnik');
  var default_marker_icon = L.AwesomeMarkers.icon({ icon: 'home', iconColor: 'white', prefix: 'fa', markerColor: 'darkblue' });
  mleafletmap1.addMarkerIcon(default_marker_icon, $myLat, $myLng, '/kontakt/', 'Kontakt', '');
</script>
";

$content .= '
<div class="row">
  <div class="gmroute" style="z-index: 30001;position: relative;height: 24px;right: 20px;top: 40px;">
    <a class="gmroute-link" href="https://www.google.de/maps/dir//Meine+Str.+9+D-72829+Engstingen" target="_blank" style="float: right;">Route planen</a>
  </div>
  <div class="col-sm-12" style="height:400px;">'
    .$mapMarkup.'
  </div>
</div>

Geocoder

Das Modul verwendet an zwei Stellen einen Geocoder.

Am wichtigsten ist er wenn man ein Feld definiert hat. In der Karte gibt es eine kleine Lupe mit der man nach Adressen suchen kann. Dies wird realisiert über die JavaScript Datei:

Control.Geocoder.js

Sie enthält Code für verschiedene Geocoding Dienste. Standard ist Nominatim (von OpenStreetMap). Eventuell muss man diesen Code ab und zu anpassen, wenn sich die APIs der Anbieter ändern.

Beispiele

Siehe Webmynet Cloud für aktuelles Beispiel cloud.webmynet.de (Developer/ProcessWire/Module)

Multiple Markers

Die Render Funktion kann auch mit mehreren Seitenobjekten umgehen und erstellt dann eine Karte mit mehreren Markern.

$items = $pages->find("A SELECTOR THAT GETS YOUR PAGES WITH MARKER FIELDS");
echo $map->render($items, 'YOUR MARKER FIELD');

Multiple Markers von selektierten Seiten

Es sollen Orte (LeafletMapMarker) von Unterseiten geholt werden und aus diesen eine Map mit mehreren Markern generiert werden. Viele Marker auf engem Raum werden geclustert.

Voraussetzungen im Beispiel

  • die Kindseiten werden über ihr template selektiert. Im Beispiel wird das durch ein Textfeld im Parent Template festgelegt (Feldname template_title)
  • der Leaflet code wird nur bei Bedarf geladen. Das geschieht über eine Switch Anweisung im Repeater
  • Leaflet Dateien sind lokal hinterlegt (siehe js und css Anweisungen).

mytemplate.php

$additionalHeaderData .= '
<!-- Styles supporting the use of Leaflet.js -->
<link rel="stylesheet" type="text/css" href="'.$config->urls->templates.'vendors/leaflet/leaflet.css" />
<link rel="stylesheet" type="text/css" href="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-markercluster/MarkerCluster.css" />
<link rel="stylesheet" type="text/css" href="'.$config->urls->templates.'styles/MarkerCluster.Custom.css" />

<!-- Scripts supporting the use of Leaflet.js -->
<script type="text/javascript" src="'.$config->urls->templates.'vendors/leaflet/leaflet.js"></script>
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-markercluster/leaflet.markercluster.js"></script>
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-providers/leaflet-providers.js"></script>
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/MarkupLeafletMap.js"></script>

<!-- Extend Leaflet with Awesome.Markers -->
<link rel="stylesheet" type="text/css" href="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-awesome-markers/leaflet.awesome-markers.css" />
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-awesome-markers/leaflet.awesome-markers.min.js"></script>
';

$map = wire('modules')->get('MarkupLeafletMap');
$options = array('markerColour' => 'green');
$mySelector = 'template=event';
$places = $pages->find($mySelector);
$mapMarkup = $map->render($places, 'location' ,$options);

Leaflet Skripte lokal einbinden (keine externen Skripte laden)

Dies sind die benötigten Header Zeilen. leaflet.css und leaflet.js sollte dann entsprechend vorhanden sein. Der Rest kommat aus dem Modul Verzeichnis.

Hinweis: Font Awesome muß ebenfalls vorhanden sein (Bisher - September 2018, die 4er Version).

$additionalHeaderData = '
<!-- Styles supporting the use of Leaflet.js -->
<link rel="stylesheet" type="text/css" href="'.$config->urls->templates.'vendors/leaflet/leaflet.css" />
<link rel="stylesheet" type="text/css" href="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-markercluster/MarkerCluster.css" />
<link rel="stylesheet" type="text/css" href="'.$config->urls->templates.'styles/MarkerCluster.Custom.css" />

<!-- Scripts supporting the use of Leaflet.js -->
<script type="text/javascript" src="'.$config->urls->templates.'vendors/leaflet/leaflet.js"></script>
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-markercluster/leaflet.markercluster.js"></script>
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-providers/leaflet-providers.js"></script>
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/MarkupLeafletMap.js"></script>

<!-- Extend Leaflet with Awesome.Markers -->
<link rel="stylesheet" type="text/css" href="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-awesome-markers/leaflet.awesome-markers.css" />
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/leaflet-awesome-markers/leaflet.awesome-markers.min.js"></script>
';

Scroll Zoom abschalten

Am einfachsten im Modul (Nachteil: Vorsicht beim Update)

Evtl. fürs Frontend könnte man auch im Nachhinein in einem eigenen Skript abschalten über die Funktion:

map.scrollWheelZoom.disable(); // map ist die Mapinstanz. Muß evtl. angepasst werden.

Im Frontend (Fieldtype)

/site/modules/FieldtypeLeafletMapMarker/MarkupLeafletMap.js

In MarkupLeafletMap.js die Option hinzufügen.

this.options = {
        zoom: 10,
        center: null,
        scrollWheelZoom: false, // diese option einfügen
    };

    this._currentURL = '';
    this.init = function(mapID, lat, lng, provider) {
        if(lat != 0) this.map = L.map(mapID, {
          center: [lat, lng],
          zoom: this.options.zoom,
          scrollWheelZoom: this.options.scrollWheelZoom // und dieses wenn nicht vorhanden
        } );
        L.tileLayer.provider(provider).addTo(this.map);
    }

Im Backend

Hier muß mann den Code des Inputfield anpassen. Direkt in den Optionen hat das bei mir nicht funktioniert. Sieht so aus als ob nur der zoom statt alle Optionen gesetzt wird. Daher einfach nach der Instanzerzeugung der karte den ScrollWheelZoom abschalten:

FieldtypeLeafletMapMarker/InputfieldLeafletMapMarker.js

var map = L.map(document.getElementById(mapId)). setView([lat, lng], options.zoom); // nach dem hier
map.scrollWheelZoom.disable(); // dieses einfügen.

Modul Gesture Handling

Leaflet - Gesture Handling
https://elmarquis.github.io/Leaflet.GestureHandling/
Bildet das Verhalten von Google Maps nach:

Desktop

  • Karte Ignoriert Mausrad
  • User wird Informiert mit ctrl+scrool Karte zoomen

Mobile

  • Karte ignoriert Ein Finger Drag
  • User wird über 2 Finger Pan informiert

In ProcessWire einbauen

  • Unterordner 'dist' in 'Leaflet.GestureHandling' umbenennen und im FieldtypeLeafletMapMarker Modul unter assets ablegen
  • anpassen des JS für die Frontendausgabe
/site/modules/FieldtypeLeafletMapMarker/MarkupLeafletMap.js
  • Init Funktion anpassen:
    this.init = function(mapID, lat, lng, provider) {
        if(lat != 0) this.map = L.map(mapID, {
          center: [lat, lng],
          zoom: this.options.zoom,
          scrollWheelZoom: this.options.scrollWheelZoom,
          gestureHandling: true
        } );
        L.tileLayer.provider(provider).addTo(this.map);
    }
  • Einbinden von CSS und JS
<!-- Extend Leaflet with Gesture Handling -->
<link rel="stylesheet" href="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/Leaflet.GestureHandling/leaflet-gesture-handling.min.css" type="text/css">
<script type="text/javascript" src="'.$config->urls->siteModules.'FieldtypeLeafletMapMarker/assets/Leaflet.GestureHandling/leaflet-gesture-handling.min.js"></script>

Allgemein

<div id='map'></div>

<script>
	var cities = new L.LayerGroup();

	L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.').addTo(cities),
	L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.').addTo(cities),
	L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.').addTo(cities),
	L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.').addTo(cities);


	var mbAttr = 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, ' +
			'<a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
			'Imagery © <a href="http://mapbox.com">Mapbox</a>',
		mbUrl = 'https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw';

	var grayscale   = L.tileLayer(mbUrl, {id: 'mapbox.light', attribution: mbAttr}),
		streets  = L.tileLayer(mbUrl, {id: 'mapbox.streets',   attribution: mbAttr});

	var map = L.map('map', {
		center: [39.73, -104.99],
		zoom: 10,
		layers: [grayscale, cities]
	});

	var baseLayers = {
		"Grayscale": grayscale,
		"Streets": streets
	};

	var overlays = {
		"Cities": cities
	};

	L.control.layers(baseLayers, overlays).addTo(map);
</script>

Popup über URL Parameter öffnen

https://stackoverflow.com/questions/29004617/open-leaflet-marker-using-url-parameter-not-working-now-that-markercluster-is-us

Weitere Kartenanbieter

Leaflet Map Marker liefert einige Provider mit. Man kann sie über die Option provider auswählen.

"provider" => 'OpenStreetMap.Mapnik',

So lassen sich auch andere Anbieter nutzen:

"provider" => 'Stadia.AlidadeSmooth',

Das JavaScript für die Anbieter liegt in leaflet-providers.js. Dort kann man auch weitere Provider anlegen.

// ...
Stadia: {
			url: 'https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png',
			options: {
				maxZoom: 20,
				attribution: '&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'
			},
			variants: {
				AlidadeSmooth: {
					url: 'https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png'
				},
				AlidadeSmoothDark: {
					url: 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png'
				},
				OSMBright: {
					url: 'https://tiles.stadiamaps.com/tiles/osm_bright/{z}/{x}/{y}{r}.png'
				},
				Outdoors: {
					url: 'https://tiles.stadiamaps.com/tiles/outdoors/{z}/{x}/{y}{r}.png'
				}
			}
		},
// ...

Customization Examples

Marker direkt verlinken (kein PopUp)

var marker = L.marker([52, 12], {});
marker.url = 'www.google.com'

marker.on('click', function(){
window.location = (this.url);
});

Probleme beheben

Feld zeigt an Error Geocoding

File Cache komplett löschen (assets/cache/...)