Skip to content

Animated line

Animated line is a component that displays a line on a map with an animation effect.

Example

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Animate a line</title>
    <meta
      property="og:description"
      content="Animate a line by updating a GeoJSON source on each frame."
    />
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://unpkg.com/@vietmap/vietmap-gl-js@4.2.0/vietmap-gl.js"></script>
    <link
      rel="stylesheet"
      href="https://unpkg.com/@vietmap/vietmap-gl-js@4.2.0/vietmap-gl.css"
    />
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      html,
      body,
      #map {
        height: 100%;
      }
    </style>
  </head>
  <body>
    <style>
      button {
        position: absolute;
        top: 0;
        margin: 20px;
      }

      #pause::after {
        content: "Pause";
      }

      #pause.pause::after {
        content: "Play";
      }
    </style>
    <div id="map"></div>
    <button id="pause"></button>
    <script>
      const map = new vietmapgl.Map({
        container: "map",
        style:
          "https://maps.vietmap.vn/mt/tm/style.json?apikey=YOUR_API_KEY_HERE",
        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 degree
      let animation; // to store and cancel the animation
      let startTime = 0;
      let progress = 0; // progress = timestamp - startTime
      let resetTime = false; // indicator of whether time reset is needed for the animation
      const pauseButton = document.getElementById("pause");

      map.on("load", () => {
        map.addSource("line", {
          type: "geojson",
          lineMetrics: true,
          data: geojson,
        });

        // add the line which will be modified in the animation
        map.addLayer({
          id: "line-animation",
          type: "line",
          source: "line",
          layout: {
            "line-cap": "round",
            "line-join": "round",
          },
          paint: {
            "line-color": "#ed6498",
            "line-width": 5,
            "line-gradient": [
              "interpolate",
              ["linear"],
              ["line-progress"],
              0,
              "blue",
              0.1,
              "royalblue",
              0.3,
              "cyan",
              0.5,
              "lime",
              0.7,
              "yellow",
              1,
              "red",
            ],
          },
        });

        startTime = performance.now();

        animateLine();

        // click the button to pause or play
        pauseButton.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 default
        document.addEventListener("visibilitychange", () => {
          resetTime = true;
        });

        // animated in a circle as a sine wave along the map.
        function animateLine(timestamp) {
          if (resetTime) {
            // resume previous progress
            startTime = performance.now() - progress;
            resetTime = false;
          } else {
            progress = timestamp - startTime;
          }

          // restart if it finishes a loop
          if (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 lineString
            geojson.features[0].geometry.coordinates.push([x, y]);
            // then update the map
            map.getSource("line").setData(geojson);
          }
          // Request the next frame of the animation.
          animation = requestAnimationFrame(animateLine);
        }
      });
    </script>
  </body>
</html>
facebook
Tổng đài hỗ trợ
089.616.4567
facebook Chat Facebook zalo Chat Zalo