Animated Data Visualizations
March 30, 2026 ยท View on GitHub
Time-Series Animation
Pattern: Animate data over time
let currentTime = 0;
const times = [0, 6, 12, 18, 24]; // Hours of day
let animationId;
map.on('load', () => {
map.addSource('hourly-data', {
type: 'geojson',
data: getDataForTime(currentTime)
});
map.addLayer({
id: 'data-layer',
type: 'circle',
source: 'hourly-data',
paint: {
'circle-radius': 8,
'circle-color': ['get', 'color']
}
});
// Animation loop
function animate() {
currentTime = (currentTime + 1) % times.length;
// Update data
map.getSource('hourly-data').setData(getDataForTime(times[currentTime]));
// Update UI
document.getElementById('time-display').textContent = `${times[currentTime]}:00`;
animationId = setTimeout(animate, 1000); // Update every second
}
// Start animation
document.getElementById('play-button').addEventListener('click', () => {
if (animationId) {
clearTimeout(animationId);
animationId = null;
} else {
animate();
}
});
});
function getDataForTime(hour) {
// Fetch or generate data for specific time
return {
type: 'FeatureCollection',
features: data.filter((d) => d.properties.hour === hour)
};
}
Real-Time Data Updates
Pattern: Update data from live sources
map.on('load', () => {
map.addSource('live-data', {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: []
}
});
map.addLayer({
id: 'live-points',
type: 'circle',
source: 'live-data',
paint: {
'circle-radius': 6,
'circle-color': '#ff4444'
}
});
// Poll for updates every 5 seconds
setInterval(async () => {
const response = await fetch('https://api.example.com/live-data');
const data = await response.json();
// Update source
map.getSource('live-data').setData(data);
}, 5000);
// Or use WebSocket for real-time updates
const ws = new WebSocket('wss://api.example.com/live');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
map.getSource('live-data').setData(data);
};
});
Smooth Transitions
Pattern: Animate property changes
// Smoothly transition circle sizes
function updateVisualization(newData) {
map.getSource('data-source').setData(newData);
// Animate circle radius
const currentRadius = map.getPaintProperty('data-layer', 'circle-radius');
const targetRadius = ['get', 'newSize'];
// Use setPaintProperty with transition
map.setPaintProperty('data-layer', 'circle-radius', targetRadius);
// Or use expressions for smooth interpolation
map.setPaintProperty('data-layer', 'circle-radius', ['interpolate', ['linear'], ['get', 'value'], 0, 2, 100, 20]);
}