Book Image

Learning Bing Maps API

By : Artan Sinani
Book Image

Learning Bing Maps API

By: Artan Sinani

Overview of this book

Provided as a part of Microsoft's Bing suite of search engines, Bing Maps is a web mapping service powered by the Bing Maps for Enterprise framework. The need for geospatial data has increased dramatically in the last few years. Adding a mapping context to any location-based data is becoming more and more common, and businesses are embracing it to improve their user experience with new data richness. Comprising of simple, follow-along examples, Learning Bing Maps API will show you how to use the many features of Bing Maps, from dropping a simple map on a web page, to fetching geospatial data from the Microsoft servers. Through the course of this book you will build a solid foundation for creating your own geo-applications.Following the hands-on recipes of this book, you will build a different web app in each chapter as you communicate with different APIs provided by Bing Maps. You will build your own library of JavaScript modules that talk to the Microsoft Maps API.You will create a custom theme for the map, with your own controls. Taking advantage of the global reach of Bing Maps, you will learn how to build a route scheduler for a delivery company in Madrid, Spain, and then you will discover how to create jobs on the Bing Maps servers for geocoding addresses in California, USA. By the end of the book you will have learned everything you need to know to embed a map on a web page, with your own geo-data, or data obtained by the Bing Map Services.
Table of Contents (14 chapters)

Custom modules


We'll add our own controls to the map; they will change the zoom level and the map type. For this, we will take advantage of the module structure of Bing Maps. The modules are just JavaScript functions that are loaded dynamically by Bing Maps AJAX Control. Apart from better code organization, the modules provide on-demand downloads, reducing the initial script load.

On the flip side, this means that the JavaScript files will be loaded in multiple HTTP requests. If you prefer your scripts merged into a single HTTP request, you can use tools that merge and minimize website assets, such as Asset Bundler in ASP.NET, Sprockets in Ruby, gzipit in PHP, and so forth. In this case, make sure that the custom modules are instantiated after the map is loaded (more information about the Bing Maps modules can be found at http://msdn.microsoft.com/en-us/library/hh125836.aspx).

We'll call our module LearningTheme, and place it under a learningTheme folder. Let's write our module within a self-calling, immediately invoked function in the learningTheme.js file:

(function () {
  var lbm = window.lbm = {};
  lbm.LearningTheme = function(map) {
    this._map = map;
  };
  Microsoft.Maps.moduleLoaded('lbm.LearningTheme');
})(this);

We have placed our LearningTheme module under the namespace lbm, just as we did with the CSS styles. This way, we expose only one global variable, lbm.

The module is just a normal JavaScript function with one argument, that is, map. This is a reference to the Bing Maps map we instantiated earlier, which we'll store into a private variable named as _map.

Note

We'll use the convention of starting the variable names with an underscore in this book, to indicate that they should be considered as private variables, and not be called outside our module. There are ways to achieve better access restriction for objects in JavaScript, but they are outside the scope of this book.

After the module body, we add the following line, which turns our function into a Bing Maps module:

Microsoft.Maps.moduleLoaded('lbm.LearningTheme');

We then load the module in our window.onload function by first registering it:

Microsoft.Maps.registerModule('lbm.LearningTheme', 'learningTheme/learningTheme.js');
Microsoft.Maps.loadModule('lbm.LearningTheme', {
  callback: function() {
    var learningTheme = new lbm.LearningTheme(map);
  }
});

The registration function accepts two arguments: the name of the module, and its relative or absolute (or remote) location. We then call Microsoft.Maps.loadModule, which again needs the module name, and an options object. With the latter argument, we can specify what should happen when the module is loaded. In this case, we instantiate it by passing a reference to the map we created earlier.

Let's add the two buttons that will control the zoom level, one with a minus (-) sign that will decrease the zoom level, and one with a plus (+) sign that will increase it. We'll also add a third button that will toggle the map type between road and aerial.

A function within the module's prototype (a private instance method we can call later with the this keyword) achieves the following:

lbm.LearningTheme.prototype = {
  _addHeader: function() {
    var header = document.createElement('div');
    header.className = 'lbm-map-header';
    header.innerHTML = [
      '<button class="lbm-btn" id="lbm-map-btn-zoomin">-</button>',
      '<button class="lbm-btn" id="lbm-map-btn-zoomout">+</button>',
      '<button class="lbm-btn" id="lbm-map-btn-maptype">Aerial</button>'
    ].join('');
    
    this._map.getRootElement().appendChild(header);
  }
};

First, we create a DOM div element and give it a class name OF lbm-map-header, so that we can style it later. The markup for the buttons is simple, shown as follows:

<button class="lbm-btn" id="lbm-map-btn-zoomin">-</button>

Again we specify a class (lbm-btn) for styling and an ID (lbm-map-btn-zoomin) for controlling its behavior. We place the buttons in an array that we later join with an empty string. This is a common technique for building HTML strings in a JavaScript code, BECAUSE it improves the readability of the code.

At the end, we append the markup to the map's root element. Bing Maps provide a nice utility method to get the latter, getRootElement. (The list of methods, properties, and events of the map can be found at http://msdn.microsoft.com/en-us/library/gg427609.aspx).

We want the header to be added to the map when the module is loaded; therefore, we call the _addHandler method in the module's constructor, which now looks like this:

lbm.LearningTheme = function(map) {
  this._map = map;
  this._addHeader();
};

If you view the index.html file on the browser, you will not see the default Bing Maps dashboard, but you won't see our controls either. This is because we have not added our styles yet. Let's place them in a learningTheme.css file inside the learningTheme folder, as shown in the following code:

.lbm-map-header {
  position: absolute;
  top: 1em;
  left: 1em;
  width: 100%;
  color: #fff;
  z-index: 100;
}

.lbm-map-header .lbm-btn {
  font-size: 1em;
  border: 0;
  background: #F04C40;
  color: #fff;
  display: inline-block;
  text-decoration: none;
  width: 2.5em;
  height: 2em;
  line-height: 2em;	
  padding: 0;
  margin: 0 1px 0 0;
  outline: 0;
  text-align: center;
  cursor: pointer;

  opacity: .8;

  border-radius: .2em;
  -webkit-border-radius: .2em;
  -moz-border-radius: .2em;
}

.lbm-map-header #lbm-map-btn-zoomin {
  border-top-right-radius: 0;
  -webkit-border-top-right-radius: 0;
  -moz-border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  -webkit-border-bottom-right-radius: 0;
  -moz-border-bottom-right-radius: 0;
}

.lbm-map-header #lbm-map-btn-zoomout {
  border-top-left-radius: 0;
  -webkit-border-top-left-radius: 0;
  -moz-border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  -webkit-border-bottom-left-radius: 0;
  -moz-border-bottom-left-radius: 0;
}

.lbm-map-header .lbm-btn:hover {
  background: #cf343e;
}

.lbm-map-header .lbm-btn:active {
  background: #cc1d28;
}

.lbm-map-header #lbm-map-btn-maptype {
  margin-left: 2em;
  width: auto;
  padding: 0 .8em;
}

We make sure that the buttons' container has an absolute position and a high z-index value, so that it appears above the map.

Now, we need to add a link to the CSS file to our HTML document, and we'll do this when the module is loaded. This way, if the module is never loaded, then the stylesheet is not loaded either. Again, loading our CSS file on demand means another HTTP request, and if you prefer to have the styles merged into a single file, then you can use the same technique as for the JavaScript files, and skip the following step:

We'll add a link to our CSS file to the head of the page as shown in the following code snippet:

_addCss: function() {
  var link = document.createElement('link');
  link.setAttribute('rel', 'stylesheet');
  link.setAttribute('href', 'learningTheme /learningTheme.css');
  var head = document.getElementsByTagName('head')[0];
  head.appendChild(link);
}

First, the preceding function creates a link element, with a href attribute pointing at our learningTheme.css file. Then, it gets a reference to the head of the document, and it appends to it the newly created element.

As with the buttons markup, we need the stylesheet to be loaded with the module, so we'll call this function in the module's constructor, as shown in the following code:

lbm.LearningTheme = function(map) {
  this._map = map;
  this._addCss();
  this._addHeader();
};

If we open the index.html file on a browser now, we can finally see our controls, as shown in the following screenshot: