Integrations
vis-network
Drive a live, physics-simulated network visualization directly from temporal97 Deltas.
vis-network renders interactive network diagrams with built-in physics, pan/zoom, and click events. Its DataSet API is built for incremental updates — which maps directly onto temporal97's Delta.
Installation
npm install vis-network vis-dataSetup
Create DataSet instances and wire them to a Network. The datasets hold the live state; the network just renders them.
import { DataSet } from 'vis-data';
import { Network } from 'vis-network';
import { TemporalGraph, type Delta } from 'temporal97';
type NodeAttrs = { label: string };
type EdgeAttrs = { source: string; target: string };
const temporal = new TemporalGraph<NodeAttrs, EdgeAttrs>();
const nodes = new DataSet<{ id: string; label: string }>();
const edges = new DataSet<{ id: string; from: string; to: string }>();
const network = new Network(
document.getElementById('network')!,
{ nodes, edges },
{ physics: { stabilization: false } },
);Syncing with Delta
function syncDelta(delta: Delta) {
nodes.remove([...delta.nodes.removed]);
edges.remove([...delta.edges.removed]);
for (const id of delta.nodes.added) {
const n = temporal.getNode(id)!;
nodes.add({ id, label: n.label });
}
for (const id of delta.edges.added) {
const e = temporal.getEdge(id)!;
edges.add({ id, from: e.source, to: e.target });
}
for (const id of delta.nodes.updated) {
const n = temporal.getNode(id)!;
nodes.update({ id, label: n.label });
}
for (const id of delta.edges.updated) {
const e = temporal.getEdge(id)!;
edges.update({ id, from: e.source, to: e.target });
}
}Every temporal97 operation now feeds the visualization automatically:
syncDelta(temporal.append({
snapshot: 0,
mutations: [
{ kind: 'node', op: 'set', id: 'alice', value: { label: 'Alice' } },
{ kind: 'node', op: 'set', id: 'bob', value: { label: 'Bob' } },
{ kind: 'edge', op: 'set', id: 'alice->bob', value: { source: 'alice', target: 'bob' } },
],
}));
syncDelta(temporal.append({
snapshot: 1,
mutations: [
{ kind: 'node', op: 'set', id: 'charlie', value: { label: 'Charlie' } },
{ kind: 'edge', op: 'set', id: 'bob->charlie', value: { source: 'bob', target: 'charlie' } },
],
}));
// Charlie and his edge disappear from the canvas automatically
syncDelta(temporal.rewind(0));Building a timeline scrubber
Use getSnapshotIds() with a range input to let users drag through history:
const snapshotIds = temporal.getSnapshotIds();
const slider = document.getElementById('slider') as HTMLInputElement;
slider.min = '0';
slider.max = String(snapshotIds.length - 1);
slider.value = String(snapshotIds.length - 1);
slider.addEventListener('input', () => {
syncDelta(temporal.seekTo(snapshotIds[Number(slider.value)]));
});