Browse Source

fix: Angle snapping around bindable objects incorrectly resolves (#10501)

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
Co-authored-by: zsviczian <viczian.zsolt@gmail.com>
pull/10456/merge
Márk Tolmács 2 days ago committed by GitHub
parent
commit
f06484c6ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 31
      packages/element/src/binding.ts
  2. 20
      packages/element/src/linearElementEditor.ts
  3. 18
      packages/excalidraw/actions/actionFinalize.tsx
  4. 2
      packages/excalidraw/components/App.tsx

31
packages/element/src/binding.ts

@ -146,6 +146,8 @@ export const isBindingEnabled = (appState: AppState): boolean => { @@ -146,6 +146,8 @@ export const isBindingEnabled = (appState: AppState): boolean => {
export const bindOrUnbindBindingElement = (
arrow: NonDeleted<ExcalidrawArrowElement>,
draggingPoints: PointsPositionUpdates,
scenePointerX: number,
scenePointerY: number,
scene: Scene,
appState: AppState,
opts?: {
@ -158,6 +160,8 @@ export const bindOrUnbindBindingElement = ( @@ -158,6 +160,8 @@ export const bindOrUnbindBindingElement = (
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
arrow,
draggingPoints,
scenePointerX,
scenePointerY,
scene.getNonDeletedElementsMap(),
scene.getNonDeletedElements(),
appState,
@ -557,6 +561,8 @@ const bindingStrategyForSimpleArrowEndpointDragging_complex = ( @@ -557,6 +561,8 @@ const bindingStrategyForSimpleArrowEndpointDragging_complex = (
export const getBindingStrategyForDraggingBindingElementEndpoints = (
arrow: NonDeleted<ExcalidrawArrowElement>,
draggingPoints: PointsPositionUpdates,
screenPointerX: number,
screenPointerY: number,
elementsMap: NonDeletedSceneElementsMap,
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
appState: AppState,
@ -583,6 +589,8 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = ( @@ -583,6 +589,8 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
return getBindingStrategyForDraggingBindingElementEndpoints_simple(
arrow,
draggingPoints,
screenPointerX,
screenPointerY,
elementsMap,
elements,
appState,
@ -593,6 +601,8 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = ( @@ -593,6 +601,8 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
arrow: NonDeleted<ExcalidrawArrowElement>,
draggingPoints: PointsPositionUpdates,
scenePointerX: number,
scenePointerY: number,
elementsMap: NonDeletedSceneElementsMap,
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
appState: AppState,
@ -670,7 +680,15 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = ( @@ -670,7 +680,15 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
elementsMap,
(e) => maxBindingDistance_simple(appState.zoom),
);
const pointInElement = hit && isPointInElement(globalPoint, hit, elementsMap);
const pointInElement =
hit &&
(opts?.angleLocked
? isPointInElement(
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
hit,
elementsMap,
)
: isPointInElement(globalPoint, hit, elementsMap));
const otherBindableElement = otherBinding
? (elementsMap.get(
otherBinding.elementId,
@ -944,6 +962,8 @@ export const bindOrUnbindBindingElements = ( @@ -944,6 +962,8 @@ export const bindOrUnbindBindingElements = (
bindOrUnbindBindingElement(
arrow,
new Map(), // No dragging points in this case
Infinity,
Infinity,
scene,
appState,
);
@ -1146,7 +1166,14 @@ export const updateBindings = ( @@ -1146,7 +1166,14 @@ export const updateBindings = (
},
) => {
if (isArrowElement(latestElement)) {
bindOrUnbindBindingElement(latestElement, new Map(), scene, appState);
bindOrUnbindBindingElement(
latestElement,
new Map(),
Infinity,
Infinity,
scene,
appState,
);
} else {
updateBoundElements(latestElement, scene, {
...options,

20
packages/element/src/linearElementEditor.ts

@ -343,6 +343,8 @@ export class LinearElementEditor { @@ -343,6 +343,8 @@ export class LinearElementEditor {
[idx],
deltaX,
deltaY,
scenePointerX,
scenePointerY,
elementsMap,
element,
elements,
@ -498,7 +500,6 @@ export class LinearElementEditor { @@ -498,7 +500,6 @@ export class LinearElementEditor {
width + pivotPoint[0],
height + pivotPoint[1],
);
deltaX = target[0] - draggingPoint[0];
deltaY = target[1] - draggingPoint[1];
} else {
@ -519,6 +520,8 @@ export class LinearElementEditor { @@ -519,6 +520,8 @@ export class LinearElementEditor {
selectedPointsIndices,
deltaX,
deltaY,
scenePointerX,
scenePointerY,
elementsMap,
element,
elements,
@ -2066,6 +2069,8 @@ const pointDraggingUpdates = ( @@ -2066,6 +2069,8 @@ const pointDraggingUpdates = (
selectedPointsIndices: readonly number[],
deltaX: number,
deltaY: number,
scenePointerX: number,
scenePointerY: number,
elementsMap: NonDeletedSceneElementsMap,
element: NonDeleted<ExcalidrawLinearElement>,
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
@ -2106,6 +2111,8 @@ const pointDraggingUpdates = ( @@ -2106,6 +2111,8 @@ const pointDraggingUpdates = (
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
element,
naiveDraggingPoints,
scenePointerX,
scenePointerY,
elementsMap,
elements,
app.state,
@ -2228,10 +2235,15 @@ const pointDraggingUpdates = ( @@ -2228,10 +2235,15 @@ const pointDraggingUpdates = (
// We need to use a custom intersector to ensure that if there is a big "jump"
// in the arrow's position, we can position it with outline avoidance
// pixel-perfectly and avoid "dancing" arrows.
const customIntersector =
// NOTE: Direction matters here, so we create two intersectors
const startCustomIntersector =
start.focusPoint && end.focusPoint
? lineSegment(start.focusPoint, end.focusPoint)
: undefined;
const endCustomIntersector =
start.focusPoint && end.focusPoint
? lineSegment(end.focusPoint, start.focusPoint)
: undefined;
// Needed to handle a special case where an existing arrow is dragged over
// the same element it is bound to on the other side
@ -2268,7 +2280,7 @@ const pointDraggingUpdates = ( @@ -2268,7 +2280,7 @@ const pointDraggingUpdates = (
nextArrow.endBinding,
endBindable,
elementsMap,
customIntersector,
endCustomIntersector,
) || nextArrow.points[nextArrow.points.length - 1]
: nextArrow.points[nextArrow.points.length - 1];
@ -2299,7 +2311,7 @@ const pointDraggingUpdates = ( @@ -2299,7 +2311,7 @@ const pointDraggingUpdates = (
nextArrow.startBinding,
startBindable,
elementsMap,
customIntersector,
startCustomIntersector,
) || nextArrow.points[0]
: nextArrow.points[0];

18
packages/excalidraw/actions/actionFinalize.tsx

@ -103,11 +103,19 @@ export const actionFinalize = register<FormData>({ @@ -103,11 +103,19 @@ export const actionFinalize = register<FormData>({
return map;
}, new Map()) ?? new Map();
bindOrUnbindBindingElement(element, draggedPoints, scene, appState, {
newArrow,
altKey: event.altKey,
angleLocked: shouldRotateWithDiscreteAngle(event),
});
bindOrUnbindBindingElement(
element,
draggedPoints,
sceneCoords.x,
sceneCoords.y,
scene,
appState,
{
newArrow,
altKey: event.altKey,
angleLocked: shouldRotateWithDiscreteAngle(event),
},
);
} else if (isLineElement(element)) {
if (
appState.selectedLinearElement?.isEditing &&

2
packages/excalidraw/components/App.tsx

@ -8617,6 +8617,8 @@ class App extends React.Component<AppProps, AppState> { @@ -8617,6 +8617,8 @@ class App extends React.Component<AppProps, AppState> {
},
],
]),
point[0],
point[1],
this.scene,
this.state,
{

Loading…
Cancel
Save