Adds an interactive slider to a Mapbox GL or MapLibre GL map that
steps through a sequence of values and filters one or more layers by
a numeric feature property. Works source-agnostically: GeoJSON,
vector tile, and PMTiles layers all compose through the same filter
pipeline. Optional play button animates through the steps;
"cumulative" mode accumulates features through the range rather
than swapping them.
Usage
add_slider_control(
map,
layers,
property = NULL,
time_unit = NULL,
values = NULL,
labels = NULL,
min = NULL,
max = NULL,
step = 1,
mode = c("sequential", "cumulative", "window"),
window = NULL,
presentation = c("compact", "timeline"),
window_behavior = c("auto", "resizable", "fixed"),
histogram = FALSE,
histogram_data = NULL,
counts = NULL,
initial_value = NULL,
paint_property = NULL,
paint_expressions = NULL,
paint_properties = NULL,
play_button = FALSE,
animation_duration = 1000,
loop = TRUE,
title = NULL,
show_value = TRUE,
slider_style = NULL,
width = 280,
position = "top-left",
draggable = FALSE,
background_color = "#ffffffcc",
text_color = "#404040",
accent_color = "#4a90e2"
)Arguments
- map
A map object created by
mapboxgl()ormaplibre(), or a proxy object frommapboxgl_proxy()/maplibre_proxy().- layers
Character vector of layer IDs the slider should affect. Layers need not exist yet — if a matching layer is added later via proxy, the slider's current filter and/or paint expression is applied on its first paint.
- property
Name of the numeric feature property to filter on. Optional: if
NULL, no filter behavior. At least one ofpropertyorpaint_propertymust be supplied.- time_unit
Optional. Only consequential when a target layer is a flowmap (
add_flowmap()): ordinary layers filter on the numericpropertydirectly, but flowmap layers need an absolute timestamp range, so in"window"mode the numeric value is converted to a flowmap time range using this unit. One of"seconds","date", or"year"(the absolute units produced byas_time_property())."month"/"day"are calendar indices, not instants, and cannot drive a flowmap window.- values
Numeric vector of steps. Required unless
minandmaxare supplied.- labels
Optional character vector of display labels (one per value). When omitted, labels default to
as.character(values), except whentime_unitis"seconds"or"date": then the numeric values are formatted back into readable timestamps ("%Y-%m-%d %H:%M"in UTC for seconds,"%Y-%m-%d"for dates) so a time-driven slider does not display raw epoch numbers. Pass an explicit vector to localize or change the format.- min, max, step
Numeric range specification used when
valuesis not supplied.valuesis generated viaseq(min, max, by = step).- mode
One of
"sequential"(default) — each step shows only features matching that exact value;"cumulative"— shows everything up through the current value; or"window"— shows a moving[start, end]range (the end is the current value). Window mode emits a range filter for ordinary layers and aselectedTimeRangefor flowmap layers, making it the mode used to drive temporal flowmaps. Only applies whenpropertyis set.- window
Only used when
mode = "window".NULL(default) makes a cumulative range[min(values), T]; a positive number makes a sliding window[T - window, T], wherewindowis expressed in the same units asvalues(e.g. foras_time_property()unit = "date",window = 7is a 7-day window).- presentation
Visual style of the control.
"compact"(default) is a small slider (optionally with a density strip behind it)."timeline"renders a prominent, brushable histogram as the control itself – drag the selected window across the bars, or drag its edges to resize it (as in FlowMapBlue's time control)."timeline"requires histogram data (countsorhistogram_data) and implieshistogram = TRUE.- window_behavior
Only used when
mode = "window"."auto"(default) uses a fixed-duration window whenwindowis supplied and a resizable range otherwise."fixed"pins the window width towindowand moves the whole[end - window, end]band."resizable"lets the user drag either edge to resize the selected range.- histogram
Logical; if
TRUE, draw a density strip behind the slider showing how many features fall at each value (a data-density backdrop, most useful withmode = "window"where the selected band highlights the covered bars). Loads d3 on demand. Supply the bar heights viacountsorhistogram_data. DefaultFALSE.- histogram_data
Numeric vector of the raw property values across your features; binned in R to the nearest
valuesstep to produce the histogram bar heights. Use this when you have the underlying data to hand. Ignored unlesshistogram = TRUE.- counts
Numeric vector of pre-computed bar heights, one per
values. An alternative tohistogram_datawhen you already have per-step counts. Ignored unlesshistogram = TRUE.- initial_value
Value to start on. In
"window"mode this is the window end value and defaults to the last value; other modes default to the first value.- paint_property
Optional Mapbox paint property the slider should animate, supplied in snake_case to match the rest of the package (e.g.
"fill_color","fill_extrusion_height","circle_radius"). Kebab-case is also accepted for convenience when copying from Mapbox docs. Shortcut for the single-property case; when set,paint_expressionsmust also be supplied. For animating more than one paint property together (e.g. height and color), usepaint_propertiesinstead.- paint_expressions
List of Mapbox expressions, one per value in
values. On each step, the expression at the matching index is applied to each target layer viamap.setPaintProperty(). Build expressions withinterpolate(),match_expr(), or raw lists.- paint_properties
Optional named list for animating multiple paint properties simultaneously. Shape:
list(fill_color = list(<expr_0>, <expr_1>, ...), fill_extrusion_height = list(...))— names are snake_case (kebab-case also accepted), each value is a list of expressions the same length asvalues. Cannot be combined withpaint_property/paint_expressions. Each property's pre-slider value is captured on mount and restored on removal, independently.Logical; include a play/pause button next to the slider. Default
FALSE.- animation_duration
Milliseconds to wait between steps while playing. Default
1000.- loop
Logical; when playback reaches the last value, return to the first. Default
TRUE.- title
Optional title shown above the slider.
- show_value
Logical; show the current label beside the slider. Default
TRUE.- slider_style
Optional appearance for the slider: a preset string (
"light","dark", or"auto") or aslider_style()object. When omitted, the legacywidth,background_color,text_color, andaccent_colorarguments are used.- width
Slider container width in pixels. Default
280.- position
One of
"top-left","top-right","bottom-left","bottom-right". Default"top-left".- draggable
Logical, whether the slider panel can be dragged to a new position on the map by the user. Default
FALSE, keeping it docked atposition.- background_color, text_color, accent_color
Styling overrides. Defaults match the package's other controls. For full control of the slider appearance, use
slider_style.
Details
Values commonly represent time (years, months, epoch seconds) but need not — any monotonic numeric sequence works (magnitude thresholds, percentile coverage, depth bins, etc.).
The slider composes with other filter sources rather than replacing
them: a layer's initial filter = argument, a subsequent
set_filter() call, and an interactive add_legend() can all be
active at the same time as the slider, and the layer's resolved
filter is the ["all", ...] intersection.
Date and time values
The slider requires numeric values. Because sf objects are
serialized to GeoJSON via geojsonsf::sf_geojson(), Date and
POSIXct columns become JSON strings, not numbers — so you must
pre-coerce your time column to numeric before adding the layer. Use
as_time_property() for the common cases (year, month index, epoch
seconds, days-since-epoch).
Positioning and collisions
The slider is implemented as a native control and stacks beside
other native controls (navigation, scale, geolocate, fullscreen) via
Mapbox/MapLibre's built-in positioning. Overlays such as
add_legend() and add_layers_control() are absolutely-positioned
and do not participate in that flow — placing a slider in the same
corner as a legend will overlap it. Choose a different corner or
adjust the overlay's margins.
Examples
if (FALSE) { # \dontrun{
library(mapgl)
library(sf)
quakes <- sf::read_sf(
"https://docs.mapbox.com/mapbox-gl-js/assets/significant-earthquakes-2015.geojson"
)
quakes$month <- as.POSIXlt(quakes$time / 1000, origin = "1970-01-01")$mon
mapboxgl(center = c(-45, 0), zoom = 0.25) |>
add_circle_layer(
id = "quakes",
source = quakes,
circle_color = "#FCA107",
circle_radius = 20,
circle_opacity = 0.75
) |>
add_slider_control(
layers = "quakes",
property = "month",
values = 0:11,
labels = month.name,
title = "Significant earthquakes in 2015",
play_button = TRUE
)
# --- Paint animation: step through a choropleth's color over years
# Given an sf object with columns pop2020, pop2021, ..., pop2024:
# mapboxgl() |>
# add_fill_layer(id = "tracts", source = tracts, fill_opacity = 0.85) |>
# add_slider_control(
# layers = "tracts",
# values = 2020:2024,
# paint_property = "fill_color",
# paint_expressions = lapply(2020:2024, function(y) {
# interpolate(
# column = paste0("pop", y),
# values = c(0, 5e5, 2e6),
# stops = c("#f7f4f9", "#67a9cf", "#02818a")
# )
# }),
# play_button = TRUE
# )
} # }
