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

   
Beginning Location: Ending Location:
Lat: 00.0000 Lng: 00.0000 Lat: 00.0000 Lng: 00.0000
Hold down control key & [left] click and drag on the map to draw the selection box.
Concept: Selection Box, Part 2

This example builds off of the selection box example, which covered the mechanics of implementing selection box. In this example, the process of selecting push pins is implemented.

In the example to the right, a series of random push pins have been added to the map (if the placement is not ideal, just hit refresh for a new set). Now when the selection box is drawn on the map, any push pin anchor points that fall within the bounds of the selection box will be highlighted.


Walk Through:

As mentioned, this example builds off of the previous selection box example. Given that, there are only a couple of changes to the previous code to implement the selection process.

First, push pins needed to be added to the map so that there was something to select. For illustration purposes, 10 push pins are randomly added to the map. The code for this is not really important as your maps will deal with real locations that originate from some other data source. Additionally, style information has been defined for the push pins. This is just for illustration purposes also, your style needs will probably vary.

That being the case, I will not go into detail on this aspect of this example. However, if you are interested in the process, please feel free to view the source of this page for more information on how the push pins are created and styled.

The main change to the previous example is the selection process itself. Previously, three mouse events were handled. They are “onmousedown”, “onmousemove” and “onmouseup”. When these events are fired they will execute the JavaScript functions “MouseDownHandler”, “MouseMoveHandler” and “MouseUpHandler”, respectively. The MouseDownHandler() and MouseMoveHandler() are effectively the same as they deal with the creation of the selection box. The MouseUpHandler(), however, has been extended to now deal with the selection process.

MouseUpHandler() – Previously the MouseUpHandler() only performed some “clean-up” work. Now it has been extended to handle the selection process. The function is ideal for this process as it is invoked after the selection box has been drawn and the selection boundaries have been defined. The [new] implementation is as follows:
    function MouseUpHandler(e){ 
        // On mouse up, if not in selecting mode, do nothing, otherwise cancel selecting mode
        if(selecting){ 
            // cancel selecting mode
            selecting = false;
            
            //Determine if any of the push pins are within the selection box bounds
            if (StartLatLon.Latitude > EndLatLon.Latitude) {
                var eBound = StartLatLon.Latitude;
                var wBound = EndLatLon.Latitude;
            } else {
                var eBound = EndLatLon.Latitude;
                var wBound = StartLatLon.Latitude;
            }
            
             if (StartLatLon.Longitude > EndLatLon.Longitude) {
                var nBound = StartLatLon.Longitude;
                var sBound = EndLatLon.Longitude;
            } else {
                var nBound = EndLatLon.Longitude;
                var sBound = StartLatLon.Longitude;
            }
            
            var mainLayer = map.GetShapeLayerByIndex(0);
            numShapes = mainLayer.GetShapeCount();
            
            for(var i=0; i < numShapes; ++i){
                var currentShape = mainLayer.GetShapeByIndex(i);
                if (currentShape.GetType() == VEShapeType.Pushpin){
                    if(currentShape.Latitude < eBound && currentShape.Latitude > wBound 
                        && currentShape.Longitude < nBound && currentShape.Longitude > sBound){
                        currentIcon = currentShape.GetCustomIcon();
                        currentShape.SetCustomIcon(currentIcon.replace('pinStyle', 'pinSelectStyle'));
                    } else {
                        currentIcon = currentShape.GetCustomIcon();
                        currentShape.SetCustomIcon(currentIcon.replace('pinSelectStyle', 'pinStyle'));
                    }
                }
            } 
        } 
    } 
    
Since this function will be executed each time a mouse button is released, we need to test to see if we are in selecting mode. If we are in selecting mode, then the process continues otherwise the function exits.

If we are in selecting mode and the mouse button is released, then the presumption is that the selecting has been completed, so the selection mode is disabled. This is accomplished by setting the value of the Boolean variable “selecting” to false.

Next we need to determine the north, south, east and west boundaries of the selection box. Since the selection box can be drawn in any direction, we need to compare the known corners of the selection box to determine the boundaries. If you recall, two VELatLong objects are persisted during the selection box creation. These represent the starting and ending corners of the selection box and are represented by the variables “StartLatLon” and “EndLatLon”. By comparing the Latitude and Longitude values of these corners, we are able to establish the north, south, east and west boundaries of the selection box.

Now that the latitude and longitude boundaries have been established, we can find all of the push pins that fall with in those bounds. Since we need to access all of the push pins, we need to have a reference to the layer that contains all of the push pins. The GetShapeLayerByIndex() method will return a VEShapeLayer object for a given index. The default layer is zero (0), so that value is passed into this methods and the returning VEShapeLayer reference is assigned to the variable “mainLayer”.

Since we are going to loop through all of the VEShape objects in the VEShapeLayer object, mainLayer, we need to know how many shapes there are. This can be determined by invoking the GetShapeCount() method in the VEShapeLayer object, mainLayer. This method will return an integer representing the number of VEShape objects contained in VEShapeLayer object. This integer is assigned to the variable “numShapes”. Now that we’ve identified how may shapes are in the default layer, we can loop through the collection of shapes and determine if the shapes anchor point falls with in the selection box boundaries.

A loop is established using the numShape variable which represents the number of VEShapes in the default layer and will also be the number of iterations in the loop. An instance of a VEShape object is retrieved from the default layer. This is accomplished via the GetShapeByIndex() method in the VEShapeLayer object, mainLayer. This method returns an instance of a VEShape object based on the index of the VEShape. The VEShape object returned is assigned to the variable “currentShape”.

The default layer (or any layer for that matter) can contain any type of VEShape onbject (push pin, polyline or polygon). Since we are only concerned with pushpins, we need to check the type of VEShape that has been assigned to the variable currentShape. This is accomplished via the GetType() method in the VEShape object, currentShape. The GetType() method in currentShape (VEShape object) returns a VEShapeType enumeration. VEShapeType values are VEShapeType.Pushpin, VEShapeType.Polyline, or VEShapeType.Polygon. The currentShape type is evaluated to make sure it is of the type VEShapeType.Pushpin and if so, the process continues, otherwise no code is executed.

Once we know the currentShape variable is a push pin, we can check to see if it falls within the bounds of the selection box. The Latitude and Longitude properties of the VEShape object, current shape are tested against the Latitude and Longitude boundaries of the selection box represented by the variables nBound, sBound, eBound and wBound.

If the push pin falls with in these boundaries, the style in formation for the push pin is updated so that the push pin appears to be highlighted. The push pin icon information is retrieved via the GetCustomIcon() method in the VEShape object, currentShape. This HTML string is assigned to the variable “currentIcon”. Since currentIcon is a JavaScript String object, the replace() method is available to manipulate the string information. The string “pinStyle” is replaced with the string “pinSelectStyle”, which effectively changes the CSS class. The updated HTML is then used for the icon of the push pin by passing it to the SetCustomIcon() method in the VEShape object, currentShape.

If the push pin does not fall with in the selection box boundaries, then icon HTML is reset to the original state. This follows a similar process as the highlighting approach using the replace() method to resent the CSS class back to “pinStyle”. This is more of a housekeeping item so that as the user re-selects an area on the map, only the pins with in that new selection box are highlighted.

Once this process has been completed, it is repeated for each iteration in the loop.

Wrap-up:

The previous example outlines how a selection process could be implemented once a selection box has been defined. This example uses a limited number of push pins for illustration purposes. There may be situations where a larger number of push pins need to be evaluated and looping through all of the push pins may not be the most effective approach.

In those instances some additional filtering may be needed to increase efficiency. Additionally, a database that supports spatial functions, such as SQL Server 2008, could be used to determine if specific locations fall with in the boundaries of a given selection box.

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

Return to Home Page

©2007-2017, Mike Garza, All Rights Reserved