Skip to content

fix: preserve graph layout on viewer refresh#803

Open
mturac wants to merge 2 commits into
rohitg00:mainfrom
mturac:fix/issue-691-graph-layout-stability
Open

fix: preserve graph layout on viewer refresh#803
mturac wants to merge 2 commits into
rohitg00:mainfrom
mturac:fix/issue-691-graph-layout-stability

Conversation

@mturac
Copy link
Copy Markdown

@mturac mturac commented Jun 3, 2026

Summary

  • preserve existing graph node positions when the viewer graph reloads
  • keep the current graph pan and zoom across refreshes instead of recentering every time
  • avoid stacking stale resize listeners during repeated graph initialization
  • add regression coverage for graph layout and viewport preservation

Tests

  • git diff --check
  • npm test -- test/viewer-graph-cooldown.test.ts
  • npm run build

Closes #691

Summary by CodeRabbit

  • Bug Fixes

    • Graph viewer now preserves node positions and viewport zoom/pan across refreshes and window resizes; avoids duplicate resize handlers and restores prior view or recenters as needed.
    • Prevents overlapping animations by canceling any in-flight animation loop before restarting.
  • Tests

    • Added tests verifying layout and viewport preservation and that animation frames are properly canceled.

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

@mturac is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: af82a008-94d1-4c45-aefe-63bf57373b21

📥 Commits

Reviewing files that changed from the base of the PR and between 4f8e523 and 959be76.

📒 Files selected for processing (2)
  • src/viewer/index.html
  • test/viewer-graph-cooldown.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/viewer/index.html

📝 Walkthrough

Walkthrough

Updated the graph viewer to preserve node positions and velocities plus pan/zoom across graph re-initialization and window resize events. The simulation now snapshots prior layout and viewport, removes duplicate resize listeners, cancels any running RAF before restarting, reattaches a single resize handler, and restores previous node coordinates and viewport when nodes are recreated.

Changes

Graph State Preservation Across Re-initialization

Layer / File(s) Summary
Simulation state tracking infrastructure
src/viewer/index.html
graphSim gains a resizeHandler field. initGraph snapshots previous node layout by id, captures prior pan/zoom, cancels any active RAF, and removes an existing window resize listener registered by a prior graphSim.resizeHandler before re-initialization.
Pan/zoom and node position restoration
src/viewer/index.html
The local resize is assigned to graphSim.resizeHandler and registered on window. Canvas dimensions are measured and prior pan/zoom are restored when a previous layout exists; otherwise the view is centered. When rebuilding graphSim.nodes, node x/y/vx/vy are reused from previousLayout[id] for matching nodes instead of random initialization, while radius/size logic remains unchanged.
State preservation and RAF lifecycle tests
test/viewer-graph-cooldown.test.ts
New assertions check that node positions reuse previousLayout[n.id] on reload, viewport panX/zoom are preserved across refresh, and any in-flight RAF is canceled and cleared (cancelAnimationFrame(graphSim.raf) and graphSim.raf = null).

Sequence Diagram

sequenceDiagram
  participant Window
  participant initGraph
  participant graphSim
  participant Canvas

  Window->>initGraph: trigger (loadGraph / resize)
  initGraph->>graphSim: capture previousLayout, previousPan/Zoom, cancel RAF
  initGraph->>Window: remove old resize listener
  initGraph->>Window: add resize listener (graphSim.resizeHandler)
  initGraph->>graphSim: recreate nodes (reuse previous x/y/vx/vy when id matches)
  graphSim->>Canvas: set panX/panY/zoom and node positions
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through nodes with glee,
No more jumps — the graph stays steady! 🐰
Pan and zoom restored with care,
Velocities kept and RAFs laid bare,
Smooth layouts now dance free.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses the primary objective from #691 (preserve node positions on refresh) and improves viewport stability. However, the velocity cap requirement (MAX_VEL) mentioned in #691 is not implemented in the code changes. Implement the velocity cap (MAX_VEL: 50 px/frame) in the physics simulation loop to prevent unbounded repulsion forces, as specified in #691's proposed fix.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: preserving graph layout when the viewer refreshes, which matches the primary objective of the pull request.
Out of Scope Changes check ✅ Passed All changes are directly related to graph layout preservation and viewport state management. The modifications to initialization, node position restoration, and animation frame cancellation all support the core objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/viewer/index.html`:
- Around line 1818-1820: initGraph currently calls runSimulation()
unconditionally and can start a new rAF chain while a previous one is still
scheduled; fix by tracking the animation handle (e.g., a module-level variable
like rafId) and calling cancelAnimationFrame(rafId) (and setting rafId = null)
at the start of initGraph before calling runSimulation(), and ensure
runSimulation stores the returned requestAnimationFrame id into rafId each frame
so subsequent re-inits can cancel the pending frame.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a321c945-7f2e-4754-b78c-1500d0196d50

📥 Commits

Reviewing files that changed from the base of the PR and between d442fee and 4f8e523.

📒 Files selected for processing (2)
  • src/viewer/index.html
  • test/viewer-graph-cooldown.test.ts

Comment thread src/viewer/index.html
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.

[viewer] Graph nodes jumping/flickering on every poll refresh due to missing position preservation and no velocity cap

1 participant