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 ( 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)
    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.
  • Control over the minimap is limited. It cannot be aligned to the right or bottom of the map control. You can set the offset from the top left, which really makes no sense because that’s where the toolbar is already, so you’d never want the Minimap there anyway.
  • The CustomIcon() can have a different offset, you need to manually compensate to place the custom icon in the correct location. To do this, you need the full VECustomIconSpecification.
  • Coordinates only in decimal Lat / Long, no Deg/Min/Sec
  • It’s not possible to initialize a VEMap in 3D with Bird’s Eye
  • There is no easy way to get a pointer to a specific ShapeLayer. Only by index.
  • I will write a folluw-up article on some of the more interesting topics I challenged.


    One thought on “First encounter with Microsoft Virtual Earth API

    1. 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.


    Comments are closed.