Animations with Mapbox GL

The following provides an example of AMP radar animations integrated with the Mapbox GL API library. For an example using our JS SDK, please visit the AerisWeather JS SDK docs.

 
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Mapbox GL Animation - AerisWeather Mapping Platform</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <style>
        html, body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
        #map {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>

<div id="map"></div>

<script>

const frameCount = 10; // total intervals
const startMinutes = -60; // start time offset relative to now, where negative means past
const endMinutes = 0;

const MAPBOX_TOKEN = 'MAPBOX_TOKEN';
const AERIS_ID = 'CLIENT_ID';
const AERIS_KEY = 'CLIENT_SECRET';
const NUM_COLORS = '256'; // set to empty string for true color png
const TILE_SIZE = 256;

// layer to include on the map
// uncomment more layers or add more!
const layers = [
    // 'alerts',
    // 'satellite',
    'radar',
    'stormcells'
];

function getTilePath(server, interval) {
    return `https://maps${server}.aerisapi.com/${AERIS_ID}_${AERIS_KEY}/${layers.join(',')}/{z}/{x}/{y}/${interval}min.png${NUM_COLORS}`;
}

window.addEventListener('load', () => {
    mapboxgl.accessToken = MAPBOX_TOKEN;

    const map = new mapboxgl.Map({
        container: 'map',
        style: 'mapbox://styles/mapbox/streets-v11',
        center: [-95, 40],
        zoom: 4
    });

    function addRasterLayer(map, interval, opacity = 0) {
        const id = `amp-${layers.join('::')}-${interval}`;
        map.addSource(id, {
            type: 'raster',
            tiles: [1, 2, 3, 4].map((s) => getTilePath(s, interval)),
            tileSize: TILE_SIZE,
            attribution: '<a href="https://www.aerisweather.com/">AerisWeather</a>'
        });
        map.addLayer({
            id, 
            type: 'raster',
            source: id,
            minzoom: 0,
            maxzoom: 22,
            paint: {
                'raster-opacity': opacity,
                'raster-opacity-transition': {
                    duration: 0,
                    delay: 0
                }
            }
        });

        return id;
    }

    function setRasterLayerOpacity(map, id, opacity) {
        map.setPaintProperty(id, 'raster-opacity', opacity);
    }

    map.on('load', () => {
        const interval = (endMinutes - startMinutes) / frameCount;
        // set up the animation frames and layers
        const frames = [];
        for (let i = 0; i < frameCount; i += 1) {
            const opacity = (i === 0) ? 1 : 0;
            const timeOffset = startMinutes + interval * i;
            const id = addRasterLayer(map, timeOffset, opacity);
            frames.push(id);
        }

        // wait time determines how long to wait and allow frames to load before
        // beginning animation playback
        const waitTime = 5000;

        // step time determines the time in milliseconds each frame holds before advancing
        const stepTime = 1000;

        let currentOffset = 0;
        let previousOffset = currentOffset;

        setTimeout(() => {
            setInterval(() => {
                previousOffset = currentOffset;
                currentOffset += 1;
                if (currentOffset === frames.length - 1) {
                    currentOffset = 0;
                }
                setRasterLayerOpacity(map, frames[previousOffset], 0);
                setRasterLayerOpacity(map, frames[currentOffset], 1);
            }, stepTime);
        }, waitTime);
    });
});
</script>

<script src="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.js" async defer></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css" rel="stylesheet" />

</body>
</html>

Last modified: August 28, 2020