This example comes from Steve Lombardi’s blog post last year and has been updated to the latest version of Virtual Earth at the time of writing. The code and collection was presented at the Museums and the Web conference in Montreal, Canada.
In the space of 10 minutes you can present a custom collection presented on the Virtual Earth platform within your own web site by leveraging http://maps.live.com as your content editor and storage and using the Virtual Earth API. Here we present the simple code to do this and some extra features like a map search, custom numbered icons and an outline text listing with clickable titles.
To begin, navigate to http://maps.live.com. This is Microsoft’s consumer mapping site built on top of the Virtual Earth API but with many more features. Here you can sign in using live ID and add pushpins, polylines, polygons and even 3D models to a collection. For example add some pushpins of famous landmarks in your area, add textual description, an image and a link to further information. Now save your collection and make it public. Here is an example of some landmarks around Montreal:
http://maps.live.com/?v=2&encType=1&cid=5CB0B41C15FA0196!437
Most of the hard work is now done, you have an interface to create and edit your content and share it with the world via GeoRSS, KML or as a VE collection. We will use the last option for this example. In order to access the VE collection you have made we need the collection ID, I find the easiest way to retrieve this is from the Actions -> Send to -> email in the collections panel. The link provided in the email contains the collection ID we will need it will look something like this (Note the exclamation point and following digits are part of the ID):
http://maps.live.com/?v=2&encType=1&cid=5CB0B41C15FA0196!437
The Virtual Earth API is a JavaScript file, hosted by Microsoft. In order to be compatible with many of its features you must set your page doctype to XHTML and use UTF8 encoding. The following shows a complete HTML page, the import of our collection, creation of a text outline listing, custom icons and a custom location search. The important concept here is the asynchronous nature of this technology, you must hook into events that fire when actions complete. The sequence we will follow here is:
- Page Body loads -> load the map
- Map Loads -> load the collection
- Collection Loads -> change the icons and make the text outline with links
<!--Set the doctype to be XHTML--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>The 10 Minute Map</title> <!--Set the Character set to UTF8 --> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <!--Add your style sheet to make it look pretty--> <link type="text/css" rel="stylesheet" href="styles.css" /> <!--Include the latest Virtual Earth Control--> <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script> <script type="text/javascript"> //Global varible for our map object var map = null; //Once the Page (DOM) has completly loaded we can create our map function Page_Load() { //First we create our object passing the ID of the Div for our map map = new VEMap('mymapdiv'); //Next we set the function to execute once the map has loaded map.onLoadMap = fnLoadCollection; //Now we load the map map.LoadMap(); } //When the map has loaded we can load our collection function fnLoadCollection() { //set a loading label document.getElementById('outline').innerHTML = "<b>Loading Collection...</b>"; //import our layer //First we create a new layer var layer = new VEShapeLayer(); //Then add this new blank layer to the map map.AddShapeLayer(layer); //Then we create a ShapeSourceSpecification, here we use a VECollection, pass its ID and our new layer. var veLayerSpec = new VEShapeSourceSpecification (VEDataType.VECollection, "5CB0B41C15FA0196!437", layer); //finally we call the import method, when it is finished we can access the data, we also set the map to show the best fit map.ImportShapeLayerData(veLayerSpec, fnLayerLoaded, true); } //When our collection layer has loaded we can access its data function fnLayerLoaded(layer) { //build up a HTML string to give a text outline of all the items var outline = ""; //how many items are in our collection? var totalShapes = layer.GetShapeCount(); //loop through them all building our HTML and changing to a custom Icon based on their index for (var cnt=0;cnt < totalShapes; cnt++) { //get the actual shape object by its index var shape = layer.GetShapeByIndex(cnt); //create some HTML var lnk = "<a href='#' onclick='javascript:map.SetCenterAndZoom(new VELatLong(" + shape.GetPoints()[0].Latitude + "," + shape.GetPoints()[0].Longitude + "),16);'>"; outline = outline + "<b>" + lnk + (cnt+1) + ". " + shape.GetTitle() + "</a></b><br><img src='" + shape.GetPhotoURL() + "' style='width:200px' /><br />" + shape.GetDescription() + "<br><br>"; //Update each Pushpins Icon to be a numbered circle. shape.SetCustomIcon("http://dev.virtualearth.net/legacyService/i/bin/1.3.1204222815.33/pins/RedCircle" + (cnt+1) + ".gif"); } //set our outline text document.getElementById('outline').innerHTML = outline; } //A simple event to trigger a map search function SearchClick() { //here we search for a location (where) so the first parameter (what) is null. map.Find(null, document.getElementById('txtFind').value); } //When the page unloads we dispose the map object to free up memory function Page_Unload() { if (map) {map.Dispose();} } //set page event handlers if (window.attachEvent) { window.attachEvent("onload", Page_Load); window.attachEvent("onunload", Page_Unload); } else { window.addEventListener("DOMContentLoaded", Page_Load, false); window.addEventListener("unload", Page_Unload, false); } </script> </head> <body> <div class="title">The 10 Minute Map</div> <div> <input id="txtFind" type="text" name="Find" size="30"/> <input id="btnSearch" type="button" value="Find Place" name="Search" onclick="return SearchClick()"/> </div> <div id="mymapdiv" style="height:500px;width:600px;overflow:hidden;position:relative"></div> <div id="outline"></div> </body> </html>
In your application move all the JavaScript code into another file, this will keep it tidy, maintainable and allow browsers to cache it on future requests.
See the final page in action here:
http://www.soulsolutions.com.au/legacyimages/10minmap/10minutemap61.htm