Skip to content

feat(proxy-ui): force-directed interactive topology with hover focus, dragging and zoom #128

Description

@zhy1658858023

Background

PR #127 replaced the original text topology with an SVG-based Scheduler → Proxy → Instance diagram and significantly improved readability. However, the current topology still uses a deterministic row-and-column hierarchy: Scheduler and Proxy are vertically aligned, Instances are placed in fixed rows, and links mainly flow from top to bottom.

The result still looks closer to an organizational chart than an interactive network topology such as ONOS. Current hover behavior is also limited to a thicker halo and drop shadow; it does not highlight connected links, emphasize neighbors, dim unrelated nodes, or show a styled real-time tooltip.

Goal

Upgrade the Proxy topology into a stable, organic, force-directed network visualization with deterministic pseudo-random placement and richer pointer/keyboard interaction.

The topology should feel dynamic and network-oriented without causing nodes to move randomly on every polling refresh.

Requirements

1. Replace the fixed row-and-column layout

Keep Scheduler and Proxy as logical anchor nodes, but stop placing all Instances in fixed horizontal rows.

Use a deterministic force-directed or force-relaxed layout implemented with native JavaScript. It should include:

  • Link spring force between Scheduler and Proxy.
  • Link spring force between Proxy and each Instance.
  • Repulsion between visible nodes.
  • Collision avoidance using node radius and label bounds.
  • Weak centering force that keeps the graph inside the viewport.
  • Radial tendency that keeps Instances around Proxy.
  • Different preferred radii as the Instance count grows.

Place Proxy near the visual center. Scheduler may be above-left or above Proxy rather than strictly vertically aligned. Instances should appear around Proxy at different angles and slightly different radii.

2. Stable pseudo-random placement

Do not use uncontrolled Math.random() for persistent positions.

Create a deterministic hash from node type and node ID and use it to derive:

  • Initial angle.
  • Initial radius.
  • Small x/y jitter.
  • Optional link-curvature direction.

The same node IDs must produce the same initial layout. Metric-only polling updates must not move nodes.

Store resolved positions in frontend state and recompute layout only when:

  • Node membership changes.
  • Viewport size changes materially.
  • The user clicks Reset Layout.
  • Nodes are added or removed.

When one Instance is added, preserve existing node positions as much as possible.

3. Lightweight native force simulation

Do not introduce React, Vue, D3, Cytoscape, vis-network, a frontend build pipeline, or another large graph dependency.

Implement a bounded native simulation:

  • Initialize positions from stable hashed polar coordinates.
  • Run approximately 80–150 iterations only when recalculation is required.
  • Apply repulsion, spring forces, radial force, collision correction, and boundary constraints.
  • Save settled positions.
  • Animate changes with requestAnimationFrame.
  • Do not run a permanent CPU-intensive simulation.

4. Curved links with varied geometry

Do not generate every link with the same vertical cubic Bézier shape.

Calculate paths from the actual source-target vector. Connect paths to the edge of node halos rather than node centers. Use deterministic perpendicular curvature derived from the link ID.

Proxy-to-Instance links should radiate naturally in different directions. Avoid excessive curvature and avoid passing through unrelated nodes where practical.

5. Strong hover and keyboard-focus interaction

On pointer hover or keyboard focus:

  • Add is-hovered to the focused node.
  • Add is-neighbor to directly connected nodes.
  • Add is-related to connected links.
  • Add is-dimmed to unrelated nodes and links.
  • Scale the focused node to about 1.08–1.12.
  • Increase halo stroke and glow.
  • Emphasize label and status.
  • Increase related-link width and opacity.
  • Make related flow animation more visible.

Relationship rules:

  • Scheduler hover: highlight Scheduler, Proxy, and their link.
  • Proxy hover: highlight Proxy, Scheduler, all Instances, and all connected links.
  • Instance hover: highlight that Instance, Proxy, and their connecting link.

Mouse hover and keyboard focus must be equivalent.

6. Custom HTML tooltip

Do not rely only on SVG <title> tooltips.

Create one reusable HTML tooltip positioned near the pointer and clamped inside the topology viewport.

For Instance nodes show available values:

  • Instance ID.
  • Host and port.
  • Alive/stale/unknown state.
  • CPU utilization.
  • System memory used/total.
  • GPU utilization.
  • GPU memory used/total.
  • Inflight.
  • QPS.
  • Prepare queue depth.
  • Ready queue depth.
  • Active prepare.
  • Active ready.
  • Last-seen age.
  • Resource-report age.

For Proxy show Proxy ID, health, alive/total Instance counts, and topology-link count.

For Scheduler show registration state, Proxy ID when available, and last known Scheduler status.

Missing data must display an em dash and must never be converted to zero. Escape all tooltip text before insertion.

7. Animated data-flow particles

Keep the dashed-link animation and add lightweight moving particles on active links.

  • Use native SVG.
  • Use no more than one or two particles per active link.
  • Do not animate stale, inactive, or unknown links.
  • Related particles may become brighter or faster during hover.
  • Respect prefers-reduced-motion and the existing Pause state.

8. Node dragging

Allow Scheduler, Proxy, and Instance nodes to be dragged using pointer events.

During dragging:

  • Capture the pointer.
  • Move the node immediately.
  • Update connected links immediately.
  • Keep the node inside graph bounds.
  • Mark the node as manually positioned.
  • Prevent accidental navigation after movement exceeds a drag threshold.

A normal click without meaningful movement must continue to open Instance Detail. Pinned positions must survive polling refreshes.

Add a Reset Layout control that clears pinned positions and recomputes the deterministic layout.

9. Zoom, pan, and fit controls

Add compact controls:

  • Zoom in.
  • Zoom out.
  • Fit to view.
  • Reset layout.

Support wheel zoom and background pointer-drag panning. Put links and nodes in one SVG viewport group and transform that group. Enforce safe min/max zoom levels and prevent the graph from becoming permanently lost outside the viewport.

10. Preserve existing functionality

Preserve:

  • Scheduler, Proxy, and Instance icons.
  • Alive, stale, unknown, and unavailable states.
  • Polling controls and Pause behavior.
  • Dark and light themes.
  • Instance Detail hash routing.
  • Enter/Space activation.
  • Raw diagnostics.
  • Strict null semantics.
  • prefers-reduced-motion.
  • No frontend build pipeline.

11. Performance

  • Do not recompute layout during every polling interval.
  • Use a stable topology signature based on sorted node IDs.
  • Reuse existing position objects.
  • Install event handlers once or use event delegation.
  • Keep the topology responsive with at least 50 Instance nodes.

12. Testing

Add pure-function tests for:

  • Stable string hashing.
  • Deterministic initial positions.
  • Same IDs producing the same layout.
  • Different IDs producing different positions.
  • Bounds and collision distance.
  • Stable positions across metric-only updates.
  • Adding one Instance without resetting all previous positions.
  • Deterministic link curvature.
  • Hover relationships for Scheduler, Proxy, and Instance.
  • Null-safe tooltip data.

Add DOM-level fixture tests for:

  • Pointer hover classes.
  • Focus and blur classes.
  • Tooltip show/hide and viewport clamping.
  • Drag threshold versus click navigation.
  • Pause state.
  • Reset Layout.
  • Reduced-motion mode.

Run:

node --check UI/proxy_ui/static/app.js
node UI/proxy_ui/test_proxy_ui_pure.js
python3 -m py_compile UI/proxy_ui/proxy_ui_server.py

13. Visual acceptance criteria

Provide screenshots or a short recording for:

  • 4 Instances.
  • 8 Instances.
  • 20 Instances.
  • 50 Instances.
  • Mixed alive/stale Instances.
  • Scheduler unavailable.
  • Hovering an Instance.
  • Hovering Proxy.
  • Tooltip near the right viewport edge.
  • A dragged Instance.
  • Zoomed and panned topology.
  • Dark theme.
  • Light theme.

The final topology must look like an organic network graph rather than a top-down hierarchy. It may appear slightly irregular, but the same node set must remain visually stable between polling updates.

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