Fit button: webframe iframe overlay does not follow the frame to its fitted position #118

Open
opened 2026-04-30 10:59:57 +00:00 by AhmedHanafy725 · 3 comments
Member

Summary

Click the Fit button (zoom reset to fit all content) on a board that has a webframe object. The Konva frame moves to its new position, but the iframe DOM overlay stays at its old screen position — the website pane visibly shifts away from the frame.

Steps to reproduce

  1. Add a webframe to a board and load any embeddable URL (e.g. example.com).
  2. Pan / zoom so the frame is somewhere off-center.
  3. Click the Fit button (or use the keyboard equivalent that calls WhiteboardApp.zoomReset()).

Expected

The iframe overlay re-anchors to the frame's new screen position; frame and website stay aligned.

Actual

The frame redraws at the fitted position; the iframe overlay stays where it was.

Root cause

crates/hero_whiteboard_ui/static/web/js/whiteboard/canvas.js::setZoom already calls WhiteboardWebframe.refreshAllOverlays() after applying scale/position. But crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js::zoomReset bypasses setZoom and mutates stage.scale / stage.position directly, then calls syncScaleFromStage / drawGrid / saveView — but not refreshAllOverlays. Two of the three branches inside zoomReset (the empty-bbox fallback and the normal fit) take this direct path; the empty-board branch routes through setZoom and is fine.

Fix

Call WhiteboardWebframe.refreshAllOverlays() after the direct stage.scale / stage.position mutations in zoomReset (the two branches that don't already route through setZoom).

## Summary Click the **Fit** button (zoom reset to fit all content) on a board that has a webframe object. The Konva frame moves to its new position, but the iframe DOM overlay stays at its old screen position — the website pane visibly shifts away from the frame. ## Steps to reproduce 1. Add a webframe to a board and load any embeddable URL (e.g. example.com). 2. Pan / zoom so the frame is somewhere off-center. 3. Click the **Fit** button (or use the keyboard equivalent that calls `WhiteboardApp.zoomReset()`). ## Expected The iframe overlay re-anchors to the frame's new screen position; frame and website stay aligned. ## Actual The frame redraws at the fitted position; the iframe overlay stays where it was. ## Root cause `crates/hero_whiteboard_ui/static/web/js/whiteboard/canvas.js::setZoom` already calls `WhiteboardWebframe.refreshAllOverlays()` after applying scale/position. But `crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js::zoomReset` bypasses `setZoom` and mutates `stage.scale` / `stage.position` directly, then calls `syncScaleFromStage` / `drawGrid` / `saveView` — but **not** `refreshAllOverlays`. Two of the three branches inside `zoomReset` (the empty-bbox fallback and the normal fit) take this direct path; the empty-board branch routes through `setZoom` and is fine. ## Fix Call `WhiteboardWebframe.refreshAllOverlays()` after the direct `stage.scale` / `stage.position` mutations in `zoomReset` (the two branches that don't already route through `setZoom`).
Author
Member

Implementation Spec for Issue #118

Objective

The Fit button (zoomReset) must re-anchor every webframe iframe overlay to its frame's new screen position, the same way setZoom already does. Today only the empty-board branch routes through setZoom; the other two branches mutate stage directly and skip the overlay refresh, so iframes visibly shift away from their frames.

Files to Modify

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js — append a WhiteboardWebframe.refreshAllOverlays() call to the two branches of zoomReset that mutate stage.scale / stage.position directly. The empty-board branch (which already routes through setZoom) is already correct.

Implementation Plan

Step 1: Refresh overlays after direct stage transforms

File: crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js

Two spots inside zoomReset apply the stage transform directly and end with saveView():

  1. The "empty bounding box" fallback (lines ~686–691).
  2. The normal fit branch (lines ~708–716).

After each, add (defensively guarded against the module not being loaded):

if (typeof WhiteboardWebframe !== 'undefined' && WhiteboardWebframe.refreshAllOverlays) {
    WhiteboardWebframe.refreshAllOverlays();
}

The empty-board branch (lines ~642–647) already calls WhiteboardCanvas.setZoom(1), which internally refreshes overlays — leave it untouched.

Dependencies: none.

Acceptance Criteria

  • Add a webframe, pan/zoom so it sits off-center, click Fit. The iframe stays aligned with its frame at the fitted position.
  • Repeated Fit + zoom + Fit cycles don't drift the iframe.
  • + / - keyboard zoom (which goes through setZoom) still works as before.
  • No webframe on the board → no JS error from the new calls (the helper is a no-op).
  • cargo fmt, cargo clippy --workspace --all-targets -- -D warnings, cargo test --workspace --lib clean.

Notes

  • Why not refactor zoomReset to route through setZoom: setZoom doesn't accept an explicit position, only a scale. Threading position through it (or duplicating logic) is a larger change than this two-line patch warrants.
  • Why touch only zoomReset: the only other direct stage mutator is fitMindmapToView, which lives in the standalone mindmap fullscreen view where webframes don't render. Out of scope.
## Implementation Spec for Issue #118 ### Objective The Fit button (`zoomReset`) must re-anchor every webframe iframe overlay to its frame's new screen position, the same way `setZoom` already does. Today only the empty-board branch routes through `setZoom`; the other two branches mutate `stage` directly and skip the overlay refresh, so iframes visibly shift away from their frames. ### Files to Modify - `crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js` — append a `WhiteboardWebframe.refreshAllOverlays()` call to the two branches of `zoomReset` that mutate `stage.scale` / `stage.position` directly. The empty-board branch (which already routes through `setZoom`) is already correct. ### Implementation Plan #### Step 1: Refresh overlays after direct stage transforms File: `crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js` Two spots inside `zoomReset` apply the stage transform directly and end with `saveView()`: 1. The "empty bounding box" fallback (lines ~686–691). 2. The normal fit branch (lines ~708–716). After each, add (defensively guarded against the module not being loaded): ```js if (typeof WhiteboardWebframe !== 'undefined' && WhiteboardWebframe.refreshAllOverlays) { WhiteboardWebframe.refreshAllOverlays(); } ``` The empty-board branch (lines ~642–647) already calls `WhiteboardCanvas.setZoom(1)`, which internally refreshes overlays — leave it untouched. Dependencies: none. ### Acceptance Criteria - [ ] Add a webframe, pan/zoom so it sits off-center, click Fit. The iframe stays aligned with its frame at the fitted position. - [ ] Repeated Fit + zoom + Fit cycles don't drift the iframe. - [ ] `+` / `-` keyboard zoom (which goes through `setZoom`) still works as before. - [ ] No webframe on the board → no JS error from the new calls (the helper is a no-op). - [ ] `cargo fmt`, `cargo clippy --workspace --all-targets -- -D warnings`, `cargo test --workspace --lib` clean. ### Notes - **Why not refactor `zoomReset` to route through `setZoom`:** `setZoom` doesn't accept an explicit position, only a scale. Threading position through it (or duplicating logic) is a larger change than this two-line patch warrants. - **Why touch only `zoomReset`:** the only other direct stage mutator is `fitMindmapToView`, which lives in the standalone mindmap fullscreen view where webframes don't render. Out of scope.
Author
Member

Test Results

  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • cargo test --workspace --lib — 0 failed
  • node --check app.js — clean
## Test Results - `cargo fmt --all -- --check` — clean - `cargo clippy --workspace --all-targets -- -D warnings` — clean - `cargo test --workspace --lib` — 0 failed - `node --check app.js` — clean
Author
Member

Implementation Summary

zoomReset (Fit) was applying the stage transform directly in two of its three branches and skipping the iframe-overlay refresh that setZoom already performs. The webframe stayed at its old screen position while its Konva frame moved to the fitted position.

crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js

Added a WhiteboardWebframe.refreshAllOverlays() call after the stage transform in:

  1. The empty-bounding-box fallback branch.
  2. The normal fit branch.
if (typeof WhiteboardWebframe !== 'undefined' && WhiteboardWebframe.refreshAllOverlays) {
    WhiteboardWebframe.refreshAllOverlays();
}

The empty-board branch already routes through WhiteboardCanvas.setZoom(1), which internally refreshes overlays — left untouched.

Files Changed

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js+6 / 0

Test Results

  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • cargo test --workspace --lib — 0 failed
  • node --check app.js — clean

Manual smoke

  1. Add a webframe, pan/zoom so the frame is off-center, click Fit. Iframe stays aligned with its frame at the fitted position.
  2. Repeated Fit + manual zoom + Fit cycles do not drift the iframe.
  3. Empty board → Fit still resets to origin at 100% with no JS error.
  4. + / - keyboard zoom (already routed through setZoom) unchanged.

Notes

  • Why not refactor zoomReset to route through setZoom: setZoom accepts only a scale, not a position; threading position through would be a larger change than this two-line patch warrants.
  • fitMindmapToView not touched — it lives in the standalone mindmap fullscreen view where webframes don't render.
## Implementation Summary `zoomReset` (Fit) was applying the stage transform directly in two of its three branches and skipping the iframe-overlay refresh that `setZoom` already performs. The webframe stayed at its old screen position while its Konva frame moved to the fitted position. ### `crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js` Added a `WhiteboardWebframe.refreshAllOverlays()` call after the stage transform in: 1. The empty-bounding-box fallback branch. 2. The normal fit branch. ```js if (typeof WhiteboardWebframe !== 'undefined' && WhiteboardWebframe.refreshAllOverlays) { WhiteboardWebframe.refreshAllOverlays(); } ``` The empty-board branch already routes through `WhiteboardCanvas.setZoom(1)`, which internally refreshes overlays — left untouched. ### Files Changed - `crates/hero_whiteboard_ui/static/web/js/whiteboard/app.js` — `+6 / 0` ### Test Results - `cargo fmt --all -- --check` — clean - `cargo clippy --workspace --all-targets -- -D warnings` — clean - `cargo test --workspace --lib` — 0 failed - `node --check app.js` — clean ### Manual smoke 1. Add a webframe, pan/zoom so the frame is off-center, click Fit. Iframe stays aligned with its frame at the fitted position. 2. Repeated Fit + manual zoom + Fit cycles do not drift the iframe. 3. Empty board → Fit still resets to origin at 100% with no JS error. 4. `+` / `-` keyboard zoom (already routed through `setZoom`) unchanged. ### Notes - **Why not refactor `zoomReset` to route through `setZoom`:** `setZoom` accepts only a scale, not a position; threading position through would be a larger change than this two-line patch warrants. - **`fitMindmapToView` not touched** — it lives in the standalone mindmap fullscreen view where webframes don't render.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_whiteboard#118
No description provided.