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

   
Drawing Mode: Disabled
Concept: Draw Polyline

In this example we will look at the functionality needed to dynamically draw a polyline on the map. In the example to the right, functionality has been added so that you can dynamically draw a polyline on the displayed map. At the bottom of the map there is a button that needs to be clicked to start the process.

Once clicked, the map is put into “drawing” mode and the polyline can be created. While in drawing mode, as you click various locations on the map, a polyline is created and extended to follow your click path. Once you are done drawing the polyline, pressing the escape key cancels the drawing mode and the map function returns to normal. Clicking on the button again deletes the previous polyline and the process can be repeated.

Walk Through:

As you would expect, the map is created in the typical fashion, so we won’t go into that as by now we are all experts with that implementation. And as you would expect, like most of the examples on this site, the mouse is involved so we are going to have to wire up some events. However, unlike the previous examples on this site, we are going to be working with the keyboard events, so there will be a new event to work with. I know you are as excited as me, so let’s move on.

Three events are used in this example; two for the mouse, onmousedown and onmousemove, and one for the keyboard, on keypress. These events need to be registered and the implementation is as follows:
    // Attach the event handlers to the mouse 
    map.AttachEvent("onmousedown", mouseDownHandler);
    map.AttachEvent("onmousemove", mouseMoveHandler);
    map.AttachEvent("onkeypress", keyPressHandler); 
    
These events are registered via the AttachEvent() method on the VEMap object, map. When the onmousedown event is fired, the MouseDownHandler function will be executed. When the onmousemove event is fired, the MouseMoveHandler function will be executed. When the onkeypress event is fired, the KeyPressHandler function will be executed. For more information on event handling, please refer to the Virtual Earth SDK (http://msdn2.microsoft.com/en-us/library/bb412543.aspx ).

Now that the basic map and events have been put in place, we can outline the code needed to draw the polyline. As mentioned previous the first step in the process is to click the button at the bottom of the map, cleverly named “Click here to begin drawing”. When clicked, the JavaScript function startDrawing() will be executed. The implementation of this function is as follows:
    function startDrawing(){
        if (polyline && !drawing){
                map.DeleteShape(polyline);
                polyline = null;
                points.length = 0;  
        }
        
        map.vemapcontrol.EnableGeoCommunity(true);
        drawing = true;
        document.getElementById("ModeIndicator").innerHTML = 'Enabled';
        document.getElementById("MapDiv").style.cursor = 'crosshair';
        document.getElementById("cmdDraw").value = 'Press ESC to exit drawing mode';
        document.getElementById("cmdDraw").disabled = true;
    }
    
First we test to see if the “polyline” variable is not null and that the map is not in drawing mode. The polyline variable is a VEShapeObject that represents a polyline that has been drawn and Boolean variable “drawing” indicates if the map is in drawing mode or not. If no polyline has been previously drawn, then this variable will be null. If both of these conditions are true, then the previously drawn polyline is removed from the map. Additionally, the variables that support the drawn polyline are reinitialized by setting the the VEShape “polyline” to null and removing the VELatLong objects from the “points” array.

Since we are going to be interacting with the map using the mouse, the default map mouse functionality needs to be disabled. This is accomplished by passing the value “true” to the EnableGeoCommunity method. Next the map is put into drawing mode by setting the global Boolean variable “drawing” to “true.

Lastly, some visual cues are added to the map to indicate that we are now in drawing mode. Text is updated on the screen to indicate that drawing mode has been enabled, the cursor for the map itself is changed to a “crosshair” and the button that was just clicked is disabled and the text is changed to some more meaningful text. All of this is accomplished in a typical fashion using DHTML.

Now that the map is in drawing mode, the polyline can be drawn. This is accomplished by clicking on the appropriate points on the map. As each point is clicked, the polyline on the map updated to reflect the series of points that have been clicked. Additionally, as the mouse is moved while the map is in drawing mode, a line mask is dynamically drawn in the screen to show where the new line segment will be placed when the next point is clicked. The mouseMoveHandler and mouseDownHandler provide this functionality and this implementation, beginning with mouseMoveHandler, is as follows:
    //onmousemove handler
    function mouseMoveHandler(e) {
        if (drawing) {
            var loc = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
            if (points.length > 0){polylineMask.Show()};
            maskPoints[1] = loc
            polylineMask.SetPoints(maskPoints);
        }
    }
    
The mouseMoveHandler will be executed each time the mouse is moved. The main purpose of this function is to dynamically draw the line mask that represents the line segment being drawn. Since the logic in this function should only be executed with the map is in drawing mode, the first thing we do is evaluate the variable “drawing” to determine if the map is in drawing mode. If this variable is true then the remainder of the logic is executed.

First we record the current location of the cursor by capturing the mapX and mapY properties of the event object, e, and create a VELatLong object named “loc”. Next we determine if the line mask should be displayed. We only want to display the line mask if at least one point for the new polyline has been selected. We check the length of the “points” array, which contains all of the points for the polyline being drawn, and if there at least one point in this array, this line mask is displayed via the Show() method on the VEShape, polylineMask. Next the array maskPoints is updated to reflect the current location of the cursor by assigning the loc variable to the second element of the array. The maskPoints array represents the points of the line segment being drawn. There are only two points in this array which are the last point of the line that is being drawn and the current location of the cursor. Lastly, the line mask is updated with new points captured during the mouse movement. This is accomplished by passing the maskPoints array to the SetPoints() method in the VEShape object, polylineMask.

Once the desired point has been reached, clicking the left mouse button will capture and add the current mouse location as the last location on the polyline being drawn. This process is handled by the mouseDownHandler function and the implementation is as follows:
    function mouseDownHandler(e){
        if (drawing){
            currentLatLon = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
            points.push(currentLatLon);
            maskPoints[0] = currentLatLon;
            
            if (points.length > 1){
                if (!polyline){
                    polyline = new VEShape(VEShapeType.Polyline, points);
                    polyline.HideIcon();
                    map.AddShape(polyline);
                    
                    maskPoints[1] = currentLatLon
                } else {
                    polyline.SetPoints(points);
                }
            }
        }
    }
    
Just as with the mouseMoveHandler, we want to make sure that the map is in drawing mode before we process the click logic. This is accomplished the same way by testing the value of the Boolean variable “drawing” and if true, the remainder of the logic is executed. First we record the current location of the cursor by capturing the mapX and mapY properties of the event object, e, and create a VELatLong object named “loc”. Next the points array, which represents all of the points of the polyline being drawn, is updated with current location of the cursor by pushing the VELatLong object, loc, onto the end of the array. Also, the beginning point of the line mask (used in the mouseMoveHandler) is updated with the same location by assigning the loc variable to the first element of the array maskPoints.

The last thing that needs to be done is to update the points on the polyline that is being drawn. Before we can do this, we need to first check to see if the there are at least two points in the points array and that polyline already exists. The reason for this is because when the map is first put into drawing mode, the points array is empty and polyline does not exist. Since a polyline requires two points before it can be created, we first examine the length property of the points array and if there is more than one point the remainder of the logic is executed. If the polyline does exist, then all that is needed is to pass the points array to the SetPoints method in the VEShape object, polyline. If the polyline does not exist, then the polyline is created using the location information in the points array. Additionally, the end point of the line mask is updated to support the functionality in the mouseMoveHandler.

The drawing process continues as needed as the user moves the mouse and clicks various points on the map. When the ployline drawing has been completed, pressing the “escape” key takes the map out of drawing mode and returns the map to the original state. This is handled by the keyPressHandler function and the implementation is as follows:
	function keyPressHandler(e){
	    if (drawing && e.keyCode == 27 ){
            drawing = false;                
            map.vemapcontrol.EnableGeoCommunity(false);
            document.getElementById("ModeIndicator").innerHTML = 'Disabled';
	        document.getElementById("MapDiv").style.cursor = '';
	        document.getElementById("cmdDraw").value = 'Click to begin drawing';
	        document.getElementById("cmdDraw").disabled = false;
	        polylineMask.Hide();
        }
	}
    
The keyPressHandler is executed each time a key on the keyboard is pressed. Because of this, we need to test for two conditions before we execute any of the logic in this function. First we need to make sure that it was the “escape” that was pressed. This is accomplished by evaluating the keyCode property on the event object, e. If the value of this property is 27, then the escape key was pressed. Also, we want to test to see if the map was in drawing mode. Again, this is accomplished by evaluating the Boolean variable “drawing”. If both of these conditions are true, then the process continues.

The remainder of the logic in this function takes the map out of drawing mode. The Boolean variable “drawing” is set to false. Control is returned to the map by passing the value “false” to the EnableGeoCommunity method. The visual cues implemented previously are undone.

Wrap-up:

The previous was an overview of how you could implement dynamically drawn polylines in your application. As usual, there are a lot of different ways this concept could be implemented. This is just one of many approaches that can be used and is intended to illustrate this concept. Hopefully this will provide a building block for the implementation that is most appropriate for your needs.

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