Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save hhkaos/70faf59003bd2e3579e93b947620e7bb to your computer and use it in GitHub Desktop.
Save hhkaos/70faf59003bd2e3579e93b947620e7bb to your computer and use it in GitHub Desktop.
ArcGIS Developer Guide: Find the speed limit of the closest road
<!--
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>
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="initial-scale=1,maximum-scale=1,user-scalable=no"
/>
<script src="https://unpkg.com/[email protected]/dist/maplibre-gl.js"></script>
<link
href="https://unpkg.com/[email protected]/dist/maplibre-gl.css"
rel="stylesheet"
/>
<script
type="module"
src="https://js.arcgis.com/calcite-components/3.2.1/calcite.esm.js"
></script>
<script src="https://unpkg.com/@terraformer/arcgis"></script>
<script src="https://unpkg.com/@esri/arcgis-rest-request@4/dist/bundled/request.umd.js"></script>
<script src="https://unpkg.com/@esri/arcgis-rest-feature-service@4/dist/bundled/feature-service.umd.js"></script>
<style>
html,
body,
#map {
padding: 0;
margin: 0;
height: 100vh;
width: 100vw;
}
.button-container {
position: absolute;
right: 15px;
top: 15px;
z-index: 1001;
padding: 6px;
background-color: #ffffff;
}
</style>
</head>
<body>
<div class="button-container">
<calcite-button id="snapButton" label="Run snap to roads operation"
>Snap GPS points</calcite-button
>
<calcite-button
id="resetButton"
icon-start="reset"
label="Remove result layers"
disabled
></calcite-button>
</div>
<div id="map"></div>
<script type="module">
const appConfig = {
// for basemap styles service
ACCESS_TOKEN: "YOUR_ACCESS_TOKEN",
// Snap to roads operation URL
SNAP_TO_ROADS_URL:
"https://route-api.arcgis.com/arcgis/rest/services/World/SnapToRoadsSync/GPServer/SnapToRoads/execute",
// input points service URL
INPUT_TRACKS_URL:
"https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/clt_track_points/FeatureServer/0",
// Basemap styles service URL
BASE_MAP_URL:
"https://basemapstyles-api.arcgis.com/arcgis/rest/services/styles/v2/styles/",
// Basemap family/style name
BASEMAP_STYLE_NAME: "arcgis/human-geography",
}
let inputPoints
// Create a blank featurecollection
const emptyDS = {
type: "FeatureCollection",
features: [],
}
// create a popup
const popup = new maplibregl.Popup()
// Instantiate a new map control
const map = new maplibregl.Map({
container: "map", // the id of the div element
style: `${appConfig.BASE_MAP_URL}${appConfig.BASEMAP_STYLE_NAME}?token=${appConfig.ACCESS_TOKEN}`, // basemap style
zoom: 14, // starting zoom
center: [-80.8574, 35.2213], // starting location [longitude, latitude]
})
/**
*
*/
const addResults = async fromResponse => {
const snappedSource = map.getSource("snappedPoints")
await snappedSource.setData(fromResponse.snappedPoints)
const snappedLineSource = map.getSource("snappedLines")
await snappedLineSource.setData(fromResponse.snappedLines)
map.fitBounds(await snappedSource.getBounds())
}
/**
* Run the snap to roads operation using our input track points and
* update the UI with it's progress.
*/
const snapPoints = async () => {
const snapButton = document.getElementById("snapButton")
try {
snapButton.loading = true
map.getSource("snappedPoints").setData(emptyDS)
map.getSource("snappedLines").setData(emptyDS)
const headerParams = {
// Authorization: `Bearer ${appConfig.ACCESS_TOKEN}`,
"Content-Type": "application/x-www-form-urlencoded",
}
const agsPoints = Terraformer.geojsonToArcGIS(inputPoints)
const queryParams = new URLSearchParams({
f: "json",
token: appConfig.ACCESS_TOKEN,
points: JSON.stringify({ features: agsPoints }),
return_location_fields: true,
return_lines: true,
road_properties_on_lines: JSON.stringify([
"posted_speed_limit_mph",
"length_miles",
]),
})
const service = appConfig.SNAP_TO_ROADS_URL
const response = await fetch(service, {
method: "POST",
headers: headerParams,
body: queryParams,
})
const agsJSONResponse = await response.json()
// Convert ArcGIS JSON to GeoJSON
const geojsonResults = Terraformer.arcgisToGeoJSON(
agsJSONResponse.results[0].value
)
const lineResults = Terraformer.arcgisToGeoJSON(
agsJSONResponse.results[1].value
)
addResults({
snappedPoints: geojsonResults,
snappedLines: lineResults,
})
} catch (err) {
console.log(err)
} finally {
snapButton.loading = false
document.getElementById("resetButton").disabled = false
}
}
/**
* Map load event handler. Adds our layers to the map.
*/
const mapDidLoad = async () => {
// Query the featureservice for our input tracks in GeoJSON format.
inputPoints = await arcgisRest.queryFeatures({
url: appConfig.INPUT_TRACKS_URL,
where: "1=1",
f: "geojson",
returnGeometry: true,
})
// Add track points to the map
map.addSource("inputPoints", {
type: "geojson",
data: inputPoints,
})
map.addLayer({
id: "inputPointsLayer",
type: "circle",
source: "inputPoints",
paint: {
"circle-color": "rgba(52, 122, 196, 0.78)",
"circle-stroke-width": 1,
"circle-radius": 5,
"circle-stroke-color": "rgba(255, 255, 255, 1)",
},
})
// add our result routes to the map
map.addSource("snappedLines", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [],
},
})
map.addLayer({
id: "snappedLinesLayer",
type: "line",
source: "snappedLines",
paint: {
"line-width": 6,
"line-color": [
"interpolate",
["linear"],
["get", "posted_speed_limit_mph"],
20,
"#d53e4fff",
35,
"#fc8d59ff",
40,
"#fee08bff",
45,
"#e6f598ff",
50,
"#99d594ff",
55,
"#006837ff",
],
},
})
// add the snapped point results to the map
map.addSource("snappedPoints", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [],
},
})
map.addLayer({
id: "snappedPointsLayer",
type: "circle",
source: "snappedPoints",
paint: {
"circle-radius": 4,
"circle-color": "rgba(0, 0, 0, 0.75)",
"circle-stroke-width": 1,
"circle-stroke-color": "rgba(255, 255, 255, 0.75)",
},
})
// Listen for map mouse events to display popups
map.on("mouseenter", "snappedLinesLayer", e => {
map.getCanvas().style.cursor = "pointer"
popup
.setLngLat(e.lngLat)
.setHTML(
`Segment id: ${e.features[0].properties.ObjectID}<br>
Segment length (miles): ${e.features[0].properties.length_miles.toFixed(
4
)}<br>
Speed limit (mph): ${e.features[0].properties.posted_speed_limit_mph.toFixed(
0
)}`
)
.addTo(map)
})
map.on("mouseleave", "snappedLinesLayer", () => {
map.getCanvas().style.cursor = "default"
popup.remove()
})
}
// Add our layers to the map once it has been loaded
map.once("load", mapDidLoad)
// Add Esri attribution
// Learn more in https://esriurl.com/attribution
map._controls[0].options.customAttribution += " | Powered by Esri "
map._controls[0]._updateAttributions()
// Handle button click events
document
.getElementById("snapButton")
.addEventListener("click", snapPoints)
document.getElementById("resetButton").addEventListener("click", () => {
document.getElementById("resetButton").disabled = true
map.getSource("snappedPoints").setData(emptyDS)
map.getSource("snappedLines").setData(emptyDS)
})
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment