Image Overlays with Bing Maps (JavaScript)

There are a lot of different types of data that can be overlaid on top of Bing Maps. In this post, we are going to look at how to overlay images on top of the Bing Maps V7 AJAX and Windows Store JavaScript controls. Over the years, I’ve seen a lot of great use cases for overlaying images on top of the map. Some of the more common use cases include: floor plans, satellite imagery of hurricanes or other natural disasters, historic maps, and other maps,

There are two main approaches for overlaying images on Bing Maps. The first approach is to turn the image into map tiles ahead of time and serve them up to the application as a custom tile layer. This has been a common approach for many and have accomplished this by using a tool called MapCruncher. This approach does require hosting the tiles on a server, which can be slow going due to the number of tile loads. This approach is ideal for when you want to overlay a high resolution image with a large file size. The second approach is to overlay the image directly on the map and lock it to a specific bounding box, scaling and positioning it accordingly as the map moves. With the Bing Maps Silverlight control we are able to overlay images on top of the map by simply adding the image as a child of a layer and providing a bounding box for the image. A sample of this can be found here. While this approach is much simpler than the tiled, it is not recommended for images that have large file sizes.

MapCruncher Approach

MapCruncher is a Microsoft Research project that makes it easy to cross reference an image with a location on a map and then turn the image into a tile layer. Instructions on how to use MapCruncher can be found here. By default, MapCruncher will generate a test application for you that is built on Bing Maps V6.3. For a better user experience you will want use the Bing Maps V7 AJAX control. To do this, simply locate the folder from the output directory that contains the map tiles. You will want to add these as a folder in your project on a server. You can then add it as a custom tile layer.

Scaling Image Approach

When the Bing Maps Silverlight control was released one of the new features we found was the ability to overlay any UIElement such as an image or video on top of the map and having it bound to a specific bounding box on the map. This feature was never available in the JavaScript version of Bing Maps, but has been something of interest to me.

Looking at the Bing Maps JavaScript controls we have the ability to overlay custom HTML pushpins. We can easily use a custom image to create a pushpin, but it will not be positioned or scaled properly without a little work. If we attached to the viewchangeevent of the map, and update the size and position of the image, we can properly bind it to a specific bounding box. To accomplish this, lets create a reusable module for Bing Maps.

Open up a text editor and copy and paste the following code and save it as ImageOverlayModule.js.

var ImageOverlay;

(function () {
var canvasIdNumber = 0;

function generateUniqueID() {
var canvasID = 'strechedImg' + canvasIdNumber;
canvasIdNumber++;

if (window[canvasID]) {
return generateUniqueID();
}

return canvasID;
}

// map - Microsoft.Maps.Map object
// imageURL - String URL to where the image is located
// boundingBox - Microsoft.Maps.LocationRect object
ImageOverlay = function (map, imageURL, boundingBox) {
var _basePushpin = new Microsoft.Maps.Pushpin(boundingBox.center);
var _opacity = 1;
var _id = generateUniqueID();

function render(){
var size = calculateSize();

var pushpinOptions = {
width: null,
height: null,
anchor: new Microsoft.Maps.Point(size.width/2, size.height/2),
htmlContent: "<img id='" + _id + "' style='width:" + size.width + "px;height:" + size.height + "px;opacity:" + _opacity + ";filter:alpha(opacity=" + (_opacity * 100) + ");' src='" + imageURL + "'/>"
};

_basePushpin.setOptions(pushpinOptions);
}

function calculateSize(){
var nwPixel = map.tryLocationToPixel(boundingBox.getNorthwest());
var sePixel = map.tryLocationToPixel(boundingBox.getSoutheast());

var width = Math.abs(sePixel.x - nwPixel.x);
var height = Math.abs(nwPixel.y - sePixel.y);

return {
width: width,
height: height
};
}

_basePushpin.Refresh = function () {
var size = calculateSize();

_basePushpin.setOptions({anchor : new Microsoft.Maps.Point(size.width/2, size.height/2)});

var elm = document.getElementById(_id);

if(elm){
elm.style.width = size.width + 'px';
elm.style.height = size.height + 'px';
}
};

_basePushpin.SetOpacity = function (opacity) {
if (opacity >= 0 || opctity <= 1) {
_opacity = opacity;
render();
}
};

//Map view change event to resize the image
Microsoft.Maps.Events.addHandler(map, 'viewchange', function (e) {
if (!e.linear) {
//Check if zoom level has changed. If it has then resize the pushpin image
_basePushpin.Refresh();
}
});

render();

return _basePushpin;
};
})();

//Call the Module Loaded method
Microsoft.Maps.moduleLoaded('ImageOverlayModule');

This module creates a class called ImageOverlay which we takes in a reference of the map, a URL to the image we want to overlay and a LocationRect of the bounding box to bind the image. The following is an example of how you can use this module with the Bing Maps V7 AJAX control.

Note: you could also use this module with the Bing Maps Windows Store JavaScript control.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>

<script type="text/javascript">
var map;

function GetMap() {
// Initialize the map
map = new Microsoft.Maps.Map(document.getElementById("myMap"),
{
credentials: "YOUR_BING_MAPS_KEY",
center: new Microsoft.Maps.Location(40.25, -123.25),
zoom: 7
});

//Register and load the Image Overlay Module
Microsoft.Maps.registerModule("ImageOverlayModule", "scripts/ImageOverlayModule.js");
Microsoft.Maps.loadModule("ImageOverlayModule", { callback: function () {
var imageRect = Microsoft.Maps.LocationRect.fromCorners(new Microsoft.Maps.Location(40.5, -123.5), new Microsoft.Maps.Location(40, -123));
var imgPin = ImageOverlay(map, 'images/topographicMap.gif', imageRect);
imgPin.SetOpacity(0.5);
map.entities.push(imgPin);
}});
}
</script>
</head>
<body onload="GetMap();">
<div id='myMap' style="position:relative;width:800px;height:600px;"></div>
</body>
</html>

For this example, I grabbed a topographic map image from Bing image search and gave it an approximate bounding box. NASA also has a lot of great imagery you can overlay that is geo-referenced. I’ve even seen some pretty cool animated gif’sthat would work too. When you run the application you should see your image overlaid on top of the map like this:

clip_image001

This module has also been made available through the Bing Maps V7 Modules CodePlex project.

About these ads

3 thoughts on “Image Overlays with Bing Maps (JavaScript)

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