A Pen by Raul Jimenez Ortega on CodePen.
Created
July 2, 2025 09:20
-
-
Save hhkaos/55744a9532be8db63fb8ab2acb328e54 to your computer and use it in GitHub Desktop.
ArcGIS Developer Guide: Snap to roads using travel mode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
To run this demo, you need to replace 'YOUR_ACCESS_TOKEN' with an access token from ArcGIS that has the correct privileges. | |
To get started, sign up for a free ArcGIS Location Platform account or a free trial of ArcGIS Online and create developer credentials. | |
https://developers.arcgis.com/documentation/security-and-authentication/get-started/ | |
--> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta | |
name="viewport" | |
content="initial-scale=1,maximum-scale=1,user-scalable=no" | |
/> | |
<title> | |
ArcGIS Developer Guide: Snap to roads using a travel mode. | |
</title> | |
<link | |
rel="stylesheet" | |
href="https://js.arcgis.com/4.32/esri/themes/light/main.css" | |
/> | |
<!-- <link rel="stylesheet" href="https://js.arcgis.com/4.32/esri/themes/light/main.css" /> --> | |
<script src="https://js.arcgis.com/4.32/"></script> | |
<!-- <script src="https://js.arcgis.com/4.32"></script> --> | |
<!-- Load Calcite Components --> | |
<script | |
type="module" | |
src="https://js.arcgis.com/calcite-components/3.1.0/calcite.esm.js" | |
></script> | |
<style> | |
html, | |
body, | |
#viewDiv { | |
height: 100%; | |
width: 100%; | |
margin: 0; | |
padding: 0; | |
} | |
#travelModeSelectContainer { | |
padding: 6px; | |
background-color: #ffffff; | |
} | |
</style> | |
<script type="module"> | |
const [ | |
EsriConfig, | |
EsriMap, | |
EsriMapView, | |
EsriDraw, | |
EsriGraphic, | |
EsriPolyline, | |
EsricrossesOperator, | |
EsriPoint, | |
EsriGeoprocessor, | |
EsriWebMercatorUtils, | |
EsriGraphicsLayer, | |
EsriFeatureLayer, | |
] = await $arcgis.import([ | |
"@arcgis/core/config", | |
"@arcgis/core/Map", | |
"@arcgis/core/views/MapView", | |
"@arcgis/core/views/draw/Draw", | |
"@arcgis/core/Graphic", | |
"@arcgis/core/geometry/Polyline", | |
"@arcgis/core/geometry/operators/crossesOperator", | |
"@arcgis/core/geometry/Point", | |
"@arcgis/core/rest/geoprocessor", | |
"@arcgis/core/geometry/support/webMercatorUtils", | |
"@arcgis/core/layers/GraphicsLayer", | |
"@arcgis/core/layers/FeatureLayer", | |
]) | |
let currentVertices, currentTravelMode | |
const accessToken = "YOUR_ACCESS_TOKEN" | |
EsriConfig.apiKey = accessToken | |
const serviceURL = | |
"https://route-api.arcgis.com/arcgis/rest/services/World/SnapToRoadsSync/GPServer/SnapToRoads" | |
const travelModeURL = | |
"https://route-api.arcgis.com/arcgis/rest/services/World/Utilities/GPServer/GetTravelModes" | |
const inputPointsLayer = new EsriFeatureLayer({ | |
portalItem: { id: "75fba88319044f499271b5040467bc4f" }, | |
}) | |
const map = new EsriMap({ | |
basemap: "arcgis/navigation-night", | |
layers: [inputPointsLayer], | |
}) | |
const view = new EsriMapView({ | |
container: "viewDiv", | |
map: map, | |
zoom: 17, | |
center: [-117.1557, 32.7297], | |
}) | |
// add the button for the draw tool | |
view.ui.add("travelModeSelectContainer", "top-right") | |
const drawRoutes = async () => { | |
const btn = document.getElementById("snapPointsButton") | |
try { | |
btn.loading = true | |
const result = await createGraphic() | |
if (result[0] && result[1]) { | |
// /event.preventDefault() | |
// view.goTo(result.snappedRoutes[0].geometry.extent) | |
view.graphics.removeAll() | |
view.graphics.addMany([...result[0], ...result[1]]) | |
} | |
} catch (err) { | |
console.log(err) | |
} finally { | |
btn.loading = false | |
} | |
} | |
// create a new graphic presenting the polyline that is being drawn on the view | |
const createGraphic = async () => { | |
let snappedResults = null | |
snappedResults = await snapToRoads() | |
return snappedResults | |
} | |
// get network travel modes from our portal | |
const getTravelModes = async modeName => { | |
const params = { | |
token: accessToken, | |
f: "json", | |
} | |
const response = await EsriGeoprocessor.execute(travelModeURL, params) | |
const tmode = response.results[0].value.features.find(f => { | |
return f.attributes.Name === modeName | |
}) | |
return tmode.attributes.TravelMode | |
} | |
// send request to the Snap to Roads operation | |
const snapToRoads = async () => { | |
const pts = await inputPointsLayer.queryFeatures() | |
const inputParams = { | |
points: pts, | |
travel_mode: currentTravelMode, | |
return_location_fields: true, | |
road_properties_on_lines: ["length_miles"], | |
token: accessToken, | |
return_lines: true, | |
} | |
const results = await EsriGeoprocessor.execute(serviceURL, inputParams) | |
const routes = results.results[1].value.features.map(r => { | |
return new EsriGraphic({ | |
geometry: r.geometry, | |
attributes: r.attributes, | |
symbol: { | |
type: "simple-line", // autocasts as new SimpleFillSymbol | |
color: [0, 150, 255, 0.5], | |
width: 4, | |
cap: "round", | |
join: "round", | |
}, | |
popupTemplate: { | |
title: "Segment id: {ObjectID}", | |
content: [ | |
{ | |
type: "fields", | |
fieldInfos: [ | |
{ | |
fieldName: "line_type", | |
label: "Line type", | |
}, | |
{ | |
fieldName: "length_miles", | |
label: "Segment length (miles)", | |
format: { places: 2 }, | |
}, | |
], | |
}, | |
], | |
}, | |
}) | |
}) | |
const resultPoints = results.results[0].value.features.map(pt => { | |
return new EsriGraphic({ | |
geometry: pt.geometry, | |
attributes: pt.attributes, | |
symbol: { | |
type: "simple-marker", | |
color: [0, 0, 0, 1], | |
size: "9px", | |
outline: { | |
color: "#ffffff", | |
width: 1, | |
}, | |
}, | |
popupTemplate: { | |
title: "Snapped point {ObjectID}", | |
content: [ | |
{ | |
type: "fields", | |
fieldInfos: [ | |
{ | |
fieldName: "confidence", | |
label: "Snap confidence", | |
format: { places: 5 }, | |
}, | |
{ | |
fieldName: "line_id", | |
label: "Line ID", | |
}, | |
], | |
}, | |
], | |
}, | |
}) | |
}) | |
return [routes, resultPoints] | |
} | |
document | |
.getElementById("snapPointsButton") | |
.addEventListener("click", drawRoutes) | |
document.getElementById("resetButton").addEventListener("click", () => { | |
view.graphics.removeAll() | |
}) | |
// get the list of travel modes | |
currentTravelMode = await getTravelModes("Walking Distance") | |
</script> | |
</head> | |
<body> | |
<div id="viewDiv"> | |
<div id="travelModeSelectContainer" class="esri-widget"> | |
<calcite-button id="snapPointsButton" icon-start="pin-plus" | |
>Snap GPS points</calcite-button | |
> | |
<calcite-button id="resetButton" icon-start="reset"></calcite-button> | |
</div> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment