fix: Turn into inside bind when angle locked (#10479)

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Márk Tolmács
2025-12-09 19:36:28 +01:00
committed by GitHub
parent 8d18078f5c
commit bf4c65f483
4 changed files with 36 additions and 31 deletions
+22 -2
View File
@@ -151,6 +151,7 @@ export const bindOrUnbindBindingElement = (
opts?: { opts?: {
newArrow?: boolean; newArrow?: boolean;
altKey?: boolean; altKey?: boolean;
angleLocked?: boolean;
initialBinding?: boolean; initialBinding?: boolean;
}, },
) => { ) => {
@@ -561,7 +562,7 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
appState: AppState, appState: AppState,
opts?: { opts?: {
newArrow?: boolean; newArrow?: boolean;
shiftKey?: boolean; angleLocked?: boolean;
altKey?: boolean; altKey?: boolean;
finalize?: boolean; finalize?: boolean;
initialBinding?: boolean; initialBinding?: boolean;
@@ -597,7 +598,7 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
appState: AppState, appState: AppState,
opts?: { opts?: {
newArrow?: boolean; newArrow?: boolean;
shiftKey?: boolean; angleLocked?: boolean;
altKey?: boolean; altKey?: boolean;
finalize?: boolean; finalize?: boolean;
initialBinding?: boolean; initialBinding?: boolean;
@@ -770,6 +771,12 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
} }
: { mode: null }; : { mode: null };
const otherEndpoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
arrow,
startDragged ? -1 : 0,
elementsMap,
);
const other: BindingStrategy = const other: BindingStrategy =
otherBindableElement && otherBindableElement &&
!otherFocusPointIsInElement && !otherFocusPointIsInElement &&
@@ -779,6 +786,19 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
element: otherBindableElement, element: otherBindableElement,
focusPoint: appState.selectedLinearElement.initialState.altFocusPoint, focusPoint: appState.selectedLinearElement.initialState.altFocusPoint,
} }
: opts?.angleLocked && otherBindableElement
? {
mode: "orbit",
element: otherBindableElement,
focusPoint:
projectFixedPointOntoDiagonal(
arrow,
otherEndpoint,
otherBindableElement,
startDragged ? "end" : "start",
elementsMap,
) || otherEndpoint,
}
: { mode: undefined }; : { mode: undefined };
return { return {
+6 -28
View File
@@ -26,7 +26,6 @@ import {
import { import {
deconstructLinearOrFreeDrawElement, deconstructLinearOrFreeDrawElement,
getHoveredElementForBinding,
isPathALoop, isPathALoop,
moveArrowAboveBindable, moveArrowAboveBindable,
projectFixedPointOntoDiagonal, projectFixedPointOntoDiagonal,
@@ -306,21 +305,11 @@ export class LinearElementEditor {
const customLineAngle = const customLineAngle =
linearElementEditor.customLineAngle ?? linearElementEditor.customLineAngle ??
determineCustomLinearAngle(pivotPoint, element.points[idx]); determineCustomLinearAngle(pivotPoint, element.points[idx]);
const hoveredElement = getHoveredElementForBinding(
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
elements,
elementsMap,
);
// Determine if point movement should happen and how much // Determine if point movement should happen and how much
let deltaX = 0; let deltaX = 0;
let deltaY = 0; let deltaY = 0;
if ( if (shouldRotateWithDiscreteAngle(event)) {
shouldRotateWithDiscreteAngle(event) &&
!hoveredElement &&
!element.startBinding &&
!element.endBinding
) {
const [width, height] = LinearElementEditor._getShiftLockedDelta( const [width, height] = LinearElementEditor._getShiftLockedDelta(
element, element,
elementsMap, elementsMap,
@@ -358,7 +347,7 @@ export class LinearElementEditor {
element, element,
elements, elements,
app, app,
event.shiftKey, shouldRotateWithDiscreteAngle(event),
event.altKey, event.altKey,
); );
@@ -492,22 +481,11 @@ export class LinearElementEditor {
const endIsSelected = selectedPointsIndices.includes( const endIsSelected = selectedPointsIndices.includes(
element.points.length - 1, element.points.length - 1,
); );
const hoveredElement = getHoveredElementForBinding(
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
elements,
elementsMap,
);
// Determine if point movement should happen and how much // Determine if point movement should happen and how much
let deltaX = 0; let deltaX = 0;
let deltaY = 0; let deltaY = 0;
if ( if (shouldRotateWithDiscreteAngle(event) && singlePointDragged) {
shouldRotateWithDiscreteAngle(event) &&
singlePointDragged &&
!hoveredElement &&
!element.startBinding &&
!element.endBinding
) {
const [width, height] = LinearElementEditor._getShiftLockedDelta( const [width, height] = LinearElementEditor._getShiftLockedDelta(
element, element,
elementsMap, elementsMap,
@@ -545,7 +523,7 @@ export class LinearElementEditor {
element, element,
elements, elements,
app, app,
event.shiftKey, shouldRotateWithDiscreteAngle(event) && singlePointDragged,
event.altKey, event.altKey,
); );
@@ -2092,7 +2070,7 @@ const pointDraggingUpdates = (
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
elements: readonly Ordered<NonDeletedExcalidrawElement>[], elements: readonly Ordered<NonDeletedExcalidrawElement>[],
app: AppClassProperties, app: AppClassProperties,
shiftKey: boolean, angleLocked: boolean,
altKey: boolean, altKey: boolean,
): { ): {
positions: PointsPositionUpdates; positions: PointsPositionUpdates;
@@ -2133,7 +2111,7 @@ const pointDraggingUpdates = (
app.state, app.state,
{ {
newArrow: !!app.state.newElement, newArrow: !!app.state.newElement,
shiftKey, angleLocked,
altKey, altKey,
}, },
); );
@@ -18,6 +18,7 @@ import {
KEYS, KEYS,
arrayToMap, arrayToMap,
invariant, invariant,
shouldRotateWithDiscreteAngle,
updateActiveTool, updateActiveTool,
} from "@excalidraw/common"; } from "@excalidraw/common";
import { isPathALoop } from "@excalidraw/element"; import { isPathALoop } from "@excalidraw/element";
@@ -105,6 +106,7 @@ export const actionFinalize = register<FormData>({
bindOrUnbindBindingElement(element, draggedPoints, scene, appState, { bindOrUnbindBindingElement(element, draggedPoints, scene, appState, {
newArrow, newArrow,
altKey: event.altKey, altKey: event.altKey,
angleLocked: shouldRotateWithDiscreteAngle(event),
}); });
} else if (isLineElement(element)) { } else if (isLineElement(element)) {
if ( if (
+6 -1
View File
@@ -8619,7 +8619,12 @@ class App extends React.Component<AppProps, AppState> {
]), ]),
this.scene, this.scene,
this.state, this.state,
{ newArrow: true, altKey: event.altKey, initialBinding: true }, {
newArrow: true,
altKey: event.altKey,
initialBinding: true,
angleLocked: shouldRotateWithDiscreteAngle(event.nativeEvent),
},
); );
} }