Surveying in Virtual Earth

Many organizations now use polls and surveys to get information about their end users and evaluate how they are perceived in the market.  Another common thing that surveys are used for is to gather demographic information.

In Auckland there is some talk about a second .Net User Group.  So to help get an idea of where people are going from, coming too and what sort of location would be good for a .Net User group I wrote a simple survey tool in Virtual Earth to figure out where people live and where they work.

This solution is currently not in use in the wild, however, I thought I'd put the code up here as it is quite a cool way of getting information from users and adding it to a database.

Firstly I've constructed this as a HTML page, but you could modify it to work in an ASP.Net page pretty easily.  I've also set the form to post to another page rather than handle that in the same page -but again, you could modify the behavior of this to suit.

So - to get started have a look at the SDK at https://dev.live.com/virtualearth/sdk - its interactive - tell it what you want and it spits out the code.  The following is really just a hashing together of the elements that are needed.

The concept of this solution is that the user can right click on the map to place a push pin - when they do this they get the option to specify whether the push pin indicates where they work or live.  They select one which makes a permanent push pin appropriately labeled in the specified location.  In addition the Lat/Long coordinates of the location is logged to the text boxes at the bottom of the form.  In the real world, you'd probably want to hide these, but they are shown here for demo purposes.

Firstly, you'll want to put together the basics of the page.  The base page is pretty simple and looks like this:

The first thing to add is the line for the Virtual Earth map script, some textboxes for the coordinates and the form to do the submit.  After this it looks like this:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="https://www.w3.org/1999/xhtml">
 <head>
  <title>Virtual Earth Survey</title>

   <script type="text/javascript" src="https://dev.virtualearth.net/mapcontrol/v4/mapcontrol.js"></script>        </head>

   <body>
   <h3>Darryl's quick survey tool.</h3>
   <p>Zoom in to where you work and live, then right click to place a push pin and set the location.</p>
    <form id='whereamiform' action='somepage.html' onsubmit ='return dosubmit()'> 
   <div id='myMap' style="position:relative; width:400px; height:400px;"></div>   
   Home Latitude: <input type="text" id="lat1" name="lat1" /><br  />   Home Longitude: <input type="text" id="long1" name="long1" /><br 
 />   Work Latitude: <input type="text" id="lat2" name="lat2" /><br 
 />   Work Longitude: <input type="text" id="long2" name="long2" /><br 
 />   <input type='submit' value='Save' style='display:none' id='cmdSave' name='cmdSave'  
 />   </form
 > 
   </body>
</html>

The script line is the map controls used by Virtual Earth.  All the mapping commands you'll use are in here - its essentially the API.  Next you'll also notice I've put in the boxes for the Latitude and Longitude and a form with a save button to send the data to the "somepage.html" page that will handle the postback - although you'll notice that the button is hidden by style.

Lets add some code.  Firstly we need to modify the body tag to read: <body onload="GetMap();">

We also need to add the GetMap function to the head of the document.  This is a simple piece of javascript that looks like this:

     function GetMap()
    {
        map    = new VEMap('myMap');
        map.LoadMap(new VELatLong(-41.28259567324982, 174.77662324905393), 12 ,'r' ,false);
    }

The LoadMap function takes a Latitude/Longitude argument, a zoom (from 1-16), the type of map ('r' = road, 'h'=hybrid, etc) and the last one is to show whether the map is fixed so the user cannot change it. More details and options on the LoadMap call are here. You should now be able to load the page and you should have a map appear on the page.

To make the context menu appear we need to Attach an event to the map.  The Virtual Earth API allows you to add your own events pretty easily.  The following line at the end of the GetMap() function will do this for us:

         map.AttachEvent("oncontextmenu", AddMyPin); 

This will cause the AddMyPin() function to be called whenever the context menu is called - that is when the right mouse button is clicked.  Next I'm going to add some variables which we'll use later on - these go before the GetMap() function:

     var map = null;
    var pinID = 1;
    var workPin;
    var homePin;

Next we need to make AddMyPin() do something useful.  My AddMyPin() function looks like this:

     function AddMyPin(e)
    {
        var pin = new VEPushpin(
            pinID,
            new VELatLong(e.view.LatLong.Latitude, e.view.LatLong.Longitude),
            null,
            'Locating me...',
            '<a href="javascript:AddWork('+e.view.LatLong.Latitude+','+e.view.LatLong.Longitude+','+pinID+')">This is where I work</a><br /><a href="javascript:AddHome('+e.view.LatLong.Latitude+','+e.view.LatLong.Longitude+','+pinID+')">This is where I live</a>'
            );
        map.AddPushpin(pin);
        pinID++;
    }

Thats is pretty ugly.  What I'm doing here is adding a new pushpin.  the Pushpin takes a bunch of arguments - which are in order: the pin number (for easy identification later), the location of the pin (in this case the latitude/longitude that the user clicked - which was sent as part of the event argument "e"), the icon for the pushpin image (null = default), the Title of the call out and the text for the call out.  In the Text for the call out, I've put in some pretty ugly javascript.  What this gives the user is two hyperlinks to click - each of these hyperlinks calls another function depending on whether they select the "work" hyperlink or the "home" hyperlink.  There are other arguments you could add to this - more details here.

Next we need to add the functions that clicking these links will call.  There are three functions - one for home, one for work and one which checks whether to display the save button or not.  You could probably reduce this to just one function pretty easily by adding some more variables to the function call, but for the sake of simplicity, here are my functions:

     function AddWork(e,f,pinNum)
    {
        try
        {
            map.DeletePushpin(workPin);            
        }
        catch (err)
        {
        }
        map.DeletePushpin(pinNum);
        var pin = new VEPushpin(
            pinID,
            new VELatLong(e,f),
            null,
            "This is where I work"
        );
        map.AddPushpin(pin);
        document.forms[0].lat2.value=e;
        document.forms[0].long2.value=f;
        workPin=pinID;
        pinID++;
        checkSubmit();
    }

    function AddHome(e,f,pinNum)
    {
        try
        {
            map.DeletePushpin(homePin);
        }
        catch (err)
        {
        }
        map.DeletePushpin(pinNum);
        var pin = new VEPushpin(
            pinID,
            new VELatLong(e,f),
            null,
            "This is where I live"
        );
        map.AddPushpin(pin);
        document.forms[0].lat1.value=e;
        document.forms[0].long1.value=f;
        homePin=pinID;
        pinID++;
        checkSubmit();
    }

    function checkSubmit()
    {
        if ((document.forms[0].lat1.value != '') && (document.forms[0].long1.value != '') && (document.forms[0].lat2.value != '') && (document.forms[0].long2.value != ''))
        {
            document.forms[0].cmdSave.style.display='inline';
        }
    }

The work and home functions remove any existing work or home pushpins (after all you can't live in more than one place at a time - or can you?), then they add a new pushpin and save the Pin ID to the appropriate variable, and record the latitude and longitude in the text boxes in the form.  The last thing the functions do is check to see if both work and home have been identified and if they have show the save button.

The only other thing that is necessary for this form is to do any processing that might need to be done when the form is submitted.  I've just put the following place holder function in to do this for the moment:

     function dosubmit()
    {
        alert("in the real world you'd have just told someone where you live and work");
        return false;
    }

Thats pretty much it.  You'll want to make it look pretty and create a page to receive the information and do something with it (like store it) but for all intents and purposes, you've now got yourself a survey tool in Virtual Earth in around 100 lines of html and javascript code.

The best place to figure out the API for all these things IMHO is the Reference SDK (note you'll want to click the tab oddly called "Reference SDK" on this page to find it)

Technorati tags: Virtual Earth, live local, live, Visual Studio, mashup, HTML, JavaScript