Overlaying images on Virtual Earth without tiling

One thing a lot of people complain about web mapping applications is having to create tiles to be able to overlay images as new map layers. Tiling is boring, time consuming and pointless if all you have is a 100 KB image (not images of different details for different zoom levels) with no noticeable distorted look due to projection difference. It is a serious time sink when you need to create them on the fly (creating tiles from an image generated by an application that uses real-time data). And what if you want to overlay an animation? For my case, I create the images programmatically and re-project them during the process if necessary. So I skipped the tiling part and below is how I did it, should you want to do it as well.

Let's start with just putting the image on top of the map in which case we'll be adding the following line in the body of the document. Here the assumption is that the map has a z-index less than 1000.

<img src="myimage.gif" id="overlay" style="z-index:1000; opacity: 0.7; filter: alpha(opacity=70);position:absolute;left:20px;top:20px"/>

Here left, top values are completely arbitrary. Below you can see how the image can be positioned properly. originalHeight and originalWidth are the dimensions of your image in pixels. Latitude and longitude are in decimal degrees.

var imageUpperLeftCornerLatitude = 42.335; var imageUpperLeftCornerLongitude = -112.6791; var originalHeight = 300; var originalWidth = 296; var imageLatLon = map.LatLongToPixel(new VELatLong(imageUpperLeftCornerLatitude, imageUpperLeftCornerLongitude)); var imageOverlay = document.getElementById('overlay'); imageOverlay.style.top = imageLatLon.y; imageOverlay.style.left = imageLatLon.x;

At this point, the image doesn't respond to zoom/pan events. And the worst news is, once you move your mouse over the image, you're no longer interacting with the map.

This issue can be solved by making the overlay a part of VELayerListDiv.

var VElyrs = document.getElementById('VELayerListDiv'); var imageOverlay = document.getElementById('overlay'); VElyrs.appendChild(imageOverlay);

Once you add this, you will see that the overlay responds to 'pan event' the same way a tile layer does. However 'zoom' doesn't work the way it's supposed to. So we need to write a custom function to handle the zoom event. You will also notice that position is adjusted, as well.

function RedrawImage(){ var imageOverlay = document.getElementById('overlay'); var currentZoomLevel = map.GetZoomLevel(); imageOverlay.width = Math.round(originalWidth*(Math.pow(2,(currentZoomLevel-imageZoomLevel)))); imageOverlay.height = Math.round(originalHeight*(Math.pow(2,(currentZoomLevel-imageZoomLevel)))); var imageLatLon = map.LatLongToPixel(new VELatLong(imageUpperLeftCornerLatitude, imageUpperLeftCornerLongitude)); imageOverlay.style.top = imageLatLon.y; imageOverlay.style.left = imageLatLon.x; }

You can see that the image is resized using a function based on the difference between the map zoom level and 'imageZoomLevel'. ImageZoomLevel is the zoom level at which a pixel in the image corresponds to a pixel on the Virtual Earth map. In other words if you're dealing with a satellite image or numerical model output with a grid size of 5 kilometers, the zoom level at which a pixel on the Virtual Earth map corresponds to 5 kilometers is the ImageZoomLevel (which doesn't have to be an integer). Ground resolution (meters per pixel) at a given latitude and zoom level can be calculated using the following function where 6378137 meters is earth's radius.

Ground resolution = (cos(latitude * pi/180) * 2 * pi * 6378137 meters) / (256 * 2 zoom level)

Especially if you're programmatically re-projecting your image to Mercator, you can use a random latitude in this function. Otherwise I'd assume that you don't mind a little distortion (and your image is not close to the poles). Now we can attach the event to RedrawImage function. (This needs to be done when you initiate the map.)

map.AttachEvent('onendzoom', RedrawImage);

However, the zoom event still doesn't look very smooth. A show/hide while resizing takes place can fix this.

map.AttachEvent('onstartzoom', HideImage);

Where HideImage would do the following

imageOverlay.style.visibility='hidden';

which requires an update on the RedrawImage method so that the image is visible again after the transformation.

imageOverlay.style.visibility='visible';

And there you have it. This way you can overlay animated GIFs, tables, iframes .... i.e. almost anything. Let's hope that VE API natively supports this in future releases.

 

Original posting