Skip to main content
The filtering system determines which nodes and edges are visible at any given time.

Filter Composition Pipeline

Multiple filters are applied in sequence:
1

All Nodes

Start with complete dataset
2

Node Type Filter

Hide specific types (Property, Field, etc.)
3

Namespace Filter

Hide entire namespaces
4

Selection Depth Filter (BFS)

Show only nodes within N hops of selected nodes
5

Edge Type Filter

Hide specific edge types (CONTAINS, etc.)
6

Visible Result

Final set of visible nodes and edges

BFS Algorithm

The applyUnifiedFilter method in OverlayFilterService:
Input:
  - selectedNodeIds: Set of explicitly selected node IDs
  - hiddenEdgeTypes: Set of edge types to exclude
  - selectionDepth: Number of hops to expand

Algorithm:
  1. Build adjacency list from all edges (respecting hiddenEdgeTypes)
  2. Initialize visibleNodes = copy of selectedNodeIds
  3. Initialize frontier = selectedNodeIds
  4. For depth = 1 to selectionDepth:
       a. newFrontier = empty set
       b. For each node in frontier:
            - Get neighbors from adjacency list
            - Add unvisited neighbors to newFrontier and visibleNodes
       c. frontier = newFrontier
  5. Filter edges: both endpoints must be in visibleNodes
  6. Update Three.js graphData with filtered nodes/edges
  7. Sync instanced renderer visibility mask

Output:
  - Only nodes within selectionDepth hops are visible
  - Edges only shown if both endpoints visible

Position Synchronization

When nodes are filtered out and back in, their positions must be preserved:
1

Before Filter

_syncPositionsToAllNodes() - Copy current positions from graphData to allNodes
2

Apply Filter

Rebuild graphData with new filter criteria
3

After Filter

_syncInstancedRenderer() - Restore positions from allNodes to graphData
Directly replacing graphData without syncing positions causes nodes to jump back to their original positions.

Single Filter Path

Edge type filtering should only go through applyUnifiedFilter:

Correct

All filtering through single applyUnifiedFilter call

Wrong

Adding a separate useEffect that also filters edges (causes race conditions)

Common Pitfalls

Duplicate Filter Paths

Adding a separate useEffect that also filters edges creates race conditions and inconsistent state.

Missing Adjacency List Updates

The adjacency list in GraphStateManager must be rebuilt when edges change. Always rebuild in updateGraphData().

Reference vs Value in Sets

// WRONG - Always false for Sets!
if (selectedNodeIds === prevSelectedNodeIds)

// CORRECT - Compare contents
const changed = currentArray.length !== prevArray.length ||
  currentArray.some((id, i) => id !== prevArray[i])