Minimap & UI Components
Built-in canvas UI: minimap, toolbar, search, tooltips, context menus, and info panels. No external DOM needed.
Minimap
Zoomed-out overview with viewport rectangle. Click or drag to navigate.
const app = create(container, {
nodes: [...],
edges: [...],
layout: 'force',
minimap: {
enabled: true,
position: 'bottom-left',
width: 180,
height: 120,
mode: 'dots', // 'dots' | 'heatmap' | 'both'
},
}); | Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Show/hide minimap. |
position | string | 'bottom-left' | Corner placement. |
width | number | 180 | Width in px. |
height | number | 120 | Height in px. |
mode | 'dots' | 'heatmap' | 'both' | 'dots' | Render mode. See Render modes. |
heatmapGrid | number | 8 | Grid resolution for heatmap/both: density aggregates into a n × n lattice. |
heatmapPalette | string[] | 5-stop blue→red | Cold-to-hot color ramp for heatmap cells. |
compactBreakpoint | number | 640 | Container width below which the minimap shrinks to a compact size. |
hideBreakpoint | number | 480 | Container width below which the minimap hides entirely. |
Render modes
| Mode | What it shows | When to use |
|---|---|---|
'dots' (default) | One dot per visible node, plus edges. | Small / medium graphs where identity matters. |
'heatmap' | Grid-aggregated node density shaded cold → hot. Edges suppressed. | Large graphs where individual dots become a hairball-in-miniature. |
'both' | Heatmap underneath dots, edges suppressed. | Recommended when node count > 30 — orientation and identity. |
Heatmap helpers
Both helpers used to compute the heatmap are exported for embedders who want to drive their own overlays.
import {
computeHeatmapDensity,
sampleHeatmapColor,
DEFAULT_HEATMAP_PALETTE,
} from '@topokit/renderer-canvas';
const { counts, max } = computeHeatmapDensity(nodes, bounds, 8);
// counts: Uint32Array of length gridSize²; max: peak cell count
const color = sampleHeatmapColor(DEFAULT_HEATMAP_PALETTE, 0.7);
// Interpolates between cold-to-hot stops at t ∈ [0, 1] Toolbar
const app = create(container, {
nodes: [...],
edges: [...],
toolbar: {
enabled: true,
position: 'top-right',
items: ['zoom-in', 'zoom-out', 'fit', 'fullscreen', 'separator', 'layout-select'],
},
}); | Item | Description |
|---|---|
'zoom-in' | Increase zoom |
'zoom-out' | Decrease zoom |
'fit' | Fit graph to viewport |
'fullscreen' | Toggle fullscreen |
'layout-select' | Layout algorithm dropdown |
'separator' | Visual separator |
Search Bar
const app = create(container, {
nodes: [...],
edges: [...],
search: {
enabled: true,
placeholder: 'Search nodes...',
position: 'top-left',
fields: ['style.label', 'data.name', 'data.email'],
highlightMatches: true,
dimOpacity: 0.1,
panToMatch: true,
},
}); Tooltip
const app = create(container, {
nodes: [...],
edges: [...],
tooltip: {
enabled: true,
delay: 300,
node: (node) => [
{ label: 'Name', value: node.data.name },
{ label: 'Type', value: node.data.type },
],
edge: (edge) => [
{ label: 'Relationship', value: edge.data.type },
],
},
}); Context Menu
const app = create(container, {
nodes: [...],
edges: [...],
contextMenu: {
enabled: true,
node: (node) => [
{ label: 'Expand neighbors', action: () => graph.expand(node.id) },
{ label: 'Highlight connections', action: () => {
const ids = [node.id, ...graph.getNeighbors(node.id).map(n => n.id)];
graph.highlightNodes(ids);
}},
{ separator: true },
{ label: 'Remove node', action: () => graph.removeNode(node.id), danger: true },
],
},
}); Info Panel
const app = create(container, {
nodes: [...],
edges: [...],
infoPanel: {
enabled: true,
position: 'right',
width: 320,
trigger: 'click',
node: (node) => ({
title: node.data.name,
subtitle: node.data.type,
fields: [
{ label: 'ID', value: node.id },
{ label: 'Department', value: node.data.department },
],
actions: [
{ label: 'Expand', onClick: () => graph.expand(node.id) },
],
}),
},
}); All Components Together
const app = create(container, {
nodes: data.nodes,
edges: data.edges,
layout: 'force',
theme: 'dark',
minimap: { enabled: true, position: 'bottom-right' },
toolbar: { enabled: true, position: 'top-right' },
search: { enabled: true, position: 'top-left' },
tooltip: { enabled: true, delay: 200 },
contextMenu: { enabled: true },
infoPanel: { enabled: true, position: 'right' },
legend: { enabled: true, groupBy: 'data.type', position: 'bottom-left' },
}); Runtime Control
// Toggle components at runtime
app.setMinimap({ enabled: true });
app.setMinimap({ enabled: false });
app.setToolbar({ enabled: false });
app.setSearch({ enabled: true });
app.setTooltip({
node: (node) => [{ label: 'Name', value: node.data.name }],
}); Next Steps
- Legend -- color/shape key
- Node Badges -- status indicators
- Web Worker Layout -- responsive with large graphs