Short answer

A time slider turns a web map's time dimension into something a user can scrub. As the control's value changes, the application decides which temporal slice of data to display — swapping raster tile sets per date, filtering vector features by a timestamp attribute, or stepping through frames of a time-enabled service. Done well, it lets someone watch a glacier retreat, a flood spread, a coastline shift, or a mine expand without opening twenty separate maps.

The hard parts are not the slider widget itself; they are the temporal data model behind it, the loading strategy that keeps animation smooth, and the honesty of the result. Earth observation time series are irregular, cloud-gapped, and acquired by changing sensors, and a naive slider can imply continuous, steady change that the data never supported.

The temporal data model

Before any UI, decide how time is encoded.

Rasters generally take one of three shapes:

  • One tile pyramid per timestep. Pre-render each date to XYZ or WMTS tiles. Simple, cacheable, fast to switch, but storage grows linearly with the number of dates.
  • Cloud-Optimized GeoTIFFs (COGs) with a STAC catalogue. Each scene is a COG; a SpatioTemporal Asset Catalog (STAC) records its datetime, footprint, and bands. A dynamic tiler (for example a TiTiler-style service) renders tiles on demand for the requested date. This scales to large archives without pre-rendering everything.
  • Time-enabled WMS/WMTS. The OGC TIME dimension lets a single endpoint serve any date via a TIME=2024-07-01 parameter. Convenient when you already run a server like GeoServer.

Vectors are simplest when every feature carries explicit validity timestamps — for example t_start and t_end (ISO 8601, UTC). The client then filters by the slider value instead of loading a separate file per date. For large vector series, encode the timestamp into vector tiles and use the renderer's filter expression so only matching features draw.

A reliable convention: store all timestamps in UTC ISO 8601, keep the acquisition date (not the processing date) as the temporal key, and carry an explicit list of available timesteps so the slider snaps to real dates rather than interpolating across gaps.

Implementation patterns

MapLibre GL

MapLibre has no built-in time control, so you drive it from your own slider. Two robust patterns:

  • Source/layer swap per date. Add a raster source per timestep (or rewrite a single source's tiles URL template to point at the new date), then toggle layout.visibility. To avoid a blank flash, set the next layer's raster-opacity from 0 to 1 while fading the previous one out, and only remove the old layer after map.once('idle', ...) confirms the new tiles loaded.
  • Attribute filter for vectors. Keep one source and update a filter expression against the timestamp field as the slider moves, e.g. ["all", ["<=", ["get", "t_start"], current], [">", ["get", "t_end"], current]]. No new network requests, so this animates very smoothly.

deck.gl

deck.gl excels at large temporal point/feature sets. Pass the slider value as a uniform/prop and use getFilterValue with the DataFilterExtension to GPU-filter features by time, or use a TripsLayer for trajectories where time is intrinsic. Because filtering happens on the GPU, you can scrub through millions of timestamped points without re-uploading data each frame.

3D and globe context

When the story needs terrain or globe scale — ice sheets, regional subsidence — CesiumJS has a first-class clock and timeline and consumes time-dynamic 3D Tiles and imagery providers natively, which is often less work than reinventing temporal logic on a 2D engine.

Keeping it smooth: the loading strategy

The flicker problem is almost always a loading-order problem. Mitigations that work:

  • Prefetch neighbours. When the slider sits on date t, quietly request tiles for t−1 and t+1 so a scrub or play step hits warm cache.
  • Crossfade, don't blink. Never remove the current layer before the next is ready; overlap them and fade.
  • Throttle the clock. During "play", advance the time index on a fixed interval (e.g. 2-4 fps) rather than every animation frame, so you do not queue more tile requests than the network can satisfy.
  • Cap concurrent requests and abort in-flight requests for dates the user has already scrubbed past, so the browser is not finishing downloads nobody will see.
  • Reuse one source where possible. Rewriting a tile-URL template or filtering an attribute is far cheaper than adding and removing sources every step.

A worked sequence

For a Sentinel-2 cloud-free composite series over a study area:

  1. Build monthly cloud-masked composites and write each as a COG; register them in a STAC collection with datetime per item.
  2. Stand up a dynamic tiler that accepts a date and band combination and returns XYZ tiles.
  3. In the client, fetch the STAC collection's item list to populate the slider's discrete tick marks with the real available months.
  4. On slider change, update the MapLibre raster source's tiles template to the selected month, crossfade, and prefetch the adjacent months.
  5. Show the exact acquisition/composite date, the cloud-cover percentage, and the source ("Sentinel-2 L2A monthly composite") in a caption that updates with the frame.

Common pitfalls and why they happen

  • Constant speed over irregular gaps. Playing dates spaced 5 days then 40 days apart at one frame each implies uniform change; viewers read motion as rate. Either space frames by real time or annotate the gap.
  • Mistaking data gaps for ground change. A cloud-masked NoData hole or a missing scene can look like the surface disappeared. Render NoData distinctly (hatch or grey), not as transparent ground.
  • Sensor changes mid-series. Switching from Landsat 7 to 8, or recolouring composites between dates, creates apparent change that is purely instrumental. Keep stretch, bands, and processing identical across the series, and flag sensor transitions.
  • Timezone drift. Mixing local and UTC timestamps shifts features by hours and misaligns the slider; standardise on UTC.
  • Remove-then-add layer churn. Deleting the old layer before the new one loads is the direct cause of the white flash users complain about.

Validation and QA

Test the slider with the full date range and realistic data volume, not a three-frame sample — performance problems only appear at scale. Verify each frame's caption matches the data actually drawn (a classic bug is the label updating before the tiles do). Confirm NoData and cloud gaps render distinctly. Scrub backward as well as forward to catch request-cancellation and caching bugs. Finally, hand it to someone unfamiliar with the dataset and check they can tell when each frame is from and what is real change versus a gap.

Bathyl perspective

We treat the time axis as data to be respected, not a transition effect. The composites are built consistently, the real acquisition dates and gaps stay visible in every frame, and the loading strategy keeps animation honest at full scale — so a scrub through a decade of imagery reads as evidence rather than a slideshow.

Related reading

Sources