Animate a line
This example animates a line by updating a GeoJSON source on each frame.
It uses addSource
to add a GeoJSON source and uses addLayer
to add a line layer
to the map.
When the animation begins, the data in the GeoJSON object changes, and the line appears animated on the map.
<!DOCTYPE html><html><head><meta charset="utf-8" /><title>Animate a line</title><meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /><script src="https://cdn.ndrive.com/nmapsgl/v.1.6.8/nmaps-gl.js"></script><link href="https://cdn.ndrive.com/nmapsgl/v.1.6.8/nmaps-gl.css" rel="stylesheet" /><style> body { margin: 0; padding: 0; } #map { position: absolute; top: 0; bottom: 0; width: 100%; }</style></head><body><style>button {position: absolute;margin: 20px;} #pause::after {content: 'Pause';} #pause.pause::after {content: 'Play';}</style><div id="map"></div><button id="pause"></button><script> // TO MAKE THE MAP APPEAR YOU MUST ADD YOUR ACCESS TOKEN nmapsgl.accessToken = '<your access token here>'; const map = new nmapsgl.Map({container: 'map',style: 'Streets',center: [0, 0],zoom: 2}); // Create a GeoJSON source with an empty lineString.const geojson = {'type': 'FeatureCollection','features': [{'type': 'Feature','geometry': {'type': 'LineString','coordinates': [[0, 0]]}}]}; const speedFactor = 30; // number of frames per longitude degreelet animation; // to store and cancel the animationlet startTime = 0;let progress = 0; // progress = timestamp - startTimelet resetTime = false; // indicator of whether time reset is needed for the animationconst pauseButton = document.getElementById('pause'); map.on('load', () => {map.addSource('line', {'type': 'geojson','data': geojson}); // add the line which will be modified in the animationmap.addLayer({'id': 'line-animation','type': 'line','source': 'line','layout': {'line-cap': 'round','line-join': 'round'},'paint': {'line-color': '#ed6498','line-width': 5,'line-opacity': 0.8}}); startTime = performance.now(); animateLine(); // click the button to pause or playpauseButton.addEventListener('click', () => {pauseButton.classList.toggle('pause');if (pauseButton.classList.contains('pause')) {cancelAnimationFrame(animation);} else {resetTime = true;animateLine();}}); // reset startTime and progress once the tab loses or gains focus// requestAnimationFrame also pauses on hidden tabs by defaultdocument.addEventListener('visibilitychange', () => {resetTime = true;}); // animated in a circle as a sine wave along the map.function animateLine(timestamp) {if (resetTime) {// resume previous progressstartTime = performance.now() - progress;resetTime = false;} else {progress = timestamp - startTime;} // restart if it finishes a loopif (progress > speedFactor * 360) {startTime = timestamp;geojson.features[0].geometry.coordinates = [];} else {const x = progress / speedFactor;// draw a sine wave with some math.const y = Math.sin((x * Math.PI) / 90) * 40;// append new coordinates to the lineStringgeojson.features[0].geometry.coordinates.push([x, y]);// then update the mapmap.getSource('line').setData(geojson);}// Request the next frame of the animation.animation = requestAnimationFrame(animateLine);}});</script> </body></html>