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

   
Concept: Animated Push Pins

In this example we will look at adding some animation to the map. Though I don’t have an iPhone and probably never will, one of the features that I liked about it was how the mapping feature worked, specifically how push pins were added. When pins/locations are added to the map, there is an animation for the push pin that makes it appear to drop in from off screen. I thought this would be a nice animation to add to a Virtual Earth Map.

In the example to the right, a button has been place at the bottom of the map. Clicking on this button adds a new push pin and triggers an animation that makes the push pin “drop-in” from the top of the map. Additionally, there is a shadow that is part of this animation that comes in from a slightly different direction. This is to give the animation some depth.

Walk Through:

The animation process is not really part of the Virtual Earth API. The process is merely JavaScript and DHTML. The process is added to the JavaScript used to interact with the map to give the map more a little more flair.

The thing I will point out about this example is that there are some “hard coded” values in the code that would normally be derived values. In the real world, some of the value used in the animation would need to be derived based on the size of the map and the location of the pin. Since this example is just a proof of concept, these calculations are not performed and hard coded values are used. There will probably be a follow up article where these calculations are performed and multiple pins are dropped, but for now, lets examine this concept itself.

Defining the pin – The HTML used for the push pin is a little more involved than the typical HTML to produce the push pin icon. The HTML consists of a couple of DIV layers and CSS styles. The implementation is as follows:
    ...
    
    .pinStyle{
                background:url('images/pin.gif') no-repeat 0 0; 
                height:30px; 
                width:25px; 
                color:#fff; 
                text-align:center; 
                font: bold 12px Arial; 
                cursor: pointer; 
                position: relative; 
                }
                
    .pinShadowStyle{
                background:url('images/pinShadow.gif') no-repeat 0 0; 
                height:30px; 
                width:42px; 
                font: bold 12px Arial; 
                position: absolute; 
                filter: Alpha(opacity=50); 
                -moz-opacity: 0.60; 
                opacity: 0.60;
                left: 10px;
                }
    ...
    
    var pinHTML = "<div style='position:relative;'>
                    <div id='{0}'class='pinShadowStyle'>&nbsp;</div>
                    <div id='{1}' class='pinStyle'>1</div>
                   </div>";
    
    ...
    
Two CSS Styles are defined. “pinStyle” is the definition for the push pin itself and “pinShadow” style is the definition for the push pin style. I will skip going through all of the CSS attributes in the hope that most are familiar with CSS. For more information a good resource is http://www.w3schools.com/css/default.asp

The HTML for the push pin consists of three DIVs. The first DIV is a container to hold the other two DIVs. The other two DIVs are for the push pin shadow and the push pin, respectively. Each of these DIVs has the appropriate CSS class assigned. You’ll note that the push pin shadow DIV and push pin DIV have IDs defined as “{0}” and “{1}”, respectively. These are merely placeholders and will be used to define the actual DIV IDs later in the process. This HTML produces a push pin icon layered on top of a shadow icon, wrapped in a DIV container.

NOTE: There are probably a lot of different, perhaps better, way of implementing this feature. The approach that was taken here is just an approach that seemed to work.

Dropping in - Now that the push pin look and feel has been defined, a push pin can now be added to the map. The map, itself, it created in the typical fashion. We won’t go into that process in this article, but feel free to view the source code for this page for more information.

A button has been added below the map to add (or drop) the pin onto the map. When clicked, The JavaScript function “dropPin();” is invoked. The code for this function is as follows:
    function dropPin(){
        map.Clear();
        VertAmount = -170;
        HorizAmount = 190;
        intervalId = 0;

        marker = new VEShape(VEShapeType.Pushpin, map.GetCenter());
        marker.SetTitle('Marker');          
        marker.SetDescription('TBD. ');
        map.AddShape(marker)

        var currentMarkerID = marker.GetID();
        var currentPinHTML = pinHTML.replace('{0}', currentMarkerID + '_iconShadow');
        var currentPinHTML = currentPinHTML.replace('{1}', currentMarkerID + '_icon');
        marker.SetCustomIcon(currentPinHTML);

        intervalId = setInterval('animateDrop()', 10);
    }
    
This function has the responsibility of initializing the animation process, adding the push pin to the map and then triggering the animation process.

First the map is cleared of any previously added shapes. This is accomplished by invoking the “Clear()” method on the VEMap object, map. Next the variables “VertAmount” and “HorizAmount” are set. These variables contain the vertical and horizontal distance that the parts push pin will be moved. The values used in this example are values that pertain to the map used in this example and would need to be adjusted for maps of different sizes. Lastly the variable “intervalId” is initialized. “intervalId” will contain the ID to an interval timer that is used later in the process.

A push pin is then added to the map in the typical fashion. The one notable part of this code is that the HTML for the push pin, represented by the variable “currentPinHTML”, is updated via the “replace()” method available for JavaScript String Objects. This method is used to inject and ID into the appropriate DIV tags so that they can be manipulated later in the process.

Now that the animation variables have been initialized and the push pin added to the map, the animation process can be started. The animation process is essentially a loop that updates the location of the push pin graphics. The each iteration of the loop is managed via the JavaScript “setInterval” function. The setInterval function is similar to the setTimeout function except setInterval will continue to execute until the clearInterval function is used to cancel the process. The last line of the dropPin() function invokes the setInterval process establishing a call to the “animateDrop()” function every 10ms. The ID for the setInterval process is assigned to the variable “intervalId”. This ID is needed in the animateDrop() process to cancel the setInterval process at the appropriate time.

As mentioned the “animateDrop()” function is going to handle the animation of the location of the graphics of the push pin on the map. This function will be executed every 10ms until the setInterval process, which is invoking it, is cancelled. The code for this function is as follows:
    function animateDrop(){
        var currentMarkerID = marker.GetID();
        VertAmount +=10;
        HorizAmount -=10;
        document.getElementById(currentMarkerID + '_icon').style.top = VertAmount + 'px';
        document.getElementById(currentMarkerID + '_iconShadow').style.top = VertAmount + 'px';
        document.getElementById(currentMarkerID + '_iconShadow').style.left = HorizAmount + 'px';
        
        if (VertAmount >= 0) { clearInterval(intervalId)}
    }    
    
The process starts by getting the ID for the push pin that the being animated. The GetID() method in the VEShape object, marker, returns a value that represents it’s ID. This value is assigned to the variable “currentMarkerID”. Next, the variables VertAmount and HorizAmount are adjusted. These variables represent the location of the push pin graphics relative to anchor for the push pin location on the map. As the animateDrop() function is continually executed, these values will be adjusted to move the graphics closer and closer to the push pin anchor.

The adjusted location variables are then applied to the corresponding DIV tags. The DIV tag that represents the push pin is going to appear to drop in from the top of the map, so only the “top” style attribute will be adjusted. The DIV tag that represents the push pin shadow is intended to give the drop more depth so it is going appear to come in from the upper right corner of the map. For the shadow both the “top” and “left” style attributes are updated. As each respective value is updated and applied, the pin graphics will move closer to the push pin anchor.

This whole process is on a repeating timer (via the setInterval method) and will continue until the process is canceled. If the process is not cancelled, the graphics for the push pin will move past the anchor and keep going indefinitely past the boundaries of the visible map. The last line of this function ensures that the animation stops at the appropriate location.

The VertAmount variable represents the location of the push pin graphic relative to the push pin anchor. When this value is less than or equal to zero then the presumption is that the pin in at the appropriate location and the animation should stop. The value of the VertAmount variable is tested to determine if it is less than or equal to zero. If this is true then the setInterval process is canceled via the “clearInterval” method. The ID for the setInterval process, contained in the intervalId variable, is passed to the clearInterval method and the timer process is terminated.

…and that’s all there is too it…

Wrap-up:

The previous has been an example of how you could add some animation to your map. Your specific needs and animation will vary, but hopefully this sheds some light on how this “could” be done. Hopefully this example will be of some use.

There are several different ways the CSS definition or HTML structure could be implemented and you should use what is appropriate for your needs. Also, the animation path in this example is hard coded and a more flexible, dynamic approach would be needed for a real application that would use this process. Time permitting, I will try and post that type of example.

As always, feedback, comments or questions are welcome. I look forward to hearing from you.

Return to Home Page

©2007-2014, Mike Garza, All Rights Reserved