Johannes's profileHannes's Virtual Earth B...BlogListsSkyDrive Tools Help

Blog


    August 21

    Bing Maps & Wikipedia

    If you have been using the “Explore Collections” feature in the consumer facing implementation of Bing Maps before you may have wondered if it is possible to get this feature into your own Bing Maps implementation as well. Indeed that is possible and there is a quite simple approach. In the following walkthrough we will get specifically Wikipedia content into our Bing Maps.

    Let’s start with a closer look how the consumer side does it:

    If we go to Bing Maps and search for a location like “Tower of London” we’ll find that we can explore collections for this location.

    image

    These collections are basically a whole lot of community content that was created in Bing Maps collections, is available as GeoRSS, KML, KMZ or GPX on the internet and was found by the crawlers or is integrated from Wikipedia and Photosynth. We can filter this content, apply different sort criteria such as distance and then we could subscribe to an RSS-feed with the results.

    image

    A closer look at the RSS-feed will show that it is in fact a GeoRSS-feed and we know of course that we can import GeoRSS-feeds into Bing Maps using the VEMap.ImportShapeLayerData-method.

    image

    What we really want is however not a static feed, we want to update the results when we pan or zoom the map so let’s have a closer look at the URL of the feed:

    http://www.bing.com/maps/GeoCommunity.asjx?action=retrieverss&mkt=en-gb&ss=&bbox=-1.0073968023061534,51.42229465956134,-0.8444901555776242,51.50004927438254&startindex=0&order=distance&tag=Wikipedia

    So in fact we are calling a web service that generates the GeoRSS-feed dynamically and the parameter bbox contains the bounding box with the South-West and North-East corner of the area for which we want to retrieve the data. Well that is simple enough to implement but there is one more thing to consider: If we call a GeoRSS-feed that is in a different domain we get an annoying security warning from our browser:

    image

    To avoid this security warning we can set up a proxy as described by Mike McDougall here.

    Our HTML- and JavaScript code could look like this:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
       <head>
          <title></title>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
          <script type="text/javascript">
              var map = null;
    
              //VEShapeLayer
              var slGeoRSS = new VEShapeLayer();
    
              function GetMap() {
                  map = new VEMap('myMap');
                  map.LoadMap(new VELatLong(51.508145,-0.07626), 17, 'h', false);
              }
    
              function AddShape(control) {
                  if (document.getElementById(control).checked == false) {
                      //Delete all Shapes
                      slGeoRSS.DeleteAllShapes();
    
                      //Detach Map-Events
                      map.DetachEvent("onendpan", LoadData);
                      map.DetachEvent("onendzoom", LoadData);
                  }
                  else {
                      //Attach Map-Events
                      map.AttachEvent("onendpan", LoadData);
                      map.AttachEvent("onendzoom", LoadData);
                      LoadData();
                  }
              }
    
              function LoadData() {
                  map.DeleteAllShapes();
    
                  //Retrieve the boundaries of the mapview
                  var nePixel = new VEPixel(600, 0); //North-East corner of the map view
                  var swPixel = new VEPixel(0, 400); //South West corner of the map view
                  var neLatLon = map.PixelToLatLong(nePixel);
                  var neLat = neLatLon.Latitude;
                  var neLon = neLatLon.Longitude;
                  var swLatLon = map.PixelToLatLong(swPixel);
                  var swLat = swLatLon.Latitude;
                  var swLon = swLatLon.Longitude;
    
                  //Build URL to call the server
                  var url = "./GeoRSS-Proxy.ashx?source=http://www.bing.com/maps/GeoCommunity.asjx?";
                  url += "action=retrieverss&mkt=en-gb&ss=&bbox=";
                  url += swLon + ",";
                  url += swLat + ",";
                  url += neLon + ",";
                  url += neLat;
                  url += "&startindex=0&order=distance&tag=Wikipedia";
    
                  var veLayerSpec = new VEShapeSourceSpecification(VEDataType.GeoRSS, url, slGeoRSS);
                  map.ImportShapeLayerData(veLayerSpec, onGeoRSSLoad, false);
              }
    
              function onGeoRSSLoad(a, b) {
                  var numShapes = slGeoRSS.GetShapeCount();
                  var numPoints = 0;
                  for (var i = 0; i < numShapes; ++i) {
                      var s = slGeoRSS.GetShapeByIndex(i);
                      s.SetCustomIcon("IMG/wikipedia.gif");
                  }
              }
          </script>
       </head>
       <body onload="GetMap();">
          <div id='myMap' style="position:absolute; top:0px; left:0px; width:600px; height:400px;"></div><br />
          <div id='divCtrl' style="position:absolute; top:400px; left:0px; width:600px;" >
            <input id="cbGeoRSS" type="checkbox" onclick="AddShape('cbGeoRSS')" /><a>Wikipedia</a><br />
          </div>
       </body>
    </html>

    And here is the proxy implemented as a Generic WebHandler

    <%@ WebHandler Language="VB" Class="GeoRSS_Proxy" %>
    
    Imports System
    Imports System.Web
    Imports System.Net
    Imports System.IO
    
    Public Class GeoRSS_Proxy : Implements IHttpHandler
        
        Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
            Dim myUrl As String = ""
            myUrl = context.Request.QueryString(0)
            For i = 1 To context.Request.QueryString.Count - 1
                myUrl = myUrl + "&" + context.Request.QueryString.AllKeys(i) + "=" + context.Request.QueryString(i)
            Next
            '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(myUrl), HttpWebRequest)
            Dim response As HttpWebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
            Dim stream As StreamReader = New StreamReader(response.GetResponseStream(), Encoding.ASCII)
            context.Response.Write(stream.ReadToEnd())
        End Sub
     
        Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
            Get
                Return False
            End Get
        End Property
    
    End Class

    image

    The sample code is available here:

    Comments

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.
    Johannes Kebeck has turned off comments on this page.

    Trackbacks

    The trackback URL for this entry is:
    http://johanneskebeck.spaces.live.com/blog/cns!42E1F70205EC8A96!10073.trak
    Weblogs that reference this entry
    • None