sf object (no non-geometry columns) as a layer source caused a serialization error. geojsonsf::sf_geojson() simplifies property-less sf objects into a vector of individual geometry strings rather than a FeatureCollection, which htmlwidgets cannot serialize. All internal calls now use simplify = FALSE to consistently return a FeatureCollection (#212).Tooltips and popups now accept {brace} templates package-wide. Any layer's tooltip/popup (and set_tooltip()/set_popup()) can take a glue-style template such as "{name}: {population}", in addition to the existing column name and concat()/number_format() expression forms; substituted values are HTML-escaped.
New tooltip_style() / popup_style() helpers theme tooltips and popups without hand-written HTML/CSS, mirroring legend_style(). Pass a preset ("light"/"dark") or custom appearance (background, border, radius, font, padding, shadow) to the new tooltip_style/popup_style argument on layer functions (and set_tooltip()/set_popup()). Tooltips are unstyled by default, so existing maps are unchanged.
New add_flowmap() draws animated origin-destination flow maps powered by Flowmap.gl (deck.gl). It supports temporal flows, location clustering, customizable color schemes (flowmap_color_schemes()), CSS blend modes, and themeable tooltips and popups (per-object-type content via list(location = , flow = ), styled with tooltip_style()/popup_style()). Flow filters and settings can be updated reactively in Shiny with set_flowmap_filter() and set_flowmap_settings(), and a "window"-mode add_slider_control() can drive a flowmap's temporal range. The heavy flow-mapping libraries load on demand, so maps without a flowmap are unaffected. Adapted from Egor Kotov's contribution in #205, with the bundled bixi_locations and bixi_flows datasets as a ready-to-use example.
New add_slider_control() adds an interactive slider that filters and/or animates one or more layers by a numeric feature property. It composes with a layer's initial filter, later set_filter() calls, and interactive legends (intersecting via ["all", ...]) rather than replacing them. Modes are "sequential" (one value), "cumulative" (everything through a value), and "window" (a selected range that can also drive flowmap time ranges; window_behavior chooses a "resizable" two-edge range or a "fixed"-width band you pan). Two presentations: the default "compact" slider, or presentation = "timeline" — a prominent, brushable histogram (drag the selected window across the bars, drag its edges to resize) modeled on Egor Kotov's FlowMapBlue time control (#205). Supports paint-property animation, an optional play button, and an optional density histogram (histogram/histogram_data/counts, drawn with d3 loaded on demand). New slider_style() presets and overrides control the container, play button, track, thumb, and histogram appearance, and draggable = TRUE lets the user reposition the panel anywhere on the map (as with add_legend()). Companions update_slider_control() (for Shiny proxies) and as_time_property() (coerce Date/POSIXct to a numeric filter property) round out the feature.
add_categorical_legend() and add_legend() gain a patch_spacing argument ("uniform"/"proportional"). With "proportional", each legend row's height tracks its own symbol size, giving proportional vertical spacing for graduated-symbol legends; the default "uniform" preserves existing behavior (#206, thanks to @mtennekes).
New add_h3t_source() adds a tiled H3 (h3t) source for MapLibre maps, fetching only the H3 cells in the current viewport from a {z}/{x}/{y} tile endpoint via the h3tiles:// protocol — a scalable alternative to add_h3j_source() for large datasets. Works with multiple sources per map and on both sides of compare(). Bundled h3j-h3t library updated to 0.9.7 (#199, thanks to @bbest).
Update MapLibre GL JS to v5.24.0 and Mapbox GL JS to v3.24.0.
Fixed add_legend() silently ignoring the target argument for MapLibre compare widgets: the compare dispatch checked for class "maplibre_compare" while the widget class is "maplibregl_compare", so legends were attached as regular map legends instead of compare-level legends.
compare() now supports synchronizing more than two maps (#204). Pass additional maps after map1 and map2 with mode = "sync", and control the grid layout with the new ncol argument. In Shiny, maps in multi-map widgets are addressed as "map1" through "mapN" via map_side in the compare proxy functions (integers also accepted, e.g. map_side = 3), and emit input values like input$id_map3_view. Legends can be targeted at individual grid maps with target = "map3".
New bivariate mapping support with bivariate_scale(), bivariate_palettes(), and add_bivariate_legend(). Bivariate scales use 3-by-3 palettes, support custom 3-by-3 color matrices, optional x_breaks and y_breaks for stable bins, and explicit na_color handling (#181).
Continuous legends can now expose an opt-in color-ramp picker. Use color_ramps, selected_ramp, and ramp_picker = TRUE with continuous legends to let readers switch palettes directly from the legend; named ramps display labels by default, and ramp_labels = FALSE creates a compact picker.
interpolate_palette() now carries additional scale metadata for downstream legends, including the source column, missing-value color, available color ramps, and selected ramp.
Compare maps now initialize legend interactivity assets so supported dynamic legend features can be used in compare views.
GitHub source archives are now slimmed with .gitattributes export-ignore rules for generated site and vignette assets. This preserves GitHub Pages content in the repository while avoiding large downloads during GitHub-based package installs.
New save_map() function renders a map widget to a static PNG file using headless Chrome via the chromote package. Supports options for hiding controls, including/excluding legends and scale bars, replacing the basemap with a solid color, and retina-quality output with image_scale. New print_map() function provides the same capability for use in Quarto and R Markdown documents.
Update MapLibre GL JS to v5.22.0 and Mapbox GL JS to v3.21.0.
Mapbox GL JS v3.21.0 adds native PMTiles support via the TileProvider API. add_pmtiles_source() now uses the native vector tile path for Mapbox, removing the need for the custom PMTiles source implementation for vector tiles.
Support for color tables and categorical rasters in add_image_source() (#21).
New layer properties: circle_emissive_strength, circle_pitch_alignment, circle_pitch_scale, fill_pattern_cross_fade, line_elevation_reference, line_elevation_ground_scale, line_pattern_cross_fade, fill_extrusion_emissive_strength, fill_extrusion_ambient_occlusion_intensity, fill_extrusion_ambient_occlusion_radius, fill_extrusion_cast_shadows, fill_extrusion_cutoff_fade_range, fill_extrusion_vertical_gradient, raster_color, raster_color_mix, raster_color_range, raster_emissive_strength, icon_occlusion_opacity, text_occlusion_opacity.
sfc geometry vectors are now accepted wherever sf objects are accepted, including layer functions, quickview functions, and the bounds parameter (#177).
Various bug fixes and performance improvements (see GitHub issues for full list).
Esri styles support: New esri_style() function provides access to Esri basemap styles for use with MapLibre maps, with support for ArcGIS API key authentication.
MLT format support: Updated PMTiles implementation to support the MapLibre Tiles (MLT) format.
Update Mapbox GL JS to v3.19.1 and MapLibre GL JS to v5.19.0.
Bug fixes and improvements:
add_reset_control() button to match the visual style of other navigation controls (#168)set_source() not working with maplibre_compare_proxy() and mapboxgl_compare_proxy() (#171)Update Mapbox GL JS to v3.17.0 and MapLibre GL JS to v5.15.0.
Interactive legends: New opt-in interactivity for map legends enables direct data filtering from the legend:
interactive = TRUE, filter_column, filter_values, and classification in legend functionsinteractive_legend parameter in maplibre_view() and mapboxgl_view() for quick interactive visualizationsDraggable legends: New draggable = TRUE parameter allows users to drag legends to any position on the map. Supports both mouse and touch interactions.
Screenshot control: New add_screenshot_control() function allows users to capture and download map screenshots as PNG images. Includes image_scale parameter for controlling output resolution.
Globe projection for compare views: Compare maps in MapLibre now properly respect globe projection when specified.
Bug fixes and improvements:
get_legend_labels())step_expr() to properly handle quoted column names (#148)add_image() now persist across set_style() callsbounds argument in maplibre() and mapboxgl() now accepts sf::st_bbox() output with automatic CRS transformation to EPSG:4326.set_style() is called in Shiny applications.clear_controls() not properly removing controls.projection argument to maplibre() for consistency with mapboxgl().number_format() in comparison maps.palette_to_lut() function for creating custom color lookup tables in Mapbox styles.maplibre() and maplibre_view() now defaults to the globe projection.Enhanced draw control with new drawing modes and live measurements:
measurement_units parameterAdvanced layers control enhancements:
New map style support:
openfreemap_style() function providing free, open-source map styles without API key requirementsGeneral improvements:
Selective control functionality: Enhanced control over which map controls are displayed and when, providing more granular customization options
Bug fixes and stability improvements:
move_layer() functionality outside of Shiny applicationsturf_buffer(), turf_union(), turf_intersect(), turf_difference()turf_filter() with predicates (intersects, within, contains, crosses, disjoint)turf_convex_hull(), turf_concave_hull(), turf_voronoi(), turf_centroid(), turf_center_of_mass()turf_distance() and turf_area() (Shiny-only)download_button and download_filename parameters in add_draw_control(). Users can now export drawn features as GeoJSON files directly from the draw control interface.provider parameter allows choosing between "osm" (OpenStreetMap/Nominatim) and "maptiler" providers, with maptiler_api_key parameter for MapTiler authentication.add_pmtiles_source() function.query_rendered_features() and get_queried_features() allow users to directly invoke the map.queryRenderedFeatures() method from the parent libraries in Shiny apps, with guidance for users to avoid race conditions and ensure proper synchronization. Functions query visible features in the map's viewport and which can be extracted as sf objects.mapboxgl_view() and maplibre_view() now support quick view of terra rasters. A new function, add_view(), is designed to help users quickly stack layers on top of the core view functions.Added enable_shiny_hover() function for optional hover events in Shiny applications:
_hover input for mouse coordinates and _feature_hover input for feature informationmaplibre() and mapboxgl() widgets, including compare viewscoordinates = TRUE/FALSE and features = TRUE/FALSEmaplibre() |> add_circle_layer(...) |> enable_shiny_hover()"before" or "after") in input namesComprehensive legend styling system: Major enhancement to legend functionality with extensive customization options:
legend_style() function provides user-friendly interface for legend styling without requiring CSS knowledgemap_legends documentationAdvanced data classification system: New functions for automatic choropleth mapping similar to GIS software:
step_equal_interval(), step_quantile(), and step_jenks() for automatic classification with equal interval, quantile, and Jenks natural breaks methodsinterpolate_palette() for continuous color scaling with multiple interpolation methodsget_legend_labels(), get_legend_colors(), and get_breaks() for extracting classification metadataclassInt package for robust statistical classification algorithmsEnhanced MapTiler integration: Expanded support for MapTiler mapping styles:
variant parameter in maptiler_style()Robust set_style() improvements: Fixed critical issues with dynamic style switching in Shiny applications:
set_style() now properly preserves user-added layers, sources, popups, tooltips, and other map elements when switching base stylesNew number_format() function: Comprehensive number formatting for tooltips and map content:
Enhanced draw control functionality with improved feature editing capabilities:
add_features_to_draw()Fixed hover_options for vector tile sources in MapLibre (#67):
Enhanced tooltip functionality with expression support:
get_column() to reference feature properties in tooltipsconcat() helper function for combining strings and expressionstooltip = concat("<strong>Name:</strong> ", get_column("name"), "<br>Value: ", get_column("value"))set_tooltip() in Shiny applicationsmapboxgl_view() and maplibre_view() functions for quick visualization of sf objects with automatic geometry detection and column-based styling (#102).set_rain() and set_snow() functions.add_globe_control() for MapLibre maps, allowing users to toggle between "mercator" and "globe" projections.set_style() in Shiny applications for both Mapbox and MapLibre maps (#99).get_drawn_features() for Shiny modules (#95).layer_id parameter in add_legend(). When a layer is toggled in the layers control, its associated legend will automatically show or hide.margin_top, margin_right, margin_bottom, margin_left) that allow fine-grained control over legend placement.visibility = "none" showing as active in the control.compare() plugin in Shiny applications, with new rendering and proxy functions for comparison apps in Mapbox and MapLibre.mode parameter in compare() allowing users to choose between "swipe" mode with a comparison slider, and "sync" mode which displays synchronized maps side-by-side.add_image() allows you to add your own image to the map's sprite for use as an icon / symbol layeradd_geolocate_control() adds a Geolocate control to the mapadd_globe_minimap() adds a mini globe overview map that tracks how your map moves around the globeadd = TRUEmove_layer() function that gives you more fine-grained control over layer ordering in a Shiny sessionadd_geocoder_control()add_draw_control(freehand = TRUE)add_reset_control()cluster_options() function, to be used with the cluster_options argument in add_circle_layer() and add_symbol_layer()