Skip to content
This is the alpha v4 version website. Looking for the v3 documentation?

Camera API

The camera controls what portion of the graph is visible. Access it via renderer.getCamera().

State

The camera state has four properties:

interface CameraState {
x: number; // Horizontal position in framed graph space (0.5 = center)
y: number; // Vertical position in framed graph space (0.5 = center)
angle: number; // Rotation in radians
ratio: number; // Zoom level (smaller = more zoomed in)
}

The camera exposes them as read-only properties too: camera.ratio equals camera.getState().ratio. DEFAULT_CAMERA_STATE is { x: 0.5, y: 0.5, angle: 0, ratio: 1 }.

State access

MethodReturnsDescription
getState()CameraStateGet the current camera state
getPreviousState()CameraStateGet the state before the last actual change

State updates

MethodReturnsDescription
setState(partial)thisUpdate state immediately. Emits "updated" event
updateState(fn)thisUpdate state using a function: fn(currentState) => partialState

These are the only ways to move the camera instantly: the state properties cannot be assigned. Both emit "updated", but only when the state actually changes.

Animation

await camera.animate({ x: 0.5, y: 0.5, ratio: 0.5 });
// With options
await camera.animate({ ratio: 0.2 }, { duration: 1000, easing: "cubicInOut" });

The promise resolves when the animation stops, whether it completed or was interrupted by a new animation or by cancelAnimation(); read completed on animationEnd to tell those apart. On a disabled camera it resolves immediately, without moving anything.

MethodReturnsDescription
cancelAnimation()thisStop the running animation, leaving the camera as-is
isAnimating()booleanWhether an animation is running

AnimateOptions

PropertyTypeDefaultDescription
durationnumber150Animation duration in ms
easingEasing"quadraticInOut"Easing function (see below)

Easing options

Named: "linear", "quadraticIn", "quadraticOut", "quadraticInOut", "cubicIn", "cubicOut", "cubicInOut", "exponentialIn", "exponentialOut", "exponentialInOut"

Custom easing: any (t: number) => number function where t goes from 0 to 1.

Convenience methods

MethodReturnsDescription
zoomIn(opts?)Promise<void>Divide the ratio by factor (default: 1.5)
zoomOut(opts?)Promise<void>Multiply the ratio by factor (default: 1.5)
reset(opts?)Promise<void>Animate to default state (x=0.5, y=0.5, angle=0, ratio=1)

All three take the same AnimateOptions as animate(). The zoom shortcuts accept an extra factor option:

camera.zoomIn({ factor: 2 }); // Divides the ratio by 2 instead of 1.5
camera.zoomIn({ factor: 2, duration: 400, easing: "cubicInOut" });

Creating a camera

MethodReturnsDescription
Camera.from(state)CameraStatic: create a new camera initialized to the given state

Duplicating a camera is Camera.from(camera.getState()): only the state travels, not the bounds or the flags.

Interaction flags

enabled is the master switch, checked by setState() and animate(); setting it to false mid-animation stops that animation, like cancelAnimation(). The other three are honored by validateState(), so setState() calls and animations both respect them.

PropertyTypeDefaultDescription
enabledbooleantrueAccept any state change at all
enabledZoomingbooleantrueAccept ratio changes
enabledPanningbooleantrueAccept x/y changes
enabledRotationbooleantrueAccept angle changes

On a sigma-owned camera, the last three are rewritten from the enableCameraZooming, enableCameraPanning and enableCameraRotation settings on every setSettings() call: set the settings, not the flags. enabled is the one flag sigma never touches.

Bounds

PropertyTypeDescription
minRationumber | nullMinimum zoom level, derived from minCameraRatio
maxRationumber | nullMaximum zoom level, derived from maxCameraRatio

Like the flags, both are rewritten from the settings on every setSettings() call.

MethodReturnsDescription
getBoundedRatio(ratio)numberConstrain a ratio to min/max bounds
validateState(partial)CameraStateMerge a partial state into the current one, and constrain it

validateState() always returns a complete state: it drops what the flags forbid, bounds the ratio, then applies the cameraPanBoundaries setting.

Events

camera.on("updated", (state: CameraState) => {
// Camera state changed
});
camera.on("animationStart", ({ from, to }) => {
// An animation started
});
camera.on("animationEnd", ({ from, to, completed }) => {
// `completed` is false when interrupted, true when it reached `to`
});

An animation emits updated on every frame: prefer animationEnd for heavy listeners.