Learn how to find a route and directions with the route service.
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
You need an ArcGIS Location Platform or ArcGIS Online account.
Steps
Create a new pen
- To get started, you can complete the Display a map tutorial or use the .
Get an access token
You need an access token with the correct privileges to access the resources used in this tutorial.
-
Go to the Create an API key tutorial and create an API key with the following privilege(s):
- Privileges
- Location services > Basemaps
- Location services > Routing
- Privileges
-
Copy the API key access token to your clipboard when prompted.
-
In CodePen, update the
access
variable to use your access token.Token Use dark colors for code blocks const accessToken = "YOUR_ACCESS_TOKEN"; const basemapEnum = "arcgis/outdoor"; const map = new maplibregl.Map({ container: "map", // the id of the div element style: `https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/${basemapEnum}?token=${accessToken}`, zoom: 12, // starting zoom center: [-118.805, 34.027] // starting location [longitude, latitude] });
-
Run the code to ensure the basemap is displayed in the map.
To learn about the other types of authentication available, go to Types of authentication.
Add references to ArcGIS REST JS
-
In the
<head
element, add references to the ArcGIS REST JS library.> Use dark colors for code blocks <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /> <script src=https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js></script> <link href=https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css rel="stylesheet" /> <script src="https://unpkg.com/@esri/arcgis-rest-request@4/dist/bundled/request.umd.js"></script> <script src="https://unpkg.com/@esri/arcgis-rest-routing@4/dist/bundled/routing.umd.js"></script> <style> html, body, #map { padding: 0; margin: 0; height: 100%; width: 100%; font-family: Arial, Helvetica, sans-serif; font-size: 14px; color: #323232; } </style> </head>
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 const accessToken = "YOUR_ACCESS_TOKEN"; const basemapEnum = "arcgis/navigation"; const map = new maplibregl.Map({ container: "map", // the id of the div element style: `https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/${basemapEnum}?token=${accessToken}`, zoom: 12, // starting zoom center: [-79.3832, 43.6532] // Toronto });
Add end point layers
To display circles for the start and end of the route, you will two circle layers. Each layer needs a GeoJSON source which holds the data.
-
Create a function called
add
.Circle Layers Use dark colors for code blocks const map = new maplibregl.Map({ container: "map", // the id of the div element style: `https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/${basemapEnum}?token=${accessToken}`, zoom: 12, // starting zoom center: [-79.3832, 43.6532] // Toronto }); function addCircleLayers() { }
-
Add a GeoJSON source for the start and end, with ids
route-start
androute-end
. Set thedata
attribute of each source to be an empty FeatureCollection.This source will later contain the geometry information of the start or end point that the user has selected. For now, you can simply provide it with an empty piece of GeoJSON: a feature collection that contains no features.
Use dark colors for code blocks function addCircleLayers() { map.addSource("start", { type: "geojson", data: { type: "FeatureCollection", features: [] } }); map.addSource("end", { type: "geojson", data: { type: "FeatureCollection", features: [] } }); }
-
Add a layer of type
circle
for the start and end, connected to those sources. Use thecircle-color
paint property to make the start circle white and the end circle black.Each layer will display the data in its source. Since there is no data in those sources for now, nothing will display yet.
Use dark colors for code blocks function addCircleLayers() { map.addSource("start", { type: "geojson", data: { type: "FeatureCollection", features: [] } }); map.addSource("end", { type: "geojson", data: { type: "FeatureCollection", features: [] } }); map.addLayer({ id: "start-circle", type: "circle", source: "start", paint: { "circle-radius": 6, "circle-color": "white", "circle-stroke-color": "black", "circle-stroke-width": 2 } }); map.addLayer({ id: "end-circle", type: "circle", source: "end", paint: { "circle-radius": 7, "circle-color": "black" } }); }
Add a load event handler
At this stage, the layers have not been added to the map. It is important to wait for the map to finish loading before adding the layers.
-
Add an event handler to the map
load
event. Call theadd
function.Circle Layers Use dark colors for code blocks map.addLayer({ id: "end-circle", type: "circle", source: "end", paint: { "circle-radius": 7, "circle-color": "black" } }); } map.on("load", () => { addCircleLayers(); addRouteLayer(); });
Add a click handler
You will click twice to set a start and end for the route. The first click will update the start
source. The second click will update the end
source. To set the GeoJSON data you use map.get
to get the Source
, then call set
.
You use a click
event handler to respond to these clicks.
The object passed to the click
event contains several useful properties, including:
lng
: the map location where the click took place.Lat point
: the screen location in pixels where the click took place.original
: the DOM event, which contains information about modifier keys.Event
For more information, see the MapLibre GL JS documentation.
-
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.Use dark colors for code blocks map.on("load", () => { addCircleLayers(); addRouteLayer(); }); let currentStep = "start"; let startCoords, endCoords;
-
Add a
click
event handler to the map. Use thelng
property of the event parameter to create a GeoJSONLat Point
object.Use dark colors for code blocks let currentStep = "start"; let startCoords, endCoords; map.on("click", (e) => { const coordinates = e.lngLat.toArray(); const point = { type: "Point", coordinates }; });
-
Use
map.get
and theSource set
method to update the correct source with the GeoJSON object.Data Use dark colors for code blocks map.on("click", (e) => { const coordinates = e.lngLat.toArray(); const point = { type: "Point", coordinates }; if (currentStep === "start") { map.getSource("start").setData(point); startCoords = coordinates; const empty = { type: "FeatureCollection", features: [] }; map.getSource("end").setData(empty); map.getSource("route").setData(empty); endCoords = null; currentStep = "end"; } else { map.getSource("end").setData(point); endCoords = coordinates; currentStep = "start"; } });
-
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
The route object that will be retrieved is a GeoJSON Line
object. To display it, you define a GeoJSON source and a line layer.
-
Create a
add
function. Inside, add a source of typeRoute Layer geojson
with idroute
. Set itsdata
attribute to be an emptyFeature
.Collection Use dark colors for code blocks map.addLayer({ id: "end-circle", type: "circle", source: "end", paint: { "circle-radius": 7, "circle-color": "black" } }); } function addRouteLayer() { map.addSource("route", { type: "geojson", data: { type: "FeatureCollection", features: [] } }); }
-
Add a layer of type
line
with idroute-line
. Set its source to beroute
, and give it width, color and opacity attributes.This source will later contain the geometry information of the route between points that the user has selected. For now, you can simply provide it with an empty piece of GeoJSON: a feature collection that contains no features.
The layer will display the source. Since there is no data in the source for now, nothing will display yet.
Use dark colors for code blocks function addRouteLayer() { map.addSource("route", { type: "geojson", data: { type: "FeatureCollection", features: [] } }); map.addLayer({ id: "route-line", type: "line", source: "route", paint: { "line-color": "hsl(205, 100%, 50%)", "line-width": 4, "line-opacity": 0.6 } }); }
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
source with the result, get the Source with map.get
to get the Source, then call set
.
-
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 paint: { "line-color": "hsl(205, 100%, 50%)", "line-width": 4, "line-opacity": 0.6 } }); } function updateRoute() { const authentication = arcgisRest.ApiKeyManager.fromKey(accessToken); arcgisRest .solveRoute({ stops: [startCoords, endCoords], endpoint: "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World/solve", authentication }) }
-
Create a response handler. Inside, use the
set
method to update theData route
source's geometry from the response'sroutes.geojson
property.Use dark colors for code blocks arcgisRest .solveRoute({ stops: [startCoords, endCoords], endpoint: "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World/solve", authentication }) .then((response) => { map.getSource("route").setData(response.routes.geoJson); })
-
Add an error handler. Show a message and log a message if there is a problem.
Use dark colors for code blocks .then((response) => { map.getSource("route").setData(response.routes.geoJson); }) .catch((error) => { console.error(error); alert("There was a problem using the route service. See the console for details."); });
Update the click handler
If the start and end coordinates have been set by the user, you can now call your update
function.
-
Check that the start and end coordinates have been set. Then call
update
.Route Use dark colors for code blocks map.on("click", (e) => { const coordinates = e.lngLat.toArray(); const point = { type: "Point", coordinates }; if (currentStep === "start") { map.getSource("start").setData(point); startCoords = coordinates; const empty = { type: "FeatureCollection", features: [] }; map.getSource("end").setData(empty); map.getSource("route").setData(empty); endCoords = null; currentStep = "end"; } else { map.getSource("end").setData(point); endCoords = coordinates; currentStep = "start"; } if (startCoords && endCoords) { 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
, 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) => { map.getSource("route").setData(response.routes.geoJson); const directionsHTML = response.directions[0].features.map((f) => f.attributes.text).join("<br/>"); document.getElementById("directions").innerHTML = directionsHTML; }) .catch((error) => { console.error(error); alert("There was a problem using the route service. See the console for details."); });
Run the app
In CodePen, run your code to display the map.
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: