Developing JavaScript* Metro Style Apps That Use the Geolocation API and the Bing* Maps SDK

Download Article

Developing JavaScript* Metro Style Apps That Use the Geolocation API and the Bing* Maps SDK [PDF 761 KB]

Objective

This article provides an introduction on how to use the Geolocation API to detect the current location of the user’s Windows 8*-based device and how to use the Bing* Maps SDK to incorporate Bing Map controls into Metro Style apps.

 

1 Introduction

Most modern PCs/mobile/handheld devices are geolocation-enabled. The Windows.Device.Geolocation API provides the best geolocation data from all available sources, including GPS and the Windows Location Provider, which uses Wi-Fi* Triangulation or Wi-Fi IP addresses to determine the device’s location. We can develop a wide range of location-based Metro Style apps, such as searching for points-of-interest (POIs) around a location, outdoor activities, fitness, and games.

 

2 Detecting the Current Position in Metro Style Apps

In this section, we will discuss how to detect geolocation data in a Metro Style JavaScript* app. Before you try practicing the coding examples in this paper, you must have Windows 8 Release Preview installed on your development PC. Windows 8 Release Preview can be downloaded from: http://windows.microsoft.com/en-US/windows-8/download

2.1 Creating a Geolocation-Based App Project

Microsoft Visual Studio* 2012 RC (Release Candidate) is the IDE used to develop Metro Style apps. You can download and install Visual Studio 2012 from the link: http://www.microsoft.com/visualstudio/11/en-us

2.1.1 Enabling Location on the Development PC and the Deployment PC

To use geolocation data in the app, your device’s location setting must be turned on. To do this on a device running Windows 8, go to “Settings,” press “Change PC Settings,” select “Privacy,” and set “Let apps use my location” to “On.”

2.1.2 Creating a new JavaScript Project

Open Microsoft Visual Studio 2012 RC, in the “New Project” dialog box, select “JavaScript” on the left pane and “Blank App” on the right pane (Figure 1). Specify a project name and directory (in this example, we use “GeolocationTest” as the project name), and click “OK.”


Figure 1: "New Project" dialog

2.2 Declaring the Location Capacity for the App

On the “Solution Explorer” tab, double click “package.appxmanifest,” then select the “Capacities” tab, and check the “Location” item (Figure 2). Press Ctrl-S to save the file.


Figure 2: Location capacity

2.3 Adding the HTML and JavaScript Code

In Solution Explorer, under the “GeolocationTest” project, locate and double click to open the file “default.html,” replace the file content with the following code:

 

<!DOCTYPE html>
<html>
<head>
<title>Test Geolocation</title>
<!-- WinJS references --> 
<link href="//Microsoft.WinJS.1.0.RC/css/ui-light.css" rel="stylesheet" />
<script src="//Microsoft.WinJS.1.0.RC/js/base.js"></script>
<script src="//Microsoft.WinJS.1.0.RC/js/ui.js"></script>
<script src="/js/default.js"></script>
</head>
<body>
<p>
Click "Get Current Location" to get the current geolocation data.<br />
<button id="getCurLoc">Get Current Location</button>
<br />
<br />
Lat: <span id="lat"></span><br />
Long: <span id="long"></span><br />
Data Accuracy (meters): <span id="dataAccuracy"></span><br /><br />
Data Status:<span id="dataStatus"></span><br />
Error: <span id="errMsg"></span><br />
</p>
</body>
</html>


Code Example 1 (**)

 

Under the “js” folder, locate and double click to open the file “default.js”, replace the content with the following code:

 

// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
    "use strict";

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    WinJS.strictProcessing();

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();

    var geolocator = null;

    function getcurloc() {
        if (geolocator == null) {
            geolocator = new Windows.Devices.Geolocation.Geolocator();
        }
        if (geolocator != null) {
            geolocator.getGeopositionAsync().then(getCurPosHandler, errHandler);
        }
    }

    function getCurPosHandler(pos) {
        document.getElementById('lat').innerHTML = pos.coordinate.latitude;
        document.getElementById('long').innerHTML = pos.coordinate.longitude;
        document.getElementById('dataAccuracy').innerHTML = pos.coordinate.accuracy;
        document.getElementById('dataStatus').innerHTML =
                getStatusStr(geolocator.locationStatus);
    }

    function errHandler(e) {
        document.getElementById('errMsg').innerHTML = e.message;
    }

    function getStatusStr(status) {
        switch (status) {
            case Windows.Devices.Geolocation.PositionStatus.ready:
                return "Ready";
                break;
            case Windows.Devices.Geolocation.PositionStatus.initializing:
                return "Initializing";
                break;
            case Windows.Devices.Geolocation.PositionStatus.noData:
                return "noData";
                break;
            case Windows.Devices.Geolocation.PositionStatus.disabled:
                return "disabled";
                break;
            case Windows.Devices.Geolocation.PositionStatus.notInitialized:
                return "notInitialized";
                break;
            case Windows.Devices.Geolocation.PositionStatus.notAvailable:
                return "notAvailable";
                break;
            default:
                break;
        }
    }

    function init() {
        document.getElementById('getCurLoc').addEventListener("click", function (ev) { getcurloc(); });
    }

    document.addEventListener("DOMContentLoaded", init, false);
})();


Code Example 2 (**)

 

Save the two files and build the solution.

2.4 Running the App on the Simulator

On the tool bar, click the dropdown icon on the right of the “Start Debugging” (the green triangle icon), and select “Simulator” (Figure 3).


Figure 3: Run the simulator

Now press F5, you will see the simulator is launched and the app started (Figure 4).


Figure 4: "Get Current Location" UI

If your development PC is connected to a Wi-Fi access point, after you click the “Get Current Location” button, you will see the geographic coordinates (latitude and longitude) displayed in the corresponding fields.

2.5 Section Summary

In this simple app, the getcurloc() function instantiates a Geolocator object when this function is called for the first time. Then it calls getGeoPositionAsyn() and provides two handlers: getCurPosHandler() handles a successful return and errHandler() for a failed return.

 

3 Tracking Positions in Metro Style Apps

In some use cases that look up nearby POIs, getting the user’s current location is good enough. In other use cases, for example an application to record users’ hiking routes and distances, we need to track the user’s path of travel and respond to the location updates.

To track user locations, you can add two event listeners for the Geolocator object: one for the positionchanged events, the other for the statuschanged events.

You may use the following source code to replace the default.html and default.js in the previous example, then build and run the app:

default.html:

 

 

Click "Track Location" to receive location updates.
 Track Location 
 Click "Stop Tracking" to stop receiving location updates.
 Stop Tracking 

 Lat: 
 Long: 
 Data Accuracy (meters): 
 Data Status:
 Error: 


Code Example 3 (**)

 

default.js:

 

// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
    "use strict";

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    WinJS.strictProcessing();

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();

    var geolocator = null;

    function getStatusStr(status) {
        switch (status) {
            case Windows.Devices.Geolocation.PositionStatus.ready:
                return "Ready";
                break;
            case Windows.Devices.Geolocation.PositionStatus.initializing:
                return "Initializing";
                break;
            case Windows.Devices.Geolocation.PositionStatus.noData:
                return "noData";
                break;
            case Windows.Devices.Geolocation.PositionStatus.disabled:
                return "disabled";
                break;
            case Windows.Devices.Geolocation.PositionStatus.notInitialized:
                return "notInitialized";
                break;
            case Windows.Devices.Geolocation.PositionStatus.notAvailable:
                return "notAvailable";
                break;
            default:
                break;
        }
    }


    function starttracking() {
        if (geolocator == null) {
            geolocator = new Windows.Devices.Geolocation.Geolocator();
        }
        if (geolocator != null) {
            geolocator.addEventListener("positionchanged", onPositionChanged);
            geolocator.addEventListener("statuschanged", onStatusChanged);
        }
        document.getElementById('trackLocation').disabled = true;
        document.getElementById('stopTracking').disabled = false;

    }

    function stoptracking() {
        if (geolocator != null) {
            geolocator.removeEventListener("positionchanged", onPositionChanged);
        }
        document.getElementById('trackLocation').disabled = false;
        document.getElementById('stopTracking').disabled = true;
        document.getElementById('lat').innerHTML = "waiting for update...";
        document.getElementById('long').innerHTML = "waiting for update...";
        document.getElementById('dataAccuracy').innerHTML = "waiting for update...";
        document.getElementById('dataStatus').innerHTML =
                "waiting for update...";


    }

    function onPositionChanged(args) {
        var position = args.position;
        //use the position ifnormation (lat/lon/accuracy) to do some work
        document.getElementById('lat').innerHTML = position.coordinate.latitude;
        document.getElementById('long').innerHTML = position.coordinate.longitude;
        document.getElementById('dataAccuracy').innerHTML = position.coordinate.accuracy;
        document.getElementById('dataStatus').innerHTML =
                getStatusStr(geolocator.locationStatus);

    }

    // Handle change in status to display an appropriate message.        
    function onStatusChanged(args) {
        var status = args.status;
        //handle the new status
    }

    function init() {
        document.getElementById('lat').innerHTML = "waiting for update...";
        document.getElementById('long').innerHTML = "waiting for update...";
        document.getElementById('dataAccuracy').innerHTML = "waiting for update...";
        document.getElementById('dataStatus').innerHTML =
                "waiting for update...";
        document.getElementById('trackLocation').addEventListener("click", function (ev) { starttracking(); });
        document.getElementById('stopTracking').addEventListener("click", function (ev) { stoptracking(); });
        document.getElementById('trackLocation').disabled = false;
        document.getElementById('stopTracking').disabled = true;
    }

    document.addEventListener("DOMContentLoaded", init, false);
})();


Code Example 4 (**)

 

4 Adding Bing Maps to Metro Style Apps

Mapping and geographic positioning are always closely associated with each other. Using the Bing Maps SDK and the Geolocation API together provides a platform for developing a wide range of Metro Style apps. In this section, we walk through an example of how to write a Metro Style app to display the user’s current location on Bing Maps.

4.1 Installing the Bing Maps SDK for Metro Style Apps

You can download and install the Bing Maps SDK for Metro Style Apps (Release Preview) from the following link: http://visualstudiogallery.msdn.microsoft.com/0c341dfb-4584-4738-949c-daf55b82df58

As an extension to Visual Studio 2012 RC (Release Candidate), the Bing Maps SDK enables developers to incorporate Bing Maps controls in Metro Style apps. The Bing Maps SDK supports JavaScript, as well as Visual Basic, C++, and C#.

This paper will focus on how to use the Bing Maps SDK for JavaScript, which is based on the Bing Maps AJAX Control 7.0.

4.2 Obtaining a Bing Maps Key

To include Bing Maps controls in your app, you need a “Bing Maps key.” To do this, go to Bing Maps Account Center using the link: http://www.bingmapsportal.com/. After you create an account and log in, select the “Create and View Keys” under “My Account.” To create a Bing maps key, you need to provide an application name. In our example, we use “GeolocationTest.” For the application type, we select “Metro style apps (BETA)” from the dropdown box (Figure 5).


Figure 5: The "Create Key" dialog

After the Bing Maps key is created, if you select the “Create or view keys” on the left pane, they new key will display in the listsimilar to, but not exactly the same as Figure 6. You will need to copy the key string you have created in the “Key/URL” column and paste it in your app’s Bing Maps Options “credentials” property.


Figure 6: The Bing Maps key list

4.3 Adding Bing Maps References

Using Visual Studio 2012 RC, add the Bing Maps for the JavaScript extension reference by performing these steps:

  • On the Solution Explorer pane, right click the JavaScript project “GeolocationTest.”
  • From the pop-up menu select “Add Reference…”. A “Reference Manager” dialog will display (Figure 7).
  • Select “Extensions” and check “Bing Maps for JavaScript (RP).”
  • Click “OK.”


Figure 7: The "Reference Manager" dialog

You also need to add a reference to veapicore.js by adding the following in the default.html file:

 



Code Example 5 (**)

 

4.4 Loading the Map Module

You may add the JavaScript code to load the Map module:

 

Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: initMap });
…
function initMap() {
    try {
        var mapOptions =
        {
            credentials: 'Your Bing Map Key',
            center: new Microsoft.Maps.Location(37.38826, -121.962502),
            mapTypeId: Microsoft.Maps.MapTypeId.road,
            zoom: 12
        };
        map = new Microsoft.Maps.Map(document.getElementById("mapdiv"), mapOptions);

    }
    catch (e) {
        var md = new Windows.UI.Popups.MessageDialog(e.message);
        md.showAsync();
    }


Code Example 6

 

You need to replace the string inside 'Your Bing Map Key' with the actual Bing Maps key you created in Section 4.2.

4.5 Displaying the Current Location on the Maps

We modify the example in Section 2. After getting the current location, instead of displaying the latitude, longitude, and accuracy values, we display it as a Pushpin on the Bing Maps.

The complete source code is provided as follows:

default.html:

 

 



Code Example 7 (**)

 

default.js:

 

// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
    var app = WinJS.Application;

    // This function responds to all application activations.
    app.onactivated = function (eventObject) {
        if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
            WinJS.UI.processAll();
        }
    };

    app.start();

    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    WinJS.strictProcessing();

    app.onactivated = function (args) {
        if (args.detail.kind === activation.ActivationKind.launch) {
            if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                // TODO: This application has been newly launched. Initialize
                // your application here.
            } else {
                // TODO: This application has been reactivated from suspension.
                // Restore application state here.
            }
            args.setPromise(WinJS.UI.processAll());
        }
    };

    app.oncheckpoint = function (args) {
        // TODO: This application is about to be suspended. Save any state
        // that needs to persist across suspensions here. You might use the
        // WinJS.Application.sessionState object, which is automatically
        // saved and restored across suspension. If you need to complete an
        // asynchronous operation before your application is suspended, call
        // args.setPromise().
    };

    app.start();

    var geolocator = null;

    function getcurloc() {
        if (geolocator == null) {
            geolocator = new Windows.Devices.Geolocation.Geolocator();
        }
        if (geolocator != null) {
            geolocator.getGeopositionAsync().then(getCurPosHandler, errHandler);
        }
    }

    function getCurPosHandler(pos) {
        map.setView({ center: new Microsoft.Maps.Location(pos.coordinate.latitude, pos.coordinate.longitude), mapTypeId: Microsoft.Maps.MapTypeId.road, zoom: 16.0 });
        var pin = new Microsoft.Maps.Pushpin(pos.coordinate);
        map.entities.push(pin);
    }

    function errHandler(e) {
        //handle errors here
    }

    function init() {
        Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: initMap });
        getcurloc();
    }

    document.addEventListener("DOMContentLoaded", init, false);
})();

var map;
function initMap() {
    try {
        var mapOptions =
        {
            credentials: 'Your Bing Map Key',
            center: new Microsoft.Maps.Location(37.38826, -121.962502),
            mapTypeId: Microsoft.Maps.MapTypeId.road,
            zoom: 12
        };
        map = new Microsoft.Maps.Map(document.getElementById("mapdiv"), mapOptions);

    }
    catch (e) {
        var md = new Windows.UI.Popups.MessageDialog(e.message);
        md.showAsync();
    }
}


Code Example 8 (**)

 

After the app starts, you will see your current location on the map (Figure 8):


Figure 8: Displaying the current location on Bing Maps


5 Power Efficiency

When developing applications using the system’s location services, one thing we should pay attention to is the energy efficiency because using GPS normally consumes more energy than using Wi-Fi-based position detecting approaches.

Here are some guidelines you should follow when developing location-aware applications:

  • Use one-time location requests when updates are not needed

    In many use cases you do not need to track the location all the time, for example, attaching the current location to a document or a photo. In these cases the app should call getGeolocationAsyn() method to get the current location.

  • Minimize the frequency and duration of location update requests

    The app should minimize the frequency and duration of the location update request. This can be done by adjusting the Geolocator properties:

    • MovementThreshold
    • ReportInterval

Your app should also de-register location updates by calling geolocator.removeEventListener().

  • Only request the necessary accuracy level

    If your app needs GPS data, you may set the DesiredAccuracy property to HIGH. Keep in mind that GPS usually consumes more power than other location detecting methods, and you should look for ways to save power.

6 Summary

This paper provides a tutorial on how to develop JavaScript Metro Style apps using the Geolocation API and the Bing Maps SDK. It covers the general tools and plugins used in developing location-aware Metro style applications. It also provides guidelines in developing power efficient location-based applications.

 

About the Author

Miao Wei is a software engineer with Intel Corporation’s Software and Services Group.

*Other names and brands may be claimed as the property of others.

** This sample source code is released under the Intel Sample Source Code License Agreement.

Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.