An Interactive Explorer
In this tutorial you’ll build a compact graph explorer on top of a larger generated dataset. By the end you’ll have hover highlighting, click-to-select with a rectangle tool, the ability to focus the camera on any node, one-click neighbor expansion, and a search box that filters and locates matching nodes.
Each section builds on the last, and the full combined script
is at the end. It assumes you’ve installed @kortexya/nodus
and read Your First Graph.
1. Container and search box
Section titled “1. Container and search box”Add a container plus a small search input. The CSS below positions the search box over the graph; you only need this HTML and CSS once.
<div id="graph"></div><input id="search" type="text" placeholder="Search nodes…" autocomplete="off" />
<style> html, body { margin: 0; height: 100%; } #graph { width: 100vw; height: 100vh; } #search { position: fixed; top: 16px; left: 16px; z-index: 10; padding: 8px 12px; font-size: 14px; border-radius: 8px; border: 1px solid #cbd5e1; background: #ffffff; }</style>2. Create the instance and generate a graph
Section titled “2. Create the instance and generate a graph”Construct Nodus, then fabricate a larger graph with one of the seeded
generators. barabasiAlbert builds a
scale-free network — a realistic shape for an explorer, with a few high-degree
hubs and many leaf nodes. Generators are deterministic and return a Promise.
import { Nodus } from '@kortexya/nodus';
const nodus = new Nodus({ container: document.getElementById('graph') });
// Fabricate a scale-free graph to explore — generators return the graph.const g = await nodus.generate.barabasiAlbert({ nodes: 40, m0: 2, m: 1 });await nodus.setGraph(g);3. Style, lay out and frame
Section titled “3. Style, lay out and frame”Give nodes and edges a base style with rules, then apply a
layout and fit the graph to the viewport. The force layout suits an organic
network like this one; for a tree-shaped dataset you’d reach for
nodus.layouts.hierarchical instead.
nodus.styles.addNodeRule({ color: '#334155', radius: 10, shape: 'circle',});nodus.styles.addEdgeRule({ color: '#cbd5e1', width: 1.5,});
await nodus.layouts.force({ duration: 0 });await nodus.view.locateGraph();4. Hover highlighting
Section titled “4. Hover highlighting”styles.setHoveredNodeAttributes defines the visual attributes a node takes on
while the pointer is over it. It applies globally — no per-node wiring needed.
nodus.styles.setHoveredNodeAttributes({ color: '#0ea5e9', radius: 14, outline: { color: '#0ea5e9' },});Now hovering any node enlarges it and gives it a bright outline, then reverts automatically when the pointer leaves.
5. Click-to-select with the rectangle tool
Section titled “5. Click-to-select with the rectangle tool”Enable the rectangleSelect tool so dragging a box over the canvas selects the
nodes inside it. Read the current selection back with getSelectedNodes, which
returns a NodeList. You can also style the selected state with
styles.setSelectedNodeAttributes.
nodus.tools.rectangleSelect.enable();
nodus.styles.setSelectedNodeAttributes({ color: '#f59e0b', outline: { color: '#b45309' },});
// Log the selection whenever the user finishes a box.nodus.tools.tooltip.onBackgroundClick(() => { const selected = nodus.getSelectedNodes(); console.log(`${selected.size} node(s) selected`);});getNonSelectedNodes, clearSelection and the per-element node.setSelected(bool)
round out the selection API.
6. Focus the camera on a node
Section titled “6. Focus the camera on a node”When the user clicks a node, focus on it. node.locate() pans and zooms the
camera to that single element; pass a
{ duration } to animate the move.
nodus.tools.tooltip.onNodeClick((node) => { node.locate({ duration: 400 });});7. Neighbor expansion
Section titled “7. Neighbor expansion”Highlighting a node’s neighborhood is a common explorer gesture. On
double-click, read the node’s neighbors with node.getAdjacentNodes() — which
returns a NodeList — and pulse them so they stand out.
nodus.tools.tooltip.onNodeDoubleClick((node) => { const neighbors = node.getAdjacentNodes(); neighbors.pulse(); console.log(`${node.getId()} has ${neighbors.size} neighbor(s)`);});pulse is a broadcast method on a NodeList: it runs on every node in the
collection. You could equally neighbors.setSelected(true) or
neighbors.addClass('neighborhood') to mark them.
8. A live search filter
Section titled “8. A live search filter”Wire the search box to filter nodes and frame the matches. getNodes(predicate)
returns a NodeList of nodes for which the predicate is true; calling
.locate() on that list pans and zooms the camera to fit all of them.
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', (event) => { const query = event.target.value.trim().toLowerCase(); if (!query) return;
const matches = nodus.getNodes( (node) => String(node.getId()).toLowerCase().includes(query), );
if (matches.size > 0) { matches.setSelected(true); matches.locate({ duration: 400 }); }});If your nodes carry a label under data, match on node.getData().label
instead of the id.
9. The full script
Section titled “9. The full script”Everything from steps 2–8, combined. Pair it with the container and search-box HTML and CSS from step 1.
import { Nodus } from '@kortexya/nodus';
// 2. Create and generate.const nodus = new Nodus({ container: document.getElementById('graph') });const g = await nodus.generate.barabasiAlbert({ nodes: 40, m0: 2, m: 1 });await nodus.setGraph(g);
// 3. Base style, layout, frame.nodus.styles.addNodeRule({ color: '#334155', radius: 10, shape: 'circle' });nodus.styles.addEdgeRule({ color: '#cbd5e1', width: 1.5 });await nodus.layouts.force({ duration: 0 });await nodus.view.locateGraph();
// 4. Hover highlighting.nodus.styles.setHoveredNodeAttributes({ color: '#0ea5e9', radius: 14, outline: { color: '#0ea5e9' },});
// 5. Rectangle selection.nodus.tools.rectangleSelect.enable();nodus.styles.setSelectedNodeAttributes({ color: '#f59e0b', outline: { color: '#b45309' },});nodus.tools.tooltip.onBackgroundClick(() => { console.log(`${nodus.getSelectedNodes().size} node(s) selected`);});
// 6. Focus on click.nodus.tools.tooltip.onNodeClick((node) => node.locate({ duration: 400 }));
// 7. Neighbor expansion on double-click.nodus.tools.tooltip.onNodeDoubleClick((node) => { const neighbors = node.getAdjacentNodes(); neighbors.pulse();});
// 8. Live search.document.getElementById('search').addEventListener('input', (event) => { const query = event.target.value.trim().toLowerCase(); if (!query) return; const matches = nodus.getNodes( (node) => String(node.getId()).toLowerCase().includes(query), ); if (matches.size > 0) { matches.setSelected(true); matches.locate({ duration: 400 }); }});Next steps
Section titled “Next steps”- Interaction Tools — every tool and its handlers.
- Selection — the full selection model.
- Controlling the Camera — zoom, pan, fit and locate.
- Generating Graphs — all eight generators.
- A Co-author Hypergraph — the hypergraph pipeline.