If using the Bing Maps web SDK (assuming that's the case given that you are using directions manager), you can use CSS print layouts and define how instructions should be printed when the browsers print button is used (no need for a custom button to be added to your webpage). For example:
<!DOCTYPE html>
<html>
<head>
<title>directionscreatetruckrouteHTML</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
<style type='text/css'>
body {
margin:0;
padding:0;
overflow:hidden;
}
#instructionsPanel {
position: relative;
float: left;
width: 380px;
height: 100vh;
height: calc(100vh - 50px);
overflow-y: auto;
}
#myMap {
position: relative;
float:left;
width: calc(100vw - 380px);
height: 100vh;
}
/** Print layout */
@media print
{
.no-print, .no-print *
{
display: none !important;
}
#instructionsPanel {
/** Allow instructions panel to overflow so it prints across multiple pages. */
overflow: unset;
height: unset;
}
}
</style>
</head>
<body>
<div id='instructionsPanel'></div>
<!-- Add no-print class to map div. -->
<div id="myMap" class="no-print"></div>
<script type='text/javascript'>
function loadMapScenario() {
var mm = Microsoft.Maps;
var map = new mm.Map(document.getElementById('myMap'), {
/* No need to set credentials if already passed in URL */
center: new mm.Location(40.418386, -80.019262),
zoom: 16
});
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function () {
var mmd = mm.Directions;
var dm = new mmd.DirectionsManager(map);
dm.setRenderOptions({
itineraryContainer: document.getElementById('instructionsPanel')
});
dm.setRequestOptions({
routeMode: mmd.RouteMode.truck
});
dm.addWaypoint(new mmd.Waypoint({
address: '590 Crane Ave, Pittsburgh, PA',
location: new mm.Location(40.419228, -80.018138)
}));
dm.addWaypoint(new mmd.Waypoint({
address: '600 Forbes Ave, Pittsburgh, PA',
location: new mm.Location(40.437550, -79.993610)
}));
dm.calculateDirections();
});
}
</script>
<script type="text/javascript" src="https://www.bing.com/api/maps/mapcontrol?callback=loadMapScenario&key=<Your Bing Maps Key>" async defer></script>
</body>
</html>
You can use additional CSS to customize the layout if you want. If you want to include a map, it gets a bit tricky as large maps will likely end up getting clipped and excluding a portion of the map. Normally in that case you would generate a map image using the REST imagery service and include that in your page as a hidden element that is displayed when printed. However, it doesn't look like that service supports truck routes. To get around this you can grab the points that make up the route line, encode them, then use the REST imagery service to create a static map image. For example:
<!DOCTYPE html>
<html>
<head>
<title>directionscreatetruckrouteHTML</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
<style type='text/css'>
body {
margin:0;
padding:0;
overflow:hidden;
}
#printableMap {
display: none;
position: relative;
}
#instructionsPanel {
position: relative;
float: left;
width: 380px;
height: 100vh;
height: calc(100vh - 50px);
overflow-y: auto;
}
#myMap {
position: relative;
float:left;
width: calc(100vw - 380px);
height: 100vh;
}
/** Print layout */
@media print
{
.no-print, .no-print *
{
display: none !important;
}
#instructionsPanel {
/** Allow instructions panel to overflow so it prints across multiple pages. */
overflow: unset;
height: unset;
}
#printableMap {
display: unset;
}
}
</style>
</head>
<body>
<div id='printableMap'></div>
<div id='instructionsPanel'></div>
<!-- Add no-print class to map div. -->
<div id="myMap" class="no-print"></div>
<script type='text/javascript'>
var map, mm, mmd, dm;
function loadMapScenario() {
mm = Microsoft.Maps;
map = new mm.Map(document.getElementById('myMap'), {
/* No need to set credentials if already passed in URL */
center: new mm.Location(40.418386, -80.019262),
zoom: 16
});
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', function () {
mmd = mm.Directions;
dm = new mmd.DirectionsManager(map);
dm.setRenderOptions({
itineraryContainer: document.getElementById('instructionsPanel')
});
dm.setRequestOptions({
routeMode: mmd.RouteMode.truck
});
//Add event to monitor for when the directions have been updated.
mm.Events.addHandler(dm, 'directionsUpdated', directionsUpdated);
dm.addWaypoint(new mmd.Waypoint({
address: '590 Crane Ave, Pittsburgh, PA',
location: new mm.Location(40.419228, -80.018138)
}));
dm.addWaypoint(new mmd.Waypoint({
address: '600 Forbes Ave, Pittsburgh, PA',
location: new mm.Location(40.437550, -79.993610)
}));
dm.calculateDirections();
});
}
function directionsUpdated(e) {
//Create a REST imagery request that includes a truck route.
//Get the current route index.
var route = dm.getCurrentRoute();
if (route && route.routePath && route.routePath.length > 0) {
//Encode the route coordinates.
var enc = createEncodings(route.routePath);
//Get the map dimensions.
var w = map.getWidth();
var h = map.getHeight();
//Get the maps center and zoom level.
var c = map.getCenter();
var z = map.getZoom();
//Scale the map if it is too big.
if(w > 400){
var ratio = Math.floor(w / 400);
w = Math.round(w/ratio);
h = Math.round(h/ratio);
z = z - ratio + 1;
}
var startCoord = route.routePath[0];
var endCoord = route.routePath[route.routePath.length - 1];
//Get a session key from the map.
map.getCredentials((key) => {
//Create a REST request URL.
var url = `https://dev.virtualearth.net/REST/V1/Imagery/Map/Road/${c.latitude},${c.longitude}/${z}?mapSize=${w},${h}&pp=${startCoord.latitude},${startCoord.longitude};79;A&pp=${endCoord.latitude},${endCoord.longitude};80;B&dc=l,FF1E90FF,5;enc:${enc}&fmt=png&key=${key}`;
//Request and load an image.
var img = new Image();
img.onload = () => {
//Add image to the page.
var pm = document.getElementById('printableMap');
pm.innerHTML = '';
pm.appendChild(img);
//Trigger printing.
window.print();
};
img.src = url;
});
}
}
function createEncodings(coords) {
var i = 0;
var plat = 0;
var plng = 0;
var encoded_points = "";
for(i = 0; i < coords.length; ++i) {
var lat = coords[i].latitude;
var lng = coords[i].longitude;
encoded_points += encodePoint(plat, plng, lat, lng);
plat = lat;
plng = lng;
}
return encoded_points;
}
function encodePoint(plat, plng, lat, lng) {
var dlng = 0;
var dlat = 0;
var late5 = Math.round(lat * 1e5);
var plate5 = Math.round(plat * 1e5)
var lnge5 = Math.round(lng * 1e5);
var plnge5 = Math.round(plng * 1e5)
dlng = lnge5 - plnge5;
dlat = late5 - plate5;
return encodeSignedNumber(dlat) + encodeSignedNumber(dlng);
}
function encodeSignedNumber(num) {
var sgn_num = num << 1;
if (num < 0) {
sgn_num = ~(sgn_num);
}
return(encodeNumber(sgn_num));
}
function encodeNumber(num) {
var encodeString = "";
while (num >= 0x20) {
encodeString += (String.fromCharCode((0x20 | (num & 0x1f)) + 63));
num >>= 5;
}
encodeString += (String.fromCharCode(num + 63));
return encodeString;
}
</script>
<script type="text/javascript" src="https://www.bing.com/api/maps/mapcontrol?callback=loadMapScenario&key=<Your Bing Maps Key>" async defer></script>
</body>
</html>
As for sharing a truck route with a mobile device, there is a couple of ways to do this depending on how you want the end user experience to be. Sending the raw instructions is easier than sending an interactive experience. Here are a couple of ways of accomplishing this:
- Modify the example above to take in query string parameters for route (or create a separate similar page). Then grab route parameters when you want to send the route and create a query string. This will allow the user to see an interactive map and the route instructions. Note, this will not provide turn by turn navigation experience while they drive (terms of use do not allow that).
- Grab the instructions and send them via email or through a custom service to the driver. This will just provide the raw instructions.
Note that turn by turn navigation would be a lot more difficult to achieve as few mobile map apps support truck routing or passing in raw route paths. If this is a requirement, I recommend reaching out to TomTom as they have navigation SDK's and devices for trucks.