Set the visible logical range (best effort): pick a bar spacing so the span
fills the width and anchor the right edge at range.to. Bar spacing is
clamped to [min,max], so an extreme span lands at the nearest zoom. Fires the
change handler so a host that mutates the scale directly still repaints.
Zoom around an anchor x (the cursor): change bar spacing by factor
while keeping whatever logical index sits under focusX pinned there.
factor > 1 zooms in (wider bars).
Bound a pending zoom target without changing the displayed viewport.