Skip to main content
GuidesAPI ReferenceExamples

Navigation

Estimated reading time: 9 minutes

This complete example displays a movable and zoomable map, embedded inside an html element on a webpage, computes and renders a route and simulates navigation along the route.

Overview

A desired route is defined using at least a given starting point and a given destination, both specified using (longitude, latitude) coordinate pairs. Optionally, additional waypoints can be added between the starting and destination points, to more precisely determine the desired resulting route.
If the map is moved during the simulated navigation, the camera will no longer follow the green arrow.
To start following again after panning the map, click the blue arrow icon.
The map supports pan and zoom, and is fully 3D, so holding down the shift key and panning will simultaneously rotate and tilt the map.

See the example fullscreen

If you want to jump right in, you can download the HTML file and the JavaScript file for this example in the same directory, and then load the HTML file in a web browser to try it out right now!

Or you can continue reading for a detailed explanation of the code.

How it works

 // Start by setting your token from https://developer.magiclane.com/api/projects
gem.core.App.token="your_API_key_token";

The first step in JavaScript is to set your API key token gem.core.App.token, which you can get at the Magic Lane website, see the Getting Started tutorial.
You only need to type your email address and create a new password.

 function activateLocation()
{
// View of the map
var defaultView = gem.core.App.getDefaultScreen().getDefaultMapView();
// Set the camera to follow the simulated position of the green arrow along the route on the map
// when the blue arrow icon is clicked; panning or clicking on the map during the simulation
// turns off following position, and here it is turned back on upon clicking the blue arrow icon
defaultView.startFollowingPosition();
}

// Draw the next turn symbol to the left of the instructions in the top panel
function setCanvas(image_data, width, height, canvas_name)
{
var canvas = document.getElementById(canvas_name);
if (canvas)
{
var imageData = new ImageData(new Uint8ClampedArray(image_data), width, height);
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').putImageData(imageData, 0, 0);
}
else
{
console.error('Canvas name not valid');
}
}

The function to resume following the green arrow after panning the map is defined at line 4.
The function to draw the next turn symbol is defined at line 15.

// The main function
gem.core.App.registerInitialCallFunction(function()
{
// View of the map
var defaultView = gem.core.App.getDefaultScreen().getDefaultMapView();

// Sample departure point and destination coordinates for a route
var departureCoordinates = {latitude: 37.7749,longitude: -122.4194, altitude: 0, bearing: 0.0};
var destinationCoordinates = {latitude: 38.5816,longitude: -121.4944, altitude: 0, bearing: 0.0};

var defaultRoute = new gem.routesAndNavigation.RoutesRequest();
defaultRoute.addWaypoint(departureCoordinates);
defaultRoute.addWaypoint(destinationCoordinates);
defaultRoute.setBuildTerrainProfile(false);

// This function is called when calculateRoute completes
var callbackFunction = function()
{
var msecFlightDuration = 3000;

// Draw the computed route on the map
defaultView.showRouteInView(defaultRoute.get(0),true);

// Fly the camera to the result route bounding box/area, with flight duration in milliseconds
defaultView.centerOnRoute(defaultRoute.get(0),msecFlightDuration);

var navigationInstructionEM = new gem.routesAndNavigation.NavigationListener();
// Function to write navigation instructions and statistics in their respective panels on the map
var navInstructionUpdate = function()
{
// Image of the next turn displayed to the left of the instructions
var bitmapContainer = new gem.core.BitmapContainer(30,30);
gem.routesAndNavigation.Navigation.getNextTurnImageInBitmap(bitmapContainer);
setCanvas(bitmapContainer.toImageData(),30,30,"myCanvas");
var distancetoNext =
gem.routesAndNavigation.Navigation.getTimeDistanceToNextTurn().totaldistance;
var unit=" meters "
if (distancetoNext>1000)
{
distancetoNext = distancetoNext/1000.0;
unit = " Km ";
}
// Update the instructions, time and distance remaining, in the top and bottom panels
document.getElementById('navigationText').innerHTML = "<p> In " + distancetoNext.toFixed(2)
+ unit + gem.routesAndNavigation.Navigation.getNextTurnInstruction() + "</p>";
var remainedTimeDistance = gem.routesAndNavigation.Navigation.getRemainingTravelTimeDistance();
document.getElementById('bottomPanelRemainingDistance').innerHTML
= (remainedTimeDistance.totaldistance/1000).toFixed(2) + "km";
var measuredTime = new Date(null);
measuredTime.setSeconds(remainedTimeDistance.totaltime); // specify value in seconds
var MHSTime = measuredTime.toISOString().substr(11, 5);
document.getElementById('bottomPanelRemainingTime').innerHTML = MHSTime+"hr";
bitmapContainer.delete();
};
navigationInstructionEM.registerNavInstructionUpdateListener(navInstructionUpdate);
var progressListener = function()
{
// Set the camera to follow the simulated position of the green arrow along the route on the map
defaultView.startFollowingPosition();
};

// Make the navigation instructions and statistics panels visible when navigation starts
var navpanel = document.getElementById('navigationPanel');
var bottomPanel = document.getElementById('bottomPanel');

// Start simulated navigation after the fly to the route is complete
setTimeout(function()
{
navpanel.style.visibility='visible';
bottomPanel.style.visibility='visible';
gem.routesAndNavigation.Navigation.startSimulation(defaultRoute.get(0),progressListener,
navigationInstructionEM);
},msecFlightDuration);

};

// Compute the defaultRoute from the starting point to the destination initialized above
defaultRoute.calculateRoute(callbackFunction);
});

// Initializes the app
gem.core.App.initApp();

The main function where execution starts is defined: gem.core.App.registerInitialCallFunction(function()
The default view of the map is loaded: var defaultView = gem.core.App.getDefaultScreen().getDefaultMapView();

Sample departure and destination coordinates are defined for use to compute a route and to demonstrate navigation along a route.
var departureCoordinates = {latitude: 37.7749,longitude: -122.4194, altitude: 0, bearing: 0.0};
var destinationCoordinates = {latitude: 38.5816,longitude: -121.4944, altitude: 0, bearing: 0.0};

Altitude is in meters, and bearing(heading) is in degrees, where 0 is north, 90 is east, 180 is south and 270 (or -90) is west. A route request object is obtained, and the departure and destination coordinates are set in it.
var defaultRoute = new gem.routesAndNavigation.RoutesRequest();
defaultRoute.addWaypoint(departureCoordinates);
defaultRoute.addWaypoint(destinationCoordinates);

Optionally, additional waypoints could be added between the departure and the destination, so the calculated route passes through those locations.

The route calculation is requested. The given callback function is called when the route computation is complete and the simulation starts automatically.
defaultRoute.calculateRoute(callbackFunction);

This function is called when calculateRoute completes:
var callbackFunction = function()

Draw the first computed route on the map (index 0), as the route computation results in a list of routes, as there could be multiple alternate routes between the departure and destination points:
defaultView.showRouteInView(defaultRoute.get(0),true);

Fly the camera to the route bounding box/area, with flight duration in milliseconds, so this is a 3 second flight. Setting this value to 0 results in jumping instantly to the route.
defaultView.centerOnRoute(defaultRoute.get(0),msecFlightDuration);

A timeout is set, setTimeout(function() so that the navigation simulation starts automatically, gem.routesAndNavigation.Navigation.startSimulation(defaultRoute.get(0) after the flight to the first computed route in the resulting list of routes between the specified departure and destination points, is complete. \

The function to update the navigation instructions and statistics in their respective top and bottom panels on the map during simulated navigation is defined.
var navInstructionUpdate = function()

Panning or clicking on the map during the simulated navigation along the computed route turns off following position. When the blue arrow icon is clicked, this function is called, function activateLocation() which causes the camera to again follow the position of the green arrow as it moves along the route.

The example is 2 plain text files, one with the HTML code ( .html file extension) and the other with the JavaScript code ( .js file extension). To run the example, the HTML file is loaded in a browser. The .js file should be in the same directory, as it will be loaded automatically.

Source code for this example:

Right-click on the links and select Save As.

JavaScript Examples

Maps SDK for JavaScript Examples can be downloaded or cloned with Git