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

   
Mouse Location: PushPin Location:
Lat: 00.0000 Lng: 00.0000 Lat: 41.8756 Lng: -87.6456
Concept: Moveable Push Pins

The concept here is to create a map, in Virtual Earth (v6), which will allow the user to take an existing pushpin and move it to a new location on the map.

In the example to the right, a map has been created and a push pin has been added to the map. For the most part, the map functions as normal. Clicking on the map allows the user to drag the map around and moving the mouse over the push pin activates the info window. Functionality has been added so that if the user “right clicks” the push pin, they can drag the push pin to a new location on the map.

Labels have been added to the top section of the map to indicate the current mouse location as well as the location of the push pin. These labels are updated as the map in interacted with.

Walk Through

In this example, the typical approach is used for creating the map and adding the push pin. For more information on map basics, see the Virtual Earth Interactive SDK .

Once the map is created, several events handlers need to be registered. These events are as follows:
  • onmousemove – Occurs when the mouse cursor moves.
  • onmousedown – Occurs when a mouse button (left, right, or middle) is clicked (but before it is released).
  • onmouseup - Occurs when a mouse button (left, right, or middle) is released.
The implementations of these events are as follows:
    // Attach the event handlers to the mouse 
    map.AttachEvent("onmousemove", mouseMoveHandler);
    map.AttachEvent("onmousedown", mouseDownHandler);
    map.AttachEvent("onmouseup", mouseUpHandler);
    
Each of the listed mouse events is mapped to a JavaScript function via the “AttachEvent” method of the VEMap class, represented here by the JavaScript object “map”. Now, when any of these events are fired, the respective JavaScript function will be executed.

Now that the event handlers have been registered, the handlers themselves need to be created. As listed in the previous code, the handlers are mouseMoveHandler, mouseDownHandler and mouseUpHandler. The purpose and functionality of these handlers will be covered next.

“mouseDownHandler” – This function will be executed every time a mouse button (left, right or middle) is clicked. It is responsible for determining if the process for moving push pin is enabled. The implementation is as follows:
    // onmousedown handler
    function mouseDownHandler(e) {
        if (e.rightMouseButton && e.elementID) {
            moving = true;
            map.vemapcontrol.EnableGeoCommunity(true);
            document.getElementById("MapDiv").style.cursor = 'Move';
        }
    }
    
When executed, the event object, e, is passed to this function. Two conditions must be true in order to enable the process of moving the push pin. First, the button that was clicked to fire this event must be the right mouse button. Second, there must be an object associated with the event.

The event object, e, being passed to this function exposes properties that will allow these conditions to be tested. The event object exposes a Boolean property “rightMouseButton” that indicates if the button that was clicked to fire the event was the right mouse button. As expected, a value of “true” would indicate that it was. The event object also exposes a property that indicates the ID of the object that is associated with the event. Typically this is the ID of a VEShape Class Object. If no object is associated with the event, then the value of this object is NULL.

The first line of code for this function, “if (e.rightMouseButton && e.elementID) {”, tests these conditions. If either of these conditions is “false”, then no code is executed. If both of these conditions are “true”, the next three lines of code are executed to enable the move process.

Of the next three lines of code, the first two are really the key to enabling the move process. The first of these lines sets the global variable “moving” to “true”. This will be used in a later function, but it is the indicator if the map is in moving mode. The next line sets the “EnableGeoCommunity” to “true”. Setting this value allow us access the “onmousemove” handler (discussed next) while moving the mouse over the map. The last line, while not important to the actual move process, changes the style of the cursor so that the user is aware that they are in move mode.

“mouseMoveHandler” – This function will be executed each time the mouse is moved over the map. It is responsible for determining if the map is in move mode and if so to execute the appropriate code. The implementation is as follows:
    // onmousemove handler
    function mouseMoveHandler(e) {
        var loc = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
        document.getElementById("MouseLat").innerHTML = loc.Latitude.toFixed(4);
        document.getElementById("MouseLng").innerHTML = loc.Longitude.toFixed(4);
        if (moving) {
            document.getElementById("MarkerLat").innerHTML = loc.Latitude.toFixed(4);
            document.getElementById("MarkerLng").innerHTML = loc.Longitude.toFixed(4);
            map.HideInfoBox(marker);
            marker.SetPoints(loc);
        }
    }
    
In the example there are labels that indicate the current mouse position. This process is facilitated by this event handler, specifically the first three lines of code in this function. The first line of code establishes a new VELatLong Object. This is accomplished by capturing location of the cursor on the map (e.mapX & e.mapY), using it to create a new VEPixel Object and then converting that VEPixel Obect to a VELatLong Object via the “PixelToLatLong” method in the VEMap class (map). This sets the “loc” variable to an instance of a VELatLong Object that represents the location of the cursor. The next to lines of code update the labels in the example with the (rounded) latitude and longitude values for the location of the cursor.

In addition to the previous, this function also determines if the move process should be executed. The 4th line of code, “if (moving){“ determines if the map is in moving mode. This mode is set during the “onmousedown” event handled by the mouseDownHandler function, as previously outlined. If the map is not in moving mode, then no other code is executed. If the map is in moving mode then the next series of code is executed to facilitate the move process.

For all practical purposes, the only code needed to move the push pin is the last or 8th line of code, “marker.SetPoints(loc);”. “marker” represents the instance of the push pin currently on the map. A new location can be established for the marker by passing a VELatLong Object to the “SetPoints” method in the Marker (VEShape) Object. In this case the “loc” object, a VELatLong Object representing the location of the cursor, is passed to the “SetPoints” method in the marker object and the marker is moved to the new locations. The other lines of code (5 -7), again are more “housekeeping” items. Lines 5 & 6 update the labels that indicate the location of the push pin (similar to lines 2 & 3) and line 7 hides the info box for the current marker (in case it is still displayed while moving).

This process is repeated each time the mouse is moved.

“mouseUpHandler” – This function will be executed each time the mouse button is released. It is responsible for any necessary “clean-up” when exiting move mode. The implementation is as follows:
    //onmouseup handler
    function mouseUpHandler(e) {
        if (moving && e.rightMouseButton) {
            moving = false;
            map.vemapcontrol.EnableGeoCommunity(false);
            document.getElementById("MapDiv").style.cursor = '';
        }
    }
    
You guessed it, since this is an event handler, the event object, e, is passed to this function. Similar to the “mouseDownHandler” function, two conditions are tested, but this time the one of the conditions is different. The “rightMouseButton” property of the event object is still being tested to make sure that the proper button is being released, however, in this function the second condition is whether or not the map is in move mode. So, if the right mouse button is being release and we are currently in move mode, then the next series of code will be executed, otherwise no code is executed. The presumption here is that if the user is releasing the right mouse button and the map is in move mode, the marker was just placed in the desired location.

As mentioned, this function performs clean-up when exiting move mode. Since move mode is being exited, the map needs to be returned to its beginning state or to put it another way, undo what the “mouseDownHandler” did. To accomplish this, the global variable “moving” is set to false. For all practical purposes this takes us out of move mode. The “EnableGeoCommunity” value is set to false to restore to map’s mouse movement to it’s original state. Lastly, the style of the cursor is returned to its original state.

Wrap-up:

The previous has been an overview of a potential solution for moveable push pins. As with any application development code, there are many different ways that this task could be accomplished. This example is a means of illustrating one of the ways this type of functionality could be implemented. The code used here is by no means a complete solution.

Providing end users with this type of functionality could be a means of more accurately capturing geographic locations. For example, if the means in which specific locations are geo coded are not particularly accurate, dragging the push pin to a more specific location would yield a higher level of accuracy.

Any feedback, comments or questions are welcome.

Return to Home Page

©2007-2017, Mike Garza, All Rights Reserved