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;
|
||||
multiOffsets?: { id: number; offsetX: number; offsetY: number }[];
|
||||
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
|
||||
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)
|
||||
const last = wps[wps.length - 1];
|
||||
const prev = wps[wps.length - 2];
|
||||
const rbDx = last.x - prev.x, rbDy = last.y - prev.y;
|
||||
const rbCorners = orientedBoxCorners(last.x, last.y, rbDy, -rbDx, EPC_CONFIG.rightBox.w, EPC_CONFIG.rightBox.h, 'right');
|
||||
const rbDir = { x: last.x - prev.x, y: last.y - prev.y };
|
||||
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) {
|
||||
minX = Math.min(minX, bx); minY = Math.min(minY, 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;
|
||||
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 (Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!)) {
|
||||
pos.y = dragState.startY!;
|
||||
} else {
|
||||
pos.x = dragState.startX!;
|
||||
if (!dragState.shiftAxis) {
|
||||
dragState.shiftAxis = Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!) ? 'h' : 'v';
|
||||
}
|
||||
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);
|
||||
if (!sym) return;
|
||||
@ -535,13 +538,15 @@ function onMousemove(e: MouseEvent) {
|
||||
if (!pastDragThreshold(pos.x, pos.y, dragState.startX!, dragState.startY!, DRAG_THRESHOLD)) return;
|
||||
dragState.dragActivated = true;
|
||||
}
|
||||
// Shift: constrain to orthogonal axis
|
||||
// Shift: constrain to orthogonal axis — lock once, don't re-evaluate
|
||||
if (e.shiftKey) {
|
||||
if (Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!)) {
|
||||
pos.y = dragState.startY!;
|
||||
} else {
|
||||
pos.x = dragState.startX!;
|
||||
if (!dragState.shiftAxis) {
|
||||
dragState.shiftAxis = Math.abs(pos.x - dragState.startX!) >= Math.abs(pos.y - dragState.startY!) ? 'h' : 'v';
|
||||
}
|
||||
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) {
|
||||
const sym = layout.symbols.find(s => s.id === id);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user