mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-12-23 22:49:31 -05:00
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>
This commit is contained in:
@@ -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 = (
|
||||
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
|
||||
arrow,
|
||||
draggingPoints,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
scene.getNonDeletedElementsMap(),
|
||||
scene.getNonDeletedElements(),
|
||||
appState,
|
||||
@@ -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 = (
|
||||
return getBindingStrategyForDraggingBindingElementEndpoints_simple(
|
||||
arrow,
|
||||
draggingPoints,
|
||||
screenPointerX,
|
||||
screenPointerY,
|
||||
elementsMap,
|
||||
elements,
|
||||
appState,
|
||||
@@ -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 = (
|
||||
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 = (
|
||||
bindOrUnbindBindingElement(
|
||||
arrow,
|
||||
new Map(), // No dragging points in this case
|
||||
Infinity,
|
||||
Infinity,
|
||||
scene,
|
||||
appState,
|
||||
);
|
||||
@@ -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,
|
||||
|
||||
@@ -343,6 +343,8 @@ export class LinearElementEditor {
|
||||
[idx],
|
||||
deltaX,
|
||||
deltaY,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
elementsMap,
|
||||
element,
|
||||
elements,
|
||||
@@ -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 {
|
||||
selectedPointsIndices,
|
||||
deltaX,
|
||||
deltaY,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
elementsMap,
|
||||
element,
|
||||
elements,
|
||||
@@ -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 = (
|
||||
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
|
||||
element,
|
||||
naiveDraggingPoints,
|
||||
scenePointerX,
|
||||
scenePointerY,
|
||||
elementsMap,
|
||||
elements,
|
||||
app.state,
|
||||
@@ -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 = (
|
||||
nextArrow.endBinding,
|
||||
endBindable,
|
||||
elementsMap,
|
||||
customIntersector,
|
||||
endCustomIntersector,
|
||||
) || nextArrow.points[nextArrow.points.length - 1]
|
||||
: nextArrow.points[nextArrow.points.length - 1];
|
||||
|
||||
@@ -2299,7 +2311,7 @@ const pointDraggingUpdates = (
|
||||
nextArrow.startBinding,
|
||||
startBindable,
|
||||
elementsMap,
|
||||
customIntersector,
|
||||
startCustomIntersector,
|
||||
) || nextArrow.points[0]
|
||||
: nextArrow.points[0];
|
||||
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -8617,6 +8617,8 @@ class App extends React.Component<AppProps, AppState> {
|
||||
},
|
||||
],
|
||||
]),
|
||||
point[0],
|
||||
point[1],
|
||||
this.scene,
|
||||
this.state,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user