Fix shift-drag jitter: lock axis once instead of re-evaluating each frame
The axis constraint was recalculated every mouse move, causing the symbol to jerk between horizontal and vertical near the 45-degree diagonal. Now the axis locks on first movement and stays locked until shift is released. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b68622a63a
commit
67cbf5c6ea
@ -38,6 +38,7 @@ interface DragState {
|
|||||||
ghost?: HTMLDivElement;
|
ghost?: HTMLDivElement;
|
||||||
multiOffsets?: { id: number; offsetX: number; offsetY: number }[];
|
multiOffsets?: { id: number; offsetX: number; offsetY: number }[];
|
||||||
dragActivated?: boolean; // true once mouse moves past threshold
|
dragActivated?: boolean; // true once mouse moves past threshold
|
||||||
|
shiftAxis?: 'h' | 'v'; // locked axis for shift-constrained drag
|
||||||
waypointIndex?: number; // which EPC waypoint is being dragged
|
waypointIndex?: number; // which EPC waypoint is being dragged
|
||||||
deviceLabel?: string; // label to assign when dropping from device dock
|
deviceLabel?: string; // label to assign when dropping from device dock
|
||||||
}
|
}
|
||||||
@ -360,8 +361,8 @@ function recalcEpcBounds(sym: typeof layout.symbols[0]) {
|
|||||||
// Right box corners (oriented along last segment)
|
// Right box corners (oriented along last segment)
|
||||||
const last = wps[wps.length - 1];
|
const last = wps[wps.length - 1];
|
||||||
const prev = wps[wps.length - 2];
|
const prev = wps[wps.length - 2];
|
||||||
const rbDx = last.x - prev.x, rbDy = last.y - prev.y;
|
const rbDir = { x: last.x - prev.x, y: last.y - prev.y };
|
||||||
const rbCorners = orientedBoxCorners(last.x, last.y, rbDy, -rbDx, EPC_CONFIG.rightBox.w, EPC_CONFIG.rightBox.h, 'right');
|
const rbCorners = orientedBoxCorners(last.x, last.y, rbDir.x, rbDir.y, EPC_CONFIG.rightBox.w, EPC_CONFIG.rightBox.h, 'right');
|
||||||
for (const [bx, by] of rbCorners) {
|
for (const [bx, by] of rbCorners) {
|
||||||
minX = Math.min(minX, bx); minY = Math.min(minY, by);
|
minX = Math.min(minX, bx); minY = Math.min(minY, by);
|
||||||
maxX = Math.max(maxX, bx); maxY = Math.max(maxY, by);
|
maxX = Math.max(maxX, bx); maxY = Math.max(maxY, by);
|
||||||
@ -509,13 +510,15 @@ function onMousemove(e: MouseEvent) {
|
|||||||
if (!pastDragThreshold(pos.x, pos.y, dragState.startX!, dragState.startY!, DRAG_THRESHOLD)) return;
|
if (!pastDragThreshold(pos.x, pos.y, dragState.startX!, dragState.startY!, DRAG_THRESHOLD)) return;
|
||||||
dragState.dragActivated = true;
|
dragState.dragActivated = true;
|
||||||
}
|
}
|
||||||
// Shift: constrain to orthogonal axis (horizontal or vertical)
|
// Shift: constrain to orthogonal axis — lock once, don't re-evaluate
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
if (Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!)) {
|
if (!dragState.shiftAxis) {
|
||||||
pos.y = dragState.startY!;
|
dragState.shiftAxis = Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!) ? 'h' : 'v';
|
||||||
} else {
|
|
||||||
pos.x = dragState.startX!;
|
|
||||||
}
|
}
|
||||||
|
if (dragState.shiftAxis === 'h') pos.y = dragState.startY!;
|
||||||
|
else pos.x = dragState.startX!;
|
||||||
|
} else {
|
||||||
|
dragState.shiftAxis = undefined;
|
||||||
}
|
}
|
||||||
const sym = layout.symbols.find(s => s.id === dragState!.placedId);
|
const sym = layout.symbols.find(s => s.id === dragState!.placedId);
|
||||||
if (!sym) return;
|
if (!sym) return;
|
||||||
@ -535,13 +538,15 @@ function onMousemove(e: MouseEvent) {
|
|||||||
if (!pastDragThreshold(pos.x, pos.y, dragState.startX!, dragState.startY!, DRAG_THRESHOLD)) return;
|
if (!pastDragThreshold(pos.x, pos.y, dragState.startX!, dragState.startY!, DRAG_THRESHOLD)) return;
|
||||||
dragState.dragActivated = true;
|
dragState.dragActivated = true;
|
||||||
}
|
}
|
||||||
// Shift: constrain to orthogonal axis
|
// Shift: constrain to orthogonal axis — lock once, don't re-evaluate
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
if (Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!)) {
|
if (!dragState.shiftAxis) {
|
||||||
pos.y = dragState.startY!;
|
dragState.shiftAxis = Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!) ? 'h' : 'v';
|
||||||
} else {
|
|
||||||
pos.x = dragState.startX!;
|
|
||||||
}
|
}
|
||||||
|
if (dragState.shiftAxis === 'h') pos.y = dragState.startY!;
|
||||||
|
else pos.x = dragState.startX!;
|
||||||
|
} else {
|
||||||
|
dragState.shiftAxis = undefined;
|
||||||
}
|
}
|
||||||
for (const { id, offsetX, offsetY } of dragState.multiOffsets) {
|
for (const { id, offsetX, offsetY } of dragState.multiOffsets) {
|
||||||
const sym = layout.symbols.find(s => s.id === id);
|
const sym = layout.symbols.find(s => s.id === id);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user