Skip to content

Getting Started ​

The inspector is a passive visualization tool that draws a data-navigator structure object as a force-directed node-edge graph. It does not drive navigation — you set up data-navigator's rendering and input modules on your chart as normal, and call inspector.highlight() and inspector.clear() from your navigation lifecycle to keep the graph in sync.

Install ​

The inspector uses modular D3 packages internally. Install alongside data-navigator:

bash
npm install data-navigator @data-navigator/inspector

Basic Usage ​

js
import dataNavigator from 'data-navigator';
import { Inspector } from '@data-navigator/inspector';

// 1. Build a structure
const structure = dataNavigator.structure({
    data: [
        { id: 'a', cat: 'x', val: 3 },
        { id: 'b', cat: 'x', val: 1 },
        { id: 'c', cat: 'y', val: 2 }
    ],
    idKey: 'id',
    dimensions: {
        values: [
            { dimensionKey: 'cat', type: 'categorical' },
            { dimensionKey: 'val', type: 'numerical' }
        ]
    }
});

// 2. Create the inspector (passive — just draws the graph)
const inspector = Inspector({
    structure,
    container: 'inspector-div',
    size: 300
});

// 3. Set up data-navigator rendering on your chart
const entryPoint = structure.dimensions[Object.keys(structure.dimensions)[0]].nodeId;

const rendering = dataNavigator.rendering({
    elementData: structure.nodes,
    suffixId: 'my-chart',
    root: { id: 'chart-div', width: '100%', height: 0 },
    entryButton: {
        include: true,
        callbacks: {
            click: () => {
                const nextNode = input.enter();
                if (nextNode) initiateLifecycle(nextNode);
            }
        }
    },
    exitElement: { include: true }
});
rendering.initialize();

// 4. Set up input handler
const input = dataNavigator.input({
    structure,
    navigationRules: structure.navigationRules,
    entryPoint,
    exitPoint: rendering.exitElement?.id
});

// 5. Navigation lifecycle — update inspector on focus/blur
let current = null;
let previous = null;

const move = direction => {
    const nextNode = input.move(current, direction);
    if (nextNode) initiateLifecycle(nextNode);
};

const initiateLifecycle = nextNode => {
    if (previous) rendering.remove(previous);

    const element = rendering.render({
        renderId: nextNode.renderId,
        datum: nextNode
    });

    element.addEventListener('keydown', e => {
        const direction = input.keydownValidator(e);
        if (direction) {
            e.preventDefault();
            move(direction);
        }
    });

    // Connect inspector to navigation events
    element.addEventListener('focus', () => {
        inspector.highlight(nextNode.renderId);
    });
    element.addEventListener('blur', () => {
        inspector.clear();
    });

    input.focus(nextNode.renderId);
    previous = current;
    current = nextNode.id;
};

The "Enter navigation area" button appears in your chart area (from data-navigator's rendering module), not inside the inspector. The inspector just draws the force graph and updates its focus indicator when you call highlight().

What the Graph Shows ​

The inspector draws every node and edge in the structure object as a force-directed graph. Nodes are colored by their level in the hierarchy:

  • Dimension nodes (level 1) represent the top-level grouping dimensions (e.g. "category", "date").
  • Division nodes (level 2) represent the groups within a dimension (e.g. "Group A", "Group B").
  • Data nodes (level 3, leaf) represent individual data points.

Edges show the navigable connections between nodes: parent-child relationships within a dimension, sibling links between nodes at the same level, and cross-dimension links created by childmostNavigation: 'across'.

When you call highlight(nodeId), a focus indicator (black circle outline) moves to that node in the graph and a tooltip displays information about it. Calling clear() hides both.

API Options ​

js
Inspector({
    structure, // Required. A data-navigator structure object.
    container, // Required. DOM element or string ID to mount in.
    size: 300, // Width and height of the SVG graph (default: 300).
    colorBy: 'dimensionLevel', // Field to color nodes by (default: 'dimensionLevel').
    nodeRadius: 5, // Radius of node circles (default: 5).
    edgeExclusions: [], // Edge IDs to hide from the graph.
    nodeInclusions: [] // Extra pseudo-node IDs to include (e.g. 'exit').
});

Return value ​

Inspector() returns an object with:

PropertyDescription
svgThe SVG element containing the force graph.
highlight(nodeId)Move the focus indicator to a node and show its tooltip.
clear()Hide the focus indicator and tooltip.
destroy()Remove the inspector from the DOM.

Handling Exit ​

To support the Esc key for exiting navigation, add an exit edge to your structure and wire up the exit handler in your own lifecycle:

js
let exitHandler = null;

const structure = dataNavigator.structure({
    // ...data and dimensions...
    genericEdges: [
        {
            edgeId: 'any-exit',
            edge: {
                source: (_d, c) => c,
                target: () => {
                    if (exitHandler) exitHandler();
                    return '';
                },
                navigationRules: ['exit']
            }
        }
    ]
});

// After setting up rendering and input:
exitHandler = () => {
    rendering.exitElement.style.display = 'block';
    input.focus(rendering.exitElement.id);
    if (current) {
        rendering.remove(current);
        current = null;
    }
    inspector.clear();
};

Exclude the exit edge from the inspector graph (it's a logical edge, not a visual one) and include its pseudo-node:

js
Inspector({
    // ...
    edgeExclusions: ['any-exit'],
    nodeInclusions: ['exit']
});

Using with a Visualization ​

The inspector is designed to run alongside an existing visualization. You set up data-navigator's rendering and input on your chart, and connect the inspector via highlight() / clear() calls in your navigation lifecycle's focus and blur handlers. See the Stacked Bar Example for a working demonstration of this pattern.