mirror of
https://github.com/excalidraw/excalidraw
synced 2025-07-25 13:58:22 +08:00
feat: experiment with a diff shift locking behavior
This commit is contained in:
@ -124,6 +124,11 @@ export const getDefaultAppState = (): Omit<
|
||||
searchMatches: null,
|
||||
lockedMultiSelections: {},
|
||||
activeLockedId: null,
|
||||
cropPositionMovement: {
|
||||
enabled: false,
|
||||
croppingElementId: undefined,
|
||||
directionLock: null,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -249,6 +254,7 @@ const APP_STATE_STORAGE_CONF = (<
|
||||
searchMatches: { browser: false, export: false, server: false },
|
||||
lockedMultiSelections: { browser: true, export: true, server: true },
|
||||
activeLockedId: { browser: false, export: false, server: false },
|
||||
cropPositionMovement: { browser: false, export: false, server: false },
|
||||
});
|
||||
|
||||
const _clearAppStateForStorage = <
|
||||
|
@ -6994,6 +6994,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
cropPositionMovement: {
|
||||
enabled: false,
|
||||
croppingElementId: undefined,
|
||||
directionLock: null,
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -8134,20 +8136,47 @@ class App extends React.Component<AppProps, AppState> {
|
||||
};
|
||||
|
||||
// apply shift key constraint for directional movement
|
||||
const threshold = 20;
|
||||
let snappingToOrigin = false;
|
||||
if (event.shiftKey) {
|
||||
const distanceX = Math.abs(totalDragOffset.x);
|
||||
const distanceY = Math.abs(totalDragOffset.y);
|
||||
|
||||
const lockX = distanceX < distanceY;
|
||||
const lockY = distanceX > distanceY;
|
||||
|
||||
if (lockX) {
|
||||
totalDragOffset.x = 0;
|
||||
if (!pointerDownState.cropPositionMovement.directionLock) {
|
||||
if (
|
||||
Math.abs(totalDragOffset.x) > threshold ||
|
||||
Math.abs(totalDragOffset.y) > threshold
|
||||
) {
|
||||
pointerDownState.cropPositionMovement.directionLock =
|
||||
Math.abs(totalDragOffset.x) > Math.abs(totalDragOffset.y)
|
||||
? "x"
|
||||
: "y";
|
||||
} else {
|
||||
// if within threshold and not locked, always snap to origin
|
||||
snappingToOrigin = true;
|
||||
}
|
||||
} else {
|
||||
// if user moves back within threshold, unlock and snap back
|
||||
if (
|
||||
Math.abs(totalDragOffset.x) < threshold &&
|
||||
Math.abs(totalDragOffset.y) < threshold
|
||||
) {
|
||||
pointerDownState.cropPositionMovement.directionLock = null;
|
||||
snappingToOrigin = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pointerDownState.cropPositionMovement.directionLock = null;
|
||||
}
|
||||
|
||||
if (lockY) {
|
||||
if (snappingToOrigin) {
|
||||
totalDragOffset.x = 0;
|
||||
totalDragOffset.y = 0;
|
||||
}
|
||||
|
||||
if (pointerDownState.cropPositionMovement.directionLock === "x") {
|
||||
totalDragOffset.y = 0;
|
||||
} else if (
|
||||
pointerDownState.cropPositionMovement.directionLock === "y"
|
||||
) {
|
||||
totalDragOffset.x = 0;
|
||||
}
|
||||
|
||||
// scale the drag offset
|
||||
|
@ -444,6 +444,11 @@ export interface AppState {
|
||||
// as elements are unlocked, we remove the groupId from the elements
|
||||
// and also remove groupId from this map
|
||||
lockedMultiSelections: { [groupId: string]: true };
|
||||
cropPositionMovement: {
|
||||
croppingElementId?: string;
|
||||
enabled: boolean;
|
||||
directionLock: "x" | "y" | null;
|
||||
};
|
||||
}
|
||||
|
||||
export type SearchMatch = {
|
||||
@ -800,6 +805,7 @@ export type PointerDownState = Readonly<{
|
||||
cropPositionMovement: {
|
||||
croppingElementId?: string;
|
||||
enabled: boolean;
|
||||
directionLock: "x" | "y" | null;
|
||||
};
|
||||
}>;
|
||||
|
||||
|
Reference in New Issue
Block a user