Plotting Your Data Using Virtual Earth

Plotting Your Data Using Virtual Earth

Rate This
  • Comments 49

Jon  Hello SharePoint Designer users,

My name is Jon Campbell – I’m a developer for the SharePoint Designer team. My main job is to work on all things data oriented in SharePoint Designer. Today I thought I would share a tip on how to take your data views to the next level by combining some custom XSL transforms on the server with JavaScript on the client. Specifically, this post will go through the steps of how to make a data view that will show a set of points stored in a data source, such as a SharePoint list, on a map using Virtual Earth.

We have an XML file that contains the data that we want to plot as pushpins on the Virtual Earth map. The data can come from any data source, but for the sake of simplicity an XML file will do the job. The most important aspect of the data is that it must have both latitude and longitude so that it can be plotted. Without a latitude and longitude we would need to use an address and geocode it to the equivalent coordinates, which is outside the scope of this post. Create an XML file called locations.xml and set the contents as follows:

<?xml version="1.0" encoding="utf-8" ?>

<Locations>

      <Location lat="47.760101" long="-122.205141" name="place 1" description="A nifty place." />

      <Location lat="47.255436" long="-122.51739" name="place 2" description="A place for fun!" />

      <Location lat="47.831876" long="-122.277658" name="place 3" description="More fun!" />

</Locations>

Next, we need to be able to show the Virtual Earth map on the page. The basic requirements for doing so are including the Virtual Earth map control, creating a div tag to show the content, and then adding a basic script to use the map control to place the map into the div tag. Create a new ASPX page and switch to code view. Put the following code inside the form tag:

<script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5">    </script>

    <script type="text/javascript">

      var map = null;


// Loads the Virtual Earth map control

      function GetMap()

      {

            map = new VEMap('myMap');

            map.LoadMap(new VELatLong(47.6, -122.2), 8,'r' ,false);

            AddPin(47.7,-122.2,null,'place 1','A nifty place to be.');

      }

     

// Places a pushpin on the map using the parameters given, iconurl is ignored

      function AddPin(lat, lon, iconurl, title, desc)

      {

            var shape =

new VEShape(VEShapeType.Pushpin,

new VELatLong(lat,lon));

            shape.SetTitle(title);

            shape.SetDescription(desc);

            map.AddShape(shape);

      }

 

// Programmatically adds func as a handler for the onload event

// This method has been used by many developers, but the code is

// via the ViaVirtualEarth Wiki

// http://www.viavirtualearth.com/Wiki/Load+VE+control+without+body+onload.ashx

      function addLoadEvent(func)

      {

            var oldonload = window.onload;

            if (typeof window.onload != 'function')

            { window.onload = func; }

            else

            { window.onload = function()

                  { oldonload(); func(); }

            }

      }

      addLoadEvent(GetMap);

    </script>

    <div id='myMap' style="position:relative; width:400px; height:400px;"></div>

The last function, addLoadEvent(func), is used to run the map control’s code when the page is loaded without having to set the body tag’s onload event handler. This can be useful in situations where a master page is being used. If you preview the page, you should end up with a map like the one to the right.

Next you should insert a DataFormWebPart view of the locations.xml file that you created earlier. There are many methods for doing this, but the easiest way for what needs to be done is switch to design view and then drag it from the folders list and drop it onto the page. You can then switch back to code view. You should be able to find the XSL property of the DataFormWebPart that was created. Before the dvt_1 template, add the following XSLT:

<xsl:template name="AddMapPins">

    <xsl:param name="Rows"/>

    <xsl:text disable-output-escaping="yes"><![CDATA[

            <script type="text/javascript">

            function AddPins()

            {

            ]]></xsl:text>

    <xsl:for-each select="$Rows">

      <xsl:if test="not(normalize-space(@lat) = '' and normalize-space(@long) = '')">

        AddPin(<xsl:value-of select="@lat" />,

        <xsl:value-of select="@long" />,

        null,

        '<xsl:value-of select="@name" />',

        '<xsl:value-of select="@description"/>');

      </xsl:if>

    </xsl:for-each>

    <xsl:text disable-output-escaping="yes"><![CDATA[

            }

            </script>

            ]]></xsl:text>

</xsl:template>

That XSLT code will iterate over each of the rows in the dataset and create individual calls to AddPin() inside the AddPins() function. The AddPin() function uses the latitude and longitude from the row in the dataset as well as the name and the description attributes.

There are a couple things which need to be done in order to hook up the DataFormWebPart to the JavaScript code. The first is that the AddMapPins template won’t get called yet. To ensure that it gets called, add the following lines inside the dvt_1 template immediately after the Rows variable.

<xsl:call-template name="AddMapPins">

  <xsl:with-param name="Rows" select="$Rows"/>

</xsl:call-template>

Next, change the AddPin(…) call in GetMap() to be a call to AddPins(). The resulting GetMap() function should look like this:

function GetMap()

{

      map = new VEMap('myMap');

      map.LoadMap(new VELatLong(47.6, -122.2), 8,'r' ,false);

      AddPins();

}

If everything is correct then you should be able to preview the page and end up with the results shown in the screenshot to the right. This method demonstrates how client side script can be generated based on server side data using XSLT. Though JavaScript was used in this example, it is not unreasonable to imagine using this to drive other client side technologies like SilverLight. This won’t replace custom web parts, but it definitely opens up some interesting scenarios – especially for those in hosting scenarios or with limited posting privileges.

Enjoy,
Jon

Attachment: SampleMappingSource.zip
  • PingBack from http://www.virtual-generations.com/2007/05/24/sharepoint-link-love-05-24-2007/

  • Wow, thanks guys for this........thanks a lot.

  • Working demo on wssdemo.com using a SharePoint list to hold the lat/long data

    http://www.wssdemo.com/Pages/map.aspx

    Try adding your own locations...

  • Body: I threw together a quick demo http://www.wssdemo.com/Pages/map.aspx of the code demonstrated in

  • Hey , I dont'y have a file of latitudes/logitudes but i have plenty of addresses I'd like to map. Is there an api or web service I can use to geocode addresses. Can virtual earth take addresses rather than lat/lons?

  • When it comes to geocoding, things can get a bit complex. Depending on which mapping service you use to drive your view, you may or may not have a direct method to geocode your data. When using virtual earth, there is no straightforward way to give it an address and have it spit back lat/lon combination. There is a "FindLocation" function available, but that will center the map on that location and then you can plot your point. A way around that is to use a hidden iframe or div and load a second map in the background that you use for geocoding, similar to this article: http://msdn2.microsoft.com/en-us/library/bb259691.aspx.

    Outside of that, there are a variety of other geocoders available. If you have a small number of points that are fixed, then perhaps geocoding beforehand via http://www.batchgeocode.com/ or something similar might suit your needs. Beyond that, you would need to check out the various geocoders out there. MapPoint Web Service includes a geocoder, but many people prefer the yahoo maps implementation because of its simplicity (http://developer.yahoo.com/maps/rest/V1/geocode.html).

    With whatever service you choose to geocode your points, the basic gist of the task is the same. Rather than grabbing a lat/lon directly out of your data, you instead grab the address and feed it to a javascript function that will determine the coordinates for you and then plot the point. Make sure to do these calls asynchronously, otherwise you will lock up the browsing experience for your users.

  • Hi Folks,

    We are very interested in learning how to to this with a WSS list as the source. However, we have no idea how to do that. We have been able to get the demo to work from an xml file, just baffled about the list. Thanks.

  • janderson02 - can you detail some specifics of what you are running into? The steps should be the same for a sharepoint list as with a xml file. The DataFormWebPart acts the same whether its working against a sharepoint list, xml file, aggregate data source, or other source. If you would prefer to take it offline, you can email me directly at joncamp at microsoft dot com.

  • I downloaded the samplemappingsource.zip file and uploaded the files to a library on my sharepoint box and ran the simplemap example which worked fine.  When I run the Dynamic map I get an error.  I got this same error previously when I typed in the example…

    Unable to display this Web Part. To troubleshoot the problem, open this Web page in a Windows SharePoint Services-compatible HTML editor such as Microsoft Office SharePoint Designer. If the problem persists, contact your Web server administrator.

    However Jon helped me out by explaining that I needed to edit my aspx page to tell it where to find the xml file since I had it in a subsite and not in the "Shared Documents" library...

  • As Jeffrey noted, if you put the sample files into a place other than the root of the site then SimpleMap.aspx renders fine, but DynamicMap.aspx shows an error message. To fix this, you need to update the FilePath parameter of the SPXmlDataSource to add the DefaultValue attribute such that it contains the path to where the locations.xml file is stored. It is a site relative path, so in my case it was stored at http://testsite/mysubsite/Shared%20Documents/locations.xml. Therefore the DefaultValue for the FilePath would be “Shared%20Documents”. See the following code:

                   <DataSources>

                                   <SharePoint:SPXmlDataSource runat="server" id="locations_x002e_xml1">

                                     <DataFileParameters>

                                       <WebPartPages:DataFormParameter Name="FileName" ParameterKey="FileName" PropertyName="ParameterValues" DefaultValue="locations.xml"/>

                                       <WebPartPages:DataFormParameter Name="FilePath" ParameterKey="FilePath" PropertyName="ParameterValues" DefaultValue="Shared%20Documents"/>

                                     </DataFileParameters>

                                   </SharePoint:SPXmlDataSource>

                   </DataSources>

    If you want to use this sample with a source other than an xml file (SOAP web service, sql database, sharepoint list, etc) you will want to start from scratch rather than working from the samples. Converting the provided sample code to an arbitrary source can be done but it’s not for the faint of heart. The main reason for that is to ensure that SharePoint Designer can do the work to make sure that the basic DataFormWebPart has all the right stuff to start from in terms of data sources, basic XSLT, etc.

  • A quick note about the geocoding issue:

    The reason why FindLocation is unsuitable for the purpose described in this post is that it causes the map to be centered on the point that is found as a result of the call. Because of that, if you are plotting multiple points it causes the map to jump around for every address. The solution described in the msdn article that I linked to above (http://msdn2.microsoft.com/en-us/library/bb259691.aspx) is to use a second hidden map to find each address.

    If you only want to show a single address then the built in geocoding will work just fine. You can simply call FindLocation with your address data, then add a pushpin at the center of the map. This works great if you are trying to make a detail page for a contact in your address book.

  • Hi everyone, My name is Greg Chan and I’m a Program Manager in the SharePoint Designer team. I’ve also

  • Help me please! I have an Address Lists (about 400 addresses) and I want to display them in Virtual Earth. How to display many addesses by adding pushpin in VE ?

  • Dacle - the easiest solution is probably to use something like http://www.batchgeocode.com/ to give you the lats/longs for the addresses, then add them as extra columns on a sharepoint list. If your data is in sql or something and you don't have the ability to add the data to the source, you can create a parallel list and use an aggregate datasource to correlate the lat/long with the address.

  • Feature extensions to the WSS blog site template TheKid.me.uk extends the wss blog template - Check it

Page 1 of 4 (49 items) 1234
Leave a Comment
  • Please add 5 and 8 and type the answer here:
  • Post