In the first part we have been looking at some general resources to get started with your Virtual Earth development and in the second part we created an AJAX-enabled ASP.NET web site which will host our various samples. We also added the first type of content - the individual VEShape - which was in this case a pushpin with a traffic cam-image in the infobox. Now we are going a step further and will*import a number of various information into a VEShapeLayer. There are 2 ways how to do this:

  • Import from a Live Search Maps Collection and
  • Import from an GeoRSS-feed

Live Search Maps Collections

Live Search Maps is the consumer facing implementation of Virtual Earth. It uses a variety of features from the Virtual Earth API and adds a number of further features which are specific to this implementation and may even be specific to a market. For example: traffic overlays are currently only available in the United States and so are the features 'Call for free' and 'Send to mobile' which are*accessible from*the results of a business search. One*very nice*feature is however available for all markets: the Collections.

Tip: If you want to see these market-specific features*add the following URL-parameters: http://maps.live.com/?mkt=en-us

You can add the results of your searches to a scratch pad and you can even add drawings of type point, polyline or polygon to this scratchpad. These annotations to the map can contain URLs to images or further information. To make the content of the scratch pad persistent you can sign-in with your Windows Live ID and store them in a collection. Such collections can be private or shared and you can make them optionally searchable - a great feature to enhance the user experience of Live Search Maps by adding local knowledge to the global community. Here I have have such a collection for the London Bus Tour.

07-small

If*you want to share the collection you can use the menu of the scratch pad to do so. You can directly blog it, you can send the URL in an email or you can just copy it to the clipboard. What you get in any case is a tiny URL with a parameter for a Collection ID like shown*here:*http://maps.live.com/?v=2&cid=42E1F70205EC8A96!837&encType=1. While this is extremely simple to use, you might also want to make use of these collections in your custom application with your personal*branding or corporate identity. The Virtual Earth API supports the import of such collections into a VEShapeLayer and we will extend our existing AJAX-enabled application from part 2 and walk through the steps which are required to do that and.

First we add a new a AccordionPane to our ASP.NET AJAX web site. Within this pane we have a HTML-control of type checkbox and we define an onclick event for the control which calls the JavaScript-function AaddGCLayer with a couple of parameters. We will discuss these parameters a little bit later.

<ajaxToolkit:AccordionPane ID="paneCollection" runat="server">
<Header>Collection LayerHeader>
<Content>
<input id="cbLondonBus" type="checkbox" onclick="AddGCLayer('cbLondonBus',LondonBusLayer,VEDataType .VECollection,'42E1F70205EC8A96!837')" />London Bus Tour<br />
Content>
ajaxToolkit:AccordionPane>

Now let's look at the JavaScript part. In the global section we define a new VEShapeLayer in which we will import the collection

var LondonBusLayer = new VEShapeLayer();

The function AddGCLayer will import the Live Search Maps collection into this layer. It is a very generic script which will allow us to import not only collections but also GeoRSS-feeds. The parameter we use to call this function are:


  • the name of the HTML-control which is being clicked. This is just used to determine later if the checkbox has been activated or de-activated.
  • The name of the layer we want to import into
  • the VEDataType of the data source we want to import into VEShapeLayer. It is a mandatory property for the VEShapeSourceSpecification. Valid properties are VECollection and GeoRSS. The former is what we need here.
  • The collection ID if it is a VECollection or the URL if it is a GeoRSS feed

In the function we first check if the checkbox has been activated or deactivated. If it has been deactivated we remove all VEShapes from this particular layer. If it has been activated we add define the VEShapeSourceSpecification*with the parameters mentioned above and then import the data into the layer.

function AddGCLayer(control, layer, type, url)
{
if (document.getElementById(control).checked == false) {
layer.DeleteAllShapes();
}
else {
currentLayer = layer;
var layerSpec = new VEShapeSourceSpecification(type, url, layer);
map.ImportShapeLayerData(layerSpec,onGCLoad);
}
}

You also see that we define a callback-function when we execute the method ImportShapeLayerData. This*is an optional parameter and allows us e.g. to modify the data once we imported*them. In our example I want to use this function to replace the default icons with a numbered pushpin. To do that we first determine the number of VEShape-objects in our VEShapeLayer. Then we loop through all the VEShape-objects and set a custom icon. Our icons are not just defined by an image but also by a text-field which we will populate with*a number.

function onGCLoad()
{
var numShapes = currentLayer.GetShapeCount();
for(var i=0; i < numShapes; ++i)
{
var s = currentLayer.GetShapeByIndex(i);
s.SetCustomIcon("
" + (i+1) + "
"
);
}
}





Tip: If you want to debug your JavaScript in Visual Studio and your default browser is the Internet Explorer you may want to uncheck 'Disable script debugging (Internet Explorer)' in the advanced tabulator of the Internet Explorer options dialog. Now you can set breakpoints in your JavaScript and debug the code in the same*fashion as you do with .NET-managed code.
10-small

All right, that's it we can now see our Live Search Maps Collection in our custom Virtual Earth application.

09-small

GeoRSS-deeds

Since the methods to add a GeoRSS-feed are exactly the same as the ones which are being used to add a Live Search Maps collection we will add such a sample in this part as well.

GeoRSS is an extension to the well known Real Simple Syndications (RSS). It adds tags for the location information but unfortunately a unique standard has not yet*been established. Virtual Earth support the simple specification according to GeoRSS.org as well as the GML-specification as suggested by the Open Geospatial Consortium (OGC). Both of them support points, polylines and polygons. Let's have a look at such a feed. You see below that there is actually just one tag more than in a typical RSS-feed.

xml version="1.0"?>
<
rss version="2.0"
xmlns:georss="http://www.georss.org/georss"
xmlns:gml="http://www.opengis.net/gml">
<
channel>
<
item>
<
title>My Pointtitle>
<
link>link>
<
description>description>
<
georssoint>51.449139537118 -1.0529091954231georssoint>
item>
<
item>
<
title>My Linetitle>
<
description>description>
<
georss:line>51.46138386849 -0.9245842695236 ... 51.4492130864 -1.0533142089843georss:line>
item>
<
item>
<
title>My Polygontitle>
<
description>description>
<
georssolygon>51.46221441192 -0.9249061346054 ... 51.46221441192 -0.9249061346054georssolygon>
item>
channel>
rss>

The items in such a GeoRSS-feed are described within XML-tags so it is pretty simple to create your own parser if your source data is available e.g. in your existing MapPoint-files or in a database. In a later part we will have a look at how to create these GeoRSS-feeds directly from SQL Server 2008 (the one with the spatial engine). However, if you*want to reuse your existing spatial-data it is more complex and you would probably look at tools like Safe FME. Safe FME can read more than 200 spatial formats and*has a huge number of useful transformers e.g. to generalize the*geometries*(node-thinning) or to convert coordinate systems. Another tool which reads spatial data from GML, AutoDesk (*.dxf), ESRI (*.shp) and MapInfo (*.mif) as well as KML-files is the GeoFeeder from BRIGHTisolutions. It doesn't have the rich functionality of Safe FME but depending on your requirements it*might be a*cost-efficient solution.
11-small

Now let's take the GeoRSS-feed as given and implement an example in our sample web site. First we add another AccordionPane to our web site. You see that we call the same JavaScript-function as before but there are 2 differences in the parameters:


  • We use VEDataType.GeoRSS instead of VEDataType.VECollection and
  • We point the URL to our GeoRSS-feed rather than to a collection id
<ajaxToolkit:AccordionPane ID="paneGeoRSSLayer" runat="server">
<Header>GeoRSS LayerHeader>
<Content>
<input id="cbLCZ" type="checkbox" onclick="AddGCLayer('cbLCZ',LCZLayer,VEDataType.GeoRSS,'Geo RSS/LondonCongestionZone.xml')" />London Congestion Zone<br />
Content>
ajaxToolkit:AccordionPane>

As mentioned before the JavaScript part is exactly the same we are just declare one more layer in our global section

var LCZLayer = new VEShapeLayer();

This is already it. We have our first GeoRSS-feed in*our sample*application

12-small

Virtual Earth has unfortunately one limitation in the usage of GeoRSS-feeds: the GeoRSS-feed has to be on the same domain as your Virtual Earth application. Well that is usually not a problem if you just use your own data but if you want to leverage all the great information which are on the web available*as GeoRSS-feeds it can be quite disappointing. There is however a nice workaround which has been published by Mike McDougall from BRIFGTisolution on Via Windows Live. It basically uses a generic Web Handler as a proxy to execute an HTTPWebRequest to the GeoRSS-feed in the external domain. We will implement this workaround within a try ... catch clause to overlay an GeoRSS-from Flickr.

In the content part of our AccordionPane we add another HTML-control of type checkbox which uses the URL to the Flickr-feed as parameter

<input id="cbFlickr" type="checkbox" onclick="AddGCLayer('cbFlickr',FlickrLayer,VEDataType.GeoRS  S,'http://api.flickr.com/services/feeds/geo/?tags=ufo&lang=en-us&format=rss_200')" />Flickr<br />

In the global part of our JavaScript we define another layer

var FlickrLayer = new VEShapeLayer();
And then we*extend our existing JavaScript AddGCLayer*with the try ... catch clause so that we redirect to our WebHandler if we hit the error "Permission denied".
function AddGCLayer(control, layer, type, url)
{
if (document.getElementById(control).checked == false) {
layer.DeleteAllShapes();
}
else {
try
{
currentLayer = layer;
var layerSpec = new VEShapeSourceSpecification(type, url, layer);
map.ImportShapeLayerData(layerSpec,onGCLoad);
}
catch(err)
{
if (err.message="Permission denied")
{
var proxyPath = "GeoRSSProxy.ashx?source=" + url;
currentLayer = layer;
var layerSpec = new VEShapeSourceSpecification(type, proxyPath, layer);
map.ImportShapeLayerData(layerSpec, onGCLoad);
}
}
}
}

Now that this redirection is prepared we need to add of course our WebHandler. We call it GeoRSSProxy, imports the following namespaces:


  • Imports System.IO
  • Imports System.Net

...and replace the default-code in 'Public Sub ProcessRequest' with the code below

Dim source As String = context.Request.QueryString("source")
context.Response.ContentType = "text/xml"
context.Response.ContentEncoding = System.Text.Encoding.UTF8

Dim request As HttpWebRequest = DirectCast(HttpWebRequest.Create(source), HttpWebRequest)
Dim response As HttpWebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
Dim stream As StreamReader = New StreamReader(response.GetResponseStream(), Encoding.ASCII)
context.Response.Write(stream.ReadToEnd())

Here we go:

13-small*

You can preview and download the complete source code here.



Click here to view the article.