線をアニメーション化
各フレームの GeoJSON ソースを更新して、線をアニメーション化します。
<!DOCTYPE html><html><head><meta charset="utf-8"><title>線をアニメーション化</title><meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"><link href="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.css" rel="stylesheet"><script src="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.js"></script><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 FROM // https://account.mapbox.com mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';const map = new mapboxgl.Map({container: 'map',style: 'mapbox://styles/mapbox/streets-v11',center: [0, 0],zoom: 0.5}); // 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>