In this article, we will see how to incorporate the Bing Maps V8 Web Control and use the Directions Manager class in order to create sophisticated maps with routing and directions.

The process of generating map routes with the Bing Maps Control is similar to creating a static map in our previous article, however, we need to use the Directions Module and deal with multiple map coordinates when saving the map routes. In this article, we will use a ColdFusion server component in order to loop through the map routes to save them to the database. However, most of the code here is generic and you can adapt our technique for any web technology. 

Implementing the Web V8 Control to Generate Map Routes and Directions in Your Own Application


In Galaxie Blog, I have implemented the Bing V8 Control in order to allow blog administrators to generate their own Bing Maps with routing capabilities. Click on the image below to see this interface in action.


Real-Time Example

The following code will incorporate the Bing Maps control into your own application. Users will be able to add multiple locations on a map and the Bing Maps Direction Manager will suggest the best routes. Once the suggested route has been confirmed by the user, the Directions Manager will generate the route along with the directions. I will show you how to parse these routes and save them to a database in order to create a map and draw the routes like we have done here at the top of this page.


Viewing the Code

Click on the button below to view the code. Both the client-side and server-side code using ColdFusion will be shown.

 


Explaining the Code

This code contains the JavaScript functions to implement the Bing Maps V8 Web Control, CSS to set the display properties on the containers, and HTML to create the forms. Additionally, we will include an example of the ColdFusion server-side component to loop through the routes to save them to the database. 


JavaScript Code


Like our previous article discussing how to create static routes, inside of the GetMap() function, we are instantiating a map to the myMap DIV element with the Bing Maps Control.


map = new Microsoft.Maps.Map('#myMap', {});

Next, we are loading the Bing Maps Directions module and attaching the DirectionsManager class to the map that we have just created.


// Load the directions module.
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function () {
		// Create an instance of the directions manager.
		directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);

Here we are specifying where the directions manager will display the route directions and what container is used as a direction panel. Both of these DIV elements are in the HTML code.


// Specify where to display the route instructions.
directionsManager.setRenderOptions({ itineraryContainer: '#directionsItinerary' });
// Specify the where to display the input panel
directionsManager.showInputPanel('directionsPanel');

The getWayPoints() function has quite a bit of custom code that I wrote in order to format the routes. I am getting the name, waypoint, latitude, and longitude of each of the waypoints and using these values to format two different strings.

In the example at the top of the page, for example, St George Utah is the first waypoint, Zion National Park is the second waypoint, etc.

The formatting formatting for these first two waypoints is like so:


Text variables (name waypoint latitude, latitude):

  • Name St George waypoint 1 -37.095169, -113.575974
  • Name Zion National Park waypoint 2 37.297817, -113.028770
    Note: the waypoint is the numeric index of the item.

valuesList variables (name_latitude_longitude):

  • St George_-37.095169_-113.575974*
  • Zion National Park_37.297817_-113.028770*

The text variables are used to output the waypoints to the page and are written in plain English, and the valuesList variables are passed to the server.

On the server, I am treating the valuesList string as a ColdFusion list object and will loop through it on the server to save the values to the database. This should become clearer when we discuss the server-side code.

There are other ways to pass these values, for example, I could break every way-point out into its own JSON string, but ColdFusion excels at handling formatted strings like this as a list object, and am using this approach instead.


// We need to extract the waypoints
function getWaypoints(){
	var wp = directionsManager.getAllWaypoints();

	var text = '';
	var valuesList = '';
	var locationCoordinateList = '';

	for(var i=0; i < wp.length; i++){
		var loc = wp[i].getLocation();
		// console.log(loc)
		// Our text variable can be use to output the results to the console when there are errors
		text += 'name ' + loc.name + ', waypoint ' + i + ': ' + loc.latitude + ', ' + loc.longitude + '
';
		// Create a values list. We will loop through this on the server.
		if (i == 0){
			valuesList += loc.name + '_' + loc.latitude + '_' + loc.longitude;
		} else {
			valuesList += '*' + loc.name + '_' + loc.latitude + '_' + loc.longitude;
		}

	}
	//alert(text);
	// Post the values to the server
	saveMapRoute(valuesList);
}

The getWayPoints function passes the valuesList string that we created to the saveMapRoute function. The saveMapRoute function simply passes the valuesList string to the server via AJAX like so:


function saveMapRoute(locationGeoCoordinates){

	jQuery.ajax({
		type: 'post', 
		url: '<cfoutput>#application.baseUrl#</cfoutput>/common/cfc/ProxyController.cfc?method=saveMapRoute',
		// Serialize the form
		data: {
			locationGeoCoordinates: locationGeoCoordinates
		},
		dataType: "json",
		success: saveMapRouteResponse, // calls the result function.
		error: function(ErrorMsg) {
			console.log('Error' + ErrorMsg);
		}
	// Extract any errors. This is a new jQuery promise based function as of jQuery 1.8.
	}).fail(function (jqXHR, textStatus, error) {
		// Handle errors (full code is not shown in this demonstration)	
	});
}

Finally, the saveMapRouteResponse callback function is called. I use this function to draw a new map into a TinyMce editor. There is no other functionality here.


function saveMapRouteResponse(response){
	// Handle the response. I typically generate client-side HTML and insert it into a TinyMce editor here. 
}

Client-Side Code


The following code on the client side passes the Bing Maps API key to the Bing Maps map control service to initiate the Bing Maps V8 control.

The directionsContainer DIV element contains the content on the left side of the Map control and the createRoute div contains a button that invokes the getWayPoints JavaScript function that we have already covered.

The directionsPanel and directionsIntinery DIV containers are populated by the directionsManager.

Finally, the map is drawn in the empty myMap DIV at the bottom of the code.


<!--- Get the map UI from Bing --->
<script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?callback=GetMap&key=<cfoutput>#application.bingMapsApiKey#</cfoutput>' async defer></script>

<!--- Container to the left holding the search input and directions --->
<div class="directionsContainer">

	<table align="center" class="k-content" width="95%" cellpadding="5" cellspacing="0">
		<tr>
			<td>Create a route by searching in addresses between two or more points. You can add up to 15 waypoints. When complete, click on the button below to continue.</td>
		</tr>
		<tr>
			<td>
				<button id="createRoute" class="k-button k-primary" type="button" onclick="getWaypoints()">Complete</button>
			</td>
		</tr>
	</table>

	<div id="directionsPanel"></div>
	<div id="directionsItinerary"></div>

	<div id="output"></div>

</div><!---<div class="directionsContainer">--->

<!--- Map container to the right of the screen holding the map--->
<div id="myMap"></div>	

Server-Side Code


The code example shown is a small subset of the actual code but it shows you how to get the waypoints sent to the server by the saveMapRoute JavaScript via AJAX.

As I explained, I am sending in a specially formatted string that separates the rows of data with an asterisk (*), and the columnar data, such as the location, latitude, and longitude are all separated by an underscore (_). Here, we are using ColdFusion's listGetAt function to get the underlying data.

Here, we are simply looping through the locationGeoCoordinates string, creating a new row every time the asterisk is found, and getting the location, latitude, and latitude. In my actual code, I am saving these data elements to the database, but that actual code is not shown.


<cffunction name="saveMapRoute" access="public" returnType="string" output="true"
		hint="Saves a map into the database">
	<cfargument name="locationGeoCoordinates" type="string" required="false" default="" hint="Pass in the address, and latitude and longitude separated by a comma. The locationGeoCoordinates should be a CF list object. The data should be formatted like so: address_geoCoordinates_address1_geoCoordinates1*address2_geoCoordinates2_ etc">

	<!--- Save the the routes into the database --->
	<!--- Loop through our custom location geo coordinate object that was sent --->
	<cfloop from="1" to="#listLen(arguments.locationGeoCoordinates, '*')#" index="i">
		<!--- Extract the data from the list. --->
		<cfset geoLocObject = listGetAt(arguments.locationGeoCoordinates, i, '*')>
		<cfset routeLocation = listGetAt(geoLocObject, 1, '_')>
		<cfset routeLatitude = listGetAt(geoLocObject, 2, '_')>
		<cfset routeLongitude = listGetAt(geoLocObject, 3, '_')>
	</cfloop>

</cffunction>

Further Reading

Happy Mapping!