Files
wled-screen-controller-mixed/contexts/graph-editor.md
alexei.dolgolyov 39981fbc45 Add graph editor filter, anchor-based positioning, and context docs
- Add name/kind/subtype filter bar with keyboard shortcut (F key)
- Filtered-out nodes get dimmed styling, nearly invisible on minimap
- Add anchor-based positioning for minimap and toolbar (remembers
  which corner element is closest to, maintains offset on resize)
- Fix minimap not movable after reload (_applyMinimapAnchor undefined)
- Fix ResizeObserver to use anchor system for both minimap and toolbar
- Add graph-editor.md context file and update frontend.md with graph sync notes
- Add filter i18n keys for en/ru/zh locales

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:39:14 +03:00

4.8 KiB

Visual Graph Editor

Read this file when working on the graph editor (static/js/features/graph-editor.js and related modules).

Architecture

The graph editor renders all entities (devices, templates, sources, clocks, targets, scenes, automations) as SVG nodes connected by edges in a left-to-right layered layout.

Core modules

File Responsibility
js/features/graph-editor.js Main orchestrator — toolbar, keyboard, search, filter, add-entity menu, port/node drag, minimap
js/core/graph-layout.js ELK.js layout, buildGraph(), computePorts(), entity color/label maps
js/core/graph-nodes.js SVG node rendering, overlay buttons, per-node color overrides
js/core/graph-edges.js SVG edge rendering (bezier curves, arrowheads, flow dots)
js/core/graph-canvas.js Pan/zoom controller with zoomToPoint() rAF animation
js/core/graph-connections.js CONNECTION_MAP — which fields link entity types, drag-connect/detach logic
css/graph-editor.css All graph-specific styles

Data flow

  1. loadGraphEditor()_fetchAllEntities() fetches all caches in parallel
  2. computeLayout(entities) builds ELK graph, runs layout → returns {nodes: Map, edges: Array, bounds}
  3. computePorts(nodeMap, edges) assigns port positions and annotates edges with fromPortY/toPortY
  4. Manual position overrides (_manualPositions) applied after layout
  5. renderEdges() + renderNodes() paint SVG elements
  6. GraphCanvas handles pan/zoom via CSS transform: scale() translate()

Edge rendering

Edges always use _defaultBezier() (port-aware cubic bezier) — ELK edge routing is ignored because it lacks port awareness, causing misaligned bend points. ELK is only used for node positioning.

Port system

Nodes have input ports (left) and output ports (right), colored by edge type. Port types are ordered vertically: template > picture > colorstrip > value > audio > clock > scene > device > default.

Keeping the graph in sync with entity types

CRITICAL: When adding or modifying entity types in the system, these graph files MUST be updated:

Adding a new entity type

  1. graph-layout.jsENTITY_COLORS, ENTITY_LABELS, buildGraph() (add node loop + edge loops)
  2. graph-layout.jsedgeType() function if the new type needs a distinct edge color
  3. graph-nodes.jsKIND_ICONS (default icon), SUBTYPE_ICONS (subtype-specific icons)
  4. graph-nodes.jsSTART_STOP_KINDS or TEST_KINDS sets if the entity supports start/stop or test
  5. graph-connections.jsCONNECTION_MAP for drag-connect edge creation
  6. graph-editor.jsADD_ENTITY_MAP (add-entity menu entry with window function)
  7. graph-editor.jsALL_CACHES array (for new-entity-focus watcher)
  8. graph-editor.js_fetchAllEntities() (add cache fetch + pass to computeLayout)
  9. core/state.js — Add/export the new DataCache
  10. app.js — Import and window-export the add/edit/clone functions

Adding a new field/connection to an existing entity

  1. graph-layout.jsbuildGraph() edges section: add addEdge() call
  2. graph-connections.jsCONNECTION_MAP: add the field entry
  3. graph-edges.jsEDGE_COLORS if a new edge type is needed

Adding a new entity subtype

  1. graph-nodes.jsSUBTYPE_ICONS[kind] — add icon for the new subtype
  2. graph-layout.jsbuildGraph() — ensure subtype is extracted from the entity data

Features & keyboard shortcuts

Key Action
/ Open search
F Toggle filter
F11 Toggle fullscreen
+ Add entity menu
Escape Close filter → close search → deselect all
Delete Delete selected edge or node
Arrows / WASD Spatial navigation between nodes
Ctrl+A Select all nodes

Node color overrides

Per-node colors stored in localStorage key graph_node_colors. The getNodeColor(nodeId, kind) function returns the override or falls back to ENTITY_COLORS[kind]. The color bar on the left side of each node is clickable to open a native color picker.

Filter system

The filter bar (toggled with F or toolbar button) filters nodes by name/kind/subtype. Non-matching nodes get the .graph-filtered-out CSS class (low opacity, no pointer events). Edges where either endpoint is filtered also dim. Minimap nodes for filtered-out entities become nearly invisible (opacity 0.07).

Minimap

Rendered as a small SVG with colored rects for each node and a viewport rect. Supports drag-to-pan, resize handles, and position persistence in localStorage.

New entity focus

When a user adds an entity via the graph's + menu, a watcher subscribes to all caches, detects the new ID, reloads the graph, and uses zoomToPoint() to smoothly fly to the new node with zoom + highlight animation.