How to Integrate Virtual Earth Maps with a SharePoint List

How to Integrate Virtual Earth Maps with a SharePoint List

Rate This
  • Comments 99

Greg Hi everyone,

My name is Greg Chan and I’m a Program Manager in the SharePoint Designer team. I’ve also been involved in the development and testing of the Application Templates for Windows SharePoint Services 3.0. Just a couple weeks ago, I attended Tech Ed in Orlando and presented a breakout session called "Designing and Building Sophisticated Composite Applications with Microsoft Office SharePoint Designer 2007".

Today, I’ll show you how to integrate the Virtual Earth Map control with your SharePoint list. This is actually part of the demo I gave in Tech Ed, and it has generated a lot of interest. Many of you have requested more information on this, so as promised, I’m dedicating this post to it. Some of you may be wondering… "Isn’t this the same as the Plotting Your Data Using Virtual Earth blog that Jon Campbell posted awhile back?" While there are overlaps, the key difference is that this post will talk about plotting a single address as opposed to multiple addresses.  A big benefit for doing single address is that Virtual Earth is good at plotting a single address without the need for longitudes and latitudes.  We simply need to pass in the address value and take advantage of functions provided by Virtual Earth to geocode it. (I don’t know about you, but when I search for driving directions, I’m not typing in longs and lats...)

Let's get started!

Here’s the scenario -- you own a bike shop and use a SharePoint site to manage the manufacturing process for building bicycles. In your site, you have a Suppliers list that stores information about each of your supplier like phone number, address, e-mail, etc. The list is based off the Contacts list. You want to insert a map control inside the display form for each supplier to show the location of the supplier.

Step 1 - Modifying the Display Form

Open in SharePoint Designer the display form (DispForm.aspx) of the SharePoint list containing the address information. Then, we want to use the data view to generate the map. (Yet another reason why we call data view the swiss army knife of web parts...) Below are the detailed steps to do this:

  1. In SharePoint Designer, open up DispForm.aspx under the Suppliers folder.
  2. Bring up the Data Source Library task pane.
  3. Select the Suppliers list and drag it onto the design surface, below the default list form controls.
  4. Bring up the Common Data View Tasks menu for the data view.
  5. Pick the Filter option.
  6. In the Filter Criteria dialog:
    1. Field Name = ID
    2. Comparison = Equals
    3. Value = Create a new parameter
  7. In the Data View Parameters dialog:
    1. Name your parameter (i.e. SupplierID)
    2. Parameter Source = Query String
    3. Query String Variable = ID
    4. Default Value = 36 (optional, I prefer to enter a # that maps to an item that I know already exists in my list)
  8. Hit OK and OK.

Note - All standard SharePoint forms contain an ID parameter in the query section of the URL:

http://<site_name>/Lists/Suppliers/DispForm.aspx?ID=36

Each item in a SharePoint list is mapped to a unique ID value. This ID value is what we're using to filter the data view.

As a result, we’ve just inserted a data view of the suppliers list that is filtered down to show ONLY the current supplier and not all other suppliers. Right now, the data view is still rendered as a table by the default XSLT. Next step, we’re going to write custom XSLT and JavaScript to format the data view as a map!

Step 2 - Use custom XSLT + JavaScript to create Virtual Earth Map control

In order to create the Virtual Earth Map control, we’ll need to utilize some JavaScript functions provided by the Virtual Earth SDK. Below are JavaScript snippets that we need.

Load the map

var map;

 

// Loads the Virtual Earth map control

function loadMyMap() {

            map = new VEMap(&&apos;myMap&apos;);

            map.LoadMap();

            map.FindLocation &apos;<xsl:value-of select="@WorkAddress" />,     <xsl:value-of select="@WorkCity" />, <xsl:value-of select="@WorkState" />,  <xsl:value-of select="@WorkZip" />&apos;, displayPushPinCallBack);

}

FindLocation() will take the address values passed in and center the map to that location. This is a great function! For the function parameters, we’re passing in the XSL values of the Address, City, State and Zip Code field of the supplier.

Add the pushpin

function displayPushPinCallBack() {

      var pin = new VEPushpin(

          1,

          map.GetCenter(),

          null,

          &quot;<xsl:value-of select="@Title" />&quot;,

          &apos;&apos;

          );

       map.AddPushpin(pin);

}

GetCenter() will return the longitude and latitude values of the center of the map, which is currently the location of the address you passed in from FindLocation(). We’re also passing in the XSL value of the Title field of the supplier.

The entire XSL stylesheet

Here’s the entire XSL that we will use to format the data view into a Virtual Earth Map control.

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

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="html" indent="no"/>

  <xsl:template match="/">

    <xsl:call-template name="dvt_1"/>

  </xsl:template>

  <xsl:template name="dvt_1">

    <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />

    <xsl:call-template name="dvt_1.body">

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

    </xsl:call-template>

  </xsl:template>

  <xsl:template name="dvt_1.body">

    <xsl:param name="Rows" />

   

    <!-- Link to the Virtual Earth Map control JS file -->

    <script src="http://dev.virtualearth.net/mapcontrol/v4/mapcontrol.js">

    </script>

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

      <xsl:call-template name="dvt_1.rowview" />

    </xsl:for-each>

  </xsl:template>

  <xsl:template name="dvt_1.rowview">

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

    <script type="text/javascript">

 

      _spBodyOnLoadFunctionNames.push(&quot; loadMyMap &quot;);

      var map;

      // Loads the Virtual Earth map control

      function loadMyMap() {

          map = new VEMap(&apos;myMap&apos;);

          map.LoadMap();

          map.FindLocation(&apos;<xsl:value-of select="@WorkAddress" />,

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

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

<xsl:value-of select="@WorkZip" />&apos;, displayPushPinCallBack);

      }

      function displayPushPinCallBack() {

          var pin = new VEPushpin(

            1,

            map.GetCenter(),

            null,

            &quot;<xsl:value-of select="@Title" />&quot;,

            &apos;&apos;

          );

          map.AddPushpin(pin);

      }

    </script>

  </xsl:template>

</xsl:stylesheet>

  • _spBodyOnLoadFunctionNames() adds a function to the onload event of the body element. This ensures that loadMyMap() is called whenever the display form is loaded. The Using Javascript to Manipulate a List Form Field blog has a more detailed description of this.
  • The actual XSL is pretty basic. We’re simply using XSL to generate the <div> container for the map control and also passing in XSL values for the JavaScript function calls.

Next thing you'll want to do is take that entire XSL stylesheet and save it out as a separate XSL file. This will make things a lot cleaner and easier to manage. We'll save this out into a file called LiveMaps.xsl, and store it in the folder for the Suppliers list, along with the DispForm.aspx.

Step 3 - Format the data view using LiveMaps.xsl

Now we want to use LiveMaps.xsl to render the data view.

  1. Go back to DispForm.aspx in SharePoint Designer.
  2. Right-click on the data view, which is a Data Form Web Part.
  3. Select Web Part Properties.
  4. Expand the Miscellaneous category.
  5. For XSL Link, click on the button to the right of the input field.
  6. Navigate to the LiveMaps.xsl file and select it.

All Done!

Back on the browser, when you go to the display form of any supplier, there’ll be a great map view that will show you the location of the supplier. You’ll be able to interact with the map, just like you would on http://local.live.com.

Thanks,

Greg

  • Any chance you can upgrade this code for V6??  I am attempting ... can load the map but still working on the pushpins.   Thanks!

  • Direkter Download: SPPD-074-2007-07-12 [00:00] Intro [00:00] Buchtipps Microsoft Office SharePoint Server

  • I can't get this to work with V 6 either. some tips would be greatly appreciated.

    Dean

  • I got it to work with V6 -- make sure that your id='myMap' is not changed to {generatedID}.

    But, when I mouseover my pin the popup is not displayed next to the pin. The popup for the title and description is displayed outside of my VE map.

    Any ideas?

    Thanks

  • I've been needing something like this for some time now.  Greg and everyone else here, great work!  I'll throw you a bone if needed as I had to play with the SDK to get mine to work the way I wanted.  I had to create one menu for my users so that they wouldn't attempt to install VE 3D as it's not needed.  Ryan had some good ideas for making this reuseable as it's nice to have a template without having to tweak the code all the time.

    FULL MENU VE v.6

    _______________________________________________________________________________

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

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ddwrt2="urn:frontpage:internal">

     <xsl:output method="html" indent="no"/>

      <xsl:template match="/" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">

        <xsl:call-template name="dvt_1"/>

     </xsl:template>

      <xsl:template name="dvt_1">

        <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />

        <xsl:call-template name="dvt_1.body">

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

        </xsl:call-template>

     </xsl:template>

      <xsl:template name="dvt_1.body">

        <xsl:param name="Rows" />

       <!-- Link to the Virtual Earth Map control JS file -->

       <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6"></script>

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

          <xsl:call-template name="dvt_1.rowview" />

       </xsl:for-each>

     </xsl:template>

      <xsl:template name="dvt_1.rowview">

       <div id='myMap' style="position:absolute; width:635px; height:220px;"></div>

       <script id="myMap" style="position:absolute; width:635px; height:220px;">

         _spBodyOnLoadFunctionNames.push("GetMap");

         var map = null;

         // Loads the Virtual Earth map control

         function GetMap() {

             map = new VEMap('myMap');

             map.LoadMap();

             map.Find(null,'<xsl:value-of select="@WorkAddress" />,<xsl:value-of select="@WorkCity" />,<xsl:value-of select="@WorkState" />,<xsl:value-of select="@WorkZip" />', null, null, null, null, null, null, null, null, callback);

         }

         function callback() {

             var pin = new VEShape(VEShapeType.Pushpin, map.GetCenter());

             pin.SetCustomIcon();

             pin.SetTitle("<xsl:value-of select="@Company" />");

             pin.SetDescription("<xsl:value-of select="@WorkCity" />, <xsl:value-of select="@WorkState" />");

             map.AddShape(pin);

         }

       </script>

     </xsl:template>

    </xsl:stylesheet>

    SMALL MENU VE v.6

    _______________________________________________________________________________

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

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ddwrt2="urn:frontpage:internal">

     <xsl:output method="html" indent="no"/>

      <xsl:template match="/" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">

        <xsl:call-template name="dvt_1"/>

     </xsl:template>

      <xsl:template name="dvt_1">

        <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />

        <xsl:call-template name="dvt_1.body">

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

        </xsl:call-template>

     </xsl:template>

      <xsl:template name="dvt_1.body">

        <xsl:param name="Rows" />

       <!-- Link to the Virtual Earth Map control JS file -->

       <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6"></script>

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

          <xsl:call-template name="dvt_1.rowview" />

       </xsl:for-each>

     </xsl:template>

      <xsl:template name="dvt_1.rowview">

       <div id='myMap' style="position:absolute; width:635px; height:220px;"></div>

       <script id="myMap" style="position:absolute; width:635px; height:220px;">

         _spBodyOnLoadFunctionNames.push("LoadSmall");

         var map = null;

    // Loads the Virtual Earth map control with the Small Toolbar

         function LoadSmall() {

             if (map!=null) {

             map.Dispose();

         }

             map = new VEMap('myMap');

             map.SetDashboardSize(VEDashboardSize.Small);

             map.LoadMap();

             map.Find(null,'<xsl:value-of select="@WorkAddress" />,<xsl:value-of select="@WorkCity" />,<xsl:value-of select="@WorkState" />,<xsl:value-of select="@WorkZip" />', null, null, null, null, null, null, null, null, callback);

         }

         function callback() {

             var pin = new VEShape(VEShapeType.Pushpin, map.GetCenter());

             pin.SetCustomIcon();

             pin.SetTitle("<xsl:value-of select="@Company" />");

             pin.SetDescription("<xsl:value-of select="@WorkCity" />, <xsl:value-of select="@WorkState" />");

             map.AddShape(pin);

         }

       </script>

     </xsl:template>

    </xsl:stylesheet>

    _______________________________________________________________________________

    Hope this helps out those in need.

  • I have one task I'd love to take on and I'm not certain how to harvest the information and return the results onto a VE map using WSS data.  I re-wrote the xsl above for v6 and it's doing what I want for one data record.  What I want to do is take a small list of several projects which include address data and plot them on a VE map but the above code only works with one record.  Is there a way to pin multiple entries on a single map using WSS data?

    Please let me know awclayton77@msn.com

    Thanks in advance!

  • Anthony - That question comes up a lot. The basic gist is to use something similar to http://blogs.msdn.com/sharepointdesigner/archive/2007/05/23/plotting-your-data-using-virtual-earth.aspx#comments combined with elements of this post as well. My suggestion would be to use the following formula:

    0) start with your map hidden, perhaps with a loading image or something

    1) Use a DFWP to generate an array of javascript structures, one for each address

    2) call findlocation for the first address, specifying a callback that stores the lat/lon

    3) in the callback, if there are more points to plot then call findlocation on the next point

    4) if no more points are left, then plot them all

    Its not ideal, but it does work. The best solution would be to use some custom code to agressively cache the geocoded points and re-use that data when possible, but the above process should work for those without the ability to deploy custom code.

  • I need immediate help in getting this working. I get "this web part doesnt have a valid XSLT style sheet getting Live SSL from Server". Any help is highly appreciated. Thanks in advance.

  • I was able to plot multiple lists directly from a SP List vs. XML list using Jon Campbell's help at http://blogs.msdn.com/sharepointdesigner/archive/2007/05/23/plotting-your-data-using-virtual-earth.aspx

    Essentially I built the page as he states but substituted the XML data source with a data source library list from my SP site and it worked.

    Thanks again to all.

  • Hi folks. This is Greg Chan, Program Manager in the SharePoint Designer team. For those of you who attended

  • Mine is blowing out the div and going full screen... Anyone have this issue and resolve it?

  • Dave: A common reason for the map to go full sceen is when the "overflow:hidden" is not set. Try setting that on your map's div - it may solve the issue.

  • I would like to know if there is a way to intergrate your outlook contact list to the Virtual Earth so when you update the contact list it updates the collection on Virtual Earth. Anyone have any ideas on how this is done?

  • HI all

    ..

    i need help i am working on the look and feel of the page .

    what i have done is i have copied a default theme(verdant)and made changes to the

    Cust1011-65001.css and replace the content of "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\THEMES\CustomBrown\theme.css

    the changes are seen when the changes are made but when i replace the content of "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\THEMES\CustomBrown\theme.css

    and when perform the application pool recycle of that web application and when i opened the Cust1011-65001.css file the number of lines of code got increased by itself and copy of ms-pagetitle was seen  with the default  url of the image even after mnaking the changes again and again

    please help

    shiva.....

  • I have been using the Virtual Earth control a lot lately for various demos, mostly by putting customized

Page 4 of 7 (99 items) «23456»
Leave a Comment
  • Please add 6 and 2 and type the answer here:
  • Post