Skip to main content

Query terrain elevation

This example uses queryTerrainElevation to display the elevation of a pin which follows a path.

It implements ES6 async functions to increase readability of asynchronous code.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Query terrain elevation</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v3.3.0/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
<div id="map"></div>
<script>
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';
(async () => {
const map = new mapboxgl.Map({
container: 'map',
zoom: 13,
center: [6.58968, 45.39701],
pitch: 76,
bearing: 150,
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/satellite-streets-v12',
interactive: false,
hash: false
});

// Start downloading the route data, and wait for map load to occur in parallel
const [pinRouteGeojson] = await Promise.all([
fetch(
'https://docs.mapbox.com/mapbox-gl-js/assets/route-pin.geojson'
).then((response) => response.json()),
map.once('style.load')
]);

// Set custom fog
map.setFog({
'range': [-0.5, 2],
'color': '#def',
'high-color': '#def',
'space-color': '#def'
});

// Add terrain source, with slight exaggeration
map.addSource('mapbox-dem', {
'type': 'raster-dem',
'url': 'mapbox://mapbox.terrain-rgb',
'tileSize': 512,
'maxzoom': 14
});
map.setTerrain({ 'source': 'mapbox-dem', 'exaggeration': 1.5 });

const pinRoute = pinRouteGeojson.features[0].geometry.coordinates;
// Create the marker and popup that will display the elevation queries
const popup = new mapboxgl.Popup({ closeButton: false });
const marker = new mapboxgl.Marker({
color: 'red',
scale: 0.8,
draggable: false,
pitchAlignment: 'auto',
rotationAlignment: 'auto'
})
.setLngLat(pinRoute[0])
.setPopup(popup)
.addTo(map)
.togglePopup();

// Add a line feature and layer. This feature will get updated as we progress the animation
map.addSource('line', {
type: 'geojson',
// Line metrics is required to use the 'line-progress' property
lineMetrics: true,
data: pinRouteGeojson
});
map.addLayer({
type: 'line',
source: 'line',
id: 'line',
paint: {
'line-color': 'rgba(0,0,0,0)',
'line-width': 5
},
layout: {
'line-cap': 'round',
'line-join': 'round'
}
});

await map.once('idle');
// The total animation duration, in milliseconds
const animationDuration = 20000;
// Use the https://turfjs.org/ library to calculate line distances and
// sample the line at a given percentage with the turf.along function.
const path = turf.lineString(pinRoute);
// Get the total line distance
const pathDistance = turf.lineDistance(path);
let start;
function frame(time) {
if (!start) start = time;
const animationPhase = (time - start) / animationDuration;
if (animationPhase > 1) {
return;
}

// Get the new latitude and longitude by sampling along the path
const alongPath = turf.along(path, pathDistance * animationPhase)
.geometry.coordinates;
const lngLat = {
lng: alongPath[0],
lat: alongPath[1]
};

// Sample the terrain elevation. We round to an integer value to
// prevent showing a lot of digits during the animation
const elevation = Math.floor(
// Do not use terrain exaggeration to get actual meter values
map.queryTerrainElevation(lngLat, { exaggerated: false })
);

// Update the popup altitude value and marker location
popup.setHTML('Altitude: ' + elevation + 'm<br/>');
marker.setLngLat(lngLat);

// Reduce the visible length of the line by using a line-gradient to cutoff the line
// animationPhase is a value between 0 and 1 that reprents the progress of the animation
map.setPaintProperty('line', 'line-gradient', [
'step',
['line-progress'],
'red',
animationPhase,
'rgba(255, 0, 0, 0)'
]);

// Rotate the camera at a slightly lower speed to give some parallax effect in the background
const rotation = 150 - animationPhase * 40.0;
map.setBearing(rotation % 360);

window.requestAnimationFrame(frame);
}

window.requestAnimationFrame(frame);
})();
</script>

</body>
</html>
Was this example helpful?