Bing Maps Concepts
(formerly Virtual Earth)
Mike Garza   
VEMaps@garzilla.net   

   
Concept: Push Pin Side Bar

In this example, we will look at how to implement a “side bar” for all of the push pins contained on the map. When implementing a fair number of push pins on a map, it can be confusing to the end user exactly what each of the push pins is representing. The user would have to hover over each of the push pins for more information and effectively hunt down what they are looking for. Implementing a side bar can be an effective way to present summary information about the push pins and aide the end user in finding the information that they are looking for.

In the example below, 5 push pins have been added to the map. The push pins are randomly placed within the bounds of the map, so sometimes the push pins end up in the lake. Just think of them as boats. ;-) To the left of the map a side bar has been added. This side bar contains a listing of all of the push pins on the map. Each item in the list contains the appropriate push pin icon, a title and the push pin ID. Obviously, the information listed for each item could contain whatever information is relevant to the map you are producing. Thanks goes out to Keith Kinnan for providing the guidance on how to implement numbered push pins. For more information on this, check out his article “Virtual Earth API: Creating Numbered Pushpins” at http://blogs.msdn.com/keithkin/archive/2007/05/16/virtual-earth-api-creating-numbered-pushpins.aspx.

Functionality has also been added to the side bar so that when the mouse moves over a given side bar item, the Info Box is opened for the corresponding push pin on the map. Additionally, the push pin icons for both the map push pin and side bar item are changed to help indicate which items are currently being viewed.

Please note that there seems to be some timing issues in the code with the display of the Info Box. This is being looked into, but in the mean time, this example should illustrate how this works conceptually.


Walk Through

The implementation of the side bar functionality is not par of the Virtual Earth API, perse. Additional JavaScript code is added to support the needed DHTML to produce the sidebar. This code is integrated with the map code at various points. The process is as follows.

Conceptually what occurs is that when push pins are added to the map, information about the push pin is used to create the HTML needed for the side bar. Once all of the push pins have been added, the HTML is added to the side bar DIV container. The HTML in the sidebar contains events that will interact with the appropriate push pins on the map when those events are fired. Let’s look at some of the code.

The map is created in the typical fashion via the load function. No magic here. You can view the source of this page to examine that code if need be. Two events handlers are registered to help with visual appearance of the map. The events being captured are “onmouseover” and “onmouseout” and the code for this is as follows:
    // Attach the event handlers to the mouse 
    map.AttachEvent("onmouseover", mouseOverHandler);
    map.AttachEvent("onmouseout", mouseOutHandler);    
    
The functions “mouseOverHandler” and “mouseOutHandler” will handle the onmouseover and onmouseout events, respectively. These functions will help with synchronizing the visual appearance of the map push pin and the side bar icon. Well discuss this in more detail further along.

Next five push pins are added to the map. Again, via the load function. These push pins are placed at random points within the bounds of the map. The code for this is not really important as you’ll probably have real locations for your push pins and not some random point. But, if you’re curious, please feel free to view the source of this page for more information. The important thing to note is that whatever your process is for adding push pins to the map, the side bar can be created as part of this process. That being said, during the process of adding push pins in this example, the following code is used to create the side bar.
    ...
    //Build out sidebar
    var itemHTML = '';
    var currentMarkerID = marker.GetID();
    currentPinHTML = currentPinHTML.replace('<div ', '<div id=\'sideBarMarker_' + currentMarkerID+ '\' '); 
    itemHTML += '<p><span onmouseover="mouseOverSidebarItem(\'' + marker.GetID() + '\');" onmouseout="mouseOutSidebarItem(\'' 
                + marker.GetID() + '\');">';
    itemHTML += currentPinHTML;
    itemHTML += 'Marker # ' + i + '<br/>';
    itemHTML += currentMarkerID + '<br/>';
    itemHTML += '</span><br/></p>';

    document.getElementById('SideBar').innerHTML += itemHTML;
    ...
    
First some variables are established that aide in the process of creating the necessary HTML for the side bar item that represents the current push pin.
    ...
    var itemHTML = '';
    var currentMarkerID = marker.GetID();
    currentPinHTML = currentPinHTML.replace('<div ', '<div id=\'sideBarMarker_' + currentMarkerID+ '\' '); 
    ...
    
The itemHTML variable is used to hold the HTML for side bar item and is re-initialized each time a new pin is added. The CurrentMarkerID variable is set to the ID for the push pin that was just created. This value is retrieved via the GetID() method in VEShape object, marker, which represents the push pin just created. Lastly, the currentPinHTML variable is used to hold the HTML for the icon that will be used for each side bar item. This icon corresponds to the icon that is used for the current push pin in this process. The initial value for currentPinHTML is actually set earlier in the process and is a little involved, so let’s go into more detail.

At the beginning of the code, a global variable “pinHTML” is established. The code for this is as follows:
    ...
    var pinHTML = "<div class='pinStyle'>{0}</div>";
    ...
    
This variable is more or less a template for the icon of a push pin. In this HTML you’ll notice the string “{0}”. This acts as a placeholder and will ultimately contain the number of the push pin.

The initial value of currentPinHTML is set when a given push pin is created. This is accomplished as follows:
    ...
    var currentPinHTML = pinHTML.replace('{0}', i);
    ...
    
Here, the number of the current push pin is being injected into the HTML contained in the pinHTML variable. Since pinHTML is a JavaScript string object, methods native to that object are available for use, specifically the replace() method. The replace() method allows us to search for a specific string and replace it with another string. This method returns the modified version of the original string. In this case the place holder value of “{0}” is being replaced by “I”, which is the index/number of the current push pin. The modified template string is assigned to the variable currentPinHTML and is used for the icon in the current push pin.

Now that the icon HTML has been established and used for the current push pin, it can be further modified to be used in the side bar to represent the icon that corresponds to the map icon. This is accomplished as follows:
    ...
    currentPinHTML = currentPinHTML.replace('<div ', '<div id=\'sideBarMarker_' + currentMarkerID+ '\' '); 
    ...
    
While the HTML, in and of its self, would suffice as a representation of the current push pin’s icon, we need to make some changes so that we can manipulate it later in the process, specifically we need to establish an ID for this HTML element. The ID that is established needs to be unique and reproducible. At any given point we could be working with a different push pin and we need to be able to derive the ID of the corresponding side bar item. By establishing an ID that is reproducible, we know how to find the corresponding side bar item.

To establish the ID for this HTML element, the string “sideBarMarker_” is prepended to the ID of the current push pin, which is contained in the variable currentMarkerID. To put this in more real terms, if the ID of the current push pin is “msftve_1000_200000”, then the id for the corresponding side bar item would be “sideBarMarker_ msftve_1000_200000”. Now, as we work with different push pins, we know how to find the corresponding side bar item based on the ID of the push pin.

Again, since the currentPinHTML variable is a string object, we can invoke the replace() method to inject the appropriate information and return the necessary HTML. Here we are searching for the string “<div” and injecting the unique ID for this HTML element.

Now that the variables have been set, the HTML for the side bar item can be assembled. This is accomplished as follows:
    ...
    itemHTML += '<p><span onmouseover="mouseOverSidebarItem(\'' + marker.GetID() + '\');" onmouseout="mouseOutSidebarItem(\'' 
                + marker.GetID() + '\');">';
    itemHTML += currentPinHTML;
    itemHTML += 'Marker # ' + i + '<br/>';
    itemHTML += currentMarkerID + '<br/>';
    itemHTML += '</span><br/></p>';

    document.getElementById('SideBar').innerHTML += itemHTML;
    ...
    
First a <span> element is created and appended to the item HTML variable. This will house the HTML/Content pertaining to the side bar item. One thing to note is that two events are defined for this span element. These are “onmouseover” and “onmouseout”. When the user hovers over a particular side bar item, code will be executed highlight various areas of the page. When the user moves the mouse over a particular side bar item the “mouseOverSidebarItem” will be executed and when they move the mouse off of the side bar item the “mouseOutSidebarItem” will be executed. In both cases, the ID of the push pin that corresponds to the side bar item is included in this HTML so that it can be passed to the appropriate function.

The remainder of the code adds additional content to the itemHTML variable, including closing any open tags. Lastly, the DIV container, SideBar, is updated by appending the itemHTML value to the value of its innerHTML property. This process is repeated for each push pin being added to the map (in this case 5 times).

"Wire it all up" - Everything up to this point was needed to create the push pins on the map and create the side bar. Now that this has been completed, there are some necessary functions that need to be implemented. These functions are going to support the events that have been defined thus far. As you recall there were two event handlers defined for the map, which are “mouseOverHandler” and “mouseOutHandler”. Also the mouse over and mouse out event for the side bar items are being handled by “mouOverSidebarItem” and “mouseOutSideBarItem” functions. The mouseOverHandler and mouseOutHandler actually use the mouseOverSidebarItem and mouseOutSidebarItem functions, so the latter two will be outlined first and then the former two will be outlined.

The mouseOverSidebarItem and mouseOutSidebarItem functions support the interactivity between the side bar and the map. When a user moves the mouse over a particular side bar item a couple of visual cues occur and when they move the mouse off of that side bar item, the changed items are returned to their original state.

“mouseOverSidebarItem” - This function is responsible for implementing the visual cues when the user moves the mouse over a side bar item. These visual cues are changing the icon of the push pin, opening the Info Box of the push pin and changing the icon of the side bar item. The implementation of this function is as follows:
    function mouseOverSidebarItem(markerId){
        //Update pushpin
        currentShape = map.GetShapeByID(markerId);
        currentIcon = currentShape.GetCustomIcon();
        currentShape.SetCustomIcon(currentIcon.replace('pinStyle', 'pinHoverStyle'));
        map.ShowInfoBox(currentShape);
        
        //Update side bar icon
        var sideBarIconId = 'sideBarMarker_' + currentShape.GetID();
        document.getElementById(sideBarIconId).className = 'pinHoverStyle';
    }
    
When this function is executed, the variable currentShape is set to the instance of the push pin that is associated to the side bar item that invoked this function. The side bar item passes the appropriate push pin id to this function via the variable markerId. This variable is passed to the GetShapeByID() method in the VEMap object, map, which returns a specifc VEShape object which is the push pin associated to that ID.

Next the push pin icon information is retrieved via the GetCustomIcon() method in the VEShape object, currentShape. This function returns the HTML that defines the icon for the push pin and that HTML is assigned to the variable currentIcon.

The HTML in the variable currentIcon is updated to use a new style for the push pin icon and is then used to set the icon for the push pin. This is all performed in a single operation. Since currentIcon is a string object, the replace() method can be used to replace string information contained in the object. The string value of “pinStyle” is replaced with the value of “pinHoverStyle”. This changes the css class used for this DIV, which changes the push pin icon. The replace() method returns the modified version of the original string and that string is passed to the SetCustomIcon() method in the VEShape object, currentShape. Now the icon has been changed.

Once the icon has been changed, the Info Box for the current push pin needs to be displayed. The ShowInfoBox() method in the VEMap object, map, facilitates this process. This method accepts a reference to the shape for which an info box is to be shown (amongst other things). The VEShape object, currentShape, is passed to the ShowInfoBox() method causing the appropriate info box to be displayed.

Lastly, the icon for the appropriate side bar item needs to be updated as well. As you recall, previous we were able to establish a predicable ID for the side bar item, based on the ID of a given push pin. The variable sideBarIconId is used to hold the ID for the side bar item. The GetID() method in the VEShape object, currentShape, returns the ID for the current push pin. This value is appended to the value “sideBarMarker_” to derive the ID for the side bar item and that value is assigned to the variable sideBarIconId. The “className” property of the HTML element identified by the variable sideBarIconId is updated to “pinHoverStyle”, which updates the icon on the side bar to match the updated icon on the map.

“mouseOutSidebarItem” – This function is responsible for undoing the visual cues that were implemented in the mouseOverSidebarItem function. When the user moves the mouse off of a particular side bar item this function is executed. The implementation is as follows:
    function mouseOutSidebarItem(markerId){
        //Update pushpin
        currentShape = map.GetShapeByID(markerId);
        currentIcon = currentShape.GetCustomIcon();
        currentShape.SetCustomIcon(currentIcon.replace('pinHoverStyle', 'pinStyle'));
        map.HideInfoBox(currentShape);
        
        //Update side bar icon
        var sideBarIconId = 'sideBarMarker_' + currentShape.GetID();
        document.getElementById(sideBarIconId).className = 'pinStyle';
    }
    
The code in this function follows the same process as with the mouseOverSidebarItem function, so we won’t walk through it. Where it differs is that changes the css class reference for the map push pin and side bar icon back to “pinStyle” from “pinHoverStyle”. This essentially restores the push pin and side bar icon back to its original state.

With these two functions in place the side bar is now wired to interact with map. When a user navigates over the side bar items, the map will respond accordingly. Next we need to wire up the map with the side bar so that when a user navigates through the map, the side bar acts accordingly.

As you recall, two event handlers were established for the map. These two handlers, “mouseOverHandler” and “mouseOutHandler”, will handle the interaction between the map and the side bar.

"mouseOverHandler” – When the user moves the mouse over a given push pin, the onmouseover event fires and this function is executed. Conceptually, this function has the same responsibility as the mouseOverSidebarItem function. In this case, though, the process is invoked from the push pin instead of the side bar item. The implementation of this function is as follows:
    function mouseOverHandler(e){
        if (e.elementID && notOver){
            mouseOverSidebarItem(e.elementID)
            notOver = false;
        }
    }
    
As you would expect, when this event is raised, the event object (e) is passed to this handler. Two conditions are tested before the remainder of the code is executed. First, there must be an object associated with the event that was raised. This is tested by evaluating the elementID property on the event object, e. If there is an object associated with the event, this property will contain the ID for that object, otherwise the value is NULL. Second, we want to make sure that mouse was not already over a push pin. This is determined by the state of the Boolean variable “notOver”. If the value is true then the mouse was not over a push pin and if false, it was over a push pin. This will be explained more a little further along. If both of these conditions are met, then the remainder of the code is executed, otherwise the function is exited.

As mentioned, this function needs to implement the same functionality that is implemented in the mouseOverSidebarItem function, so why not just use it. The mouseOverSidebarItem function requires one parameter which is the push pin id that is being highlighted. This ID is available to us via the elementID property of the event object, e. This value is passed to the mouseOverSidebarItem function and the needed functionality is then executed.

Lastly, the value of the Boolean variable notOver is updated to “false”. This is set to ensure that code is only executed when needed. Each time the mouse moves over a push pin, the onmouseover event is fired. Even if the mouse is already over a given push pin, when the mouse moves, the onmouseover event will fire again. The notOver variable is used to make sure that code is executed when the mouse moves over the push pin for the first time. Any subsequent onmouseover events will be ignored until the mouse exits the push pin, which is handled by the mouseOutHandler function.

“mouseOutHandler” – Just like the mouseOutSidebarItem function, this function has the responsibility of undoing the visual cues that were implemented. This function is executed when the user moves the mouse off of a given push pin. The code in this function follows a similar process as the mouseOverHandler function and is as follows:
    function mouseOutHandler(e){
        if (e.elementID && !notOver){
            mouseOutSidebarItem(e.elementID)
            notOver = true;
        }
    }
    
Since the mouseOutSidebarItem function has the functionality that is needed to undo the visual cues, we will use it. The mouseOutSidebarItem requires one parameter which is the push pin ID that is being reset. Again, this ID is available to us via the elementID property of the event object, e. This value is passed to the mouseOutSidebarItem function and the needed functionality is executed.

Lastly, the Boolean variable notOver is set to “true”. This resets the variable to its initial state and indicated that we are no longer over a given push pin. Now when the mouseOverHandler function is executed next, it will recognize that we are not over a push pin and act accordingly.

Wrap-up:

Sorry for the long overview! Sometimes it just seems to take a little bit more than anticipated to explain what is going on or maybe I am just too chatty! The previous has been an overview on one of the many ways a side bar could be added to a Virtual Earth map. As mentioned, this process is not native to Virtual Earth. It is additional code that is added to the mapping process to implement a side bar that contains additional information and has some interactive qualities.

This overview is just one way of implementing a side bar. I’m sure there are other alternatives to achieving the same goal. Additionally, the code contained in this example could be implemented/optimized differently as well, depending on your coding style.

Hopefully the previous example illustrates how a side bar could be implemented and sparks some thought on how it could be used for the applications that you build. As always, I welcome any feedback, questions or comments.

Return to Home Page

©2007-2017, Mike Garza, All Rights Reserved