Modules in Bing Maps for Windows Store Apps (JavaScript)

The Bing Maps V7 AJAX control is designed as a modular framework and the Bing Maps for Windows Store App JavaScript control follows the same design. Modules allow users to load only the features and functionalities they need, rather than loading everything up when the application starts. You can save yourself a lot of development time by using modules and avoid reinventing the wheel. Out of the box, Bing Maps provides the following modules:

Name

Description

Microsoft.Maps.AdvanceShapes

Adds support for complex polygons. i.e. polygons with holes.

Microsoft.Maps.Directions

Allows you to calculate a route and display it on the map. The route is draggable by default for easy customization. The instructions will also be nicely formatted.

Microsoft.Maps.Search

Provides an easy method for geocoding address and searching for points of interest from JavaScript.

Microsoft.Maps.Themes.BingTheme

Modifies the navigation bar, pushpin and infobox look and feel to match the Bing Maps consumer site.

Microsoft.Maps.Traffic

Adds a traffic flow tile layer to the map.

Microsoft.Maps.VenueMaps

Exposes the Venue Map functionality and can be used to find nearby venue maps and load them. Venue Maps are interactive buildings on the map that often show the layout of a building. For instance, you can load a venue map of a mall and see were all the stores are located.

In addition to the modules available through the Bing Maps control, there are a large number of community created modules also available on the Bing Maps V7 Modules CodePlex project. However, not all community created modules are designed to work with Windows Store applications; you may need to make some modifications to get them to work with your code. You can also create custom modules, which is a really great way to promote code reuse. For the purpose of this post, we will build on top of the code we created in the Getting started with Bing Maps Windows Store Apps blog post.

Implementing Modules

There are three steps:

  1. Add a reference to the veapimodules.js file from the Bing Maps SDK
  2. Register the module if it isn’t already registered
  3. Load the module and run any post load logic

To add a reference to the veapimodules.js file in the Bing Maps SDK, open the default.html file and update the Bing Maps references to the following:

<!-- Bing Maps references -->

<script type="text/javascript"

        src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

<script type="text/javascript"

        src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>

Now, before you can load a module, it must first be registered. All modules built into Bing Maps are already registered, however, if you are using a custom module you will need to register it. If you have used custom modules before, be warned, registering the web version of the Bing Maps V7 AJAX control and registering modules in the Windows Store App version of the Bing Maps JavaScript control are done differently. Registering custom modules is pretty straightforward; simply add a line of code to register the name and load in the JavaScript file containing your module code. You can do this by adding code, similar to the example below, into the head of the default.html page.

<!-- Register and load the code to our Custom Module -->

<script>Microsoft.Maps.registerModule('MyModule');</script>

<script type="text/javascript" src="/js/myModule.js"></script>

One benefit of this approach is that the JavaScript file for our module will be cached as byte code by the Windows 8 framework, which makes for fast loading. However, it doesn’t have the same benefit of being able to load the code for the module on demand which we were are able to do with the built in modules. This is useful when you want the fastest possible startup for your application. With a bit of code we can use JavaScript to dynamically load our custom modules. Here is a simple function we can use to accomplish this:

function RegisterModule(name, url) {

  //Register the module

    Microsoft.Maps.registerModule(name);

 

   //Load the JavaScript File

   var script = document.createElement("script");

    script.setAttribute("type", "text/javascript");

    script.setAttribute("src", url);

    document.body.appendChild(script);

}

Now that the module is registered, we can load it. When to load a module really depends on the type of module you are using. For instance, the Bing Theme module needs to be loaded before the map is loaded, however the directions module doesn’t need to be loaded until the user wants to get directions. Here is the basic way of loading a module:

Microsoft.Maps.loadModule(“MyModule”);

With some modules you may want to run code after the module has loaded. In this case, you can pass in a callback function as an option when loading the module. Doing the following will trigger a function called myModuleLoaded when the module has completed loading.

Microsoft.Maps.loadModule("MyModule", { callback: myModuleLoaded });

Loading the Traffic Module

Now that we understand how to use the module framework in the Bing Maps control, lets implement the traffic module in our application. To start, we will add a checkbox on the map for toggling the traffic layer on and off. First, open the default.html file and the checkbox to the same floating div that has our GPS checkbox. This time we are going to give the checkbox an id property.

<!DOCTYPE html>

<html>

<head>

   <meta charset="utf-8" />

   <title>BingMapsJSIntro</title>

 

   <!-- WinJS references -->

   <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />

   <script src="//Microsoft.WinJS.1.0/js/base.js"></script>

   <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

 

   <!-- BingMapsJSIntro references -->

   <link href="/css/default.css" rel="stylesheet" />

   <script src="/js/default.js"></script>

 

   <!-- Bing Maps references -->

   <script type="text/javascript"

   src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

   <script type="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>

 

   <!-- Our Bing Maps JavaScript Code -->

   <script src="/js/bingMapsIntro.js"></script>

</head>

<body>

   <div id="myMap"></div>

    

   <div style="position:absolute;right:10px;top:10px;background-color:#808080;padding:5px;">

        <input type="checkbox" onclick="ToggleGPS(this);"/> GPS

        <input type="checkbox" onclick="ToggleTraffic();" id="TrafficChbx"/> Traffic

   </div>

</body>

</html>

Since the traffic module is a built in module in the Bing Maps SDK we do not need to worry about registering it. We also don’t need to load the traffic module until the user presses the Traffic checkbox. To add the logic for traffic checkbox open the bingMapsIntro.js file and add a global variable called trafficLayer. Next, add a function called ToggleTraffic. In this function we will check to see the trafficLayer variable is implemented. If it is, then we can get the checked state from the traffic checkbox and show or hide the traffic layer accordingly. If the trafficLayer variable is not implemented we will need to load the traffic module and create an instance of the Microsoft.Maps.Traffic.TrafficLayer class after the module has loaded. By default, the traffic tile layer has no opacity to it and it ends up covering up the names of roads. To make for a better user experience we will get the base tile layer of the traffic layer and set it’s opacity to 0.5. Finally, after we created an instance of the TrafficLayer class we will want to rerun our logic for toggling the traffic layer. To do all this, add the following code into the bingMapsIntro.js file.

var map, geoLocationProvider, gpsLayer, trafficLayer;

 

function ToggleTraffic() {

   //Check to see if the traffic layer exists

   if (trafficLayer) {

        //Get a reference to the traffic checkbox

        var chbx = document.getElementById('TrafficChbx');

 

        //Hide or Show the tile layer based on checked state

        if (chbx.checked) {

     trafficLayer.show();

        } else {

            trafficLayer.hide();

        }

    } else {

        //Load the traffic module and create the traffic layer.

        Microsoft.Maps.loadModule('Microsoft.Maps.Traffic', {

            callback: function () {

                //Create the traffic layer

                trafficLayer = new Microsoft.Maps.Traffic.TrafficLayer(map);

 

                //Get the base tile layer and set the opacity

                var layer = trafficLayer.getTileLayer();

  layer.setOptions({ opacity : 0.5 });

 

                //Toggle the traffic layer to the current state of the checkbox.

                ToggleTraffic();

            }});

    }

}

If you run the application now and press the traffic button you may not notice anything if you are zoomed out. To make things easy, I’m going to toggle on both the GPS and the Traffic functionalities. Doing this I end up with the following map:

temp2

For more information on where traffic data is available see the Bing Maps Traffic Coverage section of the MSDN documentation.

Loading a Custom Module

We have seen how to load one of the built in modules to our application, now we will look at how to implement a custom module. To do this we will make use of one of the community created modules called Point Based Clustering. This module will group pushpins together when zoomed out to make the map less crowded. This particular module uses a point based algorithm rather than a traditional grid based one. The point based algorithm gives use a much nicer user experience than the grid based algorithm, but there is a trade off in performance. With that said, this algorithm can easily handle 2,000+ pushpins.

Since this module is not really related to what we have put together in our Bing Maps Intro project we will start fresh with a new project. In Visual Studios create a new project and use the JavaScript -> Store -> Blank App template. Call the project PointBasedClustering_WinRT. Once the application is loaded, right click on the js folder and add a new JavaScript file called bingMapsClustering.js. Next, right click on the References folder and add a reference to the Bing Maps SDK. Now, go to the Point Based Clustering page and download the code. Unzip the file and copy the scripts/minified/PointBasedClustering.min.js and the scripts/TestDataGenerator.js files into the js folder of the project. After you do this your project should look like this:

clip_image003

Now we can get started on implementing this custom module. To start, we will open up the default.html file and add a textbox and a button to a floating div in the top, right hand corner of our map where the user can enter the number of pushpins to add to the map. When the button is clicked it will generate the mock pushpin data and display it on the map and clustering it automatically. We will also need to add a reference to the TestDataGenerator.js file for this example. In a production application you would not need this as you would use real data with the Point Based Clustering module. Adding this to the default.html file we end up with the following HTML:

<!DOCTYPE html>

<html>

<head>

   <meta charset="utf-8" />

   <title>BingMapsJSIntro</title>

 

   <!-- WinJS references -->

   <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />

   <script src="//Microsoft.WinJS.1.0/js/base.js"></script>

   <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>

 

   <!-- BingMapsJSIntro references -->

   <link href="/css/default.css" rel="stylesheet" />

   <script src="/js/default.js"></script>

 

   <!-- Bing Maps references -->

   <script type="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapicore.js"></script>

   <script type="text/javascript"

            src="ms-appx:///Bing.Maps.JavaScript//js/veapimodules.js"></script>

 

   <!-- Our Bing Maps JavaScript Code -->

   <script src="/js/bingMapsClustering.js"></script>z

 

   <!-- Add a reference to class for generating test data. Not needed in production apps. -->

   <script type="text/javascript" src="/js/TestDataGenerator.js"></script>

</head>

<body>

   <div id="myMap"></div>

    

   <div style="position:absolute;right:10px;top:10px;background-color:#808080;padding:5px;">

        Data Size: <input type="text" id="dataSize" style="width:30px;"/>

        <input type="button" value="Get Mock Data" onclick="RequestData();" />

   </div>

</body>

</html>

Now, open the bingMapsClustering.js file, add the following code to load the map, and register and load the Point Based Clustering Module. We will register our module right after loading the map in the GetMap function.

var map, clusterLayer;

 

function GetMap() {

   var mapOptions =

    {

        credentials: "YOUR_BING_MAPS_KEY",

        zoom: 2

    };

 

    map = new Microsoft.Maps.Map(document.getElementById("myMap"), mapOptions);

 

   //Register and load the Point Based Clustering Module

    RegisterModule("PointBasedClusteringModule", "/js/PointBasedClustering.min.js");

 

    Microsoft.Maps.loadModule("PointBasedClusteringModule", {

        callback: function () {

            clusterLayer = new PointBasedClusteredEntityCollection(map);

        }

    });

}

 

//Initialization logic for loading the map control

(function () {

   function initialize() {

        Microsoft.Maps.loadModule('Microsoft.Maps.Map', { callback: GetMap });

    }

 

    document.addEventListener("DOMContentLoaded", initialize, false);

})();

 

We also need to add the RegisterModule functions so that we can dynamically load our custom module. This can easily be done by adding the following after the GetMap function.

function RegisterModule(name, url) {

   //Register the module

    Microsoft.Maps.registerModule(name);

 

   //Load the JavaScript File

   var script = document.createElement("script");

    script.setAttribute("type", "text/javascript");

    script.setAttribute("src", url);

    document.body.appendChild(script);

}

The last item here is to add the logic for handling the button click event by creating a function called RequestData. In this function we will need to get the users input value and pass it to the test data generator to generate our mock data. To simulate an asynchronous call to get our data, which we would likely do for a production application, our test generator takes in a callback function which it will call after it generates our mock data. We will name this callback function RequestDataCallback and have it populate our cluster layer with the mock data. The following can be added after the RegisterModule function in the bingMapsClustering.js file.

//Makes a request for data

function RequestData() {

   var size = parseInt(document.getElementById('dataSize').value);

    TestDataGenerator.GenerateData(size, RequestDataCallback);

}

 

//Handle the data response

function RequestDataCallback(response) {

   if (response != null) {

        clusterLayer.SetData(response);

    }

}

Let’s run the application. In the textbox, enter the number of pushpins you would like to generate on the map and then press the button. The following is a screenshot with 1,000 pushpins being clustered and rendered on the map. As you zoom in, you will notice that the clusters begin to break apart into their individual pushpins.

temp1

- Ricky Brundritt, EMEA Bing Maps Technology Solution Professional