Learn how to find a route and directions.
Routing is the process of finding the path from an origin to a destination in a street network. You can use the route service to find routes, get driving directions, calculate drive times, and solve complicated, multiple vehicle routing problems. To create a route, you typically define a set of stops (origin and one or more destinations) and use the service to find a route with directions. You can also use a number of additional parameters such as barriers and mode of travel to refine the results.
In this tutorial, you use ArcGIS REST JS to access the routing service to get route. You click on the map to get an origin and destination that are used to get a route and directions from the route service. The directions are also displayed on the map.
Prerequisites
An ArcGIS Location Platform or ArcGIS Online account.
Steps
Get the starter app
Select a type of authentication below and follow the steps to create a new application.
Set up authentication
Create developer credentials in your portal for the type of authentication you selected.
Set developer credentials
Use the API key or OAuth developer credentials so your application can access location services.
Add references to ArcGIS REST JS
-
In the
<head
element, add references to the ArcGIS REST JS library.> Use dark colors for code blocks <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v10.1.0/ol.css" type="text/css" /> <script src="https://cdn.jsdelivr.net/npm/ol@v10.1.0/dist/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol-mapbox-style@12.3.5/dist/olms.js" type="text/javascript"></script> <script src="https://unpkg.com/@esri/arcgis-rest-request@4.0.0/dist/bundled/request.umd.js"></script> <script src="https://unpkg.com/@esri/arcgis-rest-routing@4.0.0/dist/bundled/routing.umd.js"></script>
Update the map
A navigation basemap layer is typically used in geocoding and routing applications. Update the basemap layer to use arcgis/navigation
.
-
Update the basemap and the map initialization to center on location
[-79.3832,43.6532]
, Toronto.Use dark colors for code blocks <script> /* Use for API key authentication */ const accessToken = "YOUR_ACCESS_TOKEN"; // or /* Use for user authentication */ // const session = await arcgisRest.ArcGISIdentityManager.beginOAuth2({ // clientId: "YOUR_CLIENT_ID", // Your client ID from OAuth credentials // redirectUri: "YOUR_REDIRECT_URL", // The redirect URL registered in your OAuth credentials // portal: "YOUR_PORTAL_URL" // Your portal URL // }) // const accessToken = session.token; const map = new ol.Map({ target: "map" }); const view = new ol.View({ center: ol.proj.fromLonLat([-79.3832, 43.6532]), // Toronto zoom: 13 }); map.setView(view); const basemapId = "arcgis/navigation"; const basemapURL = `https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/${basemapId}?token=${accessToken}`; olms.apply(map, basemapURL).then(function (map) { // Add Esri attribution // Learn more in https://esriurl.com/attribution const source = map.getLayers().item(0).getSource(); source.setAttributions("Powered by <a href='https://www.esri.com/en-us/home' target='_blank'>Esri</a> | ") }); </script>
Add end point layers
To display circles for the start and end of the route, you will create two circle vector layers.
-
Define variables to hold the start layer, end layer, and the route layer that you will create. Create a function called
add
.Circle Layers Use dark colors for code blocks const view = new ol.View({ center: ol.proj.fromLonLat([-79.3832, 43.6532]), // Toronto zoom: 13 }); map.setView(view); let startLayer, endLayer, routeLayer; function addCircleLayers() { }
-
Inside the function, create a new
Vector
layer for thestart
. Use aLayer Circle
style to make a white circle with black stroke. Add it to the map withmap.add
. Do the same forLayer end
, but with a black fill and white stroke.Layer Use dark colors for code blocks let startLayer, endLayer, routeLayer; function addCircleLayers() { startLayer = new ol.layer.Vector({ style: new ol.style.Style({ image: new ol.style.Circle({ radius: 6, fill: new ol.style.Fill({ color: "white" }), stroke: new ol.style.Stroke({ color: "black", width: 2 }) }) }) }); map.addLayer(startLayer); endLayer = new ol.layer.Vector({ style: new ol.style.Style({ image: new ol.style.Circle({ radius: 7, fill: new ol.style.Fill({ color: "black" }), stroke: new ol.style.Stroke({ color: "white", width: 2 }) }) }) }); map.addLayer(endLayer); }
-
Inside
olms
load handler, calladd
.Circle Layers Use dark colors for code blocks const basemapId = "arcgis/navigation"; const basemapURL = `https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/${basemapId}?token=${accessToken}`; olms.apply(map, basemapURL).then(function (map) { addCircleLayers();
Add a click handler
You need a start (origin) and end (destination) to create a route. The first click will set a source for the start
and the second click will set a source for the end
. You will use a Geo
feature format to set these sources. Use a click
event handler to respond to these clicks.
-
Add a variable to store whether the next click will be for the start or end of the route. Set it initially to
start
. Add a variable to store the coordinates for each end. Create aGeo
feature format and store it to aJSON geojson
variable.Use dark colors for code blocks map.addLayer(endLayer); } let currentStep = "start"; let startCoords, endCoords; const geojson = new ol.format.GeoJSON({ defaultDataProjection: "EPSG:4326", featureProjection: "EPSG:3857" });
-
Add a
click
event handler to the map. Inside, transform thecoordinate
property of the event object to latitude and longitude and store it in a variable. Use this to create a GeoJSONPoint
.Use dark colors for code blocks const geojson = new ol.format.GeoJSON({ defaultDataProjection: "EPSG:4326", featureProjection: "EPSG:3857" }); map.on("click", (e) => { const coordinates = ol.proj.transform(e.coordinate, "EPSG:3857", "EPSG:4326"); const point = { type: "Point", coordinates }; });
-
Use
set
on the current layer to set a newSource Vector
source. Use theread
method of theFeatures geojson
feature format you defined earlier to set the data. Save the coordinates for later use.Use dark colors for code blocks map.on("click", (e) => { const coordinates = ol.proj.transform(e.coordinate, "EPSG:3857", "EPSG:4326"); const point = { type: "Point", coordinates }; if (currentStep === "start") { startLayer.setSource( new ol.source.Vector({ features: geojson.readFeatures(point) }) ); startCoords = coordinates; currentStep = "end"; } else { endLayer.setSource( new ol.source.Vector({ features: geojson.readFeatures(point) }) ); endCoords = coordinates; currentStep = "start"; } });
-
After setting the start point source, check if there are already end coordinates stored, indicating the user is resetting the route. If so, clear the
end
variable and theCoords clear
method to remove the end point layer features.Use dark colors for code blocks startLayer.setSource( new ol.source.Vector({ features: geojson.readFeatures(point) }) ); startCoords = coordinates; // clear endCoords and route if they were already set if (endCoords) { endCoords = null; endLayer.getSource().clear(); }
-
At the top right, click Run. You should be able to click in two places to set a white circle for the start, and a black circle for the end.
Add route layer
To display the route line that you will receive from the routing service, you will create another Vector
layer.
-
Create an
add
function. Inside, define aRoute Layer route
with a blue stroke, 4 pixel width and medium opacity. UseLayer map.add
to add it to the map.Layer Use dark colors for code blocks } }); function addRouteLayer() { routeLayer = new ol.layer.Vector({ style: new ol.style.Style({ stroke: new ol.style.Stroke({ color: "hsl(205, 100%, 50%)", width: 4, opacity: 0.6 }) }) }); map.addLayer(routeLayer); }
-
Inside the map load event handler, call
add
.Route Layer Use dark colors for code blocks addCircleLayers(); addRouteLayer();
-
Update the click event handler to also clear the route when clearing the end point layer.
Use dark colors for code blocks // clear endCoords and route if they were already set if (endCoords) { endCoords = null; endLayer.getSource().clear(); routeLayer.getSource().clear();
Get the route
To find the route, you use ArcGIS REST JS to call the solve
function to access the route service. Make sure to warn the user if there is a problem accessing the service.
To update the route
with the route, you create a new Vector
source from the response's routes.geo
property.
-
Create a function called
update
. Inside, create a newRoute Api
to access the route service. CallKey Manager solve
with the two sets of coordinates as aRoute stops
array.Use dark colors for code blocks map.addLayer(routeLayer); } function updateRoute() { const authentication = arcgisRest.ApiKeyManager.fromKey(accessToken); arcgisRest .solveRoute({ stops: [startCoords, endCoords], authentication }) }
-
Create a response handler. Inside, create a new
Vector
, using thegeojson
feature format to read features from the response'sroutes.geo
property.Json Use dark colors for code blocks .solveRoute({ stops: [startCoords, endCoords], authentication }) .then((response) => { routeLayer.setSource( new ol.source.Vector({ features: geojson.readFeatures(response.routes.geoJson) }) ); })
-
Add an error handler. Inside, show an alert and log a message.
Use dark colors for code blocks routeLayer.setSource( new ol.source.Vector({ features: geojson.readFeatures(response.routes.geoJson) }) ); }) .catch((error) => { alert("There was a problem using the geocoder. See the console for details."); console.error(error); });
-
Update the click event handler to call
update
after updating the endpoint layer.Route Use dark colors for code blocks endLayer.setSource( new ol.source.Vector({ features: geojson.readFeatures(point) }) ); endCoords = coordinates; currentStep = "start"; updateRoute(startCoords, endCoords);
Show directions
The data returned from the route service contains directions information. To display it, you can create a styled <div
element. You will populate this with data drawn from the directions
attribute of the response.
-
In the
<body
section, add a> <div
element with an id of> directions
.Use dark colors for code blocks <body> <div id="map"></div> <div id="directions">Click on the map to create a start and end for the route.</div>
-
In the
<style
section, style the> #directions
element withabsolute
position so it sits in front of the map, and a fixed width and height.Use dark colors for code blocks <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } #directions { position: absolute; width: 30%; max-height: 50%; right: 20px; top: 20px; overflow-y: auto; /* Show a scrollbar if needed */ background: white; font-family: Arial, Helvetica, Verdana; line-height: 1.5; font-size: 14px; padding: 10px; } </style>
-
In the query response handler, set the contents of the
<div
element using the> directions
attribute. Join thetext
attributes of each element of thefeatures
array to make the HTML contents of the<div
element. Use> <br
tags between each line to create a line break.> The
directions
element is an array where each element corresponds to one route. Itsfeatures
attribute is an array with information about each step on the route, including the length of the maneuver, the kind of maneuver, and the text that should be shown to the user.Use dark colors for code blocks .then((response) => { routeLayer.setSource( new ol.source.Vector({ features: geojson.readFeatures(response.routes.geoJson) }) ); const directionsHTML = response.directions[0].features.map((f) => f.attributes.text).join("<br/>"); document.getElementById("directions").innerHTML = directionsHTML; document.getElementById("directions").style.display = "block"; })
-
Update the click handler to also clear the directions when clearing the route.
Use dark colors for code blocks // clear endCoords and route if they were already set if (endCoords) { endCoords = null; endLayer.getSource().clear(); routeLayer.getSource().clear(); document.getElementById("directions").innerHTML = ""; document.getElementById("directions").style.display = "none";
Run the app
Run the app.
When the map displays, you should be able to click on it once to create an origin point and again to create a destination point. The routing service should then display the resulting route and turn-by-turn directions.
What's next?
Learn how to use additional ArcGIS location services in these tutorials: