GeoLocation mit modernen Browsern
Der ein oder andere von euch hat vielleicht schonmal mit GeoLocations experimentiert. Es gibt freie GeoDatenbanken und GeoIP-Datenbanken, mit denen man eine IP-Adresse umwandeln kann in einen Ort (bzw. Region/Land).
Als ich nun vor einigen Monaten hörte, dass der Firefox bald eine neue GeoLocation-Funktionalität erhält, womit dann viele neue standortabhängige Dienste möglich sind, war ich gespannt was tolles neues dabei rauskommt. Zuerst dachte ich, dass man im Browser seine Daten eingibt, und dann sendet das der Browser an die Webseite, falls die das wissen möchte.
Doch ich habe die Rechnung ohne die ganzen mobilen Geräte gemacht, für die das Feature primär interessant ist (ich selbst habe zwar einen PDA, aber keinen Internet-Daten-Tarif, deshalb hab ich daran nicht wirklich gedacht).
Was kann das Feature nun? Es passiert folgendes: Falls die Webseite die GeoLocation ermitteln möchte, bekommt der Benutzer eine Frage präsentiert:
Man kann dann entscheiden, ob man diese Informationen senden möchte oder nicht. Falls man „Ja“ klickt, wird die IP-Adresse an einen Google-Service geschickt. Außerdem werden noch GPS-Informationen und erreichbare WLAN-Netze (incl. ermittelter Empfangsstärke) versendet an Google Location Services. Daraus kann Google dann eine mehr oder weniger genaue Position ermitteln (bei GPS natürlich sehr genau bis auf wenige Meter, bei WLAN-Informationen kann es auch schon sehr ungenau werden, je nachdem wieviele WLANs da sind und ob diese bereits kartographiert wurden).
Diese Standort-Information erhält dann der Browser, und dann kann diese Information mittels Javascript API abgefragt werden. Das hier sind die Informationen, die man erhält:
Man erhält also die Angaben in Form von Latitude und Longitude, sowie evtl. weitere GPS-Informationen wie Höhe, Geschwindigkeit usw. Falls man diese Informationen in einen Ortsnamen umwandeln möchte, benötigt man entweder wieder eine Datenbank mit Informationen oder man nutzt einen Webservice, der das selbe tut.
In meiner Demo nutze ich letzteres, und lasse anhand der Latitude/Longitude den Namen der Stadt ermitteln, dazu nutze ich www.geonames.org.
Inklusive Stadt sieht das Endergebnis dann so aus:
Wie sieht das nun im Quelltext aus? Eigentlich sehr übersichtlich:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <title>PHP Gangsta Geolocation</title> <SCRIPT TYPE="text/javascript" SRC="http://ajax.googleapis.com/ajax/libs/dojo/1.3/dojo/dojo.xd.js"></SCRIPT> <script type="text/javascript"> function startgeolocation() { // Check for geoLocation Support if (navigator.geolocation) { // the location is looked up only once navigator.geolocation.getCurrentPosition(renderPosition, renderError); // every time the location changes // navigator.geolocation.watchPosition(renderPosition, renderError); } else { dojo.byId('geoResults').innerHTML = '<p>Your browser does not support geolocation.</p>'; } } // I use Dojo to render the output and do an AJAX call to get city name function renderPosition(position) { if (!window.count) window.count = 0; count ++; // var urlJSON = 'http://ws.geonames.org/findNearbyPlaceNameJSON?lat=-36.9104718&lng=174.9133483'; var urlJSON = 'geonames.php?lat='+position.coords.latitude+'&lon='+position.coords.longitude; dojo.byId('d').innerHTML = '<div id="results" style="width: 200px; height: 200px; text-align: left"><p>' + 'Latitude: ' + position.coords.latitude + '<br />' + 'Longitude: ' + position.coords.longitude + '<br />' + 'Accuracy: ' + position.coords.accuracy + '<br />' + 'Update number: ' + count + '<br />' + 'Altitude: ' + position.coords.altitude + '<br />' + 'Altitude accuracy: ' + position.coords.altitudeAccuracy + '<br />' + 'Heading: ' + position.coords.heading + '<br />' + 'Speed: ' + position.coords.speed + '<br />' + 'Google Maps: <a href="http://maps.google.com/maps?geocode=&q=' + position.coords.latitude + '+' + position.coords.longitude + '">Click</a><br />' + '</p></div>'; // now get the XML reverse geo data dojo.xhrGet( { // // The following URL must match that used to test the server. url: urlJSON, handleAs: "json", timeout: 5000, // Time in milliseconds // The LOAD function will be called on a successful response. load: function(responseObject, ioArgs) { for each (var item in responseObject.geonames) { dojo.byId('jsonResults').innerHTML = '<p>You live in: ' + item.name + '</p>'; } return responseObject; }, // The ERROR function will be called in an error case. error: function(responseObject, ioArgs) { // console.error("HTTP status code: ", ioArgs.xhr.status); // return responseObject; } }); } function renderError() { dojo.byId('geoResults').innerHTML = '<p>The page could not get your location.</p>'; } </script> </head> <body onload="startgeolocation();"> <div align="center"> <h1>GeoLocation Demo</h1> <div id="geoResults"> <div id="d"><img src="loadingAnimation.gif" /></div> <div id="jsonResults">city information are fetched...</div> </div> </body> </html>
Das einzig verwunderliche ist vielleicht der AJAX-Aufruf. Ich hatte ja geschrieben, dass ich den Namen der Stadt von geonames.org holen möchte. Da die Cross-Domain-Policy nur einen Ajax-Aufruf zum selben Server erlaubt, brauchen wir ein kleines „Proxy-Script“, welches so aussieht:
<?php echo file_get_contents('http://ws.geonames.org/findNearbyPlaceNameJSON?lat='.$_GET['lat'].'&lng='.$_GET['lon']); ?>
Damit umgehen wir die Cross-Domain-Policy und erhalten unser Ergebnis in JSON-Form. Das war auch schon der ganze Zauber.
Aktuell beherrschen meines Wissens nach der Firefox 3.5, Chrome und die aktuellen Beta-Versionen von Safari und Opera diese Funktionalität. Google Gears bietet eine ähnliche Funktionalität (browserübergreifend), aber ich kennen niemanden, der Gears installiert hat.
Man kann übrigens im Firefox den Location Service ändern, falls man Google nicht mag:
Falls ihr ein Handy mit Internet habt, könnt ihr auch mal Google Maps Mobile ausprobieren. Außerdem könnt ihr hier mein Demo-Script ausprobieren.
Ich bin gespannt, was für interessante Dienste da bald aus dem Boden sprießen. Ich meine schonmal etwas gehört zu haben von „gucken wo Freunde gerade sind“ und sowas. Ich bin auch gespannt, wann ich endlich ein neues Handy mit Datentarif bekomme…
Das Demo-Script kann nicht auf dem iPhone ausgeführt werden. Bekomme nichtmal das Abfrage-Popup ob ich „meinen Standort übermitteln“ möchte. 🙂
Das iPhone ist jedoch die momentan wichtigeste Platform für eine GPS-Basierte Webanwendung wie ich finde.
Hier ist etwas, das sehr gut funktioniert:
http://smithsrus.com/gps-geolocation-in-safari-on-iphone-os-3-0/
Sven
10 Sep 09 at 10:58
Hi
welchen Browser hast du denn da in welcher Version?
Die Seite, die du da genannt hast, basiert auf den selben JavaScript-Funktionen. Eigentlich müßte entweder beides oder keines funktionieren…
Bekommst du JavaScript-Fehlermeldungen? Kann der Browser evtl. kein Ajax (würde mich stark wundern)?
Michael Kliewe
10 Sep 09 at 11:26
Auf dem iPhone läuft ein Safari. Hab mal die Fehlerconsole eingeschaltet und hier findest du die Ausgabe:
http://s2.directupload.net/file/d/1913/sii4wi58_jpg.htm
Sven
10 Sep 09 at 12:13
OK, danke dafür!
Es ist anscheinend die Zeile 51 im HTML-Code, die in deinem Safari Probleme macht:
for each (var item in responseObject.geonames) {
Im Firefox kommt es da nicht zu einem Parse-Error. Wie dem auch sei, ich habe die Zeile mal geändert:
for (item in responseObject.geonames) {
Bitte probier es nochmal aus. Im Firefox funktioniert es nach wie vor. Achte darauf, dass auch die neue Version geladen wird (prüfe den Quelltext in Zeile 51).
Bin gespannt!
Michael Kliewe
10 Sep 09 at 12:21
Klappt nun – nur das er meinen Ort nicht gefunden hat.
„You live in: undefined“
🙂
Sven
10 Sep 09 at 12:33
Gab es noch Javascript-Fehler?
Dann gib mal deine Longitude und Latitude, dann schau ich mal warum geonames da nichts liefert…
Michael Kliewe
10 Sep 09 at 12:36
An geonames liegt es nicht, der liefert mit den Standort richtig zurück. Hab es eben selbst mal getestet mit den Longitude und Latitude-Werten die ich angezeigt bekomme. Auch er Maps-Link funktioniert.
Leider hat der Safari 4.0.x für Windows und Mac noch keine Geounterstützung, daher fällt das debuggen flach. Wenn ich mir den Code genauer anschaue, könnte es höchstens sein das Dojo für den XHR-Request eine vollständige URL benötigt, also mit vorangestellten „http://“… sonst hab ich grad keine Idee.
Sven
10 Sep 09 at 12:57
Ups, Fehlermeldungen gibt es keine. Dachte ich hätte das schon vorhin erwähnt. Habs wohl vergessen zu schreiben 🙂
Sven
10 Sep 09 at 12:58