The mysterious Virtual Earth ERO (aka enhanced roll overs). Coded with just a little JavaScript and a lot of Cascading Style Sheets, there is so much to learn and understand about those little buggers and not much of it is documented. Well, Geoff Innis (Virtual Earth Technical Specialist out of Toronto) took the time to do a nice little write up for an application he built recently and so, I present it to you below.

Info Boxes allow us to present information to users about the shapes we add to our maps. We can extend this ability to present information with the use of tabs within our info boxes, to present more content to our users, in a structured manner.

With the VEShape.SetDescription Method, we have the ability to pass in any HTML we want, as noted in the VE SDK:

“To customize your info box to something instead of the default plain text, you can provide your own custom HTML by using the VEShape.SetDescription method details parameter. The content of the Details parameter is wrapped in a DIV tag and, along with the content defined by VEShape.SetTitle Method (if any), forms the custom info box.”

By passing in our own custom HTML for some tabs and tab content, and with the help of some JavaScript and CSS, we can create our own tabbed info box content for our VE Shapes.

image 

Here is the code for our example:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>

<head>

<!-- saved from url=(0014)about:internet -->

<title>Tabbed EROs</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

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

<script type="text/javascript">

var map = null;

var points = new Array(

new VELatLong(45.01188,-111.06687, 0, VEAltitudeMode. RelativeToGround),

new VELatLong(45.01534,-104.06324, 0, VEAltitudeMode. RelativeToGround),

new VELatLong(41.01929,-104.06, 0, VEAltitudeMode. RelativeToGround),

new VELatLong(41.003,-111.05878, 0, VEAltitudeMode. RelativeToGround)

      );

function GetMap()

      {

         map = new VEMap('myMap');

         map.LoadMap();

         AddShapes();

      }

function AddShapes()

      {

for (var i = 0; i < points.length; i++)

         {

var shape = new VEShape(VEShapeType.Pushpin, points[i]);

var shapenumber = i + 1;

var description = "";

            description += "<div class=\"tabwrapper\">";

            description +=  "<ul id=\"navigation" + shapenumber + "\" class=\"navigation\">";

            description +=   "<li class=\"tabon\"><a href=\"#\" onclick=\"showTab('" + shapenumber + "','1');return false;\">Tab 1</a></li>";

            description +=   "<li class=\"taboff\"><a href=\"#\" onclick=\"showTab('" + shapenumber + "','2');return false;\">Tab 2</a></li>";

            description +=   "<li class=\"taboff\"><a href=\"#\" onclick=\"showTab('" + shapenumber + "','3');return false;\">Tab 3</a></li>";

            description +=  "</ul>";

            description += "</div>";

            description += "<br/><br/>";

            description += "<div id=\"tabcontentcontainer" + shapenumber + "\" class=\"tabcontentwrapper\">";

            description +=  "<div class=\"tabcontenton\">Content for Tab 1</div>";

            description +=  "<div class=\"tabcontentoff\">Content for Tab 2</div>";

            description +=  "<div class=\"tabcontentoff\">Content for Tab 3</div>";

            description += "</div>";

            shape.SetTitle("");

            shape.SetDescription(description);

            map.AddShape(shape);

         }

      }

function showTab(shapenumber,tab)

      {

var myTabContent = document.getElementById('tabcontentcontainer' + shapenumber).getElementsByTagName('div');

var myTabs = document.getElementById('navigation' + shapenumber).getElementsByTagName('li');

for(var i = 0; i < myTabs.length; i++)

            {

// Show only appropriate tab content           

                myTabContent[i].style.display = (tab == (i+1)) ? "block" : "none";

// Change classNames to display selected tab name:

                myTabs[i].className = (tab == (i+1)) ? "tabon" : "taboff";

            }

      }

</script>

<style type="text/css">

.navigation { margin: 0px; float: left; padding: 1px;}

.tabwrapper { margin: 0px; border-bottom: solid 1px gray; float: left; padding: 0px;}

.navigation li { margin: 0px; display: inline; padding: 0 5px 0 5px; float: left;}

a { text-decoration: none; color: blue; }

.tabcontenton, .tabcontentoff { padding: 5px; text-align: left; height: 130px;}

.tabcontentoff { display: none;}

.tabcontentwrapper {position: relative;}

.tabon { font-weight: bold;}

.taboff { font-weight: normal;}

.taboff a {color: Gray;}     

</style>

</head>

<body onload="GetMap();">

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

</body>

</html>

In our AddShapes function, we construct the HTML for each info box. We include labels for each tab in a list, and place the content for each tab in a separate div tag.

Whenever any of the tab labels is clicked, we call our ShowTab function, passing in parameters to identify which info box and which tab were clicked. Our function then shows the content for the clicked tab, and hides the content for the others by setting the style attribute of ‘display’ to either ‘block’ or ‘none’, as appropriate . As well, we update the class name for  each of the tab labels, to identify which tab is being displayed.

This is a basic example, but you can extend it with your own enhanced style and content.

Happy Tabbing!

Nice, thanks Geoff! For those of you who don't code, I've stuck the file on my Skydrive site.

CP (and GI)