Load the map visually more quickly using a raster background

In some cases, if the map style contains many sources and layers or if the visitor has a slow connection, it can take some time for the map to start appearing visually. There are several tricks you can use to improve the perceived performance of the application.

The most basic solution is to set the page background to the expected (most dominant) map color, which in itself can significantly reduce the visual change that suddenly occurs once the map loads.

Static Maps API image supplementing zoomable maps

A more advanced solution is using our Static Maps API to supplement the map initiation process and provide a very smooth user experience.

These are the steps to follow:

  • Initialize the map the standard way.
  • Add the image of the area you want to display/the whole world (from Static Maps API) as the bottom-most layer (the visitor can still navigate the map).
  • The vector map will start appearing on top of the raster, gradually adding details and making it “come alive”.
  • Once the whole map is loaded for the first time, it’s better to remove the raster background to avoid potential rendering artifacts on the ocean edges.

Complete source code example:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.maptiler.com/mapbox-gl-js/v1.11.1/mapbox-gl.js"></script>
  <link href="https://cdn.maptiler.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />
  <style>
    #map {position: absolute; top: 0; right: 0; bottom: 0; left: 0;}
  </style>
</head>
<body>
  <div id="map"></div>
  <script>
    const KEY = 'YOUR_MAPTILER_KEY';

    // initialize the map
    var map = new mapboxgl.Map({
      container: 'map',
      style: 'https://api.maptiler.com/maps/streets/style.json?key=' + KEY,
      center: [0, 0],
      zoom: 2
    });

    // Wait until the style is parsed
    map.once('styledata', function(e) {
      var tmpStaticUrl = 'https://api.maptiler.com/maps/streets/static/-180,-85.05,180,85.05/1024x1024.png?key=' + KEY;

      // Add the whole-world raster source.
      // You can change the area of interest, but coordinates and the resolution need to match
      map.addSource('tmp-static-source', {
        'type': 'image',
        'url': tmpStaticUrl,
        'coordinates': [
          [-180, 85.05],
          [180, 85.05],
          [180, -85.05],
          [-180, -85.05]
        ]
      });

      map.addLayer({
        'id': 'tmp-static',
        'source': 'tmp-static-source',
        'maxzoom': 7,
        'type': 'raster'
      }, map.getStyle().layers[1].id); // Bottom-most layer (just above the background layer)

      // After the map is finished rendering for the first time, clean up everything
      var cleanUpListener = function(e) {
        if (map.loaded() && map.areTilesLoaded() &&
            map.getLayer('tmp-static')) {
          map.removeLayer('tmp-static');
          map.removeSource('tmp-static-source');
          map.off('render', cleanUpListener);
        }
      };
      map.on('render', cleanUpListener);
    });
  </script>
</body>
</html>

You can change the area of interest (instead of the whole world) to get a better resolution of the Static Maps image. In such a case, you need to correctly calculate the resolution based on the area and also fit the whole zoom levels of a Mercator projection tile pyramid. See Tiles ala Google Maps.

Using this approach will generate additional API requests and can result in higher charges.