Map animation with Mapbox GL

What can be more eye-catching than smooth, interactive, three-dimensional map animation? Impress your visitors by displaying your map data in stunning 3D!

Previously we have compared OpenLayers and Leaflet map libraries. Both are great choices if you want to add interactive map to your website. They are free, battle-tested, extensible and supported by active communities.

But what if you need a very fast, animated, eye-catching 3D map? Both Leaflet API and OpenMapLayersAPI do not support 3D and free-form map rotation. In this case Mapbox GL map library can be a great option.

Mapbox GL JS is one of the most advanced JavaScript map rendering libraries when it comes to smooth interactive animation. Mapbox GL API is slightly harder to use and not compatible with existing Leaflet plugins and examples. But it is using hardware-accelerated WebGL technology to dynamically draw data with the speed and smoothness of a video game.

In this article I'll show you how to animate and implement 3D map rotation around a selected point. The end result should look like this:

Map rotation animation in 3D with Mapbox GL

If you short on time and just looking for the complete HTML code, you can find it at the bottom of the page.

Setting up our 3D map

As first step, we need to add imports for Mapbox GL library and its CSS style sheet into the HEAD of our page

<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/0.53.1/mapbox-gl.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/0.53.1/mapbox-gl.js"></script>

Once imported, we can define a <div> element which will host map visualization and add Javascript code which will initialize Mapbox GL to render our map in 3D with specified initial location, zoom, pitch and bearing. Please do not forget to put your real API key instead of "YOUR_API_KEY" placeholder in the map tiles URL.

<div id="map"></div>
<script>
  var map = new mapboxgl.Map({
      container: 'map',
      style: {
          "version": 8,
          "sources": {
              "basemap": {
                  "type": "raster",
                  // map tile source
                  "tiles": [
                      "https://maps.geoapify.com/v1/tile/carto/{z}/{x}/{y}.png?api_key=YOUR_API_KEY"
                  ],
                  "tileSize": 256
              }
          },
          "layers": [{
              "id": "basemap",
              "type": "raster",
              "source": "basemap",
              "minzoom": 0,
              "maxzoom": 22
          }]
      },
      center: [-73.991462, 40.724637], // starting position
      zoom: 12, // starting zoom
      pitch: 60, // starting pitch in degrees
      bearing: 0, // starting bearing in degree
  });
</script>

This should give us basic interactive 3D map. You should be able to move the map to a different locations, zoom in and out, and change view angle.

Interactive 3D map view of Manhattan, NY

Interactive 3D map view of Manhattan, NY

Adding map rotation animation

As next step, let's add dynamic map animation, which will change view angle to create effect of flying around the map center. Please add the following code into our <script> block and refresh the page:

function rotateCamera(timestamp) {
  // rotate at approximately ~10 degrees per second
  map.rotateTo((timestamp / 100) % 360, { duration: 0 });
  // request the next frame of the animation
  requestAnimationFrame(rotateCamera);
}

map.on("load", function () {
  // start the animation
  rotateCamera(0);
});

Final steps

As the last step, let's add basic map navigation controls and basemap attribution.

// map navigation controls
map.addControl(new mapboxgl.NavigationControl());

// attribution
map.addControl(
  new mapboxgl.AttributionControl({
    compact: false,
    customAttribution:
      'Powered by <a href="https://geoapify.com/">Geoapify</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
  })
);

Complete map with controls and attribution

Complete map with controls and attribution

Complete HTML code

Final version of the HTML page could look like this. Please feel free to copy the code, insert API key and open it in your browser to see how it works.

<html>
  <head>
    <meta charset="utf-8" />
    <title>Mapbox GL example: rotate map animation in 3D</title>
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/0.53.1/mapbox-gl.css"
    />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mapbox-gl/0.53.1/mapbox-gl.js"></script>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      var map = new mapboxgl.Map({
          container: 'map',
          style: {
              "version": 8,
              "sources": {
                  "basemap": {
                      "type": "raster",
                      // map tile source
                      "tiles": [
                          "https://maps.geoapify.com/v1/tile/carto/{z}/{x}/{y}.png?api_key=YOUR_API_KEY"
                      ],
                      "tileSize": 256
                  }
              },
              "layers": [{
                  "id": "basemap",
                  "type": "raster",
                  "source": "basemap",
                  "minzoom": 0,
                  "maxzoom": 22
              }]
          },
          center: [-73.991462, 40.724637], // starting position
          zoom: 12, // starting zoom
          pitch: 60, // starting pitch in degrees
          bearing: 0, // starting bearing in degree
      });

      function rotateCamera(timestamp) {
          // rotate at approximately ~10 degrees per second
          map.rotateTo((timestamp / 100) % 360, {duration: 0});
          // request the next frame of the animation
          requestAnimationFrame(rotateCamera);
      }

      map.on('load', function () {
          // start the animation
          rotateCamera(0);
      });

      // map navigation controls
      map.addControl(new mapboxgl.NavigationControl());

      // attribution
      map.addControl(new mapboxgl.AttributionControl({
      	compact: false,
      	customAttribution: 'Powered by <a href="https://geoapify.com/">Geoapify</a> | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
      }));
    </script>
  </body>
</html>

Summary

Mapbox GL generally requires more JavaScript code to be written than Leaflet and can be more complicated to maintain.

So, you may ask when to use Leaflet and when to use Mapbox GL?

The answer is simple - if you don't need 3D and extremely fast animation then Leaflet would be the best choice. It has biggest community, best documentation, extensive set of plugins and works well in any situation. And if you really need advanced 3D maps with animations and top rendering speed on modern devices - then Mapbox GL is your friend.

Geoapify Location Platform

We offer APIs and Components for digital maps. Register and try our APIs for Free!