Restore mouse-wheel zoom on React match-results and encounter image viewers#1628
Open
JasonWildMe wants to merge 1 commit into
Open
Restore mouse-wheel zoom on React match-results and encounter image viewers#1628JasonWildMe wants to merge 1 commit into
JasonWildMe wants to merge 1 commit into
Conversation
Wheel-to-zoom was lost in the React rewrite: there was no wheel handler anywhere in the frontend, so users had to use the icon buttons to zoom match-results and encounter images. This restores it and standardizes the behavior behind a small shared hook. - New hook frontend/src/hooks/useWheelZoom.js attaches a NATIVE, non-passive "wheel" listener to a target element (React's synthetic onWheel is passive and cannot preventDefault, so the page would scroll behind the zoom). It owns no zoom state: callers pass onZoom(direction) (+1 in / -1 out) and keep their own zoom/pan/clamp semantics. A latest-callback ref avoids re-subscribing each render. - AnnotationOverlay.jsx (match-results viewer): wheel zoom mirrors the existing zoomIn/zoomOut imperative handle (clampZoom + clampPan + zoomStep), gated on imageLoaded, attached to the existing outerContainerRef. - ImageModal.jsx (encounter modal): wheel zoom matches its buttons (step 0.25, range 1..3); pan re-centers via the existing [zoom, safeIndex] effect. Listener attached to a new ref on the #image-modal-image-container. Also moved the `if (!assets...) return null` guard below the hooks (it previously sat above all hooks, a latent Rules-of-Hooks violation) and normalized the assets prop to an array so the hooks are null-safe. One wheel step per notch, centered (matches the buttons). Zoom-to-cursor is left as a future enhancement since the two viewers use different transformOrigin and pan models. ImageGalleryModal is intentionally not included here because its zoom comes from the still-open PR #1596; it will get the same hook once that merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
JasonWildMe
added a commit
to Joey-Li0118/Wildbook
that referenced
this pull request
Jun 20, 2026
Wire the shared useWheelZoom hook into the Gallery-View image modal so wheeling zooms the image (matching the zoom-in/reset buttons: step 0.25, range 1..3; pan re-centers via the existing [zoom, safeIndex] effect). The native non-passive wheel listener is attached to the non-transformed #image-modal-image container. The hook (frontend/src/hooks/useWheelZoom.js) is added here identical to the copy in PR WildMeOrg#1628 (which applies it to AnnotationOverlay + ImageModal), so the gallery viewer's wheel-zoom can be tested alongside the rest of this PR. Identical same-path content merges cleanly with WildMeOrg#1628. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A researcher reported she can no longer mouse-wheel to zoom on the React match-results page images and has to use the icon buttons. Confirmed: there is no
wheel/onWheellistener anywhere in the React frontend — wheel-to-zoom existed in the older viewer and was never ported into the React rewrite.Fix
Restore wheel-zoom and standardize it behind a small shared hook so the three (currently divergent) zoom/pan viewers can share one implementation.
frontend/src/hooks/useWheelZoom.js— attaches a native, non-passivewheellistener to a target element. A native listener is required because React's syntheticonWheelis registered passively and cannotpreventDefault(), so the page would scroll behind the zoom. The hook owns no zoom state: callers passonZoom(direction)(+1in /-1out) and keep their own zoom/pan/clamp semantics. A latest-callback ref avoids re-subscribing the listener every render.AnnotationOverlay.jsx(match-results viewer, the reported regression) — wheel zoom mirrors the existingzoomIn/zoomOutimperative handle (clampZoom+clampPan+zoomStep), gated onimageLoaded, attached to the existingouterContainerRef.ImageModal.jsx(encounter-page modal) — wheel zoom matches its buttons (step0.25, range1..3); pan re-centers via the existing[zoom, safeIndex]effect. Listener attached to a new ref on#image-modal-image-container. Also moved theif (!assets…) return nullguard below the hooks (it previously sat above all hooks — a latent Rules-of-Hooks violation) and normalized theassetsprop to an array so the hooks are null-safe.Behavior decisions
transformOrigin(top-left vs center) and pan models (clamped vs reset-on-zoom), so cursor-anchoring would reintroduce per-component divergence.preventDefault()stops the page from scrolling while zooming. The listener is scoped to the image container only.Scope / follow-up
ImageGalleryModal.jsxis intentionally excluded. Its zoom/pan comes from the still-open Gallery View Zooming and Panning Feature #1596 (no zoom onmain); adding wheel-zoom there now would conflict. It gets the sameuseWheelZoomhook in a quick follow-up once Gallery View Zooming and Panning Feature #1596 merges.Testing
git diff --checkclean./react/match-results, wheel up/down over an image zooms in/out within bounds, the page doesn't scroll, annotation rects stay aligned, and the buttons still work. Same on the encounter-page image modal.🤖 Generated with Claude Code