<link href="https://api.mapbox.com/mapbox-gl-js/v2.9.2/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.9.2/mapbox-gl.js"></script>
<script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<div id="map"></div>
<div id="animation-phase-container">
  animationPhase:
  <div id="animation-phase"></div>
</div>
body {
  margin: 0;
  padding: 0;
}
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}

#animation-phase-container {
  position: absolute;
  top: 10px;
  left: 10px;
  background: white;
  padding: 10px;
  font-family: sans-serif;
  display: flex;
  align-items: center;
  border-radius: 8px;
}

#animation-phase {
  margin-left: 5px;
  font-weight: 600;
  font-size: 30px;
}
mapboxgl.accessToken =
  "pk.eyJ1IjoiY2hyaXN3aG9uZ21hcGJveCIsImEiOiJjbGE5eTB0Y2QwMmt6M3dvYW1ra3pmMnNsIn0.ZfF6uOlFNhl6qoCR7egTSw";
const map = new mapboxgl.Map({
  container: "map", // container ID
  style: "mapbox://styles/mapbox/dark-v10", // style URL
  bounds: [-75.825258, 38.192806, -74.921632, 38.636125],
  projection: "globe" // display the map as a 3D globe
});

map.on("style.load", () => {
  // https://en.wikipedia.org/wiki/Transpeninsular_Line
  const transpeninsularLine = {
    type: "Feature",
    properties: {
      stroke: "#555555",
      "stroke-width": 2,
      "stroke-opacity": 1
    },
    geometry: {
      type: "LineString",
      coordinates: [
        [-76.328140,38.472938],
        [-75.04914164543152, 38.451252947957364]
      ]
    }
  };

  map.addSource("tp-line", {
    type: "geojson",
    data: transpeninsularLine,
    // Line metrics is required to use the 'line-progress' property
    lineMetrics: true
  });

  map.addLayer({
    id: "tp-line-line",
    type: "line",
    source: "tp-line",
    paint: {
      "line-color": "rgba(0,0,0,0)",
      "line-width": 8,
      "line-opacity": 0.7
    }
  });
  map.setFog({}); // Set the default atmosphere style

  let startTime;
  const duration = 3000;

  const frame = (time) => {
    if (!startTime) startTime = time;
    const animationPhase = (time - startTime) / duration;
    const animationPhaseDisplay = animationPhase.toFixed(2);
    $("#animation-phase").text(animationPhaseDisplay);

    // Reduce the visible length of the line by using a line-gradient to cutoff the line
    // animationPhase is a value between 0 and 1 that reprents the progress of the animation
    map.setPaintProperty("tp-line-line", "line-gradient", [
      "step",
      ["line-progress"],
      "yellow",
      animationPhase,
      "rgba(0, 0, 0, 0)"
    ]);

    if (animationPhase > 1) {
      return;
    }
    window.requestAnimationFrame(frame);
  };

  window.requestAnimationFrame(frame);

  // repeat
  setInterval(() => {
    startTime = undefined;
    window.requestAnimationFrame(frame);
  }, duration + 1500);
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.