In this second article in our series on HTML5 for mobile web (first part here), we cover the Geolocation API. For mobile users, location-based services are hugely compelling. Long the holy grail of mobile applications, and something of a missed opportunity for service providers, the addition of location-awareness to mobile apps has made for some very exciting use cases.
Apps and services can take on a whole new dimension when location is added into the mix. Search results gain an extra relevance cue when a nearby option is added, as location information provides a very useful and intuitive filter. Navigation- and map-based apps and games become possible. Even augmented reality apps are no longer beyond the reach of the mobile browser, as illustrated below.
In the following sections we take a look at HTML5 Geolocation from a mobile perspective. We look at the technologies involved and work through some map-based examples to see what the Geolocation API has to offer.
How Geolocation works
There are a variety of techniques and sensor data that modern mobile devices can tap to figure out the location of a device with varying degrees of accuracy. The most common are discussed briefly below.
- GPS: Perhaps the most familiar method of geolocation is via the GPS receiver. Many modern smartphones come with GPS sensor as standard. GPS geolocation works by detecting the signal from a number of satellites in the sky, typically four or more; by using a mathematical technique called trilateration the device can determine its location based on the timing of the statellite signals.
A downside of GPS is that it can often take a some time to lock onto enough satellites to provide a location fix. It also requires a clear view of the sky, so if you’re indoors, you’re out of luck. - A-GPS: (Assisted GPS) This approach helps to address some of the shortcomings of GPS, by augmenting the GPS receiver’s capabilities by supplying some data from the service-provider network which helps to locate the device.
- Wi-Fi based positioning: This approach was developed to address the shortcomings of Cell Triangulation and GPS approaches. The basic concept is that by correlating Wi-Fi signals with GPS and other location data, a clue to the device’s location is provided when that same Wi-Fi signal is encountered in the future.
- Cell Triangulation: An approximate location can be calculated by using information about the location of the cell towers that a mobile device is connected to at any time. This concept has been discussed previously here on mobiForge when we took a look at the OpenCellID project.
Geolocation and privacy
Geolocation was at the outset somewhat haunted by privacy concerns. Such concerns have, to a certain extent, become more muted. Or at least the privacy controls that are in place are enough to satisfy the average user such that he or she is willing to give up some degree of privacy to benefit from some location-based service. The Geolocation API quite clearly addresses privacy and puts the user firmly in control by mandating that the user’s permission must be obtained before location information can be shared. From the specification:
User agents must not send location information to Web sites without the express permission of the user. User agents must acquire permission through a user interface, unless they have prearranged trust relationships with users, as described below. The user interface must include the host component of the document’s URI. Those permissions that are acquired through the user interface and that are preserved beyond the current browsing session (i.e. beyond the time when the browsing context is navigated to another URL) must be revocable and user agents must respect revoked permissions.
So, permission must be obtained from the user, the website hostname must be displayed, and it must be possible for the user to revoke permission.
This part of the specification is manifested in a similar way across the various mobile browsers. When a location request is made from a web page, a dialog is popped into the user’s view to request permission to access the location data (Android and iOS implementations are illustrated below).
Geolocation API details
In the Geolocation API, location is defined in terms of Position
and Coordinate
objects. A Coordinate
has the properties listed in the table below.
Property | Description |
---|---|
latitude |
geographic coordinate specified in decimal degrees |
longitude |
geographic coordinate specified in decimal degrees |
altitude |
(optional) the height of the position in metres |
accuracy |
represents the accuracy of the lat and lon values |
altitudeAccuracy |
(optional) the accuracy of the altitude value, specified in metres |
heading |
(optional) the current direction of travel of the device, in degrees between 0 and 360, clockwise from North |
speed |
(optional) the current speed of the device, in metres per second |
The Position
object is simply a Coordinate
coupled with a timestamp.
As shown in the table above, the properties altitude
, altitudeAccuracy
, heading
and speed
are all optional. So only the latitude
, longitude
, and accuracy
properties are guaranteed to be present. Therefore we will focus only on these properties in our example below.
Geolocation API Example
As an example to give a flavour of the Geolocation API, we will display a map in the browser, centered on the device’s current location. To start us off, we’ll use the Google Static Maps API, which returns simple static map images. Once we’re comfortable with this, we’ll implement the more familiar interactive maps that we’re accustomed to seeing on our desktop computers.
First, the HTML. We add a div and a placeholder image. We will later update the src
attribute of the image with the URL for the static map image.
1 2 3 |
<div id="map"> <img id="static-map" src="placeholder.png" class="mfnotransform"/> </div> |
Next we will access the device position data by making a request to the Geolocation API. At its most basic, this involves a call like the following:
1 |
navigator.geolocation.getCurrentPosition(successCallback, errorCallback); |
However, we need to check for support first. To do this we make the following call:
1 |
if (navigator && navigator.geolocation) {//do something} |
We also need to define the successCallback function for when the position data is returned. It’s in this function that we will build the URL for the static map, centered on the latlon data we have just obtained.
1 |
function successCallback(position) { |
The position object is passed as argument to this function. So now we need to know how to access the location data from this object. Recall from the table above the attributes of the coordinate object, and then accessing this required data is easy:
1 |
position.coords.latitude |
and
1 |
position.coords.longitude |
will give us the data we need.
Once we have this information we need to pass it with our URL for the static map tile:
1 2 3 |
var mapUrl = "http://maps.google.com/maps/api/staticmap?center="; mapUrl = mapUrl + position.coords.latitude + ',' + position.coords.longitude; mapUrl = mapUrl + '&zoom=15&size=512x512&maptype=roadmap&sensor=true'; |
And finally, when this URL is built we simply set this as the src
attribute of the img element we created above:
1 2 |
var imgElement = document.getElementById("static-map"); imgElement.src = mapUrl; |
The whole thing looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<!DOCTYPE html> <html> <head> <title>mobiForge geolocation demo</title> <style> #map {width:100%;height:100%;} </style> <script type="text/javascript"> function initGeolocation() { if (navigator && navigator.geolocation) { navigator.geolocation.getCurrentPosition(successCallback, errorCallback); } else { console.log('Geolocation is not supported'); } } function errorCallback() {} function successCallback(position) { var mapUrl = "http://maps.google.com/maps/api/staticmap?center="; mapUrl = mapUrl + position.coords.latitude + ',' + position.coords.longitude; mapUrl = mapUrl + '&zoom=15&size=512x512&maptype=roadmap&sensor=false'; var imgElement = document.getElementById("static-map"); imgElement.src = mapUrl; } </script> </head> <body onload="javascript:initGeolocation()"> <div id="map"> <img id="static-map" src="placeholder.png" /> </div> </body> </html> |
If you’re viewing this on a suitable device, click the link below the grey box to view the map, centered on your current location. (Full example code can be downloaded at end of article).
Click to try static map geolocation example
Google Maps API map
And for our next trick, we’ll implement a Google Map using the Maps API. So while the static map might be more suitable for low-end devices with CPU and RAM limitations, the interactive map can be used with more capable devices.
Adding the interactive map is only a little more complicated. We start off with similar HTML, but we will remove the image placeholder from the previous example, and just keep the div
. We’ll be loading the map into this div
:
1 2 |
<div id="map"> </div> |
Now, let’s add in the Google Maps library by adding the following:
1 |
<script src="https://maps.googleapis.com/maps/api/js?sensor=true"></script> |
Note the sensor=true
parameter. If information from a location sensor is being used, then this parameter must have a value of true
. This parameter is used simply to indicate to Google that the map is being used with a geolocation sensor, and is required by Google as part of licensing terms with its data providers.
Now that the library is in place, we configure our map options and fire off a request for a map. The main options we will be interested in are the zoom level, the map type, and of course the latitude and longitude. We access the lat and lon from the position object as we did in the last example and pass to the LatLng
function of the Google library.
1 2 3 4 5 |
var map_options = { center: new google.maps.LatLng(position.coords.latitude, position.coords.longitude), zoom: 15, mapTypeId: google.maps.MapTypeId.ROADMAP } |
Next we grab our map div, and load the map into it:
1 2 |
map_container = document.getElementById('map'); var map = new google.maps.Map(map_container, map_options); |
So, our updated success function now looks like this:
1 2 3 4 5 6 7 8 9 10 |
function successCallback(position) { var myLatlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); var map_options = { zoom: 15, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } map_container = document.getElementById('map'); var map = new google.maps.Map(map_container, map_options); } |
To see it in action, click the link below and the map should be loaded into the grey area. (Full example code can be downloaded at end of article).
Click to try Google Maps API Geolocation example
Geolocation Options
The Geolocation API provides an interface to further tweak device location requests. The available properties are outlined below. Of particular interest is the enableHighAccuracy
option. As mentioned above, there are a number of different ways that the location of the device can be ascertained. Some approaches, such as cell tower triangulation, can be quick and dirty and provide an approximate location, while other approaches can be slower and more power-consuming, but more accurate, such as GPS. The Geolocation API offers an interface by which the desired location accuracy can be specified. Depending on your application, you may or may not require high accuracy.
Property | Description | Default |
---|---|---|
enableHighAccuracy |
indicates that the web application would like highest accuracy possible | false |
timeout |
the length of time to wait before receiving user’s location | infinity |
maximumAge |
indicates that cached location information should be no older than this number of milliseconds | 0 |
Options are passed as an object with the position request. So, to request a location update that was no older than ten minutes, with high accuracy, and with a wait of no longer than one minute before timing out, the code would look something like the following:
1 2 3 |
navigator.geolocation.getCurrentPosition(successCallback, errorCallback, {enableHighAccuracy:true, timeout:60000, maximumAge:600000}) |
Continuous position updates: watchPosition
In addition the API specifies a separate function to use if your application requires continuous position updates: watchPosition()
. The arguments are the same as the getCurrentPosition()
, but instead of requiring the developer to make repeated calls to getCurrentPosition()
the developer’s successCallback()
function will be called whenever the user’s location changes.
1 |
var watchId = navigator.geolocation.watchPosition(successCallback); |
Note that the watchPosition()
function returns an integer. We can use this value to end monitoring of the user’s location, so it’s useful to store it for use later on.
When the application has no more use for the user’s location, it should call clearWatch()
to prevent the successCallback()
function from being triggered any more. This function takes as parameter an integer value corresponding to the ID of the watch to be cleared – the value returned by the watchPosition()
call.
1 |
navigator.geolocation.clearWatch(watchId); |
Geolocation API example: Continuous position updates
For our final example, we’ll build on the previous examples, but this time we’ll use watchPosition()
to continuously re-center the map on the device location whenever the location is updated. To get the full benefit of this example you’ll need to get up and run around outside for a few minutes while looking at this page on your phone.
First, we modify our code to use the watchPosition()
function instead of getCurrentPosition()
, and we’ll store the return value for later use. As with getCurrentPosition, we specify the success callback function. This time though, we’ll add the enableHighAccuracy
option so that we’ll notice smaller movements.
1 2 3 |
var watchId = navigator.geolocation.watchPosition(successCallback, errorCallback, {enableHighAccuracy:true,timeout:60000,maximumAge:0}); |
Now we define the callback function. We only need a small modification from our previous example. This time, if it’s the first access, we need to create the map and center it on the device location. Whenever watchPosition()
reports any subsquent change to the position, we will use the panTo
method from the Google Maps API to re-center the map. We have also zoomed the map a little bit more, so that its movement will be more noticeable.
The updated function looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 |
function successCallback(position) { var myLatlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); if(map == undefined) { var myOptions = { zoom: 15, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } map = new google.maps.Map(document.getElementById("map"), myOptions); } else map.panTo(myLatlng); } |
That’s it, now out you go for a jog and click the link below the grey box to see this thing in action. (Full example code can be downloaded at end of article).
Click to try Geolocation API Continuous Position example
A shortcoming in this example is that although we center the map on the user’s location, the map is not rotated to correspond to the device orientation. The Geolocation API unfortunately does not supply this information. Conveniently though, there is another useful HTML5 API, the Device Orientation API, which can provide such information. We’ll revisit this example in a future article, and we’ll see what happens when we add orientation data into the mix.
Browser support and fallbacks
As can be seen from the table below Geolocation is widely supported across the main mobile browsers, with the exception of Opera Mini.
Android | iOS | IE Mobile | Opera Mobile | Opera Mini | Firefox Mobile | Chrome for Android |
---|---|---|---|---|---|---|
(Sources: caniuse.com, DeviceAtlas, mobilehtml5.org) |
It’s also worth noting that in the examples above the code to use the Geolocation API in a webpage was quite simple. The situation is a little more complicated in reality. The value of coupling location-awareness with mobile services has long been acknowledged and a number of handset manufacturers and other organisations have flirted with geolocation support in the browser in the past. This has resulted in various different legacy geolocation implementations. These have included BONDI from the OMTP group, Palm, RIM, and Google Gears, some of which we’ve discussed previously here on mobiForge. If location is to be supported on these devices, then a web application needs to cater for these legacy APIs too.
Thankfully there are a couple of freely (under MIT license) available scripts that have done the hard work to insulate you from the details, including
this script by Stan Wiechers, and this script by Esteban Acosta Villafañe which builds on Wiechers’ script.
Taking a peek inside them, we can see that they check the device browser for support for any of the other legacy implementations as well as the W3C API, thus relieving you, the developer, of some of the drudgery!
That’s it for now on the Geolocation API. Check back soon for the next article in our series, which will cover the Device Orientation API
Useful Links
- W3C Geolocation API: http://www.w3.org/TR/geolocation-API/
- Google Maps API: https://developers.google.com/maps/documentation/
- Geolocation script by Stan Wiechers
- Geolocation script by Esteban Acosta Villafañe
- HTML5 Augmented reality app by Dominique Hazael-Massieux
Download
Download full code examples below
Leave a Reply