Draggable Routes in Bing Maps

There have been several recent posts asking how to implement draggable routes in Bing Maps. Following on from my New Year’s resolution, I thought I’d write about how to do this.

To start with, it’s easiest to consider a route between a set number of existing draggable waypoints, as in the following code listing:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</a>>
<html>
<head>
 <title>Draggable Route</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 <script type="text/javascript" src="<a href="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&quot;">http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"</a>></script>
 <script type="text/javascript">
 var map = null;
 var waypointLayer = new Microsoft.Maps.EntityCollection();
 var routeLayer = new Microsoft.Maps.EntityCollection();

function GetMap() {
 // Initialize the map
 map = new Microsoft.Maps.Map(
 document.getElementById("mapDiv"),
 {
 credentials: "BINGMAPSKEY",
 mapTypeId: "r",
 center: new Microsoft.Maps.Location(52.75, -1),
 zoom: 7
 }
 );

// Define initial waypoints for the route
 var waypoints = [
 new Microsoft.Maps.Pushpin(new Microsoft.Maps.Location(52.6, 1.26)),
 new Microsoft.Maps.Pushpin(new Microsoft.Maps.Location(51.75, -1.26)),
 new Microsoft.Maps.Pushpin(new Microsoft.Maps.Location(53, -2)),
 new Microsoft.Maps.Pushpin(new Microsoft.Maps.Location(54, -1))
 ];

// Make the waypoints draggable, attach the drag handler, and add to the layer
 for (var i = 0; i < waypoints.length; i++) {
 waypoints[i].setOptions({ draggable: true, text: i.toString() });
 Microsoft.Maps.Events.addHandler(waypoints[i], 'dragend', UpdateRoute);
 waypointLayer.push(waypoints[i]);
 }

// Add the layers to the map
 map.entities.push(routeLayer);
 map.entities.push(waypointLayer);

// Calculate the initial route on the map
 UpdateRoute();
 }

function UpdateRoute(credentials) {
 map.getCredentials(MakeRouteRequest);
 }

function MakeRouteRequest(credentials) {

// Build up the string containing waypoint arguments
 var wpargs = "";
 for (var i = 0; i < waypointLayer.getLength(); i++) {
 var wp = waypointLayer.get(i).getLocation();
 wpargs = wpargs + "wp." + i + "=" + wp.latitude + "," + wp.longitude + "&";
 }
 // Append to the URL for the REST roue service
 var routeRequest = "<a href="http://dev.virtualearth.net/REST/v1/Routes?&quot;">http://dev.virtualearth.net/REST/v1/Routes?"</a> + wpargs + "routePathOutput=Points&output=json&jsonp=RouteCallback&key=" + credentials;

CallRestService(routeRequest);
 }

function RouteCallback(result) {
 // Check that we have a valid response
 if (result && result.resourceSets && result.resourceSets.length > 0 && result.resourceSets[0].resources && result.resourceSets[0].resources.length > 0)
 {
 // Construct a polyline of the route
 var routeline = result.resourceSets[0].resources[0].routePath.line;
 var routepoints = new Array();
 for (var i = 0; i < routeline.coordinates.length; i++) {
 routepoints[i] = new Microsoft.Maps.Location(routeline.coordinates[i][0], routeline.coordinates[i][1]);
 }
 var routeshape = new Microsoft.Maps.Polyline(routepoints, { strokeColor: new Microsoft.Maps.Color(200, 255, 140, 0) });
 // Add the route polyline to the map
 routeLayer.clear();
 routeLayer.push(routeshape);
 }
 }

function CallRestService(request) {
 var script = document.createElement("script");
 script.setAttribute("type", "text/javascript");
 script.setAttribute("src", request);
 document.body.appendChild(script);
 }
 </script>
</head>
<body onload="GetMap();">
 <div id="mapDiv" style="position: relative; width: 800px; height: 600px;"></div>
</body>
</html>

WordPress won’t let me embed an interactive map into a post, but you can see a static image of the map created below. Each waypoint is draggable, and the route is automatically recalculated whenever any point is moved.

image

Now that you’ve seen how to make a route between existing waypoints draggable, it’s relatively simple to extend this example to add additional waypoints to the route. The steps required are as follows:

  1. Firstly, you need to choose what action will be used to add the additional waypoint – for example: a click on the map, or a drag on the existing polyline route, etc., and define an appropriate handler to listen for this event using the Microsoft.Maps.Events.addHandler() method.
  2. When the event fires, create a Location object representing the coordinates of the new waypoint. To do so, convert the pixel reference passed by the event handler to a Location, using the Microsoft.Maps.Map.tryPixelToLocation() method.
  3. Now, you need to insert the new Location object at the appropriate position in the array of waypoints. Note that the “appropriate” position is subjective and depends on your application – you might, for example, want to allow users to sequentially define the order in which waypoints are visited (in which case, just push each new waypoint onto the end of the array, in the order they are defined), or you might allow users to choose only the location of the waypoints and use application logic to optimise the order in which they are visited (by, e.g. using the Haversine formula to determine the two closest existing waypoints in the route and insert the new Location between them). Perhaps you want different behaviours depending on whether the user clicked (and released), or if they clicked and dragged on the map. For example, consider the following existing route, and suppose the user clicked, dragged and released the mouse as shown:

image

The new point could be inserted into the array of waypoints between waypoints 1 and 2, since that was the position of the point on the route that was originally clicked. Or, the new waypoint could be inserted between waypoints 0 and 1, since that is the location that would optimise the generated route. Or the new waypoint could be inserted at the end of the array, after waypoint 3, since it is the last waypoint to be added to the route. It’s up to you to decide what rules to use when adding waypoints to an existing route, and where to place the new Location in the existing array of waypoints.

4.  Once you’ve added the new Location(s) into the appropriate position of the waypoints array, simple call the UpdateRoute() method to request the new route and plot it on the map.

This entry was posted in Bing Maps and tagged , , . Bookmark the permalink.

One Response to Draggable Routes in Bing Maps

  1. Pingback: benpowell.org

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s