Building a Graph
This guide covers the day-to-day work of building and maintaining a graph: how to load data, add and remove elements, query them with predicates, update their attributes and data, iterate collections, and inspect connected components.
For the underlying model (what an attribute is versus your own data), see
The Graph Model. For the full method list, see
API: Graph.
Setting up
Every example below starts from a Nodus instance. With a container you get a rendered graph; without one you run headless (useful for tests and data prep).
import { Nodus } from '@kortexya/nodus';
const nodus = new Nodus({ container: document.getElementById('graph') });Loading a graph: setGraph vs addGraph vs clearGraph
Nodus accepts plain JSON. A graph is { nodes, edges }; each node may carry an
id, visual attributes, and your own data; each edge additionally needs a
source and target.
// Replace the entire graph (clears anything already loaded).await nodus.setGraph({ nodes: [ { id: 'a', attributes: { x: 0, y: 0 } }, { id: 'b', attributes: { x: 100, y: 0 } }, ], edges: [ { source: 'a', target: 'b' }, ],});Use addGraph to merge more data into what’s already there, rather than
replacing it:
// Merge: keeps a and b, adds c and a new edge.await nodus.addGraph({ nodes: [{ id: 'c', attributes: { x: 50, y: 80 } }], edges: [{ source: 'b', target: 'c' }],});And clearGraph removes everything:
nodus.clearGraph();Try it live — this demo builds a RawGraph from plain records and loads it:
A typed example
The constructor takes two generics: ND for node data and ED for edge
data. Typing them once gives you autocomplete and type-checking everywhere you
read or write data.
import { Nodus } from '@kortexya/nodus';
interface Person { name: string; team: string; }interface Rel { kind: 'reports-to' | 'collaborates'; since: number; }
const nodus = new Nodus<Person, Rel>({ container: document.getElementById('graph'),});
await nodus.setGraph({ nodes: [ { id: 'ada', data: { name: 'Ada', team: 'core' } }, { id: 'borg', data: { name: 'Borg', team: 'core' } }, ], edges: [ { source: 'ada', target: 'borg', data: { kind: 'collaborates', since: 2021 } }, ],});Now node.getData() is typed as Person and edge.getData() as Rel.
Adding elements
Add a single element with addNode / addEdge, or many at once with
addNodes / addEdges. Each call returns the created element (or a list).
// One node — returns the created Node.const carol = nodus.addNode({ id: 'carol', data: { name: 'Carol', team: 'design' } });
// Many nodes — returns a NodeList.const newcomers = nodus.addNodes([ { id: 'dre', data: { name: 'Dre', team: 'design' } }, { id: 'efi', data: { name: 'Efi', team: 'ops' } },]);
// One edge.const link = nodus.addEdge({ source: 'ada', target: 'carol', data: { kind: 'collaborates', since: 2023 },});
// Many edges.nodus.addEdges([ { source: 'carol', target: 'dre', data: { kind: 'collaborates', since: 2022 } }, { source: 'dre', target: 'efi', data: { kind: 'reports-to', since: 2024 } },]);If you omit an id, Nodus assigns one. Visual attributes and your data are
both optional on every element.
Removing elements
The remove methods return Promise<void> — await them if you need to know the
removal has completed (for example before re-running a layout).
// By id or by element reference.await nodus.removeNode('efi');await nodus.removeEdge(link);
// In bulk — pass ids, elements, or a NodeList/EdgeList.await nodus.removeNodes(['dre', 'carol']);await nodus.removeEdges(nodus.getEdges());Removing a node also removes the edges attached to it.
Try it live — use the controls to add and remove nodes and edges on a running graph:
Querying with getNode / getNodes and predicates
getNode(id) / getEdge(id) fetch a single element. getNodes() /
getEdges() return the whole collection, or — given a predicate function —
just the matching elements.
// Single element by id.const ada = nodus.getNode('ada');
// All nodes.const everyone = nodus.getNodes();
// Filtered: only the design team. Returns a NodeList.const designers = nodus.getNodes().filter((node) => node.getData('team') === 'design');
// Filtered edges: collaborations only.const collabs = nodus.getEdges().filter((edge) => edge.getData('kind') === 'collaborates');getData(path?) reads a single field when given a path ('team') or the whole
object when called with no argument.
Updating elements
Change visual attributes with setAttributes (or setAttribute for one),
and change your payload with setData.
// Visual change — paint the core team.ada.setAttributes({ color: '#4f46e5', radius: 14 });
// Update one attribute.borg.setAttribute('radius', 18);
// Update your data. Pass a path + value...ada.setData('team', 'platform');
// ...or merge a partial object.carol.setData({ name: 'Carol R.' });Collections broadcast the same calls to every member, so you can style a whole filtered set in one line:
// Highlight every designer at once.designers.setAttributes({ outerStroke: { color: '#10b981', width: 3 } });See Styling Nodes & Edges for the full set of visual attributes.
Iterating a NodeList
A NodeList (and EdgeList) is array-like and iterable. You can loop it
directly, or use the functional helpers — filter, map, find, reduce,
sort, and friends. filter returns another NodeList, so queries compose.
const nodes = nodus.getNodes();
// Direct iteration.for (const node of nodes) { console.log(node.getId(), node.getData('name'));}
// Size and indexed access.console.log('total nodes:', nodes.size);const first = nodes.get(0);
// Functional pipeline: design-team names, sorted.const names = nodes .filter((n) => n.getData('team') === 'design') .map((n) => n.getData('name')) .sort();
// Set operations compose two lists.const others = nodes.subtract(designers);Broadcast reads return arrays: nodes.getId(), nodes.getData('team'), and
nodes.getPosition() each give you an array aligned with the list.
Connected components
getConnectedComponents() partitions the graph into its disconnected pieces —
each component is returned as a NodeList. Use it to find islands, count
clusters, or focus on the subgraph around a node.
// Every component in the graph.const components = nodus.getConnectedComponents();console.log('component count:', components.length);
for (const component of components) { console.log('size:', component.size);}
// Just the component containing a given node.const adasGroup = nodus.getConnectedComponentByNode('ada');adasGroup.setSelected(true);You can also ask an individual node for its component via
node.getConnectedComponent().
Next steps
- Arrange what you’ve built with Applying Layouts.
- Make it look right with Styling Nodes & Edges.
- Frame it on screen with Controlling the Camera.