Skip to main content

Interactivity

VizCraft provides click handlers for basic interactions and a mathematical hit testing API for building full editors.

Click events

Attach click handlers to nodes and edges with .onClick():

info

Interactive elements automatically receive cursor: pointer when an onClick handler is attached.

Hit testing

VizCraft provides a DOM-independent hit testing API for building advanced interactions (drag-and-drop, connection snapping, marquee selection). All queries run against the VizScene data structure — no DOM required.

Interactive demo

Status: Move mouse over items or click and drag to select.

Point hit testing

hitTest returns the topmost element at a given coordinate, checking in Z-index order:

import { hitTest } from 'vizcraft';

const result = hitTest(scene, { x: 250, y: 150 });

if (result?.type === 'node') {
console.log('Hit node:', result.id);
if (result.compartmentId) {
console.log('Compartment:', result.compartmentId);
}
if (result.entryId) {
console.log('Entry:', result.entryId);
}
} else if (result?.type === 'port') {
console.log('Hit port:', result.portId, 'on node:', result.nodeId);
} else if (result?.type === 'edge') {
console.log('Hit edge:', result.id);
} else {
console.log('Hit empty space');
}

Customize tolerances for edges and ports:

const easyHit = hitTest(scene, point, {
edgeTolerance: 15, // easier to click thin lines
portTolerance: 20, // easier to snap to ports
});

Rectangle selection (marquee)

hitTestRect returns all nodes and edges intersecting a rectangle:

import { hitTestRect } from 'vizcraft';

const rect = { x: 100, y: 100, w: 300, h: 200 };
const selected = hitTestRect(scene, rect);

selected.forEach((item) => {
if (item.type === 'node') {
console.log('Selected node:', item.id);
}
});

Nearest port snapping

When drawing a new connection, snap to the closest port:

import { nearestPort } from 'vizcraft';

const port = nearestPort(scene, { x: 260, y: 150 }, { maxDistance: 50 });

if (port) {
console.log(
'Snap to:',
port.nodeId,
port.portId,
'at distance:',
port.distance
);
}

Edge proximity

Check distance from a point to a specific edge:

import { edgeDistance } from 'vizcraft';

const dist = edgeDistance(scene, 'a->b', { x: 200, y: 150 });

Pan & zoom

Enable interactive viewport controls for large diagrams:

import { viz } from 'vizcraft';

const scene = viz()
.view(800, 600)
.node('a', { circle: { r: 40 }, at: { x: 200, y: 200 }, fill: '#f6c177' })
.node('b', {
diamond: { w: 100, h: 80 },
at: { x: 600, y: 200 },
fill: '#cba6f7',
})
.edge('a', 'b', { arrow: true });

const controller = scene.mount(document.getElementById('viz'), {
panZoom: true,
minZoom: 0.1, // default
maxZoom: 5, // default
initialZoom: 'fit', // default
});

Interactions:

  • Scroll wheel / trackpad to zoom
  • Click and drag background to pan
  • Double click background to auto-fit

Programmatic viewport control

// Fit all elements into view
controller.fitToContent(20); // 20px padding

// Zoom and center on a specific node
controller.zoomToNode('user-node');

// Manual control
controller.setZoom(2.5);
controller.setPan({ x: -100, y: -50 });
controller.reset();

// Subscribe to viewport changes
const unsubscribe = controller.onChange(({ zoom, pan }) => {
console.log('Scale:', zoom, 'Translation:', pan);
});

Tooltips

Add hover tooltips to nodes and edges. Tooltips appear after a short delay (300 ms by default), follow the cursor, and are keyboard-accessible.

Plain text tooltip

tip

Hover over the node to see the tooltip.

Structured tooltip

Pass an object with an optional title and an array of sections (label/value pairs) for richer content:

Edge tooltips

Edges support the same API:

Declarative form

Tooltips can also be set through the options object:

const scene = viz()
.node('n', { tooltip: 'Quick info' })
.edge('a', 'b', {
tooltip: { title: 'Link', sections: [{ label: 'Weight', value: '3' }] },
})
.done();

Theming

The tooltip element uses CSS custom properties so you can match your application's palette:

.viz-container {
--viz-tooltip-bg: #1e1e2e;
--viz-tooltip-fg: #cdd6f4;
--viz-tooltip-label: #a6adc8;
}

Keyboard accessibility

Nodes and edges that have tooltips receive tabindex="0" automatically, so users can tab to them and trigger the tooltip via focus. Pressing Escape dismisses any visible tooltip.


Found a problem? Open an issue on GitHub.