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

   
Mouse Location: Polygon point offset:
Lat: 00.0000 Lng: 00.0000 Lat: 00.0000 Lng: 00.0000
Concept: Moveable Polygon

In this example, we will look at how a polygon can be moved. Conceptually, the process is the same as moving a push pin and the implementation is similar. In Virtual Earth V6, push pins, polylines and polygons are all VEShape objects that have a specific type defined. This type is defined during construction via the VEShapeType enumeration. Members of this enumeration are Pushpin, Polyline and Polygon.

In the “Moveable Push Pin” example, we used the SetPoints() method in the VEShape class to manipulate the location of the push pin. Since a polygon is a VEShape object, the same method will be used to manipulate the location as well, however, there are additional factors that need to be managed

The example to the right contains a map that contains a polygon. By “right-clicking” anywhere on the polygon, the polygon can be moved to a new location on the map.

Walk Through

The code for this example is essentially the same as the “Moveable Push Pin” example. The same functionality and event handlers are implemented in this example. That being the case, we will not outline those areas in this article. For more information about the core logic and event handlers, please refer to the “Moveable Push Pin” example.

Since this example focuses on moving a polygon, we need to add the polygon to the map. This is performed during the load() function and the code to implement the polygon is as follows:
    //build polygon from map center
    var points = [
        new VELatLong(mapCenter.Latitude, mapCenter.Longitude - 0.15),
        new VELatLong(mapCenter.Latitude + 0.1, mapCenter.Longitude - 0.05),
        new VELatLong(mapCenter.Latitude + 0.1, mapCenter.Longitude + 0.05),
        new VELatLong(mapCenter.Latitude, mapCenter.Longitude + 0.15),
        new VELatLong(mapCenter.Latitude - 0.1, mapCenter.Longitude + 0.05),
        new VELatLong(mapCenter.Latitude - 0.1, mapCenter.Longitude - 0.05)];

    shape = new VEShape(VEShapeType.Polygon, points);            
    shape.SetLineWidth(1);
    shape.SetLineColor(new VEColor(0,0,0,1.0));
    shape.SetFillColor(new VEColor(0,100,150,0.5));
    shape.SetTitle('Draggable Polygon');
    shape.SetDescription('Hold down the right mouse button to drag me.');
    shape.SetCustomIcon('<img src=\'images/GreenDot.png\'>');
    shape.ShowIcon();
    map.AddShape(shape);
    
The process of creating the polygon is pretty standard. There is no magic here. An array of points is created based on the current center of the map. Those points are then used to create the polygon named “shape”, which is a VEShape object of the type “VEShapeType.Polygon”. Next a series of visual attributes are assigned for the polygon. These include line width, line color, fill color, title, description and icon. Lastly the polygon is added to the map.

Now that we have our polygon, we can implement the code to move it. As mentioned the code is conceptually the same as the Moveable Push Pin example. The same functions and event handlers are implemented, but some enhancements were made to deal with moving a polygon instead of a push pin. We will touch on the changes that were implemented.

“mouseDownHandler” – The primary changes to this function are as follows:
    ...
    currentShape = map.GetShapeByID(e.elementID);
    ...
    previousLoc = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
    ...
    
First the variable “currentShape” is set to the instance of the VEShape object that is associated with the mouse down event. This variable represents the shape that will be moved. Next the variable “previousLoc” is set to an instance of a VELatLong object that represents the latitude and longitude of the current location of mouse cursor.

“mouseMoveHandler” - This function contains the majority of changes that are needed for moving the polygon. The following is the code for the entire function and the new changed will be discussed individually.
    //onmousemove handler
    function mouseMoveHandler(e) {
        var loc = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
        var latVariance = 0;
        var longVariance = 0;
        
        document.getElementById("MouseLat").innerHTML = loc.Latitude.toFixed(4);
        document.getElementById("MouseLng").innerHTML = loc.Longitude.toFixed(4);
        if (moving) {
            map.HideInfoBox(currentShape);
            
            //determine offset
            latVariance = loc.Latitude - previousLoc.Latitude;
            longVariance = loc.Longitude - previousLoc.Longitude;
            
            document.getElementById("LatOffset").innerHTML = latVariance.toFixed(4);
            document.getElementById("longOffset").innerHTML = longVariance.toFixed(4);
            
            //adjust points in current shape
            var currentPoints = currentShape.GetPoints();
            for (var i = 0; i < currentPoints.length ; i++){
                currentPoints[i].Latitude += latVariance;
                currentPoints[i].Longitude += longVariance;
            }
            
            currentShape.SetPoints(currentPoints);
            previousLoc = loc;
            
        }
    }
    
Before we get into the code, let talk about what needs to occur in order to move the polygon. When moving a push pin, the new location of the push pin needed to be passed to the SetPoints() method in the VEShape object that represented the push pin. The new location was in the form of a VELatLong object.

Since our polygon is an instance of a VEShape class, the same process would take place, however, a little more is involved. When moving a push pin, we were dealing with a single point or VELatLong class. When dealing with a polygon, we have multiple points or multiple VELatLong classes. So, in order to move the polygon, all of the points (VELatLong objects) in the polygon need to be re-factored by the amount that the cursor moved. Wow, what a statement! Let’s explain…

Every time the mouse moves, the mouseMoveHandler function is executed. By comparing the previous location of the mouse to the new location of the mouse, we are able to tell how much the mouse has moved. By applying that amount of movement to all of the points in a given polygon, all of the points can be adjusted so that the polygon can be moved to the new location. This process is repeated each time the mouse is moved.

Now that we have the concept outlined, lets look at some code. First two variables are established:
    ...
    var latVariance = 0;
    var longVariance = 0;
    ...
    
These variables, latVariance and longVariance, represent the amount that mouse cursor has moved since the last mouse movement. These are set to zero (0) when the function execute to ensure that a cumulative amount of movement is not captured and only the amount of the last movement is captured.

Next, the amount of movement is captured. This is accomplished as follows:
    ...
    //determine offset
    latVariance = loc.Latitude - previousLoc.Latitude;
    longVariance = loc.Longitude - previousLoc.Longitude;
    ...
    
The current location of the mouse cursor is represented by the variable “loc”, which is a VELatLong object established at the beginning of the function. The previous location of the mouse cursor is represented by the variable “previousLoc”, which is also a VELatLong object. This variable was instantiated back in the “mouseDownHandler” and will be updated through out this process.

By subtracting the latitude and longitude of the previous location from the latitude and longitude of the current location, we are able to determine the offset or how much the latitude and longitude have changed. This offset is then persisted in the variables latVariance and longVariance.

Now that the amount of movement has been determined, it can be applied to the polygon. This is accomplished as follows:
    ...
    //adjust points in current shape
    var currentPoints = currentShape.GetPoints();
    for (var i = 0; i < currentPoints.length ; i++){
        currentPoints[i].Latitude += latVariance;
        currentPoints[i].Longitude += longVariance;
    }

    currentShape.SetPoints(currentPoints);
    previousLoc = loc;
    ...
    
First all points of the polygon are assigned to the array “currentPoints”. The is accomplished by calling the GetPoints() method on the VEShape object, currentShape. This method returns an array of VELatLong objects that are the points of the polygon.

Next the array is looped through so that all of the points in the can be adjusted accordingly. As each iteration of the loop is executed, the latitude and longitude offset/variance is applied to the latitude and longitude of the respective point (VELatLong object) in the array.

Once all of the points have been adjusted, the “currentPoints” array is passed to the SetPoints() method in the VEShape object, currentShape. This effectively moves the polygon to the new location. Lastly, since this function is ending, the previousLoc variable is updated with the current location of the mouse. This is needed in the event that the mouse moves again and the process needs to be repeated.

Wrap-up:

There ya have it….a moveable polygon. Since a polygon is a VEShape object, the process of moving it is similar to moving a push pin, but with a couple of additional steps. Since a polygon has multiple points, where a push pin has a single point, all of the points in the polygon need to be updated in order for the move to occur. Additionally, it would stand to reason that the previous example could be applied to polylines. Since a polyline is a VEShape object and has points, similar to the polygon, the same concept could be used, theoretically, to move a polyline. I’ll leave that for some one else to try. :-)

Now, you might be asking “…why do I need a moveable polygon?” and the answer would be “That’s a great question. Let me get back to you.” I’m sure there is some practical application for this type of functionality. One example might be that you have a defined area of coverage that needs to be tweaked or adjusted.

I guess I will leave the practical application of this up to you. While writing some of the other articles, this concept came into question. I felt compelled to figure it out and share the results. Hopefully it will be of some use to some one, maybe even me!

Any feedback, comments or questions are welcome.

Return to Home Page

©2007-2017, Mike Garza, All Rights Reserved