Seite 1 von 1

[Anleitung Smarty] Google Map MarkerClusterer

Verfasst: Mo 10. Okt 2016, 21:57
von homtata
Hallo Gemeinde,

ich musste in den letzten Tagen für ein Projekt eine GoogleMap einbauen, die ihre Daten aus der DB bezieht, Geocoding betreibt UND dann noch das MarkerClustering macht wie hier gezeigt:
https://github.com/googlemaps/js-marker-clusterer

Das Geocoding (= das Umrechnen einer Straßenadresse in Längen-/Breitengrad) betrieb ich anfangs direkt im GoogleMaps-Code, javascript-basiert, sozusagen live über eine eigene API, aber das führte zu Meldungen, dass zu viele Geocodinganfragen abgesetzt wurde (selbst 10 Einträge waren zuviel); der API-Key hat darauf keinen Einfluss. Daher brauchte ich ein PHP-gestütztes Geocoding mit Speicherung in der Datenbank.

Unabhängig von dieser ganzen Geschichte werden beim MarkerClusterer je nach Zoomstufe Marker gruppiert und gezählt. Das wiederum hat auch an verschiedenen Stellen gehakt, daher hier ein kurzer Abriss:

- Beim Speichern der Adressdaten über ein Formular habe ich über einen PHP-Codeschnipsel Längen- und Breitengrad für die Adresse berechnet und in die Datenbank gespeichert.
- Zur Erstellung der Karte zog ich alle nötigen Adressdaten und sonstigen Anzeigewerte (Namen, Staaten, Bilder) ebenfalls aus der Datenbank. Der ganze für Google Maps nötige Datenbestand wanderte in ein Array, das an Smarty übergeben wird.
- Neben der remote aufzurufenden Google Maps-Api bedarf es für das MarkerClustering noch lokaler Dateien, die vom o.g. Link stammen und die ich (Stand 10.10.2016) unten in die Zip-Datei gepackt habe: eine Javascript-Datei sowie diverse Bilder, die genau so nach /cms/ hochzuladen sind, wie in der ZIP angelegt. Beim o.g. Link gibt es alternative Icons für das Clustering, dann muss der Link in Smarty anders enden (jetzt heißt er "markerclusterer/m" -> würden die Bildernamen mit "p" gekennzeichnet sein, hieße der Link "markerclusterer/p"). So sind auch eigene Icons möglich und aufrufbar.
- Ihr benötigt einen eigenen API-Key für Google Maps, der aber leicht generiert werden kann. Das erhöht u.a. Euer Limit auf die Kartenzugriffe pro Tag.

Hier die php-Class, die aus der Straßenadresse die Koordinaten berechnet (Geocoder), Quelle: https://www.codeofaninja.com/2014/06/go ... e-php.html

Code: Alles auswählen

class geocoder{
	static private $url = "http://maps.google.com/maps/api/geocode/json?sensor=false&address=";
	
	static public function getLocation($address){
		$url = self::$url.urlencode($address);
		
		$resp_json = self::curl_file_get_contents($url);
		$resp = json_decode($resp_json, true);
		
		if($resp['status']='OK'){
			return $resp['results'][0]['geometry']['location'];
		}else{
			return false;
		}
	}
	
	
	static private function curl_file_get_contents($URL){
		$c = curl_init();
		curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($c, CURLOPT_URL, $URL);
		$contents = curl_exec($c);
		curl_close($c);
		
		if ($contents) return $contents;
		else return FALSE;
	}
}
Im Modulout lässt sich das über die Straßenadresse wie folgt aufrufen. Die Quellen für die Variablen müsst ihr natürlich selbst vorher belegen, wo immer die auch herkommen:

Code: Alles auswählen

//google map locations
$address=urlencode($strasse . ", " . $plz . " " . $stadt);
$loc = geocoder::getLocation($address);
print_r($loc); //nur zu Testzwecken ausgeben
$loc[lat] beinhaltet dann die Latitude.
$loc[lng] die Longitude.
Liefert $loc == false, dann speichere ich in der DB für beide Werte "0" ab -> im Smarty ist das später eine if-Abfrage, um solche Einträge zu unterdrücken. Manchmal ist über das Geocoding einfach die Adresse nicht zu finden, soll aber auch die Karte nicht zum Absturz bringen.

Baut Euch ein Array $addresslist auf, das alle Daten pro Datensatz enthält. Wie ihr im Smarty-Template seht, habe ich verschiedene Keys definiert pro Datensatz: mapslat, mapslng, street, zip, city, company, thumb und popup (da ich mit Bildern arbeite).

Hier das Smarty-Template für diese Vorgehensweise... "options" bestimmt wie gesagt die Darstellung der Cluster-Icons. "gridSize" bestimmt, wie nah die Punkte beieinander liegen müssten, um in einer bestimmten Zoomstufe zusammengefasst zu werden. Kleinere Nummer: Der Radius für ein Cluster ist klein. Je größer die Nummer, desto früher wird zusammengepackt. Eigenen API-Key im unteren Skriptaufruf nicht vergessen! Einige Werte selbst anpassen, nur Mut. Das Infowindow locations[20] lässt sich aus dem locations-Array schön zusammenpuzzeln und mit CSS stylen.

Smarty Template:

Code: Alles auswählen

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

{literal}

<script type="text/javascript">
	function initMap() {
		var map = new google.maps.Map(document.getElementById('map'), {
			zoom: 2,
			center: {lat: 28.3439907, lng: -74.0598095}
		});
		
        var options = {
			imagePath: 'images/markerclusterer/m',
			gridSize: 30
        };
		
    	var marker, i;		 
		 var markers = new Array();

		for (i = 0; i < locations.length; i++) {
		 
			 locations[i][20] = '<div id="content">' +
				 '<div id="siteNotice">' +
				 '</div>' +
				 '<h1 id="firstHeading" class="firstHeading" style="display: none;">' + locations[i][2] + '</h1>' +
				 '<div id="bodyContent">' + 
				 '<div class="address"><p><b>' + locations[i][3] + '</b><br>' + locations[i][4] + '<br>' + locations[i][5] + ' ' + locations[i][6] + '</p>'+ '</div>' +
				 '<div class="image"><a href="' + locations[i][8] + '" rel="lightbox[gallery]"><img src="' + locations[i][7] + '" ></a></div>' +
				 '</div>' + 
				 '</div>';		 
			 
			 var infowindow = new google.maps.InfoWindow({
				 content: locations[i][20]
			 });		
			 var marker = new google.maps.Marker({
				 map: map,
				position: {lat: locations[i][0], lng: locations[i][1]},
				 title: locations[i][2]
			 });
	
			markers.push(marker);
		 
			google.maps.event.addListener(marker, 'click', (function(marker, i) {
				return function() {
					infowindow.setContent(locations[i][20]);
				  infowindow.open(map, marker);
				}
			  })(marker, i));													 
	}	
        // Add a marker clusterer to manage the markers.
		var markerCluster = new MarkerClusterer(map, markers, options);
	}	
			var locations = [
		
		{/literal}
			
			{foreach from=$addresslist item=address}
		 {if $address.mapslat neq 0 } [{$address.mapslat}, {$address.mapslng}, '{$address.street} {$address.zip} {$address.city}', '{$address.company}', '{$address.street}', '{$address.zip}', '{$address.city}', '{$address.thumb}', '{$address.popup}'], {/if}
			 {/foreach}
													 
		 {literal}
		 ];

</script>
<script src="js/markerclusterer.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=HIEREURENEIGENENAPIKEYEINFUEGEN&signed_in=true&callback=initMap"
async defer></script>
{/literal} 
In den auf den o.g. Seiten gezeigten Beispielen wollte die vorgeschlagene Reihenfolge diverser Variablenaufrufe einfach nicht zum Erfolg führen; ich habe solange umgestellt und verschoben, bis es schlussendlich in dieser Kombination passte...

LG, und wenn ihr es einsetzt, gebt doch mal kurzes Feedback, das wäre nett ;-)

Viktor

Re: [Anleitung Smarty] Google Map MarkerClusterer

Verfasst: Di 11. Okt 2016, 11:58
von Faar
Danke! :)

Momentan kann ich es nicht testen aber es klingt sehr interessant.

Re: [Anleitung Smarty] Google Map MarkerClusterer

Verfasst: Mi 12. Okt 2016, 15:01
von rethus
Benötige es momentan nicht, aber dennoch Danke fürs teilen :!: