fix: tolerant Konva hit-detection for ±1 getImageData color drift (#9810)#9813
Open
sbatchelder wants to merge 1 commit into
Open
fix: tolerant Konva hit-detection for ±1 getImageData color drift (#9810)#9813sbatchelder wants to merge 1 commit into
sbatchelder wants to merge 1 commit into
Conversation
👷 Deploy request for label-studio-docs-new-theme pending review.Visit the deploys page to approve it
|
👷 Deploy request for heartex-docs 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 fixes a bug where clicking a resize handle or a region in the image editor frequently misses - the click falls through and instead draws a new box, drags the underlying annotation, or does nothing, and the resize cursor never appears. The cause seems to be that some under canvas implementations,
getImageDatarounds color channel values by ±1 per channel, which breaks Konva's exact color-key hit detection. The fix makes that hit lookup tolerant of ±1 drift, and only does extra work when Konva's exact lookup has already missed.Bug fix:
konva-hit-tolerance.ts, which wrapsKonva.Layer.prototype._getIntersectionso that, on an opaque-pixel miss, it searches the 26 color keys within ±1 RGB of the read-back pixel and resolves to that shape. Exact hits are untouched.ImageView.jsxso it applies to the image editor's Konva stage.Test:
konva-hit-tolerance.test.ts, which drives the patched lookup against a minimal Konva stand-in (no canvas/GPU needed) and covers the exact-match, ±1-drift, no-neighbor, transparent-pixel, channel-boundary, idempotency, and missing-internals cases.Fixes #9810.
Reason for change
Problem. In the image editor, clicking a Transformer resize handle or clicking a region to select it frequently misses: the pointer "clicks through" the target and instead starts a new selection box or drags the underlying rectangle, and the resize cursor never appears. On an annotation with several regions, some of the 8 resize anchors work and others don't, and which ones work changes every time the same box is re-selected. It is worst on large images. It is possibly worse also when there are 100+ annotations or highly zoomed in.
See #9810 for a video of the misbehaving handles.
Root cause. Konva identifies the shape under the pointer by drawing every shape onto an offscreen hit canvas in a unique color key, then reading that one pixel back with
getImageDataand looking the exact color up inKonva.shapes. This depends ongetImageDatareturning the exact bytes that were written. On some canvas implementations (reproduced on Chrome/Chromium/Brave with hardware-accceleration enabled),getImageDatarounds solid colors by ±1 per channel. The exact-color lookup then misses and the click falls through. I speculate that small targets, like resize handles, are more strongly affected by rounding-effect, and non-integer stage scale (zoom) makes the miss rate worse. Konva's own recovery mode (a spiral search to neighbouring pixel positions) doesn't help, because the whole anchor footprint reads the same drifted color.Solution. Wrap
Konva.Layer.prototype._getIntersectionso that, when Konva's exact lookup returns no shape for an opaque pixel, it searches the 26 color keys within ±1 RGB of the read-back value and resolves to that shape. The true shape's key is by definition one of those neighbours (the read-back drifted from it by ≤1). Color keys are spread across 16.7M values, so the odds a ±1 neighbour is a different registered shape are negligible (~0.02% worst case). The patch:This is complementary to, but distinct from, the "handles are too small" framing in #4558, #4452, and PR #9700: enlarging a handle's screen-space hit area doesn't help when the entire enlarged footprint reads a uniformly-drifted color and still returns no key.
Screenshots / recording
The change is behavioral. The canvas looks identical. The recording below shows, on a large image with RectangleLabels regions:
2026-07-08.20-31-44.mp4
Rollout strategy
No feature flag or environment variable. The patch is inert on canvases that don't drift (Konva's exact lookup succeeds and the extra path never runs), and it only ever adds a hit where Konva would otherwise have returned none. It never removes or changes an existing hit. It ships on by default. If the team would prefer it behind a
flag_setguard for a staged rollout, it's a one-line wrap to add.Testing
Acceptance criteria (QA):
Automated tests. Added
web/libs/editor/src/utils/__tests__/konva-hit-tolerance.test.ts, driving the patched lookup against a minimal Konva stand-in (no real canvas/GPU required). It covers:Manual verification. Reproduced the miss on a recent Chromium build on Linux with a large image and confirmed the fix restores reliable handle grabs and region selection.
Risks
_getIntersection), so a future Konva upgrade could change its shape. The code guards against that by feature-detecting and no-oping rather than throwing.Reviewer notes
ImageView.jsx; it wraps the prototype once and is idempotent, so import order and re-mounts are safe.getImageData, below Konva's public API — there is no prop or option to make the color-key lookup tolerant. The wrap is deliberately minimal and defensive.General notes
getImageDatanot returning the exact bytes written.konva-hit-tolerance.tsmodule docstring documents the mechanism, the ±1 drift, and why the fix is safe, for future maintainers.