OpenLayers with a Virtual Earth Widget

I recently came across a need to display a little Virtual Earth map in one of my sites. Specifically, a group of users needed to see some oblique photography.

With OpenLayers you can dump the standard VE or Google Maps tiles in your application, but the VE obliques are a bird of a different feather. Hence the need for a little widget rather than adding a VE layer to OpenLayers.

I had seen the Google Maps and Virtual Earth Side by Side stuff before, but I couldn’t find a good tutorial on doing it with OpenLayers. I also only wanted a one way handshake - navigating on OpenLayers would navigate on VE, but you can pan/zoom VE without effecting OpenLayers.

As it turns out, it so easy to do it’s almost silly. You can see the end result here (the VE map is behind the second “+” on the right).

First, you’ll have to reference the Virtual Earth Javascript library:

<script type=”text/javascript” src=”http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script&gt;

Next, you’ll need to make sure you made global variables for your maps. We’ll call the Openlayers map “map” and the VE map “vemap”:

var map;
var vemap;

The page is going to have a DIV to stick the VE map in like so:

<div id=”embedded_map_maparea” style=”position:relative; width:380px; height:300px;”></div>

Now we’re going to create the map on page load. I’m using jQuery’s ready function, but you could use something similar in your JS library of choice, or simply attach to the body onload event. I’m leaving out the map_init() function, but it’s just the OpenLayers initialization script.

$(document).ready(function() {
vemap = new VEMap(‘embedded_map_maparea’);
map_init();
var longlat = map.getCenter();
vemap.LoadMap(new VELatLong(longlat.lat, longlat.lon), map.getZoom(), VEMapStyle.Hybrid);
});

First we’re creating the VE map, then we’re creating the OpenLayers map. Then we take the OpenLayers center longitude and latitude and pan the VE map to that position at the OpenLayer’s zoom level. One thing to note here is we’re assuming we’re using 20 zoom levels in OpenLayers; if you use fewer, you’ll need to adjust accordingly. For example, my site goes from zoom levels 10 to 17. map.getZoom() will return 0 for the top level and add 1 as you zoom in, so you’d want to zoom the VE map to something like map.getZoom + 9.

Now we need to attach a navigation function on OpenLayers to the VE widget. We’re going to register a function on the OpenLayers map “moveend” event to move the VE map. The “movened” event fires after a map zoom or pan event takes place. Our code looks like so:

map.events.register(“moveend”, map, function(e) {
var longlat = map.getCenter();
vemap.SetZoomLevel(map.getZoom() + 9);
vemap.PanToLatLong(new VELatLong(longlat.lat, longlat.lon));
});

And that’s it. Seriously. ~15 lines of code. Every time the OpenLayers map moves, the VE map moves right along with it. Bob’s your uncle.

You could probably easily tie VE navigation back to OpenLayers, but I didn’t need to do it for this project. Particularly with oblique photography, I think users may want to shift the VE window around a bit without having it mess with the main map display.

Again, the working site is here. That’s Geospatial Portal, which you can get the full source code for on our Projects page.

The only downer with these kinds of mashups is you’re loading some fairly hefty JavaScript mapping libraries. If I wanted to similarly put up a little widget with Google Maps Street View (that might be coming soon), I’d be loading OpenLayers, VE, and Google libraries. That starts to add up pretty quickly. Right now, with an empty cache you’re looking at ~140kb of JavaScript (gzip’d), and size = launch speed. It isn’t a behemoth like the old ArcIMS HTML Viewer, but its back pockets are not exactly close together either. It’s something to consider when you’re doing this kind of a mashup.