Skip to content

Animate a Marker

Animate a Marker smoothly across the map using requestAnimationFrame and setLngLat().

Animate a Marker with requestAnimationFrame

javascript
const marker = new mapmetricsgl.Marker({ color: '#3b82f6' })
  .setLngLat([0, 0])
  .addTo(map);

let t = 0;

function animate() {
  t += 0.005;

  // Move in a sine wave pattern
  const lng = (t * 30) % 360 - 180;
  const lat = Math.sin(t) * 40;

  marker.setLngLat([lng, lat]);
  requestAnimationFrame(animate);
}

animate();

Animate Along Waypoints

javascript
const waypoints = [[2.35, 48.85], [-0.12, 51.50], [13.40, 52.52]];
let step = 0;
const stepsPerSegment = 100;
let subStep = 0;

function animate() {
  const from = waypoints[step];
  const to = waypoints[(step + 1) % waypoints.length];
  const t = subStep / stepsPerSegment;

  marker.setLngLat([
    from[0] + (to[0] - from[0]) * t,
    from[1] + (to[1] - from[1]) * t
  ]);

  subStep++;
  if (subStep > stepsPerSegment) {
    subStep = 0;
    step = (step + 1) % waypoints.length;
  }

  requestAnimationFrame(animate);
}

Complete Example

html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <link href="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.css" rel="stylesheet" />
    <script src="https://cdn.mapmetrics-atlas.net/versions/latest/mapmetrics-gl.js"></script>
    <style>#map { height: 500px; width: 100%; }</style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const map = new mapmetricsgl.Map({ container: 'map', style: '<StyleFile_URL_with_Token>', center: [0, 20], zoom: 1.5 });
      const marker = new mapmetricsgl.Marker({ color: '#3b82f6' }).setLngLat([0, 20]).addTo(map);
      let t = 0;
      function animate() {
        t += 0.005;
        marker.setLngLat([(t * 30) % 360 - 180, Math.sin(t) * 40]);
        requestAnimationFrame(animate);
      }
      map.on('load', animate);
    </script>
  </body>
</html>
jsx
import React, { useEffect, useRef } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

const AnimateMarker = () => {
  const mapContainer = useRef(null);
  const map = useRef(null);
  const animId = useRef(null);

  useEffect(() => {
    if (map.current) return;
    map.current = new mapmetricsgl.Map({ container: mapContainer.current, style: '<StyleFile_URL_with_Token>', center: [0, 20], zoom: 1.5 });
    const marker = new mapmetricsgl.Marker({ color: '#3b82f6' }).setLngLat([0, 20]).addTo(map.current);
    let t = 0;
    const animate = () => {
      t += 0.005;
      marker.setLngLat([(t * 30) % 360 - 180, Math.sin(t) * 40]);
      animId.current = requestAnimationFrame(animate);
    };
    map.current.on('load', animate);
    return () => {
      if (animId.current) cancelAnimationFrame(animId.current);
      map.current?.remove(); map.current = null;
    };
  }, []);

  return <div ref={mapContainer} style={{ height: '500px', width: '100%' }} />;
};

export default AnimateMarker;

For more information, visit the MapMetrics GitHub repository.