Recent Blog Posts RSS
ViaWindowsLive on Via Virtual Earth Blog
The new ViaWindowsLive community site has launched and features not only a definitive set of resources on all Live Services from Microsoft but also a special section on Virtual Earth including a new site gallery for you to upload your sites, new articles on Version 6, including getting started guide, an interactive quick guide, location finder and more. Subscribe to the VWL aggregated blog to stay in touch with everything Live Services related. Find all the great content from this site and much, much more. Explore how other Live Services can compliment Virtual Earth and your applications.
Version 5 URL changed - Error: 'VEMap' is undefined on Via Virtual Earth Blog
It has been reported that the old url to access the Version5 javascript for Virtual Earth no longer works. This is effecting sites worldwide.
The correct way to reference the Version 5 javascript is:
<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5"></script>
If you have been effected a forum thread has been started here
Silverlight Virtual Earth viewer on Via Virtual Earth Blog
With the launch of silverlight yesterday I was digging around and found this viewer for Virtual Earth by Greg Schechter. It does use the 1.1 alpha of silverlight. It gives some interesting ideas for where Virtual Earth could be headed. Certainly the demo of the performance of silverlight compared to javascript for processing showed a significant increase. This could be very useful.
And of course on the gamer front check this out by Andy Beaulieu and shoot down some UFO's over Birdseye images.
John.
So much new Virtual Earth Imagery Worldwide. on Via Virtual Earth Blog
I subscribe to all the VE blogs and recently the posts about updated imagery has been more and more frequent.
The latest is here and for myself downunder we saw three updates, Canberra, Newcastle and Uluru:


Derek Chan posts 3 Articles in a month! on Via Virtual Earth Blog
A big thank you to the efforts of Derek Chan who posted his third VE article today (he actually had it ready weeks ago but had to wait for Mr Bottleneck here at VVE ;) )
The 3 articles are all relivant to Version 5 of Virtual Earth and deal with the Mini Map, debugging javascript and now custom pins in routes.
All these can now be found in our articles section.
If you have something to contribute send us an email.
John (The bottleneck)
Getting Started with V3 of the API (Part 1) RSS
This article will help you understand how to get started using version 3 of the Virtual Earth Map Control. The map control used in Virtual Earth is a JScript control, this can be used to present a great user experience for online map content. This article can be downloaded in PDF here.
By the end of this article you will have created a web page that displays a map control and allows for some user input as show in figure 1. This page can be found here http://www.viavirtualearth.com/MyVirtualEarth/v3/gettingstartedpt1.htm

Figure 1
Using the MapControl
The Virtual Earth Map Control script can be found at: http://dev.virtualearth.net/mapcontrol/v3/MapControl.js
You should link directly to this on your site to ensure you always use the most update version of the control.
Unlike previous versions of the map control this contains everything you are likely to need for this article; you do not have to include an external link to a CSS file.
Creating a Map instance
To create a new instance of a Virtual Earth Map Control you will need to write a small method in JScript on your page. This will create an instance of the VEMap, position it on the page and set up the initial content of the control.
The VEMap object constructor has the following prototype:
VEMap(control_id);
- control_id
- The ID of the HTML control that will contain the map on your web page.
Once you have created an instance of the VEMap you need to call the LoadMap method to display the map in the HTML control specified.
The LoadMap method can be called with no parameters, in which case you will get a map which shows the USA zoomed out to show most of the north American states (zoom level 4) and displayed using the road style.
VEMap.LoadMap(VELatLong, zoom, style, fixed);
- VELatLong
- An object that represents the center of the map
- zoom
- The zoom level to display. Valid values range from 1 through 19.
- style
-
The map style. Valid values are:
- a for aerial
- h for hybrid
- for oblique (bird's eye)
- r for road
- fixed
- A Boolean value that specifies whether the map view is displayed as a fixed map that the user cannot change. True indicates the map is fixed and cannot be changed, false indicates the map is not fixed and can be changed by the user.
The advantage of this approach (over earlier versions of the map control) will be seen later in the article when you add a second map to the same page.
Example:
A simple web page with a Virtual Earth map control can then be created as shown in Listing 1.
<html>
<head>
<title>My Virtual Earth</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script
src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js">
</script>
<script>
var map = null;
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-33.7939, 151.1093), 10, 'r', false);
}
</script>
</head>
<body onload="OnPageLoad();">
<div id='myMap' style=" position:relative;width:600px; height:400px;"></div>
</body>
</html>
Listing 1
This should allow you to create a page that looks similar to that shown in figure 2 below. The control provides a number of features for �free�. You should be able to:
- move the map around by dragging it
- zoom in and out with the mouse wheel
- zoom in by double clicking on a location
- change the map style from road to aerial using the dashboard
- move around the map using the compass control on the dashboard
- zoom in and out of the map using the dashboard

Figure 2
Receiving Events from the Map Control
As the map displayed on the control is changed by the user the map control raises events that provide information about the map currently displayed in the control. The events you can receive from the control are:
- onchangeview
- Occurs whenever the map view changes.
- onclick
- Occurs when the user clicks on the map.
- oncontextmenu
- Occurs when the user right-clicks on the map.
- onendcontinuouspan
- Occurs when a continuous pan of the map ends.
- onendzoom
- Occurs when the map zoom ends.
- onerror
- Occurs when there is a map control error.
- onchangemapstyle
- Occurs when the map style changes.
- onLoadMap
- Occurs when the map is first loaded.
- onmouseup
- Occurs when the user releases a mouse click on the map.
- onobliquechange
- Occurs only when the Bird's Eye image scene ID is changed. This event only fires if the map is currently displaying a Bird's Eye image and that image is changed.
- onobliquechange
- Occurs only when the bird's eye image scene ID is changed. This event fires only if the map is currently displaying a bird's eye image and that image is changed.
- onobliqueenter
- Occurs when switching to bird's eye imagery from another map style.
- onobliqueleave
- Occurs when switching from bird's eye imagery to another map style.
- onresize
- Occurs when the map is resized.
- onstartcontinuouspan
- Occurs when a continuous pan of the map begins.
- onstartzoom
- Occurs when the map zoom begins.
All of the event functions are passed a single parameter. This event parameter contains a view member that represents the current view on the map. While it would have been nice if Microsoft had not obfuscated the code we can see that the MapView object contains a number of useful properties:
- mapStyle
- The map style of the current map view.
- zoomLevel
- The zoom level of the current map view.
- center
- The center point (pixel) of the current map view.
- latlong
- The center point (LatLong)of the current map view.
- pixelRect
- The bounding rectangle (pixel) of the current map view.
- latlongRect
- The bounding rectangle (latlong) of the current map view.
- sceneId
- The ID of the oblique scene in the current map view. Returns null if MapStyle is not 'o'.
- sceneOrientation
- The orientation of the oblique scene in the current map view. Returns null if MapStyle is not 'o'.
The first events we will examine are the panning events. These are raised each time the map starts or stops panning, or scrolling. As you might expect the onstartcontinouspan event is raised when the map starts scrolling and the onendcontinouspan event is raised when the map control finishes scrolling the map.
To the simple page you created in the previous step you can add some code to handle the onendcontinouspan event and display information as to the new centre point of the map.
The code shown in Listing 2 demonstrates this.
<html>
<head>
<title>My Virtual Earth</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>
<script>
var map = null;
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-33.7939, 151.1093), 10, 'r', false);
map.AttachEvent("onendcontinuouspan",
function(e)
{
document.getElementById("info").innerHTML =
'Latitude = ' +
e.view.latlong.latitude +
', Longitude = '
+ e.view.latlong.longitude +
', Zoom=' +
e.view.zoomLevel;
} ) ;
}
</script>
</head>
<body onload="OnPageLoad();">
<div id="info" style="position:relative;height:50px;font-size:10pt"></div>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
</body>
</html>
Listing 2
We can do the same with the onendzoom event by adding a function to handle that event, Listing 3.
<html>
<head>
<title>My Virtual Earth</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>
<script>
var map = null;
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-33.7939, 151.1093), 10 ,'r' , false);
map.AttachEvent("onendcontinuouspan", function(e)
{
document.getElementById("info").innerHTML =
'Latitude = ' +
e.view.latlong.latitude +
', Longitude = '
+ e.view.latlong.longitude +
', Zoom=' +
e.view.zoomLevel;
} ) ;
map.AttachEvent("onendzoom", function(e)
{
document.getElementById("info").innerHTML =
'Latitude = ' +
e.view.latlong.latitude +
', Longitude = '
+ e.view.latlong.longitude +
', Zoom=' +
e.view.zoomLevel;
} ) ;
}
</script>
</head>
<body onload="OnPageLoad();">
<div id="info" style="position:relative;height:50px; font-size:10pt"></div>
<div id="myMap" style="position:relative;width:600px; height:400px;"></div>
</body>
</html>
Listing 3
The page should now appear as shown in Figure 3.

Figure 3
Refactoring out the Duplicate Code
In your JScript you now have duplicate code in the onendcontinouspan and onendzoom event handlers. It is a good practice to replace duplicate code with a single function that is called from both places. The AttachEvent method allows you to use a method name as well as putting the code inline.
The code can therefore be changed to look like Listing 4.
<html>
<head>
<title>My Virtual Earth</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>
<script>
var map = null;
function UpdateInfo(e)
{
document.getElementById("info").innerHTML =
'Latitude = ' +
e.view.latlong.latitude +
', Longitude = '
+ e.view.latlong.longitude +
', Zoom=' +
e.view.zoomLevel;
}
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-33.7939, 151.1093), 10, 'r' , false);
map.AttachEvent("onendcontinuouspan", UpdateInfo);
map.AttachEvent("onendzoom", UpdateInfo);
}
</script>
</head>
<body onload="OnPageLoad();">
<div id="info" style="position:relative;height:50px;font-size:10pt"></div>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
</body>
</html>
Listing 4: refactored out the duplicated code
Changing the Map Style
Previously, in the first version of the Virtual Earth map control you had to add code to change the map style between aerial, road and hybrid. The new MapControl does most of the hard work for us. You may still want to change the map style from your code and the mechanism for doing this remains the same, using the SetMapStyle function.
The available map styles are:
- aerial: an aerial satellite image of the map display
- road: a street map of the area in the control
- hybrid: a combination of aerial and vector (the aerial image is overlayed)
- oblique: oblique or birds eye imagery
Once the map control is displayed it is possible to change the map style by using the SetMapStyle function on the Map Control:
SetMapStyle(mapStyle)
The function takes one parameter to indicate the style. Similar to setting the initial style the parameter is the first single character of the style; �a�, �r�, �h� or �o�. Alternatively (and preferably) you can use the VEMapStyle enumeration:
VEMapStyle { Road, Aerial, Hybrid, Oblique }
For example:
map.SetMapStyle(VEMapStyle.Aerial);
Adding a Pushpin to the Map
The ability to add pins to the map allows us to indicate particular locations on the map control. Pins work by overlaying information on the map control. The prototype of the AddPushpin method looks like this:
AddPushpin(pin)
- pin
- A VEPushpin object
The VEPushpin object is new to the version 3 beta and lets you describe the pushpin you want to add to the map. The constructor for the Pushpin has the following signature:
VEPushpin(id, location, icon_url, title, details, iconStyle, titleStyle, detailsStyle);
- id
- The ID of the pushpin that will be added the map. This id must be unique for each pushpin on a map control.
- location
- The location of the pushpin, specified as a VELatLong object.
- icon_url
- The URL that points to the file you want to use as an icon.
- title
- The string to display in the Title field of the pushpin popup.
- details
- The string to display in the Details field of the pushpin popup.
- iconStyle
- A cascading style sheet (CSS) class name that defines the look of the icon.
- titleStyle
- A cascading style sheet (CSS) class name that defines the look of the title field of the popup.
- detailsStyle
- A cascading style sheet (CSS) class name that defines the look of the description field of the popup.
NOTE: The first two parameters are the only ones that are required. The rest of the parameters are optional.
In the following example (Listing 5) the onclick event is used to add a pushpin to the map where the user clicked.
<html>
<head>
<title>My Virtual Earth</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>
<script>
var map = null;
function UpdateInfo(e)
{
document.getElementById("info").innerHTML =
'Latitude = ' +
e.view.latlong.latitude +
', Longitude = '
+ e.view.latlong.longitude +
', Zoom=' +
e.view.zoomLevel;
}
function MouseClick(e)
{
map.DeleteAllPushpins();
var pin = new VEPushpin(1,
new VELatLong(e.view.LatLong.Latitude, e.view.LatLong.Longitude),
'http://localhost/MyVirtualEarth/V3/pin.jpg',
'My Pin',
'Text that describes my pin'
);
map.AddPushpin(pin);
}
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-33.7939, 151.1093), 10 ,'r' , false);
map.AttachEvent("onendcontinuouspan", UpdateInfo);
map.AttachEvent("onendzoom", UpdateInfo);
map.AttachEvent("onclick", MouseClick);
}
</script>
</head>
<body onload="OnPageLoad();">
<div id="info" style="position:relative;height:50px;font-size:10pt"></div>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
</body>
</html>
Listing 5
Viewing this page in a browser will now allow push pins to be added by clicking on the map. There are a couple of issues with this:
- Each time the map is dragged another push pin gets added.
- Double clicking on the map to zoom in no longer works, because a pin is added first that receives the double click event.
A solution would be not to add push pins using the onclick event. For now let�s stick with this but notice that we can only have one pushpin as we are calling DeleteAllPushpins before each call.
To remove a specific pin use the DeletePushpin function.
DeletePushpin(id);
This function takes a single parameter which identifies the pin to remove. Deleting a pushpin that does not exist will throw an exception.
The MouseClick function shown in Listing 5 can be changed to remove the previous pin as shown in Listing 6.
var pushpinOnMap = false;
function MouseClick(e)
{
if (pushpinOnMap)
{
map.DeletePushpin(1);
}
var pin = new VEPushpin(1,
new VELatLong(e.view.LatLong.Latitude, e.view.LatLong.Longitude),
'http://localhost/MyVirtualEarth/V3/pin.jpg',
'My Pin',
'Text that describes my pin'
);
map.AddPushpin(pin);
pushpinOnMap = true;
}
Listing 6
We should now have a page that will contain a single push pin indicating the last place on the map that was clicked, Figure 4.

Figure 4
Adding Navigation Controls
The map control has some useful built in navigation features but it is sometimes useful to provide extra controls on the web page to allow the user to navigate around the map. In this final section of this article you will learn how to add buttons to the web page that can control the contents of the map control.
Panning
You will start by adding buttons to pan around the map. In the body element of the HTML page buttons can be added with simple HTML code:
<input type="button" value="Pan Up" onclick="DoPanUp()" id="PanUpButton" name="PanUpButton" style="position:absolute;left:60px;top:500px;"/>
<input type="button" value="Pan Left" onclick="DoPanLeft()" id="PanLeftButton" name="PanLeftButton" style="position:absolute;left:10px;top:530px;"/>
<input type="button" value="Pan Right" onclick="DoPanRight()" id="PanRightButton" name="PanRightButton" style="position:absolute;left:100px;top:530px;"/>
<input type="button" value="Pan Down" onclick="DoPanDown()" id="PanDownButton" name="PanDownButton" style="position:absolute;left:45px;top:560px;"/>
The code to action on the button clicks can then be added to the script section in the page. Using the Pan method on the map control. Pan takes 2 parameters, x and y. These indicate by how much to pan the map view in the x and y directions.
function DoPanUp()
{
map.Pan(0, -100);
}
function DoPanDown()
{
map.Pan(0, 100);
}
function DoPanLeft()
{
map.Pan(-100, 0);
}
function DoPanRight()
{
map.Pan(100, 0);
}
If you load this page in a browser and click the buttons you can see the map jump around. This is not a great user experience. It would be nicer to show the map scrolling smoothly in each of the directions. This can be achieved using the ContinuousPan function of the underlying map control.
The VEMap object wraps a vemapcontrol object that hosts more methods than are exposed through the documented API.
Remember that as this is not documented it is not supported either so it might change in the future.
ContinuousPan takes 2 extra parameters along with the x and y.
The third parameter indicates how many times to repeat the pan. In this way a number of small operations can be put together to provide the appearance of the map scrolling.
The final parameter is related to the keyboard panel, for the moment you can set it to false.
function DoPanUp()
{
map.vemapcontrol.ContinuousPan(0, -10, 20, false);
}
function DoPanDown()
{
map.vemapcontrol.ContinuousPan(0, 10, 20, false);
}
function DoPanLeft()
{
map.vemapcontrol.ContinuousPan(-10, 0, 20, false);
}
function DoPanRight()
{
map.vemapcontrol.ContinuousPan(10, 0, 20, false);
}
Zooming
Next you will add 2 buttons in the HTML; to zoom in and to zoom out.
<input type="button" value="Zoom In" onclick="DoZoomIn()" id="ZoomInButton" name="ZoomInButton" style="position:absolute;left:250px;top:530px;"/>
<input type="button" value="Zoom Out" onclick="DoZoomOut()" id="ZoomOutButton" name="ZoomOutButton" style="position:absolute;left:340px;top:530px;"/>
The accompanying script code can use the ZoomIn and ZoomOut functions of the map control. Each functional call will simply increase or decrease the zoom level by 1.
function DoZoomIn()
{
map.ZoomIn();
}
function DoZoomOut()
{
map.ZoomOut();
}
Hiding the Control Dashboard
Now you have added you own controls to pan and zoom around the map you may wish to hide the built in controls and allow the user to see more of the map. You can do that by calling the HideDashboard method. You can do this at the end of your OnPageLoad method.
Adding a second map control
Now you have some more space on the map you might want to add a second map to provide guidance as to where in the world the user is exploring on the main map.
Start by declaring a second global variable to hold the new map control:
var insetMap = null;
Then in the HTML body add a new div element to host the inset map:
<div id="inMap" style="position:absolute;top:50px;width:200px;height:200px;"></div>
You can then instatiate and load the new insetMap object in the OnPageLoad method:
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-33.7939, 151.1093), 10, 'r', false);
insetMap = new VEMap('inMap');
insetMap.LoadMap(new VELatLong(-33.7939, 151.1093), 2, 'h', true);
map.AttachEvent("onendcontinuouspan", UpdateInfo);
map.AttachEvent("onendzoom", UpdateInfo);
map.AttachEvent("onclick", MouseClick);
map.HideDashboard();
}
Finally you can add some code in the UpdateInfo method you can pan the insetMap to center on the location being shown in the main map control.
function UpdateInfo(e)
{
document.getElementById("info").innerHTML =
'Latitude = ' +
e.view.latlong.latitude +
', Longitude = '
+ e.view.latlong.longitude +
', Zoom=' +
e.view.zoomLevel;
insetMap.PanToLatLong(new VELatLong(e.view.latlong.latitude, e.view.latlong.longitude));
}
Conclusion
If you have followed along with this article you should now have a page that looks similar to that shown in Figure 1. The complete code listing is provided in Listing 7 below. If you have used previous versions of the VirtualEarth map control you will notice that even less code is needed now to carry out the same tasks.
Using the Virtual Map Control is relatively simple and it provides a very compelling user experience for mapping and location identification.
<html>
<head>
<title>My Virtual Earth</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://dev.virtualearth.net/mapcontrol/v3/mapcontrol.js"></script>
<script>
var map = null;
var insetMap = null;
function UpdateInfo(e)
{
document.getElementById("info").innerHTML =
'Latitude = ' +
e.view.latlong.latitude +
', Longitude = '
+ e.view.latlong.longitude +
', Zoom=' +
e.view.zoomLevel;
insetMap.PanToLatLong(new VELatLong(e.view.latlong.latitude, e.view.latlong.longitude));
}
var pushpinOnMap = false;
function MouseClick(e)
{
if (pushpinOnMap)
{
map.DeletePushpin(1);
}
var pin = new VEPushpin(1,
new VELatLong(e.view.LatLong.Latitude,
e.view.LatLong.Longitude),
'pin.jpg',
'My Pin',
'Text that describes my pin'
);
map.AddPushpin(pin);
pushpinOnMap = true;
}
function OnPageLoad()
{
map = new VEMap('myMap');
map.LoadMap(new VELatLong(-33.7939, 151.1093), 10, 'r', false);
insetMap = new VEMap('inMap');
insetMap.LoadMap(new VELatLong(-33.7939, 151.1093), 2, 'h', true);
map.AttachEvent("onendcontinuouspan", UpdateInfo);
map.AttachEvent("onendzoom", UpdateInfo);
map.AttachEvent("onclick", MouseClick);
map.HideDashboard();
}
function DoPanUp()
{
map.vemapcontrol.ContinuousPan(0, -10, 20, false);
}
function DoPanDown()
{
map.vemapcontrol.ContinuousPan(0, 10, 20, false);
}
function DoPanLeft()
{
map.vemapcontrol.ContinuousPan(-10, 0, 20, false);
}
function DoPanRight()
{
map.vemapcontrol.ContinuousPan(10, 0, 20, false);
}
function DoZoomIn()
{
map.ZoomIn();
}
function DoZoomOut()
{
map.ZoomOut();
}
</script>
</head>
<body onload="OnPageLoad();">
<div id="info" style="position:relative;height:50px;font-size:10pt"></div>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
<div id="inMap" style="position:absolute;top:50px;width:200px;height:200px;"></div>
<input type="button" value="Pan Up" onclick="DoPanUp()" id="PanUpButton" name="PanUpButton" style="position:absolute;left:60px;top:500px;"/>
<input type="button" value="Pan Left" onclick="DoPanLeft()" id="PanLeftButton" name="PanLeftButton" style="position:absolute;left:10px;top:530px;"/>
<input type="button" value="Pan Right" onclick="DoPanRight()" id="PanRightButton" name="PanRightButton" style="position:absolute;left:100px;top:530px;"/>
<input type="button" value="Pan Down" onclick="DoPanDown()" id="PanDownButton" name="PanDownButton" style="position:absolute;left:45px;top:560px;"/>
<input type="button" value="Zoom In" onclick="DoZoomIn()" id="ZoomInButton" name="ZoomInButton" style="position:absolute;left:250px;top:530px;"/>
<input type="button" value="Zoom Out" onclick="DoZoomOut()" id="ZoomOutButton" name="ZoomOutButton" style="position:absolute;left:340px;top:530px;"/>
</body>
</html>
Listing 7


