feat: arrow-key pan for zoomed images with remappable hotkeys (#9811)#9814
Open
sbatchelder wants to merge 1 commit into
Open
feat: arrow-key pan for zoomed images with remappable hotkeys (#9811)#9814sbatchelder wants to merge 1 commit into
sbatchelder wants to merge 1 commit into
Conversation
👷 Deploy request for heartex-docs pending review.Visit the deploys page to approve it
|
👷 Deploy request for label-studio-docs-new-theme pending review.Visit the deploys page to approve it
|
✅ Deploy Preview for label-studio-storybook ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for label-studio-playground ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
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.
This pull request adds configurable keyboard shortcuts for panning a zoomed-in image, so annotators can move around a magnified image with the arrow keys instead of reaching for the mouse. The four directions are registered through the editor Hotkey system, default to the arrow keys, and appear in Account Settings / Hotkeys under a new "Zoomed Image Controls" section where they can be rebound. Making the arrow keys rebindable required a fix to the hotkey recorder, which previously saved arrow presses under the wrong key name. That fix is included and is a prerequisite for the feature to work properly.
User story: As an annotator working on a zoomed-in image, I want to pan with the arrow keys so that I can move around the image without switching between the keyboard and the mouse on every pan.
Closes #9811.
Feature:
tool:pan-on-zoom-left/-right/-up/-down— that pan the targeted zoomed image by 10% of the visible canvas per press. Defaults (left/right/up/down) live inkeymap.json.hotkeys.addNamed) inImageView.jsx, and exposed them in Account Settings / Hotkeys under a new "Zoomed Image Controls" section (defaults.js) so users can rebind them.Prerequisite fix (hotkey recorder):
Item.tsx: recording an arrow key now normalizes the browser key name to the editor keymap name (ArrowLeft→left, etc.) so a recorded arrow-key shortcut actually matches the keymap and fires. Without this, rebinding the pan actions to arrow keys silently would not work.useHotkeys.ts: extended the custom-hotkey prefix filter to recognize the newzoomed_imagesection so its shortcuts are passed through to the editor.Reason for change
Problem. When an image is zoomed in, there is no keyboard way to move around it. Every pan method (middle-click-drag, shift-click-drag) requires a pointer device. On large images where you zoom in to label small objects, constantly switching between the keyboard (labels/tools) and the mouse (panning) is slow and breaks the labeling flow. This is also an accessibility barrier: annotators who avoid mice/trackpads (repetitive-strain or other reasons) can drive nearly everything else in Label Studio from the keyboard, but not zoomed-image panning. The arrow keys, the natural way to nudge the viewport, do nothing for a zoomed image. See #9811.
Solution. Add four configurable pan actions registered through the editor Hotkey system, so they behave like every other shortcut (visible in settings, rebindable) rather than being a bare key listener. Each pans the current zoomed image by
PAN_STEP(10% of the visible canvas). Key behaviors:syncImagePanHotkey()only registers the pan hotkeys while a valid pan target exists (a mounted, zoomed image), and removes them otherwise, so the arrow keys keep their default behavior (page scroll, etc.) when there is nothing to pan.ctrl/meta/alt/shift) are left alone so they remain available to other actions, and keypresses while an editable/focused input is active are ignored.Why the recorder fix is included. The pan actions default to the arrow keys, and we want users to be able to rebind them. The Account Settings hotkey recorder captured the browser
KeyboardEvent.keyname (ArrowLeft) instead of the editor/keymaster name (left) that the keymap uses, so any arrow-key shortcut a user recorded silently never matched at runtime. NormalizingArrow*to the short names in the recorder is therefore a prerequisite for this feature. Without it, the "rebind the pan keys to arrow keys" flow wouldn't work. The regex change inuseHotkeys.tsis the matching plumbing to route the newzoomed_imagesection's custom hotkeys to the editor.Screenshots / recording
The recording below shows:
2026-07-08.21-36-47.mp4
_
Prior to this feature, trying to bind a hotkey to an arrowkey looked like this.
2026-07-08.21-13-35.mp4
Rollout strategy
No feature flag or environment variable. The pan hotkeys are only registered while a zoomed image is present, so the change is inert for every other configuration and for un-zoomed images; arrow keys behave exactly as before. It ships on by default. It'd be great if this could be included in v1.24.0.
Testing
Acceptance criteria (QA):
preventDefault).left/right/up/downand fires at runtime.Automated tests. Extended
web/libs/editor/src/components/ImageView/__tests__/ImageView.test.jsxto cover the pan behavior (direction handling, the zoomed-only gate, modifier/editable-target guards, and pan-target resolution).Manual verification. Verified panning on a zoomed image with single and multiple
<Image>tags, confirmed arrow keys fall through to default behavior when not zoomed, and confirmed that recording an arrow key in Account Settings now saves the short name and the rebound shortcut fires. Rebinding Zoomed Image Pan commands to WASD allows for the panning of a zoomed image with WASD, as seen in the video above.Risks
preventDefault) whenever there is no pan target, and the registration is torn down when the target goes away, so TimeSeries and other arrow-key consumers keep the keys when appropriate.normalizeKeychange affects all recorded shortcuts, not just pan — but it only mapsArrow*to the names the keymap already uses and lowercases others (previouslykey.toLowerCase()), so it strictly improves correctness for arrow keys and is a no-op for keys that were already correct.Reviewer notes
syncImagePanHotkey()and driven by mount/interaction, so import order and re-mounts are safe; hotkeys are added and removed as the pan target appears/disappears.keymap.json; the settings surface (section + per-action labels) lives indefaults.jsunder thezoomed_imagesection.General notes
PAN_STEP = 0.1is the fraction of the visible canvas moved per key press; the direction map matches the existing trackpad-scroll convention inhandleZoom(right/down reveal content in that direction).ArrowLefttoleft) which mirrors the names used throughout the editor keymap, so recorded and default arrowkey bindings now share one vocabulary.