vellumwidget 0.6.0
-
Bug fix: legend swatches no longer jump off-screen under axis-aware zoom.
Withaxis_zoom/zoom_marks = "fixed"(both default), the constant-size counter-
scale was applied to every glyph mark, including discrete legend swatches. Because
a swatch is positioned by atransformattribute (unlike data points, which carry
absolute coordinates), the inline counter-scale overrode that attribute and flung
the swatch to a corner. The counter-scale is now restricted to marks inside the
pannable data region, so legend swatches stay put. -
Axis-aware zoom (
axis_zoom, defaultTRUE). Wheel/drag zoom scales only
the plot's data region and re-ticks the axes for the visible range — holding the
frame (axes, titles, legend) in place the way a charting library zooms, rather
than scaling the whole scene like an image. Hit-testing (hover/brush/lasso), the
crosshair, and theinput$<id>_zoomdata range all follow the zoomed data region.
Applies to a single linear cartesian panel (continuousidentity/reverse
axes) rendered as SVG; plots with log/date/discrete axes, several panels, or in
raster mode silently fall back to the ordinary whole-scene zoom, so it is safe to
leave on. Setaxis_zoom = FALSEfor the plain whole-scene zoom. Built on vellum's
pannable-panel contract (vl_viewport(pannable=)) and the panel scale metadata
vellumplotemits (needs the current developmentvellum/vellumplot). -
Constant-size markers on zoom (
zoom_marks, default"fixed"). Under
axis-aware zoom, glyph marks (points, circles, hexagons, sector wedges) now keep
their original pixel size and only their positions re-map — so points stay round
and don't stretch into ellipses under the navigator's x-only zoom, the way a
charting library zooms. Positional marks (bars, error bars, lines, areas) still
scale with the data; their stroke width is held constant. Setzoom_marks = "scale"for the old behaviour where glyphs grow with the zoom (useful to read
density). Applies to SVG axis-aware zoom and the raster crisp-point layer. -
Interactive continuous colorbar filter (visualMap). When a
vellumplotplot
maps a continuouscolorscale, its colorbar becomes a range filter: drag the
two handles on the gradient bar to a value range and marks whose colour value
falls outside it fade out (and drop out of hover/brush hit-testing); double-click
the bar to reset. The selected range is reported to Shiny as
input$<id>_colorfilter = c(lo, hi)(NULLat the full range). Automatic — no
argument to set — whenever the plot has a continuous colorbar (needs the current
developmentvellumplot; SVG mode). Discrete/binned colour legends keep their
existing click-to-hide interaction. -
Tooltip polish.
as_widget()gainstooltip_delay(ms to wait before the
tooltip appears — the highlight is immediate, only the tooltip waits),
tooltip_follow(TRUE, the default, tracks the cursor;FALSEanchors above
the mark), andtooltip_sticky(the tooltip accepts pointer events and lingers
briefly on leave, so tooltips containing links/buttons are usable). The tooltip
also now auto-flips below the cursor when there isn't room above and clamps
horizontally so it doesn't overflow the widget. -
Overview navigator (
navigator = TRUE). An opt-in strip below the plot that
renders the whole scene in miniature with a draggable, resizable window marking
the visible x-range: drag the window to pan, drag a handle to zoom. Zoom is
x-only — the selected x-range fills the width while the full y-range stays on
screen (a time-series range selector). Withaxis_zoom(the default) it is
rendered through the axis-aware zoom, so the x-axis re-ticks crisply; otherwise
the view stretches horizontally. It stays two-way in sync with the main view —
wheel/keyboard/brush, the toolbar, and linked-group pan/zoom all move the window,
and moving the window drives them. Useful for scrubbing long series.
navigator_heightsets the strip height (default 56px). Client-side; off by
default. -
Linked pan/zoom across a
group. Widgets sharing agroupalready linked
selection and hover; now panning or zooming one moves the others to the same
view. The view is shared as a fraction of each widget's own extent (over the
same client-side bus, no Shiny/crosstalk), so linked plots of different sizes —
small multiples — stay aligned. Reset links too. -
Brush and view now report data-space coordinates, not just pixels. When the
plot carries a cartesian scale (anyvellumplotplot),input$<id>_brushgains
the brushed region's data-space boundsx0d,y0d,x1d,y1d(plus thepanelname)
alongside the existing device-pixel rectangle, andinput$<id>_zoomgains
data = list(x=, y=, panel=), the visible range in data coordinates. This reads
the per-panel scale descriptorsvellumplotnow attaches to the scene (requires
the current developmentvellum(>= 0.4.0.9000) andvellumplot); a rawvellumscene
or a non-cartesian coordinate system reports device-pixel fields only, as before.
Date/time axes report the numeric epoch (days forDate, seconds forPOSIXct),
which you map back withas.Date()/.POSIXct(). The fields describe the
visual axes (undercoord_flip(),x0dis the plot'syaesthetic); a
discrete axis reports fractional band positions; and an axis built with a custom
scales::transform_*()object (beyond identity / log10 / sqrt / reverse) is
omitted from the data-space fields rather than reported wrong. (Groundwork for
axis-aware zoom.) -
Fix: cross-filtered and legend-hidden marks were still hit-testable. A
display-tier cross-filter (crosstalk orvw_filter()) and a legend
legend_click = "hide"toggle set the marks todisplay:none, but they stayed
in the spatial index — so a nearest-mark hover could still tooltip a hidden
datum, and a brush or lasso could re-select filtered-out points (propagating the
selection back to linked/crosstalk views). Keyboard traversal already skipped
hidden marks; hover, brush, lasso, and raster click-snap now do too, via a single
"inert" guard. Muted (not hidden) legend series stay interactive. -
Freehand lasso-select. A third drag mode alongside brush and pan (default
on; disable withas_widget(lasso = FALSE)). The toolbar's mode button now
cycles brush → lasso → pan, and it appears whenever at least two drag modes are
enabled. Drag a loop and every mark whose centre falls inside it is selected —
hit-tested with a point-in-polygon check over the Flatbush spatial index, so it
stays fast on large scenes. It reports throughinput$<id>_brushlike the box
brush, with alasso = TRUEflag and the loop's bounding box. -
Widgets report their current view to Shiny (
input$<id>_zoom). After a
zoom/pan settles — wheel, drag-pan release, pinch, keyboard, reset,
zoom-to-selection, or avw_zoom()proxy call — the widget publishes
list(x=, y=, w=, h=, zoomed=): the currentviewBox(device-px) and whether
the view is zoomed in. A deduped state input, so a coordinated dashboard can
react to what the user is looking at. (Data-space limits await axis/scale
metadata in the scene contract.) -
Legend click-to-hide and double-click-to-isolate.
as_widget()gains a
legend_clickargument. The default"select"is unchanged (clicking a
discrete-legend swatch selects its series)."hide"turns the legend into a
visibility toggle — a single click hides or shows the series, a double-click
isolates it (hides every other series; double-click again to restore all) — the
reflexive legend interaction from plotly / ECharts / Highcharts."mute"is the
same but dims the series rather than removing it (keeping its layout). Hovering a
swatch still highlights its series under every policy, and hidden series drop out
of hover/tooltip hit-testing. Works with keyboard (Enter/Space on a focused
swatch toggles) and is independent of the crosstalk cross-filter (the two never
clobber each other). Entirely client-side. -
Shared (unified) hover tooltips and a crosshair.
as_widget()gains a
hover_modeargument. The default"closest"is unchanged (hover shows the
single nearest mark), but"x"(or"y") turns on a unified hover: every
mark sharing the hovered x (or y) position is highlighted at once and listed
together in one tooltip box — the shared readout multi-series line and
time-series charts expect, where you want every series' value at the cursor's
x rather than one point. A companioncrosshairargument (defaultFALSE)
draws a guide rule at the hovered position: a vertical rule at the shared x in
"x"mode, a horizontal one in"y"mode, and a full cross through the mark
in"closest"mode. Both are entirely client-side and need no extra scene
metadata — the mark positions come straight from the element index — so they
work on any keyedvellumplotplot or rawvellumscene, and in raster mode.
Unified hover snaps along its axis so the readout tracks the cursor anywhere in
the plot; thehoverShiny input still reports the single nearest (primary)
mark, so the read-back contract is unchanged. -
Fix: hover/selection feedback rings were drawn offset from the mark. When
the widget container was larger than the plot's rendered box — which happens
routinely, as htmlwidgets stamps an explicitheighton the container and a
fluid layout can stretch its width — the feedback overlay filled the whole
container while the base SVG only filled its aspect-locked box. The overlay's
viewBoxthen letterboxed (centred), so every hover/selection ring drew off
the real mark: downward when the container was taller (e.g. 68px low for a
520px-tall container over a 384px plot) and sideways when it was wider. It
looked like the wrong mark was picked. Hit-testing itself was always correct;
only the visual feedback was displaced. The svg and its overlays now share a
shrink-to-fit stage, so the overlay tracks the svg box exactly at any container
size.