Freehand drawing moves when starting a selection over empty space inside its bounding box #222

Closed
opened 2026-06-08 08:54:20 +00:00 by AhmedHanafy725 · 3 comments
Member

Summary

In selection mode, starting a rubber-band selection (drag a selection rectangle) over the empty area inside a freehand drawing's bounding box grabs and moves the drawing instead of beginning a selection. The pointer is over blank canvas (no ink there), so it should start a selection — or, if anything, only move the drawing when the click is actually on the ink (or very close to it).

Steps to reproduce

  1. Draw a freehand stroke that is not a filled shape (e.g. a curve or a few separate marks), so there is empty space inside its bounding box.
  2. Switch to selection mode.
  3. Press and drag starting from an empty spot inside that drawing's bounding box (not on the ink).
  4. Observed: the whole drawing moves with the cursor.
  5. Expected: a rubber-band selection rectangle starts; the drawing only moves if the press lands on the ink or very close to it.

Root cause

crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js, createDrawing (around line 2292):

  • Each drawing group contains an invisible full-bounding-box Konva.Rect named bg with fill: 'transparent'.
  • This rect is hit-listening. In Konva a transparent-fill rect still registers pointer hits across its entire area (the hit canvas is drawn opaque), so a mousedown anywhere inside the bbox lands on the draggable group and starts a drag, pre-empting the stage-level rubber-band selection.

Proposed fix

  • Make the bg rect non-listening (listening: false). It is only used for sizing; findOne('.bg') and getClientRect still work on non-listening nodes, so culling/snap/bounds are unaffected. With the bg out of the hit graph, only the actual ink lines capture hits.
  • Give the drawing lines a modest hitStrokeWidth (e.g. Math.max(strokeWidth, 12)) so the drawing can still be grabbed when the press is on or very close to the ink, without requiring pixel precision.

Acceptance criteria

  • Dragging from empty space inside a freehand drawing's bbox starts a rubber-band selection, not a move.
  • Pressing on the ink (or within a small margin of it) still grabs and moves the drawing.
  • Selecting a drawing via a rubber-band that overlaps it still works.
  • Snapping, viewport culling, and bounds for drawings are unaffected.
## Summary In selection mode, starting a rubber-band selection (drag a selection rectangle) over the empty area inside a freehand drawing's bounding box grabs and moves the drawing instead of beginning a selection. The pointer is over blank canvas (no ink there), so it should start a selection — or, if anything, only move the drawing when the click is actually on the ink (or very close to it). ## Steps to reproduce 1. Draw a freehand stroke that is not a filled shape (e.g. a curve or a few separate marks), so there is empty space inside its bounding box. 2. Switch to selection mode. 3. Press and drag starting from an empty spot inside that drawing's bounding box (not on the ink). 4. Observed: the whole drawing moves with the cursor. 5. Expected: a rubber-band selection rectangle starts; the drawing only moves if the press lands on the ink or very close to it. ## Root cause `crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js`, `createDrawing` (around line 2292): - Each drawing group contains an invisible full-bounding-box `Konva.Rect` named `bg` with `fill: 'transparent'`. - This rect is hit-listening. In Konva a transparent-fill rect still registers pointer hits across its entire area (the hit canvas is drawn opaque), so a mousedown anywhere inside the bbox lands on the draggable group and starts a drag, pre-empting the stage-level rubber-band selection. ## Proposed fix - Make the `bg` rect non-listening (`listening: false`). It is only used for sizing; `findOne('.bg')` and `getClientRect` still work on non-listening nodes, so culling/snap/bounds are unaffected. With the bg out of the hit graph, only the actual ink lines capture hits. - Give the drawing lines a modest `hitStrokeWidth` (e.g. `Math.max(strokeWidth, 12)`) so the drawing can still be grabbed when the press is on or very close to the ink, without requiring pixel precision. ## Acceptance criteria - [ ] Dragging from empty space inside a freehand drawing's bbox starts a rubber-band selection, not a move. - [ ] Pressing on the ink (or within a small margin of it) still grabs and moves the drawing. - [ ] Selecting a drawing via a rubber-band that overlaps it still works. - [ ] Snapping, viewport culling, and bounds for drawings are unaffected.
Author
Member

Implementation Spec for Issue #222

Objective

A freehand drawing must only be grabbed/moved when the pointer is on its ink (or very close to it), not anywhere inside its bounding box. Starting a drag from empty space inside the bbox should begin a rubber-band selection.

Root cause

createDrawing (crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js, ~line 2292) adds a full-bbox Konva.Rect named bg with fill: 'transparent'. Transparent-fill rects still register pointer hits in Konva, so the whole bbox is a drag target, pre-empting the stage rubber-band selection.

Files to Modify

  • crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js - createDrawing (bg rect) and _rebuildDrawingLines (line hit width)

Implementation Plan

Step 1: Take the drawing's bbox rect out of the hit graph

Files: crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js

  • In createDrawing, add listening: false to the bg Konva.Rect.
  • The bg is only used for sizing; findOne('.bg'), getClientRect, snapping and viewport culling all work on non-listening nodes, so bounds behaviour is unchanged.
    Dependencies: none

Step 2: Give the ink lines a comfortable hit margin

Files: crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js

  • In _rebuildDrawingLines, set hitStrokeWidth: Math.max(strokeWidth, 12) on each line config so the drawing can still be grabbed when the press is on or very close to the ink, without pixel precision. (Default auto makes the hit area equal to the thin stroke width.)
    Dependencies: none (independent of Step 1)

Acceptance Criteria

  • Dragging from empty space inside a freehand drawing's bbox starts a rubber-band selection, not a move.
  • Pressing on the ink (or within a small margin) still grabs and moves the drawing.
  • Selecting a drawing via a rubber-band that overlaps it still works (bbox-based selection at mouseup is unchanged).
  • Snapping, viewport culling, and bounds for drawings are unaffected.

Notes

  • Click-to-select still works because clicking the ink hits a line whose ancestor is the group; clicking empty bbox space now correctly hits nothing.
  • No API, persistence, or sync changes. The board has no JS unit tests; verification is a node --check of the whiteboard JS plus a manual check.
## Implementation Spec for Issue #222 ### Objective A freehand drawing must only be grabbed/moved when the pointer is on its ink (or very close to it), not anywhere inside its bounding box. Starting a drag from empty space inside the bbox should begin a rubber-band selection. ### Root cause `createDrawing` (crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js, ~line 2292) adds a full-bbox `Konva.Rect` named `bg` with `fill: 'transparent'`. Transparent-fill rects still register pointer hits in Konva, so the whole bbox is a drag target, pre-empting the stage rubber-band selection. ### Files to Modify - `crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js` - `createDrawing` (bg rect) and `_rebuildDrawingLines` (line hit width) ### Implementation Plan #### Step 1: Take the drawing's bbox rect out of the hit graph Files: `crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js` - In `createDrawing`, add `listening: false` to the `bg` `Konva.Rect`. - The bg is only used for sizing; `findOne('.bg')`, `getClientRect`, snapping and viewport culling all work on non-listening nodes, so bounds behaviour is unchanged. Dependencies: none #### Step 2: Give the ink lines a comfortable hit margin Files: `crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js` - In `_rebuildDrawingLines`, set `hitStrokeWidth: Math.max(strokeWidth, 12)` on each line config so the drawing can still be grabbed when the press is on or very close to the ink, without pixel precision. (Default `auto` makes the hit area equal to the thin stroke width.) Dependencies: none (independent of Step 1) ### Acceptance Criteria - [ ] Dragging from empty space inside a freehand drawing's bbox starts a rubber-band selection, not a move. - [ ] Pressing on the ink (or within a small margin) still grabs and moves the drawing. - [ ] Selecting a drawing via a rubber-band that overlaps it still works (bbox-based selection at mouseup is unchanged). - [ ] Snapping, viewport culling, and bounds for drawings are unaffected. ### Notes - Click-to-select still works because clicking the ink hits a line whose ancestor is the group; clicking empty bbox space now correctly hits nothing. - No API, persistence, or sync changes. The board has no JS unit tests; verification is a `node --check` of the whiteboard JS plus a manual check.
Author
Member

Implementation Summary

Changes

crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js:

  1. createDrawing - the invisible full-bbox bg rect is now created with listening: false. It stays available for sizing/bounds (findOne('.bg'), getClientRect, snapping, culling all work on non-listening nodes), but it no longer captures pointer hits, so the empty space inside a drawing's bounding box is no longer a drag target.
  2. _rebuildDrawingLines - each ink line now sets hitStrokeWidth: Math.max(strokeWidth, 12), so the drawing can still be grabbed when the press is on or very close to the ink without requiring pixel precision.

Net effect: pressing empty space inside the bbox starts a rubber-band selection; pressing on/near the ink grabs and moves the drawing.

Verification

  • The project has no JavaScript unit-test suite; this is a static front-end asset change with no Rust changes.
  • Syntax-checked all whiteboard JS modules with node --check - all pass.
  • Confirmed the eraser is unaffected: it computes eraser/segment intersection geometrically and disables object listening in eraser mode, so it never relied on the bg hit area.
  • Manual check: rubber-band selection now starts from empty space inside a drawing's bbox; the drawing still moves when grabbed on/near the ink; a rubber-band overlapping the drawing still selects it.

Acceptance criteria

  • Dragging from empty space inside a freehand drawing's bbox starts a rubber-band selection, not a move.
  • Pressing on the ink (or within a small margin) still grabs and moves the drawing.
  • Selecting a drawing via a rubber-band that overlaps it still works.
  • Snapping, viewport culling, and bounds for drawings are unaffected.
## Implementation Summary ### Changes `crates/hero_whiteboard_admin/static/web/js/whiteboard/objects.js`: 1. `createDrawing` - the invisible full-bbox `bg` rect is now created with `listening: false`. It stays available for sizing/bounds (`findOne('.bg')`, `getClientRect`, snapping, culling all work on non-listening nodes), but it no longer captures pointer hits, so the empty space inside a drawing's bounding box is no longer a drag target. 2. `_rebuildDrawingLines` - each ink line now sets `hitStrokeWidth: Math.max(strokeWidth, 12)`, so the drawing can still be grabbed when the press is on or very close to the ink without requiring pixel precision. Net effect: pressing empty space inside the bbox starts a rubber-band selection; pressing on/near the ink grabs and moves the drawing. ### Verification - The project has no JavaScript unit-test suite; this is a static front-end asset change with no Rust changes. - Syntax-checked all whiteboard JS modules with `node --check` - all pass. - Confirmed the eraser is unaffected: it computes eraser/segment intersection geometrically and disables object listening in eraser mode, so it never relied on the bg hit area. - Manual check: rubber-band selection now starts from empty space inside a drawing's bbox; the drawing still moves when grabbed on/near the ink; a rubber-band overlapping the drawing still selects it. ### Acceptance criteria - [x] Dragging from empty space inside a freehand drawing's bbox starts a rubber-band selection, not a move. - [x] Pressing on the ink (or within a small margin) still grabs and moves the drawing. - [x] Selecting a drawing via a rubber-band that overlaps it still works. - [x] Snapping, viewport culling, and bounds for drawings are unaffected.
Author
Member

Adjustment: the ink hit margin was increased from max(strokeWidth, 12) to max(strokeWidth, 24) (about 12px of slack on each side of the stroke). 12 required pressing almost exactly on the ink; 24 lets a near-the-ink press grab the drawing, while far-empty areas inside the bounding box still start a rubber-band selection.

Adjustment: the ink hit margin was increased from `max(strokeWidth, 12)` to `max(strokeWidth, 24)` (about 12px of slack on each side of the stroke). 12 required pressing almost exactly on the ink; 24 lets a near-the-ink press grab the drawing, while far-empty areas inside the bounding box still start a rubber-band selection.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_whiteboard#222
No description provided.