Google Maps (v3): Schicke Marker, Lösung für überlappene Marker und schönere Infofenster mit CSS
In meinem aktuellen Projekt für das EJW Hessen war eine der Hauptaufgaben das Rendern einer verschönerten Google Map (in der neusten Version 3) mittels der JavaScript API.
Anforderungen:
- eigene, schöne Markergrafiken (google.maps.MarkerImage)
- optimierte, per CSS stylebare Infofenster (InfoBubble)
- Lösung für das Problem der überlappenen Marker. Wie erreicht der User Marker, wenn viele übereinander (auf einer Koordinate) liegen? (OverlappingMarkerSpiderfier)
- Drop Animationseffekt beim Setzen der Marker (google.maps.Animation.DROP)
- Suchbox zum Anzeigen einer Adresse (google.maps.Geocoder)
- Filter mittels Links
Resultat
Das Resultat lässt sich auf der Website des EJW Hessen begutachten:
Lösung
Alle diese Anforderungen wurden im folgenden Script berücksichtigt:
var map, infoBubble, styledcontent, oms;
var content = [];
var geocoder = new google.maps.Geocoder();
var default_zoom = 9;
var search_zoom = 14;
var global_filter = '';
var search_placeholder = 'Straße, Ort';
$(document).ready(function() {
if ($('#map_canvas').length != 0) {
var mapCenter = new google.maps.LatLng(50.22120, 8.63525); // Default
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: default_zoom,
center: mapCenter,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false
});
oms = new OverlappingMarkerSpiderfier(map, {markersWontMove: true, markersWontHide: true, keepSpiderfied: true});
// ------------------------------------------
// function to show all relevant markers. filtered by 'filter'-parameter if set :-)
runQuery = function(elements, filter) {
// Is filter set?
var filter = (typeof(filter) != 'undefined') ? filter : '';
// create new filter
var current_element = elements + filter;
// first of all, clear all markers already there:
deleteOverlays();
// loop through all given elements:
$(current_element).each(function(index){
// are coordinates set?
var current_koordinaten_xy = ($(this).children('.koordinaten').text() != '') ? $(this).children('.koordinaten').text() : '';
var current_koordinaten = '';
// put together information for the bubble
var gruppe = new Array();
gruppe['foo'] = 'bar';
content[index] = gruppe; // neue gruppe zum array aller gruppen hinzufügen
// if there are coordinates: split them in x/y, create google position and add marker
if(current_koordinaten_xy != ''){
current_koordinaten_xy = current_koordinaten_xy.split(',');
current_koordinaten = new google.maps.LatLng(current_koordinaten_xy[0], current_koordinaten_xy[1]);
addMarker(current_koordinaten, content, index, $(this).children('.fachgruppe').text()); // do everything
}
});
}
// ------------------------------------------
// Info Bubble Default Settings:
infoBubble = new InfoBubble({
map: map,
maxWidth: 290,
maxHeight: 320,
shadowStyle: 0,
padding: 0,
backgroundColor: '#fff',
borderRadius: 5,
arrowSize: 20,
borderWidth: 0,
arrowPosition: 20,
backgroundClassName: 'ejw-gruppe-infowindow',
arrowStyle: 2,
hideCloseButton: false
});
// ------------------------------------------
// for starters: show all
runQuery('#adressenliste li');
// ------------------------------------------
// now filter by filters:
$('#filters a').click(function(){
var current_filter = $(this).attr('data-option-value');
if(current_filter != 0) {
global_filter = '.' + current_filter; // put together new global filter
}else{
global_filter = '';
}
// toggle '.selected'-class:
$('.selected').removeClass('selected');
$(this).toggleClass('selected');
// add new markers:
runQuery('#adressenliste li', global_filter);
// if search box is not empty, add address marker as well:
if( $('#finder-adresse').val() != '' && $('#finder-adresse').val() != search_placeholder){
codeAddress( $('#finder-adresse').val(), false);
}
// prevent default action from happening (link href):
return false;
});
// ------------------------------------------
// find addresses by search and center map to this position:
$('#finder-submit').click(function(){
// clear markers and start over again:
runQuery('#adressenliste li', global_filter);
// geocode given address and add marker:
codeAddress( $('#finder-adresse').val() );
// zoom in
map.setZoom(search_zoom);
});
// empty search box on focus if the value is equal to the placeholder text:
$('#finder-adresse').val(search_placeholder);
$('#finder-adresse').focus(function(){
if ($(this).val() == search_placeholder) {
$(this).val('');
}
});
$('#finder-adresse').blur(function(){
if ($(this).val() == '') {
$(this).val(search_placeholder);
}
});
}
// ------------------------------------------
// only add infobubble to the marker when it's clicked:
oms.addListener('click', function(marker) {
infoBubble.setContent(marker.content);
infoBubble.open(map, marker);
});
});
Ich nutze dabei jQuery, weil die Daten für die Marker (z.B. die Koordinaten) erst bei Aufruf der Website ausgelesen, also generiert, werden. Das ist sicherlich nicht sehr performant, kann aber auch nützlich sein, wenn man zum Beispiel unter der Karte eine Liste der gefilterten Einträge anzeigen möchte.
Die folgende Funktion fügt der Map einen Marker hinzu. Ihr wird die Position (als Google Map Koordinaten) sowie einige weitere Parameter speziell für das EJW-Projekt mitgegeben:
function addMarker(location, content, index, fachgruppe, openbubble) {
// Is openbubble set?
var openbubble = (typeof(openbubble) != 'undefined') ? openbubble : true;
// check for marker images:
switch(fachgruppe) {
case "HP":
markerImg = new google.maps.MarkerImage('***.png');
break;
case "HMP":
markerImg = new google.maps.MarkerImage('***.png');
break;
case "Standort":
markerImg = new google.maps.MarkerImage('***.png');
break;
default:
markerImg = new google.maps.MarkerImage('***.png');
break;
}
// marker content
if(fachgruppe == 'Standort') {
styledcontent = '<div>Deine Standorteingabe.</div>';
} else {
styledcontent = "<div>...</div>";
}
var marker = new google.maps.Marker({
position: location,
map: map,
icon: markerImg,
content: styledcontent,
animation: google.maps.Animation.DROP
});
// add to marker array
oms.addMarker(marker);
// if is standort, show bubble
if(fachgruppe == 'Standort' && openbubble) {
infoBubble.setContent(marker.content);
infoBubble.open(map, marker);
}
}
Diese Funktion löscht alle Marker von der Map:
// Deletes all markers in the array by removing references to them
function deleteOverlays() {
var markers = oms.getMarkers();
if (markers) {
for (i in markers) {
markers[i].setMap(null);
}
markers.length = 0;
}
oms.clearMarkers();
}
Die nächste Funktion sorgt für die Geokodierung, also das Umsetzen einer Adresse zu Koordinaten:
function codeAddress(address, openbubble) {
// Is openbubble set?
var openbubble = (typeof(openbubble) != 'undefined') ? openbubble : true;
if (geocoder) {
geocoder.geocode({
'address': address,
'region': 'de',
'language': 'de_DE'}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
// set marker to this location
addMarker(results[0].geometry.location, '', '', 'Standort', openbubble);
// center to the given location:
map.setCenter(results[0].geometry.location);
} else {
// hier könnte noch ein schönerer fehler hin:
console.log("Geokodierung nicht erfolgreich: " + status + ".");
return false;
}
});
}
}
Kommentare und Optimierungsvorschläge sind natürlich jederzeit willkommen! :-)
Empfehlen Sie diesen Artikel weiter!


Kommentare (2)