The Geolocation API

INTRODUCTION

This chapter presents the new Geolocation API and illustrates its use with several examples.

The Geolocation HTML5 JavaScript API is implemented by most modern Web browsers, and uses different means to get the current location: GPS, GSM/3G triangulation, Wifi, IP address, etc.

It is possible to prompt the user to activate the GPS (this is what most GPS navigation software does on mobile phones), or ask for a particular mean among those available. It is also possible to track the current position when it changes. This is useful for writing a navigation application or for tracking in real time the position of different participants in the case of an application that involves several persons at the same time (using WebSockets, for example).

CURRENT SUPPORT IS EXCELLENT

As at June 2016, support for this API is excellent, both on mobile and on desktop devices.

geolocation support table

To get an updated table, check caniuse.com

TYPICAL USE

  1. navigator.geolocation.getCurrentPosition(showPosition, onError);
  2.  
  3. function showPosition(position) {
  4.     console.log(“latitude is: “ + position.coords.latitude);
  5.     console.log(“longitude is: “ + position.coords.longitude);
  6. }
  7.  
  8. function onError(err) {
  9.     console.log(“Could not get the position”);
  10. }

This online example at JS Bin shows how to get the current longitude and latitude and display them in an HTML page. Try it below in your browser:

Note that the first time you execute this example, for privacy reasons, the browser will ask if you agree to share your position with the application.

Source code of this typical example:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4. <title>Basic example of use of the geolocation API</title>
  5. </head>
  6. <body>
  7. <p id=“msg”>Click the button to get your coordinates:</p>
  8. <button onclick=getLocation()>Where am I ?</button>
  9.     var displayCoords=document.getElementById(“msg”);
  10.     function getLocation() {
  11.        if (navigator.geolocation) {
  12.           navigator.geolocation.getCurrentPosition(showPosition);
  13.        } else {
  14.           displayCoords.innerHTML=“Geolocation API not supported by your browser.”;
  15.        }
  16.    }
  17.    function showPosition(position) {
  18.        displayCoords.innerHTML=“Latitude: “ + position.coords.latitude +
  19.                                
    Longitude: “
    + position.coords.longitude;
  20.    }
  21. </body>
  22. </html>

Explanations:

    • Line 14 checks if the Web browser supports the geolocation API by testing the variable navigator.geolocation. If not null, then the geolocation API is supported.
    • Line 15 callsnavigator.geolocation.getCurrentPosition(showPosition) passing a callback function as a parameter (in this example we did not specify a callback in case of error). When a current position is available, the callback function will be called asynchronously, and the input parameter of this callback function will be the current position, like in the functionshowPosition(position) of the example.
    • Line 22: the position objects has a coords property that is the object that holds the longitude and the latitude.

EXTERNAL RESOURCES:

The different properties of the coords object

In the previous example, we used the coords property of the position passed as an input parameter to the callback function. This coords object has many properties:

Properties of the coords object
latitude The latitude of the position
longitude The longitude of the position
altitude The altitude of the position
accuracy The accuracy of the measure of the longitude and latitude (in meters)
altitudeAccuracy The accuracy of the measure of the altitude (in meters)
heading gives the orientation relative to north, in degrees
speed current speed in meters/second

Not all these values may be available in all Web browsers. When one of these properties is null, it means that it is not available.

 

Geolocation error codes

In the last example, we used the navigator.geolocation.getCurrentPosition(showPosition) with only one callback function (in the case of success), but it is also possible to pass a second parameter that is another callback function called in the case of error.

This example on JS Bin shows how to properly check against the different possible errors, it’s just a slightly different version of the previous example. Try it, then turn your WiFi off or unplug your Ethernet cable (or turn off GPS and 3G/4G on a mobile phone). You should see an error message.

Source code of the example:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4. <title>Basic example of use of the geolocation API</title>
  5. </head>
  6. <body>
  7. <p id=“msg”>Click the button to get your coordinates:</p>
  8. <button onclick=getLocation()>Where am I ?</button>
  9.    var displayCoords=document.getElementById(“msg”);
  10.    function getLocation() {
  11.       if (navigator.geolocation) {
  12.          navigator.geolocation.getCurrentPosition(showPosition, errorPosition);
  13.       } else {
  14.         displayCoords.innerHTML=“Geolocation API not supported by your browser.”;
  15.       }
  16.    }
  17.    function showPosition(position) {
  18.       displayCoords.innerHTML=“Latitude: “ + position.coords.latitude +
  19.                                
    Longitude: “
    + position.coords.longitude;
  20.    }
  21.    function errorPosition(error) {
  22.       var info = “Error during geolocation: “;
  23.       switch(error.code) {
  24.          case error.TIMEOUT:
  25.             info += “Timeout !”;
  26.             break;
  27.          case error.PERMISSION_DENIED:
  28.             info += “Permission denied, geolocation could not be obtained…”;
  29.             break;
  30.          case error.POSITION_UNAVAILABLE:
  31.             info += “Location could not be obtained though the available means…”;
  32.             break;
  33.          case error.UNKNOWN_ERROR:
  34.             info += “Unknown error”;
  35.             break;
  36.       }
  37.       displayCoords.innerHTML = info;
  38.     }
  39. </body>
  40. </html>

Tracking a position in real time

INTRODUCTION

In order to track the current position, the geolocation API provides a method similar to the getCurrentPosition(onSuccess, onError) named watchPosition(onSuccess, onError).

When getCurrentPosition gives a position when called, watchPosition does the following:

    • It gets the callback function only when the current position changes. If you stay in the same location, the callback function won’t be called regularly.
    • It returns an id so that you can use the clearWatch(id) method to stop the current tracking.

TYPICAL USE

  1. // get an id of the current tracking, the showPosition callback is like the one we saw in earlier examples.
  2. var watchPosId = navigator.geolocation.watchPosition(showPosition);
  3. // stop the tracking
  4. navigator.geolocation.clearWatch(watchPosId);

As an exercise, you may just try to change getCurrentPosition to watchPosition in the previous examples, and try this code using a mobile phone or tablet, walk for 20 meters and see the position changing.

External resource

OPTIONS AVAILABLE WHEN USING THE GEOLOCATION API, IN PARTICULAR REAL TIME TRACKING

Several options are available when using HTML5 geolocation. We can pass a third parameter to the getCurrentPosition and watchPosition methods, that will hold one or several of the following options:

Properties of the coords object
enableHighAccuracy A boolean (true/false) which indicates to the device that you wish to obtain its most accurate readings. in other words: use the GPS please! (However, this parameter may or may not make a difference, depending on your hardware, GPS availability, etc.)
maximumAge The maximum amount of time (in milliseconds) the position may remain in the cache (this is appropriate as the device may cache readings to save power and/or bandwidth).
timeout The maximum time (in milliseconds) for which you are prepared to allow the device to try to obtain a Geo location. After this timeout value has elapsed, the onError callback is called.

Example of use (see the explanations in the lines of comment):

  1. // Just ask to turn GPS on, if available
  2. navigator.geolocation.getCurrentPosition(onSuccess, onError,
  3.                                      {enableHighAccuracy:true});
  4. // maximumAge = 10 mins, the position can be cached for 10 mins,
  5. // useful when in tunnels…When the device tries to get
  6. // a position, if it does not succeed, then go on error
  7. // immediately
  8. navigator.geolocation.getCurrentPosition(onSuccess, onError,
  9.                                 {maximumAge:600000timeout:0});
  10. // Position will never come from the cache (maximumAge: 0), and
  11. // if after 0.1s the position could not be computed, then go on
  12. // error
  13. navigator.geolocation.getCurrentPosition(onSuccess, onError,
  14.                                    {maximumAge:0timeout:100});
  15. // Ask for GPS, cache for 30s, 27s before going on error…
  16. watchId=navigator.geolocation.watchPosition(onSuccess, onError,
  17.     {enableHighAccuracy:true, maximumAge:30000, timeout:27000});

Practical examples: use the geolocation API together with Google Maps

This section presents some examples of how to get a static map (a picture), using the Google Static Map API, how to display an interactive map using the Google Map JavaScript API and even how to get an estimation of a physical address from the longitude and latitude, using the Google Reverse Geocoding JavaScript API.

The following three examples increase in complexity, but most of the code is reused and adapted without even reading the Google documentation about the different APIs.

EXAMPLE 1 (EASY):  HOW TO GET A STATIC IMAGE MAP CENTERED ON YOUR LONGITUDE AND LATITUDE

Online example available on JS Bin, or try it here in your browser:

It also illustrates the use of the error callback from the previous section. The Google Map API is used to get an image centered at the longitude and latitude collected with the HTML5 Geolocation API.

Source code extract:

  1. <!DOCTYPE html>
  2. <html>
  3. <body>
  4. <p id=“demo”>Click the button to get your position:</p>
  5. <button onclick=getLocation()>Try It</button>
  6. id=“mapholder”>

  7. var x=document.getElementById(“demo”);
  8.  
  9. function getLocation() {
  10.    if (navigator.geolocation) {
  11.       navigator.geolocation.getCurrentPosition(showPosition,showError);
  12.    } else{
  13.       x.innerHTML=“Geolocation is not supported by this browser.”;
  14.    }
  15. }
  16.  
  17. function showPosition(position) {
  18.    // Google map API needs the latitude and longitude separated by a comma
  19.    var latlon=position.coords.latitude+“,”+position.coords.longitude;
  20.    // Google map API URL that returns an image centered on the longitude and latitude
  21.    var img_url=https://maps.googleapis.com/maps/api/staticmap?center=&#8221;
  22.                +latlon+“&zoom=14&size=400×300&sensor=false”;
  23.    document.getElementById(“mapholder”).innerHTML=+img_url+“‘ />”;
  24. }
  25.  
  26.  function showError(error) {
  27.     … 
  28.  }
  29. </body>
  30. </html>

The magic occurs at line 23, where we use the Google Static Map API.

EXAMPLE 2 (A BIT MORE COMPLICATED…) THAT SHOWS HOW TO DISPLAY AN INTERACTIVE GOOGLE MAP CENTERED ON THE CURRENT POSITION

This example is just given “as is”, as there are so many possibilities for rendering a map with the Google Map API. However, we think having such a basic example might be useful.

Online example at JS Bin

Source code of the example:

  1. <!doctype html>
  2. <html>
  3. <head>
  4. </head>
  5. <body>
  6. <!– for position display –>
  7. id=“myposition”>

  8.  
  9. <!– for gmap display –>
  10. id=“map” style=width:640px;height:480px>

  11.  
  12. <!– get gmap API –>
  13. src=https://maps.google.com/maps/api/js?sensor=false&#8221;>
  14.  
  15. // Default position
  16. var centerpos = new google.maps.LatLng(48.579400,7.7519);
  17.  
  18. // default options for the google map
  19. var optionsGmaps = {
  20.     center:centerpos,
  21.     navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL},
  22.     mapTypeId: google.maps.MapTypeId.ROADMAP,
  23.     zoom: 15
  24. };
  25.  
  26. // Init map object
  27. var map = new google.maps.Map(document.getElementById(“map”), optionsGmaps);
  28.  
  29. if(navigator.geolocation) {
  30.  
  31.     // callback function, called by getCurrentPosition() in case of success
  32.     function drawPosition(position) {
  33.        var infopos = “Got position :
    ;
  34.        infopos += “Latitude : “+position.coords.latitude +
    ;
  35.        infopos += “Longitude: “+position.coords.longitude+
    ;
  36.        infopos += “Altitude : “+position.coords.altitude +
    ;
  37.        document.getElementById(“myposition”).innerHTML = infopos;
  38.  
  39.        // Make new object LatLng for Google Maps
  40.        var latlng = new google.maps.LatLng(position.coords.latitude,               
  41.                                            position.coords.longitude);
  42.  
  43.        // Add a marker at position
  44.        var marker = new google.maps.Marker({
  45.                              position: latlng,
  46.                              map: map,
  47.                              title:“You are here”
  48.        });
  49.        // center map on longitude and latitude
  50.        map.panTo(latlng);
  51.     }
  52.  
  53.     // callback function, called by getCurrentPosition() in case of error
  54.     function errorPosition(error) {
  55.        …
  56.     }
  57.     navigator.geolocation.getCurrentPosition(drawPosition,errorPosition);
  58. } else {
  59.     alert(“Geolocation API not supported by your browser”);
  60. }
  61. </body>
  62. </html>

EXAMPLE 3 (ADVANCED) SHOWS HOW TO GET A PHYSICAL ADDRESS FROM THE LONGITUDE AND LATITUDE

This is another example that obtains an address from longitude and latitude. It usesthe Google Reverse Geocoding JavaScript API. For those of you who are really interested to know how this API works, please read the Google documentation and tutorials.

Without going into detail, the below example might be useful to copy/paste/adapt for trying to pre-fill a form where one is asked for an address. Geolocation is useful for guessing the country, city, zip code, street, etc. Some examples that use this feature will be given in the next section of the course.

Online example at JS Bin.

Source code of the example:

  1. <!DOCTYPE html>
  2. <html lang=“en”>
  3. <head>
  4.      src=https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&#8221;>
  5. // p elements for displaying lat / long and address
  6. var displayCoords, myAddress;
  7. // used with the google apis
  8. var geocoder;
  9. var map;
  10. var infowindow = new google.maps.InfoWindow();
  11. var marker;
  12. // Called when the page is loaded
  13. function init() {
  14.     displayCoords=document.getElementById(“msg”);
  15.     myAddress = document.getElementById(“address”);
  16.     geocoder = new google.maps.Geocoder();
  17.     // In order to show something even before a user clicks on the button
  18.     var latlng = new google.maps.LatLng(34.0144, 6.83);
  19.     var mapOptions = {
  20.        zoom: 8,
  21.        center: latlng,
  22.        mapTypeId: ‘roadmap’
  23.     }
  24.     map = new google.maps.Map(document.getElementById(‘map_canvas’), mapOptions);
  25. } // end of init()
  26. // Called when the button is clicked
  27. function getLocation() {
  28.     if (navigator.geolocation) {
  29.        navigator.geolocation.getCurrentPosition(showPosition);
  30.     } else {
  31.        displayCoords.innerHTML=“Geolocation API not supported by your browser.”;
  32.     }
  33. }
  34. // Called when a position is available
  35. function showPosition(position) {
  36.     displayCoords.innerHTML=“Latitude: “ + position.coords.latitude +
  37.                            
    Longitude: “
    + position.coords.longitude;
  38.     // Display the map
  39.     showOnGoogleMap(new google.maps.LatLng(position.coords.latitude,       
  40.                                            position.coords.longitude));
  41.  }
  42.  function showOnGoogleMap(latlng) {
  43.    // Ask google geocoder for an address once we get a longitude and
  44.    // a latitude. In fact, the reverse geocoder sends back an array of “guesses”
  45.    // i.e. not just one address object, but several. Each entry in this array
  46.    // has several properties such as street, city, etc. We use the “formatted_address”
  47.    // one here, but it might be interesting to get the detailed properties in other
  48.    // applications like a form with street, city, zip code etc.
  49.    geocoder.geocode({‘latLng’: latlng},reverseGeocoderSuccess);
  50.    function reverseGeocoderSuccess(results, status) {
  51.      if (status == google.maps.GeocoderStatus.OK) {
  52.         if (results[1]) {
  53.            map.setZoom(11);
  54.            marker = new google.maps.Marker({
  55.                                 position: latlng,
  56.                                 map: map
  57.                         });
  58.            infowindow.setContent(results[1].formatted_address);
  59.            infowindow.open(map, marker);
  60.            // Display address as text in the page
  61.            myAddress.innerHTML=“Adress: “ + results[0].formatted_address;
  62.         } else {
  63.            alert(‘No surface address found’);
  64.         }
  65.       } else {
  66.          alert(‘Geocoder failed due to: ‘ + status);
  67.       }
  68.     } // end of reverseGeocoderSuccess
  69. } // end of showOnGoogleMap
  70. </head>
  71. <body onload=init()>
  72. <title>HTML5 + Geolocalisation + Google Maps API Reverse Geocoding</title>
  73. <p id=“msg”>Click the button to get your coordinates:</p>
  74. <p id=“address”></p>
  75. <button onclick=getLocation()>Where am I ?</button>
  76. id=“map_canvas” style=width: 500px; height: 300px>

  77. </body>
  78. </html>

Example: fill a form’s address fields automatically

INTRODUCTION

In the previous example, we used the results returned by the Google reverse geocoding service, without going into detail.

In this section, we will see how we can get the different parts of the responses (city, street, zip code, country, etc.) The reverse geocoding service tries to guess what is the “best” address that matches the longitude and latitude, but sometimes the first guess is not the best one.

HOW TO PARSE THE GOOGLE REVERSE GEOCODING RESULTS?

What are the Google reverse geocoding results exactly?

A common question is: how to have a robust code for parsing the Google reverse geocoding, to properly get the city, street, country, etc.

Depending on your location/country and on the geolocation method used by your browser (GPS on phone, IP, WiFi, 3G, etc.), some of the data might not be available (i.e., no street). So, there is no guarantee that all candidate addresses will get the same defined properties. For example, the first result may give a defined city, but the third result may not.

Look at this line of code from the last example from the previous page – the example that showed the address when you clicked on the button:

  1. // Display address as text in the page
  2. myAddress.innerHTML=“Adress: “ + results[0].formatted_address;

At line 2, we get the first address returned by the Google reverse geocoding service, and use the formatted_address property. Let’s suppose that it contained the best address, formatted as a string. We chose to use it and showed it in the page by setting myAddress.innerHTML with its value (myAddress pointed to the <p id=”address”></p> element in the page).

Let’s examine the detailed results

We add a console.dir(results) in the code, to see a structured view of the results in dev. tools console.

Once we get the results, we can get the different parts:

Here is an example of how we can parse such a field. Notice that each field is tested to see if it exists. The results are stored in the variables defined at line 1.

  1. var country, postalCode, state, route, streetNumber, locality, areaLvl1, areaLvl2;
  2. function parseResult(result) {
  3.      for(i in result){
  4.          console.log(“type = “ + result[i].types[0] + ” long_name = “ +
  5.                      result[i].long_name);
  6.          if(result[i].types[0] == ‘postal_code’)
  7.              postalCode = result[i].long_name;
  8.          if(result[i].types[0] == ‘country’)
  9.              country= result[i].long_name;
  10.          if(result[i].types[0] == ‘street_number’)
  11.              streetNumber= result[i].long_name;
  12.          if(result[i].types[0] == ‘route’)
  13.              route= result[i].long_name;
  14.          if(result[i].types[0] == ‘locality’)
  15.              locality= result[i].long_name;
  16.          if(result[i].types[0] == ‘state’)
  17.              state= result[i].long_name;
  18.          if(result[i].types[0] ==‘administrative_area_level_2’)
  19.              arealLvl2= result[i].long_name;
  20.          if(result[i].types[0] ==‘administrative_area_level_1’)
  21.              areaLvl1= result[i].long_name;
  22.      }
  23.      // added this for debugging in the console
  24.     console.log(“postalCode = “ + postalCode);
  25.     console.log(“country = “ + country);
  26.     console.log(“streetNumber = “ + streetNumber);
  27.     console.log(“route = “ + route);
  28.     console.log(“locality = “ + locality);  
  29.     console.log(“Administrative area level 1 “ + areaLvl2);
  30.     console.log(“Administrative area level 2 “ + areaLvl1);
  31. }

 

A FORM THAT AUTO FILLS THE ADDRESS INPUT FIELDS

Example at JS Bin

It’s very hard to create a single code that will work in all situations and in all countries, since postal addresses are formatted differently depending on the country. A decoder that works well 99% of the time in the UK may be wrong for Australia, for instance. So, it’s just a “guess system”, and in real life, if you create a Web site and would like to help the user with completing a form, just fill in the country, city, postal code, and suggest the rest, propose a small icon for deleting the street input field content, etc. You could also add a drop down menu that offers not only the first guess but the second and third, etc.

Source code extract:

  1. function showOnGoogleMap(latlng) {
  2.    …
  3.    // Display address as text in the page
  4.    myAddress.innerHTML=“Adress: “ + results[0].formatted_address;
  5.    // Call the function that parses the results and fills
  6.    // the input fields
  7.    parseResult(results[0].address_components);
  8.    …
  9. }
  10. var country, postalCode, state, route, streetNumber, locality, areaLvl1, areaLvl2;
  11. function parseResult(result) {
  12.     for(i in result){
  13.        // Let’s print all the data we can collect from the reverse geocoder,
  14.        // Look at the debug console to see what we get…
  15.        console.log(“type = “ + result[i].types[0] + ” long_name = “ +
  16.                                result[i].long_name);
  17.  
  18.        if(result[i].types[0] == ‘postal_code’)
  19.           postalCode = result[i].long_name;
  20.        …
  21.        // fill input fields now, check if variables are undefined
  22.        if((route != undefined) && (streetNumber !=undefined)) {
  23.           console.log(“let’s fill the street”);
  24.           document.querySelector(“#address1”).value = streetNumber + ” “ + route;
  25.        }
  26.        if(locality != undefined) {
  27.           console.log(“let’s fill the city”);
  28.           document.querySelector(“#address2”).value = locality;
  29.        }
  30.        if(country != undefined) {
  31.           console.log(“let’s fill the country”);
  32.           document.querySelector(“#country”).value = country;
  33.        }
  34.        …
  35.     }
  36. }
  37. </script>

This example is rather long and we have only shown an extract of the source code. Take your time and look at the online example.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s