Skip to Content
ExamplesChange Timeline Range

MapsGL - Change timeline range

This example demonstrates how to update the timeline start and/or end date range in real-time.

When time-based layers are active on the map, then new time intervals will be calculated for the new time range whenever the start or end times change. Thus, new data may be required to load when resuming playback of the timeline if the previous data does not cover the new time range and required intervals.

change-timeline-range.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>MapsGL SDK - Change timeline range</title> <meta name="description" content="Update the timeline start and/or end date range in real-time." /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <link href="https://api.mapbox.com/mapbox-gl-js/v3.12.0/mapbox-gl.css" rel="stylesheet" /> <script defer src="https://api.mapbox.com/mapbox-gl-js/v3.12.0/mapbox-gl.js"></script> <link href="https://cdn.aerisapi.com/sdk/js/mapsgl/1.9.1/aerisweather.mapsgl.css" rel="stylesheet" /> <script defer src="https://cdn.aerisapi.com/sdk/js/mapsgl/1.9.1/aerisweather.mapsgl.js"></script> <style> body, html { margin: 0; padding: 0; } #map { height: 100vh; width: 100%; } #controls { display: flex; flex-direction: column; gap: 12px; position: absolute; top: 10px; left: 10px; z-index: 1; background: rgba(255, 255, 255, 0.8); padding: 10px; border-radius: 5px; font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; font-size: 12px; } #controls h3 { margin: 0 0 8px; font-size: 14px; } #controls .container { display: flex; flex-direction: row; justify-content: center; align-items: center; gap: 20px; } #controls .control { display: flex; flex-direction: row; gap: 4px; } #controls .control-field { display: flex; flex-direction: column; gap: 2px; } #controls .control label { margin-top: 2px; font-weight: bold; } #controls .control span { font-size: 10px; } #controls .animation { display: flex; flex-direction: row; align-items: center; gap: 8px; min-height: 20px; } #controls .loader { display: none; height: 20px; } .loader .ring { display: inline-block; position: relative; width: 20px; height: 20px; } .loader .ring div { box-sizing: border-box; display: block; position: absolute; width: 18px; height: 18px; margin: 1px; border: 2px solid #333; border-radius: 50%; animation: loader-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite; border-color: #333 transparent transparent transparent; } .loader .ring div:nth-child(1) { animation-delay: -0.45s; } .loader .ring div:nth-child(2) { animation-delay: -0.3s; } .loader .ring div:nth-child(3) { animation-delay: -0.15s; } @keyframes loader-ring { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } </style> </head> <body> <div id="map"></div> <div id="controls"> <div class="animation"> <button class="btn-play">Play</button> <button class="btn-pause">Pause</button> <div class="loader"> <div class="ring"> <div></div><div></div><div></div><div></div> </div> </div> </div> <div class="container"> <div id="timeline-start" class="control"> <label for="range-start">Start</label> <div class="control-field"> <select id="range-start"></select> <span class="value"></span> </div> </div> <div id="timeline-end" class="control"> <label for="ramge-end">End</label> <div class="control-field"> <select id="range-end"></select> <span class="value"></span> </div> </div> </div> </div> <script> function formatDate(date) { return `${date.toLocaleDateString('en', { weekday: 'short' })} ${date.toLocaleTimeString('en')}`; } window.addEventListener('load', () => { // Set up UI elements const controls = { play: document.querySelector('#controls .btn-play'), pause: document.querySelector('#controls .btn-pause'), loader: document.querySelector('#controls .loader'), selectStart: document.querySelector('#range-start'), selectEnd: document.querySelector('#range-end'), labelStart: document.querySelector('#timeline-start span'), labelEnd: document.querySelector('#timeline-end span'), }; const dateRanges = [ { label: 'Now', value: '0' }, { label: '1 day', value: '24' }, { label: '3 days', value: '72' }, { label: '7 days', value: '168' } ]; dateRanges.forEach(({ label, value }) => { [controls.selectStart, controls.selectEnd].forEach((select, index) => { const option = document.createElement('option'); option.value = value; option.text = /\d+/.test(label) ? (index === 0 ? `-${label}` : `+${label}`) : label; select.append(option); }); }); // Set initial range values controls.selectStart.value = '0'; controls.selectEnd.value = '24'; // Create the Mapbox map instance mapboxgl.accessToken = 'MAPBOX_TOKEN'; const map = new mapboxgl.Map({ container: document.getElementById('map'), style: 'mapbox://styles/mapbox/light-v9', center: [20, 47], zoom: 4 }); // Set up MapsGL account and map controller with the timeline range const account = new aerisweather.mapsgl.Account('CLIENT_ID', 'CLIENT_SECRET'); const controller = new aerisweather.mapsgl.MapboxMapController(map, { account, animation: { start: new Date(Date.now() - (controls.selectStart.value * 3600000)), end: new Date(Date.now() + (controls.selectEnd.value * 3600000)) } }); // Update timeline when the selected start/end date changes controls.selectStart.addEventListener('change', () => { controller.timeline.startDate = new Date(Date.now() - (controls.selectStart.value * 3600000)); controls.labelStart.innerHTML = `${formatDate(controller.timeline.startDate)}`; }); controls.selectEnd.addEventListener('change', () => { controller.timeline.endDate = new Date(Date.now() + (controls.selectEnd.value * 3600000)); controls.labelEnd.innerHTML = `${formatDate(controller.timeline.endDate)}`; }); // Set initial timeline range controls.labelStart.innerHTML = `${formatDate(controller.timeline.startDate)}`; controls.labelEnd.innerHTML = `${formatDate(controller.timeline.endDate)}`; // Set up timeline controls and loading indicator controls.pause.disabled = true; controller.on('load:start', () => { controls.loader.style.display = 'block'; }); controller.on('load:complete', () => { controls.loader.style.display = 'none'; }); controller.timeline.on('play', () => { controls.play.textContent = 'Stop'; controls.pause.textContent = 'Pause'; controls.pause.disabled = false; }).on('stop', () => { controls.play.textContent = 'Play'; controls.pause.textContent = 'Pause'; controls.pause.disabled = true; }).on('pause', () => { controls.pause.textContent = 'Resume'; }).on('resume', () => { controls.pause.textContent = 'Pause'; }); controls.play.addEventListener('click', (e) => { e.preventDefault(); if (controller.timeline.isActive) { controller.timeline.stop(); } else { controller.timeline.play(); } }); controls.pause.addEventListener('click', (e) => { e.preventDefault(); if (controller.timeline.isPaused) { controller.timeline.resume(); } else { controller.timeline.pause(); } }); controller.on('load', () => { controller.addWeatherLayer('wind-particles'); }); }); </script> </body> </html>
© 2026 Xweather (opens in a new tab)Terms of Service (opens in a new tab)Privacy Policy (opens in a new tab)