Using the Geolocation API together with Google Maps API
Although not officially part of the HTML5 specification, Geolocation has become one of a number of new technologies that have recently come to light with advent of HTML5. Remy Sharp and Bruce Lawson also felt it important enough to write a whole chapter about in their brilliant book, Introducing HTML5.
The Geolocation API is used to find the location of your users. You've probably noticed a similar technology on many apps used on smartphones — checking into places through Facebook or Foursquare, for example. The same can be done with most modern web browsers. When used in conjunction with the Google Maps API, you can get some pretty cool results and add some great features to your website or web apps.
It would help if you had a basic understanding of Javascript, jQuery and PHP for this article, but I try to explain everything, so it isn’t essential.
The actual JavaScript code to get a user’s location is really simple. We should first check whether our user’s browser supports Geolocation. If it doesn't you should provide some sort of fallback for your website or web app — allow the user to manually enter their location for example. You would generally assign this code to an onclick event of a button.
if(navigator.geolocation) {
...
} else {
// Fallback code here
...
}
If you are using Modernizr, you could also make the same test with that using Modernizr.geolocation. Next we define two callback functions for the API to use — one to be called when our geolocation request succeeds, and one when it fails.
if(navigator.geolocation) {
function GeoSuccess(position) {
...
}
function GeoFailure() {
...
}
navigator.geolocation.getCurrentPosition(GeoSuccess, GeoFailure);
}
You’ll notice that the success function accepts one argument, an object, position. This object will give us, amongst other things, the latitude and longitude coordinates of the user’s location:
if(navigator.geolocation) {
function GeoSuccess(position) {
alert('Latitude: ' + position.coords.latitude + '. Longitude: ' + position.coords.longitude);
}
function GeoFailure() {
alert('There was an error.');
}
navigator.geolocation.getCurrentPosition(GeoSuccess, GeoFailure);
}
I’ve used alert() here just to show you how the extracted information could be displayed. Although it’s great for debugging, it should be generally be avoided — there are much nicer ways of alerting the user. What we have so far is as basic as the Geolocation API gets; we have the location of the user, but in it’s coordinate form, it isn’t much help, or very meaningful. We can use it in conjunction with the Google Maps API to get an actual street name, town, county or country.
If we had an embedded Google map on our website, we could easily plot our user’s location on the map, but in this example I’m going to show how we can make a lookup using the Google Maps service and use the more meaningful results returned on our website or web app. I'm going to make an AJAX request in jQuery, and process it in PHP, then handle the response we get in jQuery. That might seem a complicated mix of languages/technologies, but it’s all pretty easy to follow.
if(navigator.geolocation) {
function GeoSuccess(position) {
$.ajax({
url: 'ajax.php',
type: 'POST',
data: 'action=geolocation&latitude='+position.coords.latitude+'&longitude='+position.coords.longitude,
success: function(ret) {
...
}
});
}
function GeoFailure() {
alert('There was an error.');
}
navigator.geolocation.getCurrentPosition(GeoSuccess, GeoFailure);
}
If you aren't familiar with jQuery AJAX requests, lines 5 to 14 first define what file we are making the request to, in this case a PHP file called ajax.php; then the request type, in this case POST; then the data we are sending, in this case three parameters; action with the value of “geolocation”, and latitude and longitude with the values returned from the geolocation API; we then specify a success function for when the AJAX request succeeds, in this case an anonymous function that accepts one argument, “ret”, which will hold whatever is returned from our ajax.php file. I use the action argument because we may have other AJAX requests on our website or web app and this way, we can separate the requests.
Before we continue with the client side code, we’ll now cover the PHP code in our ajax.php file:
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
switch($_POST['action']) {
case "geolocation" :
...
break;
}
I’ve included the four header() lines to stop our file caching in our browser — in this case that wouldn’t be too much of an issue, but in the case of an AJAX request that retrieves live information (sports commentary, stocks, etc.), we wouldn’t want that to happen. It’s always better to be safe than sorry just in case some requests get cached.
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-cache, must-revalidate");
header("Pragma: no-cache");
switch($_POST['action']) {
case "geolocation" :
$url = 'http://maps.googleapis.com/maps/api/geocode/json?address='.$_POST['latitude'].','.$_POST['longitude'].'&sensor=false';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$geoloc = curl_exec($ch);
print($geoloc);
break;
}
We now need to connect to the Google Maps API. I have used PHP’s cURL functions, but you could use file_get_contents() to open the URL if your PHP server configuration has allow_url_fopen enabled. The cURL method should work on most server setups.
In the above code, we are opening a connection to Google’s Maps API, passing our latitude and longitude values as the address parameter, separated by a comma. I’ve also specificed that the result is returned in JSON format. Don’t worry if you are not familiar with JSON, it’s fairly easy to understand once you see it — I’ve only recently began using it and I’m still getting my head around it myself. We could get our results in XML, then use PHP’s XML parsing functions to extract the information, but as we want to return a number of parts of the results, we can return the entire data set in JSON and then process that data in Javascript. More on that shortly.
The cURL request should return one JSON string that we then print(), which will in turn be picked up by our AJAX request on the client side. As an example, when searching for the co-ordinates of 51.237054, -0.571826 — The T.G.I. Friday’s in Guildford town centre — the following JSON string will be returned:
{
"results" : [
{
"address_components" : [
{
"long_name" : "77",
"short_name" : "77",
"types" : [ "street_number" ]
},
{
"long_name" : "North St",
"short_name" : "North St",
"types" : [ "route" ]
},
{
"long_name" : "Guildford",
"short_name" : "Guildford",
"types" : [ "locality", "political" ]
},
{
"long_name" : "Surrey",
"short_name" : "Surrey",
"types" : [ "administrative_area_level_2", "political" ]
},
{
"long_name" : "United Kingdom",
"short_name" : "GB",
"types" : [ "country", "political" ]
},
{
"long_name" : "GU1 4AL",
"short_name" : "GU1 4AL",
"types" : [ "postal_code" ]
},
{
"long_name" : "GU1",
"short_name" : "GU1",
"types" : [ "postal_code_prefix", "postal_code" ]
},
{
"long_name" : "Guildford",
"short_name" : "Guildford",
"types" : [ "postal_town" ]
}
],
"formatted_address" : "77 North St, Guildford, Surrey GU1 4AL, UK",
"geometry" : {
"location" : {
"lat" : 51.23685960,
"lng" : -0.57190580
},
"location_type" : "ROOFTOP",
"viewport" : {
"northeast" : {
"lat" : 51.23820858029150,
"lng" : -0.5705568197084980
},
"southwest" : {
"lat" : 51.23551061970850,
"lng" : -0.5732547802915021
}
}
},
"types" : [ "street_address" ]
}
],
"status" : "OK"
}
This might look a little complicated, but you can get an idea of what information is being returned about the user’s position. In our client-side jQuery AJAX script, we now have to process this JSON string:
function GeoSuccess(position) {
$.ajax({
url: 'ajax.php',
type: 'POST',
data: 'action=geolocation&latitude='+position.coords.latitude+'&longitude='+position.coords.longitude,
success: function(ret) {
$json = $.parseJSON(ret);
...
}
});
}
Handily, jQuery comes with a predefined function for parsing JSON, $.parseJSON(), which we use here. It will return an object (into our $json variable) from which we can extra each individual piece of data from our JSON string. From the example JSON code above, if we wanted to extract the postal code, we would access it by doing the following:
$json.results[0].address_components[5].long_name
Again, this may seem complex, but our $json object it is essentially a multi-dimensional array. However, we cannot rely on the data being numerically indexed the same each time. Some results may contain more information than other results, and consequently the address_components object might be a different length each time a lookup is made. Therefore we cannot always reference a particular part of the data using the same numeric index. address_components[5] might be the postal code in one instance, but the locality in another.
We therefore need to identify each object by it’s listed type (administrative_area_level_2, locality, postal_town, etc.) rather than the numeric index:
success: function(ret) {
$json = $.parseJSON(ret);
$data = new Array();
for(var i=0; i<$json.results[0].address_components.length; i++) {
$data[$json.results[0].address_components[i].types[0]] = $json.results[0].address_components[i].long_name;
}
...
}
Here I create a new array, and then populate it with each object in our JSON string. This way, we can then refer to one part of our returned address using the $data array:
$data['administrative_area_level_2'] $data['locality'] $data['postal_town']
After our for loop, we can then use the data in this array however we want: to populate a text field on our web page with our user’ postal code; call another JavaScript function with the user’s town name as a parameter; show a map or flag, or change the language on our website depending on which country our user is in; or provide directions to somewhere from our user’s location.
What you do with this data really depends on your website or web application.
UPDATE: Due to a few requests, I have now implemented a few working demos of the Geolocation and Google Maps APIs working together. See them in action.
blog comments powered by Disqus