Where on Earth am I?
Every one of us occupies a location on Earth. This location is specified by a geographic coordinate system of latitude, longitude, and altitude. With the proliferation of location-aware hardware and software, finding one’s location on the Earth has never been easier. There are many techniques available to identify the location of a user. A computer browser generally uses WIFI or IP based positioning techniques whereas a mobile browser may use cell triangulation that based on your relative proximity to the different cellular towers operated by the telcos, GPS, A-GPS, or WIFI. Today, location awareness is an ever-growing trend that finds its way into many applications like:
- Showing one’s location on a map especially when you are in an unfamiliar area
- Providing turn-by-turn navigation while driving on unfamiliar journey
- Find out the points of interest in one’s vicinity
- Getting the latest weather or news of one’s area
- Tagging the location of picture
- Location tracking of a fleet of delivery trucks
Thanks to HTML5 Geolocation API, you can now look up your own location on Earth using a browser, say Firefox. It is as easy as a piece of cake. Doing is believing. Let get your hands dirty.
Setting the Stage
Type the following code in Listing 1 using a text editor, save it as “finding_me.html”, and launch it on a browser.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Finding Me</title>
<script>
function getLocation()
{
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(getPosition);
} else {
alert("Oop! This browser does not support HTML5 Geolocation.");
}
}
function getPosition(position)
{
document.getElementById("location").innerHTML =
"Latitude: " + position.coords.latitude + "<br>" +
"Longitude: " + position.coords.longitude;
}
</script>
</head>
<body>
<h1>Finding Me</h1>
<button onclick="getLocation()">Where am I?</button>
<p id="location"></p>
</body>
</html>
You should see a web page as shown in Figure 1. Note that this code will work on Firefox and Internet Explorer, but not on Google Chrome. Chrome does not allow running Geolocation API from a file:// URI, it will work if you deploy it on a web server like Apache.
Figure 1: finding_me.html on a Firefox Browser
Click on the “Where am I?” button, what do you see?
Figure 2: Seeking Permission to Share Location
A dialog box as shown in Figure 2 pops up seeking permission to share location, click on “Share Location” to grant.
Figure 3: You are found!
Voila, your location is revealed on the screen as shown in Figure 3. Isn’t that a piece of code, I mean cake.
How you wish you could show these location readings on a map so that you could view your location visually, right? Your wish will come true if you read on…
Diving Deeper…
The HTML5 geolocation API has only one object – the navigator.geolocation
object. You may liken the navigator.geolocation
to a compass on the browser. As browser support for this API is still dubious, it is a de facto practice to check for browser support before proceeding with any geolocation code, just wrap your code inside this if
-else
template as shown:
if (navigator.geolocation)
{
}
else
{
alert("Oop! This browser does not support HTML5 Geolocation.");
}
The navigator.geolocation
object exposes three methods – getCurrentPosition()
, watchPosition()
, and clearWatch()
.
getCurrentPosition()
The getCurrentPosition()
method is used to obtain the current location of the user. You have already used this method in its simplest form in the code in Listing 1.
navigator.geolocation.getCurrentPosition(getPosition);
Recall in Figure 3 where a dialog has popped up seeking your permission to share your location with the web page. This is what happens whenever the getCurrentPosition()
method is called. Users are given the choice to opt-in in order to allow the method to proceed to retrieve your current position. In other words, your privacy is well-respected and protected.
The getCurrentPosition()
method takes three parameters:
- The first parameter is a callback function to be called when the call to
getCurrentPosition()
method is successful. The callback function will be called with a position object passed from the getCurrentPosition()
method. This position object consists of 2 properties: coords
and timestamp
. In Listing 1, the callback function is “getPosition(position)
” which takes a position
object parameter and outputs the latitude
and longitude
through the coords
property of this parameter. This is illustrated in the following code:
function getPosition(position)
{
document.getElementById("location").innerHTML =
"Latitude: " + position.coords.latitude + "<br>" +
"Longitude: " + position.coords.longitude;
}
Table 1 shows the properties of the position
object.
Table 1: Position Object
Property | Description |
coords.latitude | The coords.latitude property returns the latitude of the user’s current position in decimal degrees. |
coords.longitude | The coords.longitude property returns the longitude of the user’s current position in decimal degrees. |
coords.altitude | The coords.altitude property returns the height of the user’s current position in meters above the sea level. It will return null if this information is not available. |
coords.accuracy | The coords.accuracy property returns the accuracy level of the latitude and longitude coordinates in meters. |
coords.altitudeAccuracy | The coords.altitudeAccuracy property returns the accuracy level of the altitude in meters. |
coords.heading | The coords.heading property returns the direction of travel of the location-aware device in degrees, where 0° starts from the north and counting clockwise. It will returns null if this information is not available. |
coords.speed | The coords.speed property returns the speed of the location-aware device in meters per second. It will return null if this information is not available. |
timestamp | The timestamp property returns the time when the position object was acquired. |
- The second parameter is an optional error handling callback function to be invoked when the call to
getCurrentPosition()
method encounters any one of the following circumstances:
- Request timed out
- Location information not available
- User has denied permission to share the location information
The callback function will be invoked with a position error object parameter passed from the getCurrentPosition()
method. This position error object consists of one property – code
. This code property takes one of three values corresponding to the error types as shown in Table 2.
Table 2: Location Error Codes
Property | Description |
TIMEOUT | Request for location information exceeds the timeout property set in the position options object (discussed later). |
POSITION_UNAVAILABLE | The position of the location-aware device cannot be determined. |
PERMISSION_DENIED | User has denied permission to share the location information. |
You will add a second callback function called “catchError(error)
” to the <script>
as shown in the following code and as highlighted in Figure 4:
function catchError(error) {
switch(error.code)
{
case error.TIMEOUT:
alert("The request to get user location has aborted as it has taken too long.");
break;
case error.POSITION_UNAVAILABLE:
alert("Location information is not available.");
break;
case error.PERMISSION_DENIED:
alert("Permission to share location information has been denied!");
break;
default:
alert("An unknown error occurred.");
}
}
Figure 4: catchError() Function
Next, attach the following function as the second parameter to the getCurrentPosition()
method as shown:
navigator.geolocation.getCurrentPosition(getPosition, catchError);
Save and launch it on a browser (Firefox), unplug your network cable (or turn off the wireless switch) to simulate the “no network connection” situation, grant the permission for sharing location information (Figure 2), and then click on the “Where am I?” button. What do you see?
Figure 5: Simulating an Error Situation
You should see a message box pops up saying “Location information is not available.” as shown in Figure 5. If you look back to the code in the catchError()
function, you would notice that this is the error message specified under the case of error.POSITION_UNAVAILABLE
. The cause is obviously due to the network cable being unplugged. The catchError()
function was invoked by the getCurrentPosition()
method as it is not able to obtain any location information due to the broken network connection. (You may recover the network connection to your computer.) Although this error handling parameter is optional, you should always include it as part of the geolocation code. This is one of the best practices to allow the program to fail gracefully as well as to keep the users informed of any run-time errors.
- The third parameter is an optional position options object that can be used to fine tune the position object returned by the
getCurrentPosition()
method programmatically. It has three properties as shown in Table 3.
Table 3: Position Options Object Properties Property | Description |
timeout | The timeout property denotes the number of milliseconds an application will wait for a position information to become available. The default value is infinity. |
maximumAge | The maximumAge property denotes the number of milliseconds an application can keep using the cached (previously obtained) location data before trying to obtain new location data. A zero value indicates that the application must not use the cached location data while infinity value indicates that the cached location data must be used by the application. The default value is zero. |
enableHighAccuracy | The enableHighAccuracy property denotes the condition of true or false . If it is true , the application will try to provide the most accurate position. However, this would result in slower response time and higher power consumption. The default value is false . |
You will define a position options object called “positionOptions
” and add it as the third parameter to the getCurrentPosition()
method as shown in the following code and as highlighted in Figure 6:
var positionOptions = {
timeout : Infinity,
maximumAge : 0,
enableHighAccuracy : true
};
navigator.geolocation.getCurrentPosition(getPosition, catchError, positionOptions);
Figure 6: Position Options Object
In designing your location-aware application, you should choose the degree of accuracy as well as the retention period of old location data that are most appropriate for the purpose of the application by setting the enableHighAccuracy
and the maximumAge
properties of the position options object accordingly. For example, if your application is mainly for finding points of interest in your vicinity, you probably do not need high accuracy and the location information does not have to be updated so often. On the other hand, if your application is to provide turn by turn navigation direction for driver, then high accuracy and constant update of location become necessary.
The getCurrentPosition()
method is most suitable for obtaining a one-off location information. However, for finding location information that is changing continuously, such as the turn by turn navigation that I mentioned above, you will have to call the getCurrentPosition()
method repeatedly which is obviously very cumbersome and inefficient. Fret not! HTML5 Geolocation API has provided another method to handle this kind of situation – watchPosition()
.
watchPosition()
The watchPosition()
method is almost identical to the getCurrentPosition()
method. They both return the current location information and have the same method signature – one success callback function, one error callback function, and one position options object. The only difference lies in that the getCurrentPosition()
method only returns location information once upon activation such as a button click, whereas The watchPosition()
method will continue to obtain location information every time the location of the user’s device changes after the initial activation.
The watchPosition()
method returns a watch ID that can be used to stop obtaining location information by passing it to the third method of the navigator.geolocation
object – clearWatch()
, such as when a car that uses it for navigation has arrived at the destination.
clearWatch()
The clearWatch()
method takes the watch ID of a watchPosition()
method as a parameter and stop the execution of that watchPosition()
method.
Location Tracking
As the watchPosition()
method is similar to the getCurrentPosition()
method, if you are familiar with the later, creating the watchPosition()
method will be much easier – it is mostly a matter of, believe it or not, “copy and paste”.
Open “finding_me.html” in a text editor, save it as “watching_me.html”. Then, in “watching_me.html”,
- Change “
geolocation.getCurrentPosition(getPosition, catchError, positionOptions)
” to “navigator.geolocation.watchPosition(getPosition, catchError, positionOptions)
”.
That’s all that you need to create a web page that constantly monitors and updates a browser’s current location.
However, to stop the monitoring and updating at some point in time, you will add another piece of code and a button to deactivate it. In the <script>
section of “watching_me.html”, create a function called “stopWatch()
” that calls the clearWatch()
method by passing it the watchID
of the watchPosition()
method:
function stopWatch()
{
navigator.geolocation.clearWatch(watchID);
}
Lastly, replace the HTML code in the <body>
of “watching_me.html” with:
<body>
<h1>Watching Me</h1>
<button onclick="getLocation()">Start Watching</button>
<button onclick="stopWatch()">Stop Watching</button>
<p id="location"></p>
</body>
The complete source code of "watching_me.html" is given below:
<!DOCTYPE html>
<html>
<head>
<title>Watching Me</title>
<script>
function getLocation()
{
if (navigator.geolocation)
{
var positionOptions = {
timeout : Infinity,
maximumAge : 0,
enableHighAccuracy : true
};
watchID = navigator.geolocation.watchPosition(getPosition, catchError, positionOptions);
}
else
{
alert("Oop! This browser does not support HTML5 Geolocation.");
}
}
function stopWatch()
{
navigator.geolocation.clearWatch(watchID);
watchID = null;
}
function getPosition(position)
{
document.getElementById("location").innerHTML =
"Latitude: " + position.coords.latitude + "<br>" +
"Longitude: " + position.coords.longitude;
}
function catchError(error) {
switch(error.code)
{
case error.TIMEOUT:
alert("The request to get user location has aborted as it has taken too long.");
break;
case error.POSITION_UNAVAILABLE:
alert("Location information is not available.");
break;
case error.PERMISSION_DENIED:
alert("Permission to share location information has been denied!");
break;
default:
alert("An unknown error occurred.");
}
}
</script>
</head>
<body>
<h1>Watching Me</h1>
<button onclick="getLocation()">Start Watching</button>
<button onclick="stopWatch()">Stop Watching</button>
<p id="location"></p>
</body>
</html>
Save and launch “watching_me.html” on a WIFI connected laptop (Firefox) browser, click the “Start Watching” button, grant the permission to share location, then move around with the laptop. What do you see?
Figure 7: You are being watched!
You should see your position being updated on the browser at a regular interval as shown in an example in Figure 7.
If you copy and paste the latitude and longitude values to the search box of a Google Map on your browser, Google Map will mark your approximate location with a marker. The location is approximate and may differ on different browsers and devices as the accuracy of which is dependent on a number of factors, such as your public IP address, the nearer cellular towers, GPS availability, WIFI access points, and the type of browser that you are using.
Location Tracking on Map
Let’s put the watch on a map as shown in an example in Figure 8.
Figure 8: You are on Google map!
The file is called “watching_on_map.html” as shown below and is available for download.
<!DOCTYPE html>
<html>
<head>
<title>Watching on Map</title>
<style>
html,body {
height: 100%;
margin: 0;
padding: 0;
}
#map-holder {
height: 350px;
width: 500px;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script>
var watchID;
function getLocation()
{
if (navigator.geolocation)
{
var positionOptions = {
timeout : Infinity,
maximumAge : 0,
enableHighAccuracy : true,
};
navigator.geolocation.getCurrentPosition(getPosition, catchError, positionOptions);
}
else
{
alert("Oop! This browser does not support HTML5 Geolocation.");
}
}
function watchLocation()
{
if (navigator.geolocation)
{
var positionOptions = {
timeout : Infinity,
maximumAge : 0,
enableHighAccuracy : true,
};
watchID = navigator.geolocation.watchPosition(getPosition, catchError, positionOptions);
}
else
{
alert("Oop! This browser does not support HTML5 Geolocation.");
}
}
function stopWatch()
{
navigator.geolocation.clearWatch(watchID);
}
function getPosition(position)
{
var location = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var mapOptions = {
zoom : 12,
center : location,
mapTypeId : google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-holder'), mapOptions);
var marker = new google.maps.Marker({
position: location,
title: 'Here I am!',
map: map,
animation: google.maps.Animation.DROP
});
var geocoder = new google.maps.Geocoder();
geocoder.geocode({
'latLng' : location
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[1]) {
var options = {
content : results[1].formatted_address,
position : location
};
var popup = new google.maps.InfoWindow(options);
google.maps.event.addListener(marker, 'click', function() {
popup.open(map);
});
}
else
{
alert('No results found');
}
}
else
{
alert('Geocoder failed due to: ' + status);
}
});
}
function catchError(error) {
switch(error.code)
{
case error.TIMEOUT:
alert("The request to get user location has aborted as it has taken too long.");
break;
case error.POSITION_UNAVAILABLE:
alert("Location information is not available.");
break;
case error.PERMISSION_DENIED:
alert("Permission to share location information has been denied!");
break;
default:
alert("An unknown error occurred.");
}
}
</script>
</head>
<body onload="getLocation()">
<div id="map-holder"></div>
<button onclick="watchLocation()">Start Watching</button>
<button onclick="stopWatch()">Stop Watching</button>
</body>
</html>
The logic of the code works as follows:
- When the page is first loaded, the
onload
event will be triggered and calls the getLocation()
function which in turn calls the getCurrentPosition()
method of the navigator.geolocation
object to obtain the user’s current location. - If the
getCurrentPosition()
method is successful, it will trigger the callback function getPosition()
passing it the position object. - What the
getPosition()
function does is to render a Google Map that is centered on the user’s location shown as marker. - Clicking the “Start Watching” button will call the
watchLocation()
function which in turn calls the watchPosition()
method of the navigator.geolocation
object to obtain the user’s current location at a regular interval. - If the
watchPosition()
method is successful, it will trigger the callback function getPosition()
passing it the position object. - What the
getPosition()
function does has been described above. - Clicking the “Stop Watching” button will stop the watch activity.
If you move around with your WIFI connected laptop while keeping this web page opened, you should see your location being updated on the browser regularly as you move. Have fun!
Download
The post HTML5 Geolocation appeared first on Peter Leow's Code Blog.