Skip to content

Selected/highlighted node state in renderer #5

Description

@23min

Problem

dag-map has no concept of "selected" or "highlighted" nodes. When a consumer needs to visually distinguish certain nodes (e.g., a clicked node, a pinned node, a search result), there is no built-in mechanism. Consumers must choose between:

  1. CSS overrides on g[data-node-id] — toggling a class externally and styling with CSS. This conflicts with heatmap mode where node fills are set inline, and with the dim feature which also manipulates opacity.

  2. renderNode override — writing a full custom node renderer just to add a selection ring. This is heavy: the consumer must replicate all of dag-map's default rendering (circle size by degree, interchange inner circle, gate dashes, dim opacity, metric label) just to add one visual detail.

  3. Post-render DOM mutation — querying circle[data-id="X"] and changing attributes. Fragile, lost on re-render, and fights with heatmap coloring.

None of these compose well with existing features (heatmap, dim, gate nodes).

Context

The FlowTime UI workbench paradigm requires a clear visual distinction between:

  • Default nodes (metric-colored, normal)
  • Selected/pinned nodes (user clicked to inspect — should stand out)
  • Dimmed nodes (already supported via dim: true)

Another project using dag-map may have similar needs (e.g., highlighting a search result or an active execution node).

Proposed Design

Option A: selected set in render options

Add an optional selected: Set<string> (or string[]) to renderSVG options:

renderSVG(dag, layout, {
  metrics: metricsMap,
  selected: new Set(['api_svc', 'db_pool']),
})

Selected nodes get a visual indicator that composes with all existing modes:

  • Selection ring: An outer circle with slightly larger radius, contrasting stroke (e.g., theme ink color), and higher opacity. Sits behind the node circle.
  • Works with heatmap: The metric fill is preserved; the ring is additive.
  • Works with dim: A selected+dimmed node shows the ring at full opacity but the node itself at dim opacity (selection overrides dim for the ring only).

SVG output for a selected node:

<g data-node-id="api_svc" data-node-cls="core" data-selected="true">
  <!-- Selection ring (behind node) -->
  <circle cx="95" cy="160" r="9" fill="none" stroke="#3B3530" stroke-width="2" opacity="0.6"/>
  <!-- Normal node circle -->
  <circle data-id="api_svc" cx="95" cy="160" r="5.25" fill="#F5F0E8" stroke="#D4944C" stroke-width="2.4"/>
  <text ...>api_svc</text>
</g>

The data-selected="true" attribute enables CSS-based enhancement if consumers want more (e.g., animation, glow).

Option B: nodeState map for extensible states

Instead of a single selected set, accept a state map:

renderSVG(dag, layout, {
  nodeState: new Map([
    ['api_svc', 'selected'],
    ['db_pool', 'highlighted'],
    ['auth', 'error'],
  ]),
})

Each state maps to a visual treatment defined by the theme:

// Theme extension
{
  states: {
    selected:    { ring: true, ringColor: ink, ringOpacity: 0.6 },
    highlighted: { ring: true, ringColor: '#FFD700', ringOpacity: 0.8 },
    error:       { ring: true, ringColor: '#FF4444', ringOpacity: 0.9 },
  }
}

Recommendation

Start with Option Aselected: Set<string> covers the immediate need (workbench pinning, search results) with minimal API surface. The selection ring is a single visual treatment, well-defined, composable with heatmap and dim.

Evolve to Option B if multiple distinct states prove necessary. The migration path is smooth: selected becomes nodeState with backward compatibility.

Visual Behavior

State Combination Node Circle Selection Ring Label
Default metric color or class color none normal
Selected metric color or class color theme ink, r+3, opacity 0.6 bold or normal
Dimmed faded (dimOpacity) none faded
Selected + Dimmed faded full opacity ring faded label
Selected + Heatmap metric color fill ring in contrasting color metric label

Benefits

  • Single option, no breaking changes
  • Composes with heatmap, dim, gate, interchange — no conflicts
  • data-selected attribute enables CSS-based animation if wanted
  • Clean SVG output (one extra circle per selected node)
  • Selection ring is theme-aware (uses ink color by default)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions