I’ve been progressing a bit with my little IPhone PhoneGap Bing Maps app today. I’m at the stage where I can show my custom pushpins on the map within a polygon and centre the map on the polygon.
The next ting I want to do is show the user how to drive to the pin nearest them. In my spatial database I have the latitude and longitude values for the items and I can use STDistance to find how far each item is from the user’s position. The problem here is that it give me the distance “as the crow flies” which in most cases it’s fine but if the item is on a parallel street sometimes I think it’s the closet item but would then end up driving past another item on my way around the block to reach it.
I could return my dataset ordered by the closest (as the bird flies distance). Then I’m going to assume if I grab the 5 nearest items I’ve got a pretty damn good chance that one of those is in fact the closest to drive to. I’m going to use the Bing Maps Directions Module to plot the route for each one. I take the trip from my location to an item, then back, then to the next time and back as waypoints so I can process the data.
For the purpose of this example, I’m just grabbing the first 5 points that come back from my service as it doesn’t calculate the individual distances yet. Done like so:
First we create and load the directions module.
var directionsManager; function loadDirectionsModule() { if (!directionsManager) { Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: createDirectionsManager }); } else { createDirectionsManager(); } }
function createDirectionsManager() { if (!directionsManager) { directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map); } directionsManager.resetDirections(); directionsErrorEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', function(arg) { alert(arg.message) }); directionsUpdatedEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', function() { alert(‘directions updated’)); }
After we have our current location and have called our service to get the nearby items we can determine the routes, by adding each item as return leg in the journey.
function calculateBestDrivingRoute(hydrantResult, latitude, longitude){ if (!directionsManager) { createDirectionsManager(); } directionsManager.resetDirections(); // Set Route Mode to driving directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.driving }); // your position var fromWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: new Microsoft.Maps.Location(latitude, longitude) }); directionsManager.addWaypoint(fromWaypoint); for (var i=0; i<hydrantResult.Hydrants.length; i++){ if (i<5) { // hydrant var toWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: new Microsoft.Maps.Location(hydrantResult.Hydrants[i].Latitude, hydrantResult.Hydrants[i].Longitude) }); directionsManager.addWaypoint(toWaypoint); var fromWaypoint2 = new Microsoft.Maps.Directions.Waypoint({ location: new Microsoft.Maps.Location(latitude, longitude) }); directionsManager.addWaypoint(fromWaypoint2); } else { continue; } } if (directionsManager.getAllWaypoints().length > 1){ directionsManager.calculateDirections(); } }
This gives a driving route with a number of legs that we can now manipulate. We want the shortest leg from our current position to an item, so we need to take every 2nd leg and query its distance. Once we have the shortest leg, we can then redo the route.
First we modify our handler to call another function when the directions get updated from our original search.
directionsUpdatedEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', calculateShortestRoute);
Then we loop through the legs and find the shortest one. Once we’ve found it we draw it on the map.
function calculateShortestRoute(e){ if (e.route[0].routeLegs.length > 1) { var shortestRoute = e.route[0].routeLegs[0]; for (var i=0; i<e.route[0].routeLegs.length; i= i+2) { if (shortestRoute.summary.distance > e.route[0].routeLegs[i].summary.distance){ shortestRoute = e.route[0].routeLegs[i]; } } createDrivingRoute(shortestRoute.startWaypointLocation.latitude, shortestRoute.startWaypointLocation.longitude, shortestRoute.endWaypointLocation.latitude, shortestRoute.endWaypointLocation.longitude); } }
function createDrivingRoute(fromLatitude, fromLongitude, toLatitude, toLongitude) { if (!directionsManager) { createDirectionsManager(); } directionsManager.resetDirections(); directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.driving }); var fromWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: new Microsoft.Maps.Location(fromLatitude, fromLongitude) }); directionsManager.addWaypoint(fromWaypoint); var toWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: new Microsoft.Maps.Location(toLatitude, toLongitude) }); directionsManager.addWaypoint(toWaypoint); directionsManager.calculateDirections(); }
Then it will show us the driving route to the nearest item.