Skip to content

Jump to a Series of Locations

Navigate through a series of predefined locations — either instantly with jumpTo or with a smooth animation using flyTo.

How It Works

  • jumpTo() — Instantly moves the camera with no animation
  • flyTo() — Smoothly animates the camera to the location
  • easeTo() — Animates the camera with configurable easing

Instant Jump (No Animation)

javascript
// Jump instantly to a location
map.jumpTo({
  center: [-74.006, 40.7128],
  zoom: 12,
  bearing: 0,
  pitch: 0
});

Animated Jump (With flyTo)

javascript
const locations = [
  { name: 'Paris',    center: [2.349902, 48.852966], zoom: 12 },
  { name: 'New York', center: [-74.006, 40.7128],    zoom: 12 },
  { name: 'Tokyo',    center: [139.6917, 35.6895],   zoom: 12 },
];

function goTo(index) {
  map.flyTo({
    center: locations[index].center,
    zoom: locations[index].zoom,
    speed: 2,
    essential: true
  });
}

Auto Tour

javascript
let currentIndex = 0;

// Automatically cycle through all locations
const tourInterval = setInterval(() => {
  map.flyTo({
    center: locations[currentIndex].center,
    zoom: locations[currentIndex].zoom,
    speed: 2
  });
  currentIndex = (currentIndex + 1) % locations.length;
}, 3500); // Move every 3.5 seconds

// Stop the tour
clearInterval(tourInterval);

Difference: jumpTo vs flyTo vs easeTo

MethodAnimationUse Case
jumpTo()None (instant)Quick navigation, no visual transition needed
flyTo()Zoom out → pan → zoom inBest for large distances
easeTo()Smooth pan/zoomBest for short distances

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%; }
      .controls { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; }
      button { padding: 8px 16px; background: #3b82f6; color: white; border: none; border-radius: 6px; cursor: pointer; }
      #tour-btn { background: #22c55e; }
      #stop-btn { background: #ef4444; }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <div class="controls" id="btn-container"></div>
    <script>
      const locations = [
        { name: 'Paris',    center: [2.349902, 48.852966], zoom: 12 },
        { name: 'New York', center: [-74.006, 40.7128],    zoom: 12 },
        { name: 'Tokyo',    center: [139.6917, 35.6895],   zoom: 12 },
        { name: 'Sydney',   center: [151.2093, -33.8688],  zoom: 12 },
        { name: 'Dubai',    center: [55.2708, 25.2048],    zoom: 12 },
      ];

      const map = new mapmetricsgl.Map({
        container: 'map',
        style: '<StyleFile_URL_with_Token>',
        center: locations[0].center,
        zoom: 2
      });

      map.addControl(new mapmetricsgl.NavigationControl(), 'top-right');

      // Add markers
      locations.forEach(loc => {
        new mapmetricsgl.Marker()
          .setLngLat(loc.center)
          .setPopup(new mapmetricsgl.Popup({ offset: 25 }).setHTML(`<b>${loc.name}</b>`))
          .addTo(map);
      });

      // Build buttons
      const container = document.getElementById('btn-container');
      locations.forEach((loc, i) => {
        const btn = document.createElement('button');
        btn.textContent = `${i + 1}. ${loc.name}`;
        btn.onclick = () => map.flyTo({ center: loc.center, zoom: loc.zoom, speed: 2 });
        container.appendChild(btn);
      });

      // Auto tour
      let tourInterval = null;
      let currentIndex = 0;

      const tourBtn = document.createElement('button');
      tourBtn.id = 'tour-btn';
      tourBtn.textContent = '▶ Auto Tour';
      tourBtn.onclick = () => {
        if (tourInterval) clearInterval(tourInterval);
        currentIndex = 0;
        map.flyTo({ center: locations[0].center, zoom: locations[0].zoom, speed: 2 });
        tourInterval = setInterval(() => {
          currentIndex = (currentIndex + 1) % locations.length;
          map.flyTo({ center: locations[currentIndex].center, zoom: locations[currentIndex].zoom, speed: 2 });
        }, 3500);
      };

      const stopBtn = document.createElement('button');
      stopBtn.id = 'stop-btn';
      stopBtn.textContent = '⏹ Stop';
      stopBtn.onclick = () => { if (tourInterval) clearInterval(tourInterval); };

      container.appendChild(tourBtn);
      container.appendChild(stopBtn);
    </script>
  </body>
</html>
jsx
import React, { useEffect, useRef, useState } from 'react';
import mapmetricsgl from '@mapmetrics/mapmetrics-gl';
import '@mapmetrics/mapmetrics-gl/dist/mapmetrics-gl.css';

const locations = [
  { name: 'Paris',    center: [2.349902, 48.852966], zoom: 12 },
  { name: 'New York', center: [-74.006, 40.7128],    zoom: 12 },
  { name: 'Tokyo',    center: [139.6917, 35.6895],   zoom: 12 },
  { name: 'Sydney',   center: [151.2093, -33.8688],  zoom: 12 },
  { name: 'Dubai',    center: [55.2708, 25.2048],    zoom: 12 },
];

const JumpToLocations = () => {
  const mapContainer = useRef(null);
  const map = useRef(null);
  const tourInterval = useRef(null);
  const [isTourRunning, setIsTourRunning] = useState(false);

  useEffect(() => {
    if (map.current) return;

    map.current = new mapmetricsgl.Map({
      container: mapContainer.current,
      style: '<StyleFile_URL_with_Token>',
      center: locations[0].center,
      zoom: 2
    });

    map.current.addControl(new mapmetricsgl.NavigationControl(), 'top-right');

    // Add markers for all locations
    locations.forEach(loc => {
      new mapmetricsgl.Marker()
        .setLngLat(loc.center)
        .setPopup(new mapmetricsgl.Popup({ offset: 25 }).setHTML(`<strong>${loc.name}</strong>`))
        .addTo(map.current);
    });

    return () => {
      if (tourInterval.current) clearInterval(tourInterval.current);
      map.current?.remove();
      map.current = null;
    };
  }, []);

  const goTo = ({ center, zoom }) => {
    map.current?.flyTo({ center, zoom, speed: 2, essential: true });
  };

  const startTour = () => {
    let index = 0;
    goTo(locations[index]);
    setIsTourRunning(true);
    tourInterval.current = setInterval(() => {
      index = (index + 1) % locations.length;
      goTo(locations[index]);
    }, 3500);
  };

  const stopTour = () => {
    if (tourInterval.current) clearInterval(tourInterval.current);
    setIsTourRunning(false);
  };

  const btnStyle = (bg) => ({ padding: '8px 16px', background: bg, color: 'white', border: 'none', borderRadius: '6px', cursor: 'pointer' });

  return (
    <div>
      <div ref={mapContainer} style={{ height: '500px', width: '100%' }} />
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px', marginTop: '10px' }}>
        {locations.map((loc, i) => (
          <button key={loc.name} onClick={() => goTo(loc)} style={btnStyle('#3b82f6')}>
            {i + 1}. {loc.name}
          </button>
        ))}
        {!isTourRunning
          ? <button onClick={startTour} style={btnStyle('#22c55e')}>▶ Auto Tour</button>
          : <button onClick={stopTour} style={btnStyle('#ef4444')}>⏹ Stop</button>
        }
      </div>
    </div>
  );
};

export default JumpToLocations;

For more information, visit the MapMetrics GitHub repository.