Skip to content

fix/zoom - #254

Merged
TrevorBurgoyne merged 6 commits into
mainfrom
fix/zoom
Aug 14, 2026
Merged

fix/zoom#254
TrevorBurgoyne merged 6 commits into
mainfrom
fix/zoom

Conversation

@TrevorBurgoyne

@TrevorBurgoyne TrevorBurgoyne commented Aug 13, 2026

Copy link
Copy Markdown
Member

fix/zoom

Description

  • Fix wheel-zoom and drag-zoom focal point when the ULabel container is offset from the viewport origin. handle_wheel and drag_rezoom used to pass raw clientX/clientY (viewport coords) straight into rezoom, which treats its focal-point arguments as annbox-local. When the container sat at viewport (0, 0) the two frames coincided and the bug was invisible; anywhere else (e.g. hosted inside a centered dialog, a padded panel, or below a header) zoom would snap by roughly the annbox's screen offset. Both call sites now convert to annbox-local via getBoundingClientRect() before calling rezoom, so zoom stays anchored to the cursor / mousedown point regardless of how the host embeds ULabel.
  • New config option min_zoom_fit_ratio. Sets a zoom-out floor as a multiplier of the "whole image just fits the viewport" zoom. 0 (default) preserves the existing behavior (no floor). 1.0 prevents users from zooming out past the fit-to-viewport level. >1 forces the image to always overflow. Zoom-in is unaffected. The floor recomputes from live annbox dimensions, so it adapts to browser resize.

PR Checklist

  • Merged latest main
  • Version number in package.json has been bumped since last release
  • Version numbers match between package package.json and src/version.js
  • Updated documentation if necessary (currently just in api_spec.md)
  • Added changes to changelog.md

Breaking API Changes

No

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes zoom focal-point anchoring for offset containers and adds configurable fit-relative minimum zoom.

Changes:

  • Converts wheel and drag focal points to annbox-relative coordinates.
  • Adds min_zoom_fit_ratio with tests and documentation.
  • Adds release metadata and an offset-container demo.

Reviewed changes

Copilot reviewed 13 out of 15 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/index.js Implements focal conversion and zoom floor.
src/toolbox.ts Routes button zoom through the setter.
src/configuration.ts Adds the zoom-floor configuration.
index.d.ts Exposes the zoom setter.
tests/e2e/wheel-zoom-focal-point.spec.js Tests focal-point anchoring.
tests/e2e/min-zoom-fit-ratio.spec.js Tests zoom-floor behavior.
demo/offset-container.html Adds an offset-container test demo.
demo/set-annotations.html Enables the zoom floor.
demo.js Lists the new demo URL.
api_spec.md Documents the configuration option.
ulabel-wheel-zoom-focal-point.md Documents the focal-point defect.
CHANGELOG.md Records version 0.26.3 changes.
src/version.js Bumps the runtime version.
package.json Bumps the package version.
package-lock.json Synchronizes the lockfile version.
Suppressed comments (1)

src/index.js:6796

  • The drag path has the same transformed-coordinate mismatch as wheel zoom: subtracting rect.left/top removes an offset but does not convert viewport distances back into annbox layout pixels under CSS scaling. Use the same inverse coordinate conversion here so shift-drag remains anchored in transformed hosts.
        const annbox_rect = document.getElementById(this.config["annbox_id"]).getBoundingClientRect();
        this.rezoom(
            this.drag_state["zoom"]["mouse_start"][0] - annbox_rect.left,
            this.drag_state["zoom"]["mouse_start"][1] - annbox_rect.top,

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/index.js Outdated
Comment thread src/index.js
Comment thread ulabel-wheel-zoom-focal-point.md Outdated
Comment thread demo.js

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 15 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/index.js:6662

  • viewport_to_annbox_local derives scale from rect.width / annbox.clientWidth, but clientWidth/clientHeight exclude scrollbars. Since the annbox uses overflow: scroll, this will inflate the computed scale when scrollbars are present and can reintroduce focal-point drift even with no CSS transform. Use offsetWidth/offsetHeight (layout border-box size, including scrollbars) for the scale denominator so the ratio reflects only CSS transforms.
        const scale_x = annbox.clientWidth > 0 ? rect.width / annbox.clientWidth : 1;
        const scale_y = annbox.clientHeight > 0 ? rect.height / annbox.clientHeight : 1;

tests/e2e/wheel-zoom-focal-point.spec.js:95

  • pre_zoom_until_overflows can fall out of its retry loop without ever overflowing, silently letting the test proceed with a state where the focal-point invariant cannot hold (scroll positions clamp at 0). Make this helper fail loudly if it cannot achieve overflow so failures are diagnosable rather than flaky downstream assertion failures.
        if (overflows) return;
        await page.mouse.wheel(0, -300);
        await page.waitForTimeout(30);
    }
}

tests/e2e/min-zoom-fit-ratio.spec.js:19

  • The test computes fit_zoom from annbox.clientWidth/clientHeight, but the implementation floors zoom using get_viewport_height_ratio/get_viewport_width_ratio (jQuery .height()/.width()). With overflow: scroll, scrollbars can make clientWidth/clientHeight smaller than what the code uses, leading to platform-dependent flakiness. Compute fit_zoom the same way the library does so the assertions match behavior.
        const fit_zoom = Math.min(
            annbox.clientHeight / ul.config.image_height,
            annbox.clientWidth / ul.config.image_width,
        );

@TrevorBurgoyne
TrevorBurgoyne merged commit d73befb into main Aug 14, 2026
4 checks passed
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.

2 participants