zoom

Converts ratio input to frame-by-frame scale delta. Works with pinch gestures and other ratio-based inputs.

Signature

function zoom<T extends SignalWith<{ ratio: number; phase?: string }>>(
options?: ZoomOptions
): Operator<T, T & { scale: number; deltaScale: number }>

Output Value

PropertyTypeDescription
scalenumberFrame-by-frame scale delta (not absolute scale)
deltaScalenumberSame as scale (deprecated, use scale)

Design Philosophy

The zoom operator outputs delta values rather than absolute scale. This design:

  • Keeps the operator stateless and simple
  • Lets consumers control clamping and accumulation
  • Makes it easier to combine with other transforms

Examples

Basic Pinch Zoom

import { pinch } from "cereb";
import { zoom } from "cereb/operators";
let scale = 1.0;
const MIN_SCALE = 0.5;
const MAX_SCALE = 3.0;
pinch(element)
.pipe(zoom())
.on((signal) => {
// Accumulate delta and clamp
scale += signal.value.scale;
scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, scale));
element.style.transform = `scale(${scale})`;
});

With Sensitivity Control

const PINCH_SENSITIVITY = 0.4;
pinch(element)
.pipe(
extend((signal) => ({
ratio: 1 + (signal.value.ratio - 1) * PINCH_SENSITIVITY,
})),
zoom()
)
.on((signal) => {
scale += signal.value.scale;
scale = clamp(scale, MIN_SCALE, MAX_SCALE);
element.style.transform = `scale(${scale})`;
});

Multiple Input Sources

For keyboard or wheel zoom, compute the target scale directly instead of using zoom:

// Keyboard zoom - discrete steps
keydown(window, { code: ["Equal", "Minus"] })
.on((signal) => {
const multiplier = signal.value.code === "Equal" ? 1.2 : 1 / 1.2;
scale = clamp(scale * multiplier, MIN_SCALE, MAX_SCALE);
element.style.transform = `scale(${scale})`;
});
// Wheel zoom - continuous
wheel(element, { passive: false })
.on((signal) => {
signal.value.originalEvent.preventDefault();
const multiplier = Math.exp(-signal.value.deltaY * 0.005);
scale = clamp(scale * multiplier, MIN_SCALE, MAX_SCALE);
element.style.transform = `scale(${scale})`;
});

Session Handling

The operator resets its internal state when phase is "end" or "cancel", making it ready for the next gesture session.