How to use the Geolocation API

Geolocation is a new standard that allow us to identify where a user is located by the use of scripts within the browser.

Geolocation-example

This is particularly useful when we want to offer in our web app local information to the users. Some examples of it could be a web app that tells you where is the nearest bus station, a restaurant or just to know where you are when you get lost in the city. Something that by the way, happens to me a lot.

The first thing you need to know is that the Geolocation API just defines a high-level interface to access the geolocation information, but it is completely agnostic on the system used to obtain that geolocation information.

 

 

There are several ways to get the information like:

  • GPS
  • GSM/CDMA cell IDs
  • IP address

As you can already imagine the accuracy of the results will depend a lot on how the geolocation information is retrieved.

Now that we have a little bit of background, let’s see more in detail what the Geolocation API offer us. The API defines a new interface that is called, not surprisingly, Geolocation. This interface defines three methods:

//Used to retrieve the current geolocation, just one time.
void getCurrentPosition(
     //Callback to receive geolocation info
     in PositionCallback successCallback,
     //Callback to receive errors produced during the call
     in optional PositionErrorCallback errorCallback,
     //Options about the geolocation information to retrieve
     in optional PositionOptions options);

//Used to track the geolocation of the user.
long watchPosition(
     //Callback to receive geolocation info
     in PositionCallback successCallback,
     //Callback to receive errors produced during the call
     in optional PositionErrorCallback errorCallback,
     //Options about the geolocation information to retrieve
     in optional PositionOptions options);

//Used to stop tracking the geolocation of the user.
void clearWatch(
     //id of the watch retrieved with watchPosition
     in long watchId);

At this point you will have already noticed that the method getCurrentPosition does not return any value, this is because the API is asynchronous, so in order to obtain the results we need to implement a callback function (PositionCallback) that will be called once the method has the results.

The other two parameters are optional, they let us to define another callback function to receive any error produced while calling the method and the different options to configure the geolocation information that will be retrieved.

Before we proceed to implement a real example let’s examine the rest of classes used in the API:

// used to receive successful notifications about position requests
interface PositionCallback {
    void handleEvent(in Position position);
}

// used to receive error notifications about position requests
interface PositionErrorCallback {
    void handleEvent(in PositionError error);
} 

// used to specify the options about the geolocation information to retrieve
interface PositionOptions {
    // by default false. Indicates you want to obtain the information with
    // the best accuracy available, even if that consumes more battery or
    // means slower response time.
    attribute boolean enableHighAccuracy;
    
    // expressed in milliseconds
    long timeout;

    // expressed in milliseconds. Indicates you accept a cached value
    // no greater than the specified time. If 0, acquires a new position
    long maximumAge
} 

// used to obtain geolocation position information
interface Position {
    readonly Coordinates coords;
    readonly DOMTimeStamp timestamp;
} 

// used to obtain errors while requesting geolocation information
interface PositionError {
    const unsigned short PERMISSION_DENIED = 1;
    const unsigned short POSITION_UNAVAILABLE = 2;
    const unsigned short TIMEOUT = 3;
    readonly attribute unsigned short code;
    readonly attribute DOMString message;
}

// used to obtain the geolocation position details
interface Coordinates {
    //specified in decimal degrees
    readonly attribute double latitude;
    //specified in decimal degrees
    readonly attribute double longitude;
    // specified in meters
    readonly attribute double? altitude;
    // specified in meters and corresponding to 95% confidence level
    readonly attribute double accuracy;
    // specified in meters and corresponding to 95% confidence level
    readonly attribute double? altitudeAccuracy;
    // specified in degrees, denotes the direction of travel counting
    // clockwise relative to the true north (0º to 360º)
    readonly attribute double? heading;
    // specified in meters per second
    readonly attribute double? speed;
}

Now that we have all info we can start creating a real example, to test them you will need any of the modern browsers that supports this feature like Internet Explorer 9.

<!DOCTYPE html>
<html>
    <head>
        <title>Geolocation example</title>
        <script 
            type="text/javascript" 
            src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0">
        </script>
        <script type="text/javascript">
            var map = null;

            function successCallback(position) {
                // we create the location for the Bing Map
                var userLocation = new Microsoft.Maps.Location(
                    position.coords.latitude,
                    position.coords.longitude);

                // we add the pushpin to the map
                var pin = new Microsoft.Maps.Pushpin(userLocation);
                map.entities.push(pin);

                // refresh the map centering the view on current location
                map.setView({ center: userLocation });

                showMessage("Your location is: " + userLocation.toString());
            }

            function errorCallback(error) {
                var code = error.code;
                var message = "unknown error";
                switch (code) {
                    case 1:
                        message = "permission to geolocate you has been denied";
                        break;
                    case 2:
                        message = "position is not available";
                        break;
                    case 3:
                        message = "geolocation request timed out";
                        break;
                }
                showMessage(message);
            }

            function showMessage(message) {
                var div = document.getElementById("message");
                div.innerHTML = message;
            }

            function getMap() {
                // replace with your own Bing credentials
                var mapOptions = {
                    credentials: "YOUR BING CREDENTIALS",
                    center: new Microsoft.Maps.Location(40.42, -3.8),
                    mapTypeId: Microsoft.Maps.MapTypeId.road,
                    zoom: 16
                }

                // we create the Bing map with a default position
                map = new Microsoft.Maps.Map(document.getElementById("map"), mapOptions);

                // if the browser supports Geolocation we do the request
                if (navigator.geolocation) {
                    var options = {
                        enableHighAccuracy: true,
                        timeout: 2000,
                        maximumAge: 0
                    };

                    navigator.geolocation.getCurrentPosition(
                        successCallback,
                        errorCallback,
                        options);
                }
                else {
                    showError("Your browser does not support geolocation");
                }
            }
        </script>
    </head>
    <body onload="getMap();">
        <div id="map" style="position:relative; width:400px; height:400px;">
        </div>
        <div id="message"></div>
    </body>
</html>

In the above example we have seen:

  • how to request the position of the visitor who is accessing our web page
  • how to load a Bing map using the Bing Maps API and set a pushpin in the map indicating our current location
  • how to handle the errors in the case the geolocation information could not be retrieved.

Internet Explorer and Web Standards

Many times I see people complaining about Internet Explorer 9 not rendering properly a “standard” web page, after digging into what the problem can be it normally resumes into two options:

  • The web page is not using the document mode “IE9 standards”.
  • The web page is using conditional comments making use of browser detection instead of feature detection and treats IE9 as IE7 or IE6, very old versions of IE that do not support today standards.

Let’s start with what the IE9 standards mode is.

Internet Explorer is the only browser that offers backward compatibility with older versions of the browser. This is done incorporating the new, plus the older versions of the rendering engine with each release of Internet Explorer.

As a user of IE you only need to press F12 to open the Developer Tools and select what document mode use.

InternetExplorer_document_mode_ie9_standards

This is very powerful because as developers we can decide what version of the IE rendering engine will be used to render the markup of our pages. In the case of Internet Explorer 9, as you have seen in the figure above, we can chose between the next document modes:

  • IE 9 standards: This is the default and latest standards-compliant behavior used to render webs that have a strict or unknown document type.
  • IE 8 standards: This behavior acts as it does IE8.
  • IE 7 standards: This behavior acts as it does IE7.
  • Quirks: This is the oldest behavior that can be used with IE, and applies when rendering a document with no doctype or a quirks doctype. It is similar to the behavior of IE5.

Selecting a different mode will reload the page to render it in the document mode selected, but will not change the user-agent string sent to the website. To do that you can also change the Browser Mode using the developer tools.

Regardless the best practice and my suggestion is to target always the standards and keep our sites upgraded to support them, in the case you have an old site you can’t migrate yet, you don’t need to continue using old versions of IE. You can upgrade to IE9 and use as quick fix the X-UA-Compatible meta tag to set what render engine IE has to use to display properly the page.

It is obvious but worthy to mention that if you use an older document mode as “Quirks mode”, you will use it with its full consequences. This means means that your modern IE9 browser will behave as the old IE5 browser and will not be able to use all the new standards and performance improvements that IE9 includes. You can easily see this by running this code and visualizing it in “Internet Explorer 9 standards” and any other document mode:

   1: <html>
   2:   <head>
   3:     <title>HTML5 Canvas example</title>
   4:     <script>
   5:       function drawCanvas(){
   6:  
   7:         var canvas = document.getElementById('myCanvas');
   8:  
   9:         var context = canvas.getContext('2d');
  10:  
  11:         context.fillRect (128, 25, 100, 100);
  12:       }
  13:     </script>
  14:     <style type="text/css">
  15:       canvas { border: 2px solid black; }
  16:     </style>
  17:   </head>
  18:   <body onload="drawCanvas();">
  19:  
  20:     <canvas id="myCanvas" width="260" height="200">
  21:     The document mode does not support canvas
  22:     </canvas>
  23:  
  24:   </body>
  25: </html>

 

So, if you find your website not rendering properly in IE9, first of all check that the site is being rendered in IE9 standards mode and secondly that you are not using any conditional comments that serve custom code for older versions of IE.

In this article we will not cover best practices on how to use feature detection instead of browser detection bad practices to avoid conditional comments, but I recommend reading the article Same Markup: Writing Cross-Browser Code.

You can read additional information on how internet explorer determines the document mode.

Use Skydrive from Windows Explorer

For those who do not know SkyDrive yet, it is a free online storage that offers 25 GB and has been around since beginning of 2008, it's interface has been completely rebuilt this week to make use of HTML5.

SkyDrive provides other additional features like:

- The possibility to create, view and edit Microsoft Word, Excel, PowerPoint and OneNote files without having Microsoft Office installed on your computer.

- A versioning management system that allows you to rollback to earlier versions of your documents.

- Create photo slide shows, so you can view your photos online without having to download to another PC.

- Share documents online with different levels of permissions.

In addition, if you have a Windows Phone 7 you might benefit also of SkyDrive. Since you can upload automatically from your Windows Phone 7 the pictures taken and access/upload your Office documents.

After the brief introduction to SkyDrive, I would like to explain how to use SkyDrive from Windows Explorer instead of having to use the web interface. To do it we will map a network folder in Windows Explorer to SkyDrive.

- First of all you need to create or access your SkyDrive account on http://www.skydrive.com

- Click on any of the folders available under the section Documents. This will allow you to see your unique id in the URL, which now should have the format of https://cid-xxxxxxxxxxxxxxxx.office.live.com or https://cid-xxxxxxxxxxxxxxxx.photos.live.com

- The xxxxxxxxxxxxxxxx above contains your unique id, let’s say that is, just copy the id and open Windows Explorer.

- Select the option “Map network drive” and in the textbox belonging to “Folder” type \\docs.live.net@SSL\xxxxxxxxxxxxxxxx\^2Documents replacing the fake id by your unique id and “Documents” by the name of the SkyDrive folder you want to map.

Yu will be prompted to introduce your Live Id credentials and after this you will have access to SkyDrive from Windows Explorer as with any other folder.

A day with Paul Cotton, co-chair at W3C HTML Work Group

This past Wednesday I had the pleasure to spend my day with Paul Cotton.

Paul Cotton is the Group Manager of Microsoft’s Interoperability team that covers HTML and Cloud technologies. In addition he is currently co-chair of the W3C HTML Working Group that is standardizing HTML5, Microdata, Canvas 2D Context …

During the day we were talking about many different things, but as you can imagine our main conversation subject was HTML5. It was very interesting to see the professionalism of Paul handling the two hats he needs to wear constantly, one to represent Microsoft interests and the other one to represent W3C interests, this means the interests of the entire web community and this is a huge responsibility. The first thing that called my attention on this regards was that Paul was not talking about browsers, but about user-agents in a way to abstract his conversations from specific browsers.

One of the most interesting things to reflect on was how the HTML specification and the industry could evolve from the point we are today. Far from talking about new features or new technologies to be included in the specification, Paul was talking about how the new members of the group could influence this evolution. Until today most of the members were coming from companies with a long trajectory in the web like Microsoft, Mozilla or Adobe, but now there are other members coming from very disparate industries like TV manufacturers like Sony, LG or from the entertainment world as Disney.

This proves how the web of the future is attracting a full new universe of possibilities that might change the panorama as we know it today, simple things like a browser update that is very common in the computer world, might not be desirable anymore when you need update the firmware of your TV to have its embedded browser updated.

Time will tell, but as Paul says also the technologies suffer the Darwinian evolution and I completely agree, it doesn’t matter how much you try to get stuck in one of them they will evolve or disappear, so be prepared for the change.