Workshop GoogleMaps Teil 2: Interaktive Markierungen

26.10.2006
Mit Hilfe von GoogleMaps kann man leicht interaktive Karten in die eigene Website einbinden. In diesem Workshop zeigen wir, wie Sie interaktive Markierungen in die Karte einbauen.

Kartenmaterial innerhalb einer Website – beispielsweise als Anfahrtsbeschreibung – gehört heute zum Standard jedes professionellen Webauftritts. Wer allerdings meint, er könnte einfach bestehende Stadtpläne einscannen oder Screenshots von Online-Stadtplänen einbinden, verstößt damit gegen das Urheberrecht und kann mit einer Abmahnung rechnen.

Verwendet man stattdessen GoogleMaps, kann das nicht passieren. Mit GoogleMaps bietet Google einen kostenlosen Kartendienst an. Dieser verfügt über eine Javascript-API, über die jeder Website-Betreiber dynamische Karten in die eigene Site integrieren kann. Der angezeigte Kartenausschnitt lässt sich dabei mit der Maus verschieben, und die Karten sind stufenweise scrollbar.

Wer tiefer in das API von GoogleMaps einsteigt, findet dort auch Funktionen zum Markieren von Punkten in einer Karte, und natürlich zum Auffinden von Adressen auf Basis von Straßen-, Orts- und Länderangaben. Damit lassen sich, wie dieses Tutorial zeigen wird, mit etwas Programmieraufwand auch automatische Anfahrtsskizzen oder Übersichtskarten generieren.

Im ersten Teil haben wir die Grundlagen der GoogleMaps erläutert, wie Sie Kartenausschnitte anzeigen lassen und wie Sie Adressen in Geo-Koordinaten umrechnen lassen. In diesem zweiten Teil des Workshops zeigen wir Ihnen, wie Sie Markierungen einblenden und wie Sie Webseite und GoogleMaps weiter verknüpfen.

Markierungen und Info-Fenster anzeigen

Da es mit der gerade programmierten Funktion showAddress ein Leichtes ist, auch mehrere Adressen anzuzeigen, kommt jetzt eine weitere sinnvolle Funktion von GoogleMaps ins Spiel: Das Anzeigen einer Markierung an einer bestimmten Kartenposition. Dazu erzeugen wir nach dem Aufruf von setCenter() zuerst ein neues Marker-Objekt:

var marker = new GMarker(point);

Wer möchte, kann optional noch einen Titel angeben, der dann beim MouseOver als Text eingeblendet wird (wie bei Grafiken beispielsweise üblich), also stattdessen:

var marker = new GMarker(point,{title:"Münchner Marienplatz"});

Das zweite Argument ist dabei ein Objekt des Typs GMarkerOptions, welches als Objekt Literal übergeben wird. Dabei wird die Eigenschaft title des Objekts gesetzt. Sie können zusätzlich jedoch auch noch die anderen in der API Referenz aufgelisteten Eigenschaften von GMarkerOptions setzen, beispielsweise

var marker = new GMarker(point,{title:"Münchner Marienplatz", draggable:true});

um dem Benutzer zu erlauben, die Markierung mit der Maus zu verschieben. Mit der Methode addOverlay() wird die Markierung schließlich der Karte hinzugefügt. Sie können auf diese Weise beliebig viele Markierungen setzen:

map.addOverlay(marker);

Zusätzlich zur Markierung lässt sich ein Info-Fenster über der Markierung anzeigen, und dort einen Text ausgeben. Dabei ist die Verwendung von HTML möglich, also beispielsweise

marker.openInfoWindowHtml("Der <b>Marienplatz</b> in München");

So lassen sich auch Bilder und Links in einem Info-Fenster anzeigen.

Listing: Markierungen

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
<title>Google Maps </title>
<?php require("gmap_script_inc.php") ?>
<script type="text/javascript">
//<![CDATA[
var map = null;
var geocoder = null;
var startzoom = 15;

function load() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
geocoder = new GClientGeocoder();
// add controls
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
showAddress("Marienplatz, München",startzoom);
}
}

function showAddress(address, zoomvalue) {
geocoder.getLatLng(
address,
function(point) {
if (!point) {
alert(address + " nicht gefunden");
} else {
map.setCenter(point, zoomvalue);
var marker = new GMarker(point,{title:"Münchner Marienplatz"});
map.addOverlay(marker);
marker.openInfoWindowHtml("Der <b>Marienplatz</b> in München");
}
}
);
}
//]]>
</script>
</head>
<body onload="load()" onunload="GUnload()">
<div id="map" style="width:500px; height: 300px"></div>
</body>
</html>

Adressliste interaktiv anzeigen

Um jetzt eine interaktive Adressliste mit Karte darzustellen, muss man nichts weiter machen, als die showAdress-Funktion im onClick-Event eines HTML-Elements aufzurufen und die richtige Adresse zu übergeben. Also beispielsweise

<p>Unsere Standorte in München:</p>
<ul>
<li><a href="#" onclick="showAddress('Marienplatz, München')">Marienplatz</a></li>
<li><a href="#" onclick="showAddress('Müllerstr. 41, München')">Müllerstr. 41</a></li>
<li><a href="#" onclick="showAddress('Schrobenhausenerstr. 10, München')">Schrobenhausenerstr. 10</a></li>
</ul>

Mehrere Markierungen auf einer Karte

Schwieriger wird es erst, wenn man alle Markierungen gleichzeitig in der Karte anzeigen will, um den Benutzer die Auswahl in der Karte selbst zu überlassen. Im letzten Beispiel waren die Markierungen nämlich erst in der Gesamtübersicht vorhanden, nachdem jeder Link einmal angeklickt wurde.

Um alle Orte gleichzeitig anzeigen zu lassen, müssen wir zuerst alle Markierungen zur Karte hinzufügen. Dazu ändern wir die Funktion showAdress so ab, dass sie eine Markierung an der angegebenen Adresse setzt, und zusätzlich einen Info-Text hinzufügt:

function addMarker(address, info_text) {
geocoder.getLatLng(
address,
function(point) {
var marker = new GMarker(point,{title:address});
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(info_text);
});
GEvent.addListener(marker, "mouseover", function() {
marker.openInfoWindowHtml(info_text + "<br>Koordinaten:" + point.lat() + " , " + point.lng());
});
map.addOverlay(marker);
markers[markers.length]=marker;
marker_texts[marker_texts.length] = info_text;
});
}

Erläuterung

Neu ist hier vor allem der Aufruf der Methode addListener des Objekts GEvent: Damit stellen wir sicher, dass zu einer Markierung beim MouseOver das jeweilige Infofenster geöffnet wird. Die beiden Arrays markers und markers_texts dienen zur Zwischenspeicherung der Markierungen und Markierungstexte. Dies ist leider notwendig, da GoogleMaps keine Möglichkeit bietet, auf alle Markierungen einer Map direkt zuzugreifen. Beim Aufruf von openInfoWindow werden zusätzlich zum übergebenen Infotext noch die Längen- und Breitenkoordinaten ausgegeben.

Jetzt fehlt noch das setzen der Markierungen in der load()-Funktion:

addMarker("Marienplatz, München", "<b>Marienplatz</b><br>Unser Hauptsitz");
addMarker("Schrobenhausenerstr. 10, München", "<b>Schrobenhausenerstr. 10</b><br>Unsere Filliale in Laim");
addMarker("Clemensstr. 2, München", "<b>Clemensstr. 2</b><br>Unsere Filliale in Schwabing");
addMarker("Pariser Platz, München", "<b>Pariser Platz</b><br>Unsere Filliale in Haidhausen");

Das Ergebnis ist eine Karte mit vier Markierungen, bei denen beim Überfahren mit der Maus ein Infofenster mit der Adresse und einer Beschreibung angezeigt wird.

Listing: Mehrere Markierungen

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
<title>Google Maps </title>
<?php require("gmap_script_inc.php") ?>
<script type="text/javascript">
//<![CDATA[

var map = null;
var geocoder = null;
var startzoom = 15;
var markers = new Array();
var marker_texts = new Array();

function load() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
geocoder = new GClientGeocoder();
// add controls
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(48.137135, 11.575008), 11);

// add markers
addMarker("Marienplatz, München", "<b>Marienplatz</b><br>Unser Hauptsitz");
addMarker("Schrobenhausenerstr. 10, München", "<b>Schrobenhausenerstr. 10</b><br>Unsere Filliale in Laim");
addMarker("Clemensstr. 2, München", "<b>Clemensstr. 2</b><br>Unsere Filliale in Schwabing");
addMarker("Pariser Platz, München", "<b>Pariser Platz</b><br>Unsere Filliale in Haidhausen");
}
}

function addMarker(address, info_text) {
geocoder.getLatLng(
address,
function(point) {
if (!point) {
alert(address + " nicht gefunden");
} else {
var marker = new GMarker(point,{title:address});
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(info_text);
});
GEvent.addListener(marker, "mouseover", function() {
marker.openInfoWindowHtml(info_text + "<br>Koordinaten: " + point.lat() + " , " + point.lng());
});
map.addOverlay(marker);
markers[markers.length]=marker;
marker_texts[marker_texts.length] = info_text;
}
}
);
}

//]]>
</script>
</head>

<body onload="load()" onunload="GUnload()">
<div id="map" style="width:500px; height: 300px"></div>
</html>

Filialenfinder mit klickbarer Liste

In der letzten Ausbaustufe des Filialenfinders soll jetzt zusätzlich noch eine Liste mit den Standorten ausgegeben werden. Bei Klick auf einen der Links soll die Karte automatisch den jeweiligen Standort sowie das Infofenster anzeigen.

An sich ist das kein großes Problem, allerdings muss man darauf achten, dass die Geokodierung , und damit der Aufruf von addmarker() abhängig von der Reaktionszeit des GoogleMaps-Servers ist. Daher kann es passieren, dass beispielsweise der zweite Aufruf von addmarker() vor dem ersten Aufruf abgearbeitet ist: Als Resultat wird die intern definierte namenlose Funktion des zweiten Aufrufs zuerst abgearbeitet, und die Schrobenhausenerstraße wird als erstes Element des Arrays markers[] eingetragen.

Um das zu verhindern, übergibt man am besten eine laufende Nummer. Die Aufrufe sehen dann folgendermaßen aus:

addMarker(1,"Marienplatz, München", "<b>Marienplatz</b><br>Unser Haupsitz");
addMarker(2,"Schrobenhausenerstr. 10, München", "<b>Schrobenhausenerstr. 10</b><br>Unsere Filliale in Laim");

Probleme umgehen

Innerhalb der Funktion verwendet man die Nummer als Index für die beiden Arrays. Zusätzlich fügen wir dem HTML-Element markerlist welches eine ungeordnete Liste (<ul>) darstellt, jeweils ein Listenelement <li> mit den notwendigen Informationen hinzu:

markers[marker_num]=marker;
marker_texts[marker_num] = info_text;
document.getElementById("markerlist").innerHTML += '<li><a href="#" onclick="showMarker(' + marker_num + ');">' + marker_texts[marker_num] + '</a></li>';

Das Element zur Ausgabe der Liste sieht dann im HTML-Code folgendermaßen aus:

<ul id="markerlist">
</ul>

Listing: Komplettes Beispiel

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1"/>
<title>Google Maps </title>
<?php require("gmap_script_inc.php") ?>
<script type="text/javascript">
//<![CDATA[

var map = null;
var geocoder = null;
var startzoom = 15;
var markers = new Array();
var marker_texts = new Array();

function load() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
geocoder = new GClientGeocoder();
// add controls
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());

map.setCenter(new GLatLng(48.137135, 11.575008), 11);

// add markers
addMarker(1,"Marienplatz, München", "<b>Marienplatz</b><br>Unser Haupsitz");
addMarker(2,"Schrobenhausenerstr. 10, München", "<b>Schrobenhausenerstr. 10</b><br>Unsere Filliale in Laim");
addMarker(3,"Clemensstr. 2, München", "<b>Clemensstr. 2</b><br>Unsere Filliale in Schwabing");
addMarker(4,"Pariser Platz, München", "<b>Pariser Platz</b><br>Unsere Filliale in Haidhausen");
}
}


function addMarker(marker_num, address, info_text) {
geocoder.getLatLng(
address,
function(point) {
if (!point) {
alert(address + " nicht gefunden");
} else {
var marker = new GMarker(point,{title:address});
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(info_text);
});
GEvent.addListener(marker, "mouseover", function() {
marker.openInfoWindowHtml(info_text);
});
map.addOverlay(marker);
markers[marker_num]=marker;
marker_texts[marker_num] = info_text;
document.getElementById("markerlist").innerHTML += '<li><a href="#" onclick="showMarker(' + marker_num + ');">' + marker_texts[marker_num] + '</a></li>';
}
}
);
}


function showMarker(marker_num) {
var curr_marker = markers[marker_num];
curr_marker.openInfoWindowHtml(marker_texts[marker_num]);
}

//]]>
</script>
</head>

<body onload="load()" onunload="GUnload()">
<div id="map" style="width:500px; height: 300px"></div>
<p>Unsere Standorte in München:</p>
<ul id="markerlist">
</ul>
</body>
</html>

Fazit

Der kostenlose Kartendienst von Google kann spontan begeistern – gute Programmiermöglichkeiten, schnelle Darstellung, und sehr gutes Kartenmaterial sowie teilweise exzellente hoch auflösende Satellitenfotos (Tipp: Kanarische Inseln ansehen) sprechen eine deutliche Sprache.

Trotzdem sollte man einige Kritikpunkte im Auge behalten: So erfordert die Darstellung von großen Karten zwangsläufig eine schnelle Internetverbindung – gerade wenn man sich die Satellitenfotos anzeigen lässt. Außerdem sorgt die AJAX-Programmierung für eine deutliche Rechenlast im Browser und erfordert einen einigermaßen schnellen, aktuellen Rechner. Und zu guter Letzt sollte man sich die Nutzungsbedingungen von GoogleMaps genau durchlesen – so ist es Google beispielsweise erlaubt, in Zukunft Werbung in den Karten darzustellen.

Auch eine technische Einschränkung gibt es: Die Geokodierung ist auf 50000 Aufrufe pro Tag beschränkt, wer also mehr Seitenabrufe erwartet, sollte die Geodaten lieber als Längen- und Breitengrade übergeben, oder noch besser die Längen- und Breitengrade in einer eigenen Datenbank zwischenspeichern.

Online finden Sie die komplette Dokumentation der GoogleMaps-API und die Referenz zur API. (Marco Zierl/mha)

Alternativen zu GoogleMaps

Bayernviewer

Der Bayerviewer des Landesamtes für Vermessung und Geoinformation bietet kostenlose, hochauflösende Luftbilder von ganz Bayern, die man kopieren und in eigene Websites einbauen darf (Nutzungsbedingungen beachten). Nachteile: Die Suche erfolgt nur nach Städten, Straßen müssen daher von Hand durch Scrollen gefunden werden. Eine topografische Ansicht existiert ebenfalls, leider ist diese jedoch sehr grobauflösend und einfach gehalten, und daher für die meisten Einsatzzwecke ungeeignet. Dafür kann man in dem als Java-Applet implementierten Viewer mit der Maus Distanzen, und Flächen abmessen. Qualität und Auflösung der Luftbilder sind sehr gut.

Openlayers

OpenLayers ist eine unter OpenSource veröffentlichte Javascript-Bibliothek mit der sich verschiedenste Kartendaten dynamisch in einer Website darstellen lassen. Auf diese Weise lassen sich beispielsweise auch die Kartendaten von GoogleMaps mit OpenLayers darstellen. Die Kartenansichten selbst sind interaktiv und lassen sich wie in GoogleMaps zoomen und mit der Maus verschieben.

Im Test ließ die Performance einiges zu wünschen übrig, was auch daran liegen kann, dass sich das OpenSource–Projekt noch in der Entwicklungsphase befindet.

Virtual Earth

Der Virtual Earth benannte Dienst von Microsoft stellt sich als direkte Konkurrenz zu Google Maps dar und wird bereits in Windows Live Local eingesetzt. Die Ansicht der Karten erfolgt hier ebenfalls interaktiv über Javascript. Die sehr komfortable Javascript-API bietet eine Vielzahl von Funktionen, wie Umgebungs- und Adressuche, und soll vor allem zur Suche nach Geschäften, Restaurants, Hotels etc. dienen – was bisher in deutschen Karten noch nicht verfügbar ist. Das Kartenmaterial ist sehr gut, und bietet detaillierte zoombare Informationen von der Weltansicht bis hin zur Straßenebene. Dokumentation und Performance konnten im Kurztest überzeugen und machten einen sehr professionellen Eindruck.