Skip to content

fix: Prevent image grid from blocking labeling (#3378)#9812

Open
sbatchelder wants to merge 1 commit into
HumanSignal:developfrom
sbatchelder:fix/grid-rect-develop
Open

fix: Prevent image grid from blocking labeling (#3378)#9812
sbatchelder wants to merge 1 commit into
HumanSignal:developfrom
sbatchelder:fix/grid-rect-develop

Conversation

@sbatchelder

@sbatchelder sbatchelder commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

This pull request fixes a long-standing bug where adding grid="true" to an
<Image> tag makes the image impossible to annotate — click-dragging or
double-clicking to draw a region does nothing, and rectangle labels can't be
assigned. The grid overlay was silently capturing every pointer event before it
could reach the drawing tools beneath it. The fix marks the grid layer as
non-interactive so pointer events pass through, and adds a regression test so the
grid can never re-acquire pointer capture.

Bug fix:

  • Added listening={false} to the grid ("ruler") <Layer> in ImageGrid.jsx so
    the grid opts out of Konva hit detection and no longer swallows the pointer
    events used to draw regions and assign labels.

Test:

  • Added ImageGrid.test.jsx, a regression test that renders ImageGrid and
    asserts the grid layer is non-interactive (listening={false}), plus a
    cell-count sanity check. The test fails on the unpatched component and passes
    with the fix.

Fixes #3378.

Reason for change

Problem. When grid="true" is set on an <Image> tag, users lose the ability
to annotate the image: click-drag no longer draws a region and rectangle labels
cannot be assigned. Removing grid="true" restores normal labeling. This has been
reported by multiple community users from v1.6 onward and is still reproducible on
the current develop branch.

Minimal config that reproduces the bug:

<View>
  <Image name="image" value="$image" grid="true" gridSize="40"/>
  <RectangleLabels name="label" toName="image">
    <Label value="Airplane" background="green"/>
    <Label value="Car" background="blue"/>
  </RectangleLabels>
</View>

Root cause. The grid is drawn in ImageGrid.jsx as a Konva <Layer name="ruler">
composed of one <Rect> per grid cell, and it is rendered on top of the
drawing/regions layers. By default a Konva layer participates in hit detection
(listening defaults to true), so every pointer event lands on the grid's rects
and is consumed there instead of reaching the drawing tools below. The mouse-down
that should begin a region never arrives.

Solution. Render the ruler layer with listening={false}. The grid is a passive
visual guide that never handles pointer events, so opting it out of hit detection
lets events pass straight through to the layers beneath, and drawing/labeling works
normally. The grid renders identically. This mirrors the approach the community
proposed in the issue thread.

The change is one line:

- <Layer opacity={0.15} name="ruler">
+ <Layer opacity={0.15} name="ruler" listening={false}>

Screenshots / recording

The change is behavioral, not visual - the grid looks identical before and after.
The recording below shows, on an image configured with grid="true":

  • Before: click-drag over the image does nothing; no region is created and no
    label can be assigned. See video here:
  • After: click-drag draws a rectangle and the label is assigned normally, with
    the grid still visible.
2026-07-08.19-36-40.mp4

Rollout strategy

No feature flag or environment variable. This is a correctness fix for an otherwise
broken configuration and is a no-op for any project that does not use grid. It
ships on by default.

Testing

Acceptance criteria (QA):

  • When a user opens an image configured with grid="true" and click-drags over the
    image, then a rectangle region is drawn and the selected label is assigned — the
    same as with the grid disabled.
  • When a user views that image, then the grid overlay is still rendered exactly as
    before.

Automated tests. Added web/libs/editor/src/components/ImageGrid/__tests__/ImageGrid.test.jsx
(2 tests, both passing):

  • The grid ("ruler") layer renders with listening={false} — the regression guard
    that fails if the grid ever re-acquires pointer capture.
  • An 80×80 stage with a 40px grid draws 4 cells (2×2) — a sanity check that the fix
    didn't alter grid geometry.

The test mocks react-konva so Layer/Rect render as inspectable DOM, avoiding a
real Konva <Stage>/canvas (the full editor MST/Konva stage isn't renderable in the
jest environment; the config already skips renderEditor integration tests).

Verified the test catches the bug. Reverting the one-line ImageGrid.jsx change
and re-running the suite fails the regression test with
Expected "false", Received "undefined", confirming the test is not vacuous.

Risks

  • Correctness: minimal. The grid layer has no click handlers and exists purely as a visual overlay, so removing its interactivity has no functional downside.
  • Performance: slightly better — Konva skips building a hit graph for the grid's rects.
  • Security: none.

Reviewer notes

The fix location and approach match the community suggestion in issue #3378.

Prior community PRs #8826 and #8875 proposed the same one-line change but did not include a test and were auto-closed for inactivity; this PR adds the regression test CONTRIBUTING.md requires for bug fixes.

General notes

  • listening is standard Konva/react-konva API for toggling a node's participation in hit detection; listening={false} on a layer disables it for the layer and all of its children.

@netlify

netlify Bot commented Jul 8, 2026

Copy link
Copy Markdown

👷 Deploy request for heartex-docs pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 3b72e2f

@netlify

netlify Bot commented Jul 8, 2026

Copy link
Copy Markdown

👷 Deploy request for label-studio-docs-new-theme pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 3b72e2f

@netlify

netlify Bot commented Jul 8, 2026

Copy link
Copy Markdown

Deploy Preview for label-studio-playground ready!

Name Link
🔨 Latest commit 3b72e2f
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-playground/deploys/6a4ee0882ce742000874fc05
😎 Deploy Preview https://deploy-preview-9812--label-studio-playground.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Jul 8, 2026

Copy link
Copy Markdown

Deploy Preview for label-studio-storybook ready!

Name Link
🔨 Latest commit 3b72e2f
🔍 Latest deploy log https://app.netlify.com/projects/label-studio-storybook/deploys/6a4ee088b2ed5d0008d94761
😎 Deploy Preview https://deploy-preview-9812--label-studio-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions github-actions Bot added the fix label Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

grid option in labeling interface breaks labeling

1 participant