Skip to content

VIEW-1: graph camera centering + session persistence + zoom-extents button#100

Merged
mvalancy merged 2 commits into
devfrom
feat/camera-centering
Jun 17, 2026
Merged

VIEW-1: graph camera centering + session persistence + zoom-extents button#100
mvalancy merged 2 commits into
devfrom
feat/camera-centering

Conversation

@mvalancy

Copy link
Copy Markdown
Member

What

Fixes the "graph loads off-screen then jumps in" problem and respects the user's camera within/across a session, plus adds a zoom-extents button.

Camera (#78)

  • Once-per-graph framing (guarded by fittedGraphsRef): on first load of a graph, restore the user's saved camera (localStorage graphdone:camera:<id>) or auto-fit once — never re-fitting a graph already framed, so we don't fight the user's pan/zoom.
  • Fit runs through fitViewRef (not the churning fitViewToNodes callback) so the fit timer isn't cancelled mid-settle — the root cause of graphs rendering off-screen.
  • Debounced (600ms) per-graph camera save on pan/zoom — localStorage only, no D1 chatter. Shared node-position sync to D1 is tracked separately (server-side).

Zoom-extents button (#79)

  • Maximize2 button on graph views: under the lock toggle on phones, top-left on desktop (the right corner is the docked inspector).
  • Exposes triggerZoomToFit -> fitViewRef, framing every node without touching the camera-restore state.

Tests

  • New tests/e2e/camera.spec.ts @camera3/3:
    1. graph loads framed (most nodes on-screen, not off in a corner),
    2. zoom-extents reframes after a hard wheel zoom-in,
    3. camera pan is saved per-graph and restored on reload (zoom level preserved).
  • THE GATE (test:smoke) 5/5; web typecheck clean.

🤖 Generated with Claude Code

…tton

Camera no longer loads off-screen then jumps in, and the user's view is
respected within and across a session instead of being reset on every visit.

- Once-per-graph framing guarded by fittedGraphsRef: on first load of a
  graph, restore the user's saved camera (localStorage graphdone:camera:<id>)
  or auto-fit ONCE so the graph is framed, never re-fitting a graph already
  framed (don't fight the user's pan/zoom).
- Fit runs through fitViewRef (not the fitViewToNodes callback) so the timer
  isn't cancelled by the callback's identity churning during physics settle —
  the bug that left graphs rendered off-screen.
- Debounced (600ms) per-graph camera save on pan/zoom — localStorage only, no
  D1 chatter. (Shared node-position sync to D1 is a separate, server-side item.)
- Zoom-extents button (Maximize2) on graph views: under the lock toggle on
  phones, top-left on desktop (the right corner is the docked inspector).
  Exposes triggerZoomToFit -> fitViewRef, framing every node without touching
  the camera-restore state.

Tests: tests/e2e/camera.spec.ts @CAMERA (3/3) — loads framed, zoom-extents
reframes after a hard zoom-in, pan persists across reload. THE GATE 5/5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🧪 Comprehensive Test Suite

  • Unit suites (Node 18.x & 20.x) — core, web, server, mcp-server: ✅ passed
  • Installer & deploy config: ✅ passed

Full-stack smoke gate runs in the CI workflow.

The camera-centering fix lands the graph framed + centred (offMag ~0.05, bbox
coverage ~0.93 across desktop/laptop/tablet). Turn the OpenCV balance spec from
measurement-only into a gate with wide margins over that good state:
- contentPixels > 200 (graph is on-screen, not blank)
- bbox coverage > 0.35 (framed, not cornered; pre-fix off-screen read ~0.06)
- offMag < 0.30 (centred; pre-fix off-centre read ~0.80)
Annotated overlay + raw metrics still attached to the report every run.
Runs via `npm run test:geometry` (not in the PR CI gate — needs python+cv2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🧪 Comprehensive Test Suite

  • Unit suites (Node 18.x & 20.x) — core, web, server, mcp-server: ✅ passed
  • Installer & deploy config: ✅ passed

Full-stack smoke gate runs in the CI workflow.

@mvalancy mvalancy merged commit fd4585f into dev Jun 17, 2026
16 checks passed
@mvalancy mvalancy deleted the feat/camera-centering branch June 17, 2026 23:19
mvalancy added a commit that referenced this pull request Jun 20, 2026
…plitting)

From the live audit (#100):
- Graph GetWorkItems/GetEdges poll relaxed 2s → 15s and skipped while the tab is
  hidden (skipPollAttempt); own mutations still refetch instantly. No WS subs, so
  a slow poll keeps cross-client freshness without the idle hammer. (IGV)
- useAdaptiveQuality FPS-sampler rAF loop pauses on tab-hidden (visibilitychange)
  instead of spinning forever in backgrounded tabs. (useAdaptiveQuality.ts)
- Code-splitting: vite manualChunks splits react/apollo/d3/lucide into cacheable
  vendor chunks + Admin/Backend/Ontology/Agents/Analytics are React.lazy routes.
  Entry chunk ~1.46MB → 662KB; largest gzip chunk 266KB (budget 450). (vite.config, App.tsx)

Verified: typecheck clean; production build succeeds with split chunks;
check-bundle-size within budget. (Deeper "stop rAF when graph settled" left for #100.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant