 Bing Maps Concepts(formerly Virtual Earth) Mike Garza    VEMaps@garzilla.net Mouse Location: PushPin Location: Lat: 00.0000 Lng: 00.0000 Lat: 00.0000 Lng: 00.0000
 ▲ ◄ ► ▼
Concept: Moveable Push Pins, Part 3

In part 3 of what is turning out to be a multiple part series, we’ll take a look at how the direction that a push pin is being moved can be determined. This example builds off the previous example outlined in part 2.

In this example, the map functionality was extended so that the direction that a given push pin is being moved can be determined. An indicator was added to the upper right corner of the map that will display the current direction. As the push pin is moved, the appropriate arrows will change color, indicating the direction.

Walk Through:

Now one might ask, “why would someone need this type of functionality?”. My answer would be, “I don’t really know”. This functionality, in and of itself, might not seem very useful. If you come up with a good reason, let me know. However, in working through concept for part 4 of this series, the direction a push pin was being moved may be something that is needed. Rather than explain this concept along with the concept in part 4 of this series, I thought I would outline it separately and get it out of the way.

“It’s all relative” – Determining which direction the push pin is moving can be achieved by comparing the current location of the push pin relative to where its previous. By capturing the current location of the push pin and subtracting the previous location, a latitude and longitude variance can be computed. The value of this variance can determine which direction the push pin is moving. The implementation of this code is as follow. While some of this code has been covered in previous examples, it’s included here to get a flow for the whole process.

//onmousemove handler
function mouseMoveHandler(e) {
clearTimeout(resetArrows);
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) {
document.getElementById("MarkerLat").innerHTML = loc.Latitude.toFixed(4);
document.getElementById("MarkerLng").innerHTML = loc.Longitude.toFixed(4);
map.HideInfoBox(currentShape);
currentShape.SetPoints(loc);

//determine direction
if (previousLoc){
latVariance = loc.Latitude - previousLoc.Latitude;
longVariance = loc.Longitude - previousLoc.Longitude;

if (latVariance > 0){
document.getElementById("NIndicator").style.color = 'red';
} else if (latVariance < 0){
document.getElementById("SIndicator").style.color = 'red';
}

if (longVariance > 0){
document.getElementById("EIndicator").style.color = 'red';
} else if (longVariance < 0){
document.getElementById("WIndicator").style.color = 'red';
}

resetArrows = setTimeout("resetCompass()", 100);

}
previousLoc = loc;
}
}

The new code added to this function facilitates both the rules of the process as well as updating the UI. The first new line of code is the first line, “clearTimeout(resetArrows);”. This line of code cancels a timer that will be set later in the process. The timer will reset the state of the direction indicator and does not need to be executed if this function is executed again.

Next, two additional variable are declared. They are “latVariance” and “longVariance”. These variables are initialized with the value of zero and will be used later in the process for persisting the value that represents the variance between the current latitude and longitude and the previous latitude and longitude.

The next few lines of code have not changed until you get down to the following:
//determine direction
if (previousLoc){
latVariance = loc.Latitude - previousLoc.Latitude
longVariance = loc.Longitude - previousLoc.Longitude

if (latVariance > 0){
document.getElementById("NIndicator").style.color = 'red';
} else if (latVariance < 0){
document.getElementById("SIndicator").style.color = 'red';
}

if (longVariance > 0){
document.getElementById("EIndicator").style.color = 'red';
} else if (longVariance < 0){
document.getElementById("WIndicator").style.color = 'red';
}

resetArrows = setTimeout("resetCompass()", 100);

}
previousLoc = loc;

First the variable “prevLoc” is tested to make sure it is not NULL. prevLoc is a VELatLong object that persists the previous location of the pushpin prior to entering this function. If prevLoc is NULL, then no previous location has been established and there is no need to execute any code.

If prevLoc does have a value, then a previous location has been established and code to determine which direction the push pin is moving can be executed. First the latitude and longitude variance is established. This is calculated by subtracting the previous push pin location from the current push pin location and is stored in the variables “latVariance” and “longVariance”. The value of the variance is what determines which direction the pin is moving. To be more specific, it is not so much the amount of the value perse, but whether the number is positive or negative.

The value of the variance between the current point and the previous point will be rather small (.0055, for example). If the value is positive it is moving one direction and if it is negative, it is moving the other direction. With out going into a lot of detail, Latitude and Longitude are the coordinate system that is used to identify specific locations on the earth. Latitude represents the y-axis or North/South location and Longitude represents the x-axis or East/West location.

As mentioned, the variance in Latitude and Longitude between the push pin current location and its previous location will determine direction. If the variance value is positive, then the push pin is moving up a given axis. If the variance value is negative, then the push pin is moving down a given axis. Since Latitude and Longitude as just the y and x axis, this concept is applicable.

The next section of code, beginning with “if (latVariance > 0) {“, tests the value of the latitude and longitude value to determine if it is positive or negative, thus identifying the direction. Since positive numbers are greater than zero and negative numbers are less than zero, comparing the variance to zero helps identify the direction. If the Latitude variance is positive (>0) then the push pin is moving up the y-axis or North. If the latitude variance is negative (<0) then the push pin is moving down the y-axis or South. The concept is the same for Longitude except along a different axis. If the Longitude variance is positive (>0) then the push pin is moving up the x-axis or East. If the Longitude variance is negative (<0) then the push pin is moving down the x-axis or West. Once the appropriate condition is determined for Latitude and Longitude, the color style attribute is updated to “red” for the corresponding arrow on the direction indicator added control added to the map.

Now that direction has been determined and the direction indicator control on the map has been updated, the direction indicator needs to be reset. If the control is not reset, the once a direction has been used the arrow would remain activated and the control would not indicate change in direction. This is accomplished with the following line of code:
resetArrows = setTimeout("resetCompass()", 100)

The indicator control cannot be reset immediately with in the function itself as this reset would occur to quickly. The end user would never see the updates to the direction indicator control. To address this, a “pause” is established via the setTimeout() function. A function named “resetCompass()” was created to handle the “reset” of the direction indicator. This function simply resets the color style attributes of the arrows in the indicator control. The setTimeout() function creates a timer that will execute the resetCompass() function after 100 milliseconds. While 100 msec doesn’t seem like a lot of time, it is enough time to let the remainder of the function complete and let the end user see the directional change.

A variable named “resetArrows” is assigned the id of the timer established by the setTimeout() code. If you recall, this variable is used at the beginning of this function in the following line of code:
clearTimeout(resetArrows);

The mouseMoveHandler function is executed each time the mouse is moved. Because the direction indicator control has been set to reset based on a timer, it is possible to execute this function a second time before the timer executes the reset function. If that happens, then the indicator control could reset while the handler function is executing. To avoid this, the “clearTimeout” function is used to cancel the current timer, which is represented by the resetArrows variable. This is just a means of indicating that an update to the indicator control is coming and cancel the reset.

The last line of code in this section handles the persistence of the push pins previous location. At the beginning of this function the variable “loc” is used to capture the current location (VELatLong Object) of the push pin. Now that all of the logic has been executed, we need to remember the location of the push pin so that when this function is executed again, we can make the proper assessments. Mentioned previous, the variable prevLoc is a variable (VELatLong Object) that persists the previous location of the push pin. That variable is updated with the current location with the following line of code:
previousLoc = loc;

Wrap-up:

Wow, that turned out to be quite the overview. When I first started this, I didn’t think it was going to run this long. My apologies. I guess there was more involved in describing this than I thought.

There are a couple of other concepts that are part of this example that were not covered. These are creating the direction indicator control and resetting this. These are pretty straight forward and the code in the example should be enough to indicate how they are implemented. If not, let me know and I can go into more detail.

Like I mentioned, determining which direction a push pin is being moved might not be very useful all by itself, but it may be something that is needed to support a different type of functionality. In part 4 of this series, direction is something that may be needed to implement another type of functionality. I guess we’ll find out when I am done with part 4. :-)

Any feedback, comments or questions are welcome.