First encounter with Microsoft Virtual Earth API
I spent a couple of days building a ‘mashup’ application that shows the 360 degree panorama photos from CycloMedia on top of the MS Virtual Earth Bird’s Eye views. The end result is a rich visual experience of a geographical location (see screenshot on the right)
In this document I summarize the challenges and useful experiences I gained with the VE API.
- Coming from a C# background, one would expect more control over objects through properties instead of getter / setter methods which clutter up the API. You get lots of methods like map.GetZoomLevel() and map.SetZoomLevel()
- Implementing a custom icon is very simple, as long as you stay in 2D mode where you can use the SetCustomIcon() method on a shape.
- The documentation (http://msdn2.microsoft.com/en-us/library/bb429565.aspx) is not always correct:
- The VEShape control has no ID property you can set. It has a Title property that you can get and set, but that will also appear in the info box. The JS Prototype construct came to my rescue: I added a custom property to the VEShape object to hold the Cyclomedia ID …
VEShape.prototype.CycloID = null;
- … and a function to get a pointer to a VEShape corresponding to a specific Cyclomedia ID.
function findShapeByCycloId(id)
{
for(i=0;i<shapeLayer.GetShapeCount();i++)
{
shape = shapeLayer.GetShapeByIndex(i);
if(shape.CycloID == id)
{
return shape;
}
}
return null;
}
- For debugging and development purposes, it is convenient to have the entire function that handles the onLoadMap event in a try…catch block, as well as the function that creates the map and is fired by the body.onload event. That should cover most VE exceptions. Still I found that I got unhandled VE Exceptions.

- I had the need for an arrow that indicates the view direction in the CycloScopeLite plugin and thus can be rotated. I solved this by creating a polyline arrow as a VEShape. Its nodes are calculated from the angle value supplied by the ChangeHorzViewDir event fired by the CycloScopeLite control. See result above. This is not a watertight solution though:
- Sometimes one of the arms of the arrow are not drawn. This behavior is hard to reproduce but seems to occur when sin(angle) or cos(angle) are close to 0.
- It doesn’t survive a switch to 3D mode, and won’t reappear when you switch back to 2D mode. It’s not clear to me why.
- Furthermore, a VEShape needs to be calculated in ground coordinates and its size is thus dependent on the zoom level. A scale factor is calculated to deal with this:
var scalefactor = (map.GetMapStyle() == VEMapStyle.Birdseye)?(scalefactor = 0.0001 * (2.5-map.GetZoomLevel())):(scalefactor = 0.0001 * (19.5-map.GetZoomLevel()));
- It is clear from the code snippet above that the value returned by map.GetZoomLevel() has a different range for Aerial/Road modes and for Bird’s Eye mode. Aerial/Road has 1-19, while BE has only 1 and 2.
I will write a folluw-up article on some of the more interesting topics I challenged.
A few thoughts:
You might try using an icon for the arrow that you want, rather than a shape. You just create 360 of them, or possibily use CSS to rotate the image as appropriate. The same icon is used at all zoom levels, and should be present in multiple modes.
Regarding keeping track of ShapeLayers…just keep your own array/hashmap.
-Chris
Chris Means
March 30, 2008 at 10:07 pm