fix(measurements): handles drag on the first pixel, like datum view
Handles previously had a 3 px screen-space dead zone before drag started (the click-vs-drag heuristic). On a precision-positioning tool that makes nudges feel mushy, and the datum editor — which uses Konva drag — has no such threshold. Drop the threshold; selection still happens on pointerDown so a pure click that doesn't move never enters pointerMove and the position never drifts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a499e97361
commit
f1d32d0fb2
@ -91,7 +91,11 @@ let isPanning = false
|
|||||||
let panStart = { x: 0, y: 0 }
|
let panStart = { x: 0, y: 0 }
|
||||||
let lastPinchDist = 0
|
let lastPinchDist = 0
|
||||||
|
|
||||||
// Drag state for moving/reshaping committed measurements.
|
// Drag state for moving/reshaping committed measurements. We don't gate
|
||||||
|
// drag-start on a movement threshold — handles begin tracking the cursor
|
||||||
|
// on the very first move event so positioning feels precise (matches
|
||||||
|
// Konva's behaviour in the datum editor). A pure click without movement
|
||||||
|
// never enters pointerMove, so selection on its own remains drift-free.
|
||||||
type DragMode = "none" | "move" | "handle"
|
type DragMode = "none" | "move" | "handle"
|
||||||
interface DragState {
|
interface DragState {
|
||||||
mode: DragMode
|
mode: DragMode
|
||||||
@ -102,14 +106,8 @@ interface DragState {
|
|||||||
startImg: Point
|
startImg: Point
|
||||||
// Snapshot of the measurement at drag start, for delta-based updates.
|
// Snapshot of the measurement at drag start, for delta-based updates.
|
||||||
startSnapshot: Measurement
|
startSnapshot: Measurement
|
||||||
// Did this pointer down actually move? Used to distinguish click vs drag.
|
|
||||||
moved: boolean
|
|
||||||
}
|
}
|
||||||
let dragState: DragState | null = null
|
let dragState: DragState | null = null
|
||||||
// Pixel threshold in screen space before a press becomes a drag. Small enough
|
|
||||||
// that intentional drags feel responsive; large enough that a shaky click
|
|
||||||
// still registers as a click.
|
|
||||||
const DRAG_THRESHOLD_PX = 3
|
|
||||||
|
|
||||||
function loadImg() {
|
function loadImg() {
|
||||||
const image = new Image()
|
const image = new Image()
|
||||||
@ -1257,7 +1255,6 @@ function pointerDown(screenX: number, screenY: number): "measurement" | "pan" {
|
|||||||
handleKey: hit.handleKey,
|
handleKey: hit.handleKey,
|
||||||
startImg: screenToImg(screenX, screenY),
|
startImg: screenToImg(screenX, screenY),
|
||||||
startSnapshot: cloneMeasurement(target),
|
startSnapshot: cloneMeasurement(target),
|
||||||
moved: false,
|
|
||||||
}
|
}
|
||||||
drawOverlay()
|
drawOverlay()
|
||||||
return "measurement"
|
return "measurement"
|
||||||
@ -1268,14 +1265,6 @@ function pointerMove(screenX: number, screenY: number): boolean {
|
|||||||
const nowImg = screenToImg(screenX, screenY)
|
const nowImg = screenToImg(screenX, screenY)
|
||||||
const dxImg = nowImg.x - dragState.startImg.x
|
const dxImg = nowImg.x - dragState.startImg.x
|
||||||
const dyImg = nowImg.y - dragState.startImg.y
|
const dyImg = nowImg.y - dragState.startImg.y
|
||||||
if (!dragState.moved) {
|
|
||||||
// Convert image-space delta back to screen-space via viewScale; easier
|
|
||||||
// than tracking the original screen cursor separately.
|
|
||||||
const screenDx = dxImg * viewScale.value
|
|
||||||
const screenDy = dyImg * viewScale.value
|
|
||||||
if (Math.hypot(screenDx, screenDy) < DRAG_THRESHOLD_PX) return true
|
|
||||||
dragState.moved = true
|
|
||||||
}
|
|
||||||
const next = applyDrag(
|
const next = applyDrag(
|
||||||
dragState.startSnapshot,
|
dragState.startSnapshot,
|
||||||
dragState.mode,
|
dragState.mode,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user