Animate the camera along a path
Use the FreeCamera
API to follow a path over 3D terrain.
<!DOCTYPE html><html><head><meta charset="utf-8" /><title>Animate the camera along a path</title><meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /><script src="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.js"></script><link href="https://api.mapbox.com/mapbox-gl-js/v2.0.1/mapbox-gl.css" rel="stylesheet" /><style> body { margin: 0; padding: 0; } #map { position: absolute; top: 0; bottom: 0; width: 100%; }</style></head><body><div id="map"></div> <script src="https://docs.mapbox.com/mapbox-gl-js/assets/routes.js"></script><script src="https://unpkg.com/@turf/turf/turf.min.js"></script><script> // TO MAKE THE MAP APPEAR YOU MUST // ADD YOUR ACCESS TOKEN FROM // https://account.mapbox.com mapboxgl.accessToken = '<your access token here>';var map = new mapboxgl.Map({container: 'map',zoom: 11.53,center: [6.5615, 46.0598],pitch: 65,bearing: -180,style: 'mapbox://styles/mapbox-map-design/ckhqrbxlc1awj19svtb92m0bd',interactive: false}); // `routes` comes from https://docs.mapbox.com/mapbox-gl-js/assets/routes.js,// which has properties that are in the shape of an array of arrays that correspond// to the `coordinates` property of a GeoJSON linestring, for example:// [// [6.56158, 46.05989],// [6.56913, 46.05679],// ...// ]// this is the path the camera will look atvar targetRoute = routes.target;// this is the path the camera will move alongvar cameraRoute = routes.camera; // add terrain, sky, and line layers once the style has loadedmap.on('load', function () {map.addSource('mapbox-dem', {'type': 'raster-dem','url': 'mapbox://mapbox.mapbox-terrain-dem-v1','tileSize': 512,'maxzoom': 14});map.setTerrain({ 'source': 'mapbox-dem', 'exaggeration': 1.5 });map.addLayer({'id': 'sky','type': 'sky','paint': {'sky-type': 'atmosphere','sky-atmosphere-sun': [0.0, 90.0],'sky-atmosphere-sun-intensity': 15}});map.addSource('trace', {type: 'geojson',data: {'type': 'Feature','properties': {},'geometry': {'type': 'LineString','coordinates': targetRoute}}});map.addLayer({type: 'line',source: 'trace',id: 'line',paint: {'line-color': 'orange','line-width': 5},layout: {'line-cap': 'round','line-join': 'round'}});}); // wait for the terrain and sky to load before starting animationmap.on('load', function () {var animationDuration = 80000;var cameraAltitude = 4000;// get the overall distance of each route so we can interpolate along themvar routeDistance = turf.lineDistance(turf.lineString(targetRoute));var cameraRouteDistance = turf.lineDistance(turf.lineString(cameraRoute)); var start; function frame(time) {if (!start) start = time;// phase determines how far through the animation we arevar phase = (time - start) / animationDuration; // phase is normalized between 0 and 1// when the animation is finished, reset start to loop the animationif (phase > 1) {// wait 1.5 seconds before loopingsetTimeout(function () {start = 0.0;}, 1500);} // use the phase to get a point that is the appropriate distance along the route// this approach syncs the camera and route positions ensuring they move// at roughly equal rates even if they don't contain the same number of pointsvar alongRoute = turf.along(turf.lineString(targetRoute),routeDistance * phase).geometry.coordinates; var alongCamera = turf.along(turf.lineString(cameraRoute),cameraRouteDistance * phase).geometry.coordinates; var camera = map.getFreeCameraOptions(); // set the position and altitude of the cameracamera.position = mapboxgl.MercatorCoordinate.fromLngLat({lng: alongCamera[0],lat: alongCamera[1]},cameraAltitude); // tell the camera to look at a point along the routecamera.lookAtPoint({lng: alongRoute[0],lat: alongRoute[1]}); map.setFreeCameraOptions(camera); window.requestAnimationFrame(frame);} window.requestAnimationFrame(frame);});</script> </body></html>