Eased wheel zoom (ARCHITECTURE.md §3.2, §7). A wheel tick used to land its whole zoom step on one frame, which reads as the chart jumping rather than moving. This spreads the same step over a short exponential approach, the counterpart to KineticAnimation (input/kinetic.ts) for the other half of the viewport.

applied(t) = base + (target − base) · (1 − e^(−t/tau))

The work is done in LOG space and the caller exponentiates the per-frame delta, because zoom composes multiplicatively: two 1.1x steps are 1.21x, not 1.2x. Easing the multiplier directly would make the first half of a glide cover more zoom than the second, and a glide interrupted midway would land on a different scale than one left alone.

Closed form, so it is deterministic and unit-testable with no Date or rAF inside: the caller samples ZoomGlide.appliedAt each frame and zooms by the delta since its previous sample.

interface ZoomGlideOptions {
    minLogStep: number;
    stopFraction: number;
    tau: number;
}

Properties

minLogStep: number

Skip the animation for a step smaller than this, in log units. Below it the glide is a handful of sub-pixel frames nobody can see, and scheduling them costs more than the step is worth.

stopFraction: number

Stop once this much of the remaining distance has been applied.

tau: number

Time constant in ms. The glide covers ~63% of the distance remaining after each rebase in one tau, and is cut off at stopFraction.