Camera and viewport
Sigma’s camera controls what portion of the graph is visible. You can constrain user interactions, animate the camera, and convert between coordinate systems.
Zoom and pan boundaries
Section titled “Zoom and pan boundaries”Constrain how far users can zoom:
new Sigma(graph, container, { settings: { minCameraRatio: 0.1, // Maximum zoom in (10x) maxCameraRatio: 2, // Maximum zoom out (0.5x) },});Constrain panning:
new Sigma(graph, container, { settings: { cameraPanBoundaries: { tolerance: 50 }, },});The tolerance value controls how far past the graph bounding box the user can pan, in pixels (default 0). Set
cameraPanBoundaries: true to constrain panning to the graph extent, or null (default) to disable.
Animated transitions
Section titled “Animated transitions”Use renderer.getCamera().animate() to smoothly transition the camera:
const camera = renderer.getCamera();
// Pan and zoom to a specific positioncamera.animate({ x: 0.5, y: 0.5, ratio: 0.5 });
// With custom durationcamera.animate({ x: 0.3, y: 0.7, ratio: 0.2 }, { duration: 1000 });
// Reset to default viewcamera.reset();
// Zoom in / out by a factor (1.5 by default)camera.zoomIn();camera.zoomOut({ factor: 2 });animate() returns a Promise that resolves when the animation stops, whether it completed or was interrupted by a
new animation or by camera.cancelAnimation(). See the Camera API for the full surface.
Instant updates
Section titled “Instant updates”For immediate (non-animated) changes:
camera.setState({ x: 0.5, y: 0.5, ratio: 1, angle: 0 });Coordinate conversion
Section titled “Coordinate conversion”Convert between graph space and screen space:
// Graph coordinates -> screen pixelsconst screenPos = renderer.graphToViewport({ x: 0, y: 0 });
// Screen pixels -> graph coordinatesconst graphPos = renderer.viewportToGraph({ x: 100, y: 200 });Viewport utilities
Section titled “Viewport utilities”The @sigma/utils package provides helpers for working with the viewport:
import { fitViewportToNodes, getNodesInViewport } from "@sigma/utils";
// Animate the camera to fit a set of nodesfitViewportToNodes(renderer, ["node1", "node2", "node3"], { animate: true });
// Get all nodes currently visible on screenconst visibleNodes = getNodesInViewport(renderer);import { fitViewportToNodes, getNodesInViewport } from "@sigma/utils";import Graph from "graphology";import louvain from "graphology-communities-louvain";import seedrandom from "seedrandom";import Sigma from "sigma";
import { registerControls } from "../_controls";import data from "../_data/data.json";
// Hardcoded color palette with readable namesconst COMMUNITY_COLORS: { color: string; name: string }[] = [ { color: "#e63946", name: "red" }, { color: "#457b9d", name: "blue" }, { color: "#2a9d8f", name: "teal" }, { color: "#e9c46a", name: "yellow" }, { color: "#f4a261", name: "orange" }, { color: "#6a4c93", name: "purple" }, { color: "#8ac926", name: "green" }, { color: "#ff6b6b", name: "pink" }, { color: "#4cc9f0", name: "cyan" }, { color: "#b5838d", name: "mauve" },];
const graph = new Graph();graph.import(data);
// Detect communities (seeded, so results are stable across runs)louvain.assign(graph, { nodeCommunityAttribute: "community", rng: seedrandom("sigma") });const communities = new Set<string>();graph.forEachNode((_, attrs) => communities.add(attrs.community));const communitiesArray = Array.from(communities);
// Assign colors per communityconst palette: Record<string, { color: string; name: string }> = {};communitiesArray.forEach((c, i) => (palette[c] = COMMUNITY_COLORS[i % COMMUNITY_COLORS.length]));graph.forEachNode((node, attrs) => graph.setNodeAttribute(node, "color", palette[attrs.community].color));
const container = document.getElementById("sigma-container") as HTMLElement;const renderer = new Sigma(graph, container);
// Register a button per community to fit viewportconst controls: Record<string, { type: "button"; label: string; action: () => void }> = {};communitiesArray.forEach((community) => { const { name } = palette[community]; controls[`community-${name}`] = { type: "button", label: `Fit ${name}`, action: () => { fitViewportToNodes( renderer, graph.filterNodes((_, attrs) => attrs.community === community), { animate: true }, ); }, };});controls["fit-all"] = { type: "button", label: "Fit all", action: () => { renderer.getCamera().animate({ x: 0.5, y: 0.5, ratio: 1 }, { duration: 300 }); },};registerControls(controls);
// Display live count of visible nodes in the bottom-leftconst infoEl = document.getElementById("visible-nodes-info") as HTMLDivElement;setInterval(() => { const count = getNodesInViewport(renderer).length; infoEl.textContent = count === 0 ? "No visible nodes" : count === 1 ? "1 visible node" : `${count} visible nodes`;}, 100);Updating settings at runtime
Section titled “Updating settings at runtime”renderer.setSettings({ enableCameraZooming: false });renderer.setSettings({ minCameraRatio: 0.5, maxCameraRatio: 3 });import Graph from "graphology";import { parse } from "graphology-gexf/browser";import Sigma from "sigma";
import { registerControls } from "../_controls";
const res = await fetch("/data/arctic.gexf");const gexf = await res.text();const graph = parse(Graph, gexf);
const container = document.getElementById("sigma-container") as HTMLElement;
const { enablePanning, enableZooming, enableRotation, boundCamera, minRatio, maxRatio, tolerance } = registerControls( { enablePanning: { type: "boolean", label: "Enable panning", default: true }, enableZooming: { type: "boolean", label: "Enable zooming", default: true }, enableRotation: { type: "boolean", label: "Enable rotation", default: true }, boundCamera: { type: "boolean", label: "Bound camera", default: true }, minRatio: { type: "number", label: "Min zoom ratio", default: 0.08, min: 0.001, max: 1, step: 0.001 }, maxRatio: { type: "number", label: "Max zoom ratio", default: 3, min: 0.1, max: 10, step: 0.1 }, tolerance: { type: "number", label: "Pan tolerance (px)", default: 500, min: 0, max: 2000, step: 50 }, },);
const renderer = new Sigma(graph, container, { settings: { enableCameraPanning: enablePanning, enableCameraZooming: enableZooming, enableCameraRotation: enableRotation, minCameraRatio: enableZooming ? minRatio : null, maxCameraRatio: enableZooming ? maxRatio : null, cameraPanBoundaries: boundCamera ? { tolerance } : null, },});