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:
co-authored by
zsviczian
parent
bf4c65f483
commit
f06484c6ab
@@ -146,6 +146,8 @@ export const isBindingEnabled = (appState: AppState): boolean => {
|
|||||||
export const bindOrUnbindBindingElement = (
|
export const bindOrUnbindBindingElement = (
|
||||||
arrow: NonDeleted<ExcalidrawArrowElement>,
|
arrow: NonDeleted<ExcalidrawArrowElement>,
|
||||||
draggingPoints: PointsPositionUpdates,
|
draggingPoints: PointsPositionUpdates,
|
||||||
|
scenePointerX: number,
|
||||||
|
scenePointerY: number,
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
opts?: {
|
opts?: {
|
||||||
@@ -158,6 +160,8 @@ export const bindOrUnbindBindingElement = (
|
|||||||
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
|
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
|
||||||
arrow,
|
arrow,
|
||||||
draggingPoints,
|
draggingPoints,
|
||||||
|
scenePointerX,
|
||||||
|
scenePointerY,
|
||||||
scene.getNonDeletedElementsMap(),
|
scene.getNonDeletedElementsMap(),
|
||||||
scene.getNonDeletedElements(),
|
scene.getNonDeletedElements(),
|
||||||
appState,
|
appState,
|
||||||
@@ -557,6 +561,8 @@ const bindingStrategyForSimpleArrowEndpointDragging_complex = (
|
|||||||
export const getBindingStrategyForDraggingBindingElementEndpoints = (
|
export const getBindingStrategyForDraggingBindingElementEndpoints = (
|
||||||
arrow: NonDeleted<ExcalidrawArrowElement>,
|
arrow: NonDeleted<ExcalidrawArrowElement>,
|
||||||
draggingPoints: PointsPositionUpdates,
|
draggingPoints: PointsPositionUpdates,
|
||||||
|
screenPointerX: number,
|
||||||
|
screenPointerY: number,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
@@ -583,6 +589,8 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
|
|||||||
return getBindingStrategyForDraggingBindingElementEndpoints_simple(
|
return getBindingStrategyForDraggingBindingElementEndpoints_simple(
|
||||||
arrow,
|
arrow,
|
||||||
draggingPoints,
|
draggingPoints,
|
||||||
|
screenPointerX,
|
||||||
|
screenPointerY,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
appState,
|
appState,
|
||||||
@@ -593,6 +601,8 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
|
|||||||
const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
||||||
arrow: NonDeleted<ExcalidrawArrowElement>,
|
arrow: NonDeleted<ExcalidrawArrowElement>,
|
||||||
draggingPoints: PointsPositionUpdates,
|
draggingPoints: PointsPositionUpdates,
|
||||||
|
scenePointerX: number,
|
||||||
|
scenePointerY: number,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
@@ -670,7 +680,15 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
|
|||||||
elementsMap,
|
elementsMap,
|
||||||
(e) => maxBindingDistance_simple(appState.zoom),
|
(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
|
const otherBindableElement = otherBinding
|
||||||
? (elementsMap.get(
|
? (elementsMap.get(
|
||||||
otherBinding.elementId,
|
otherBinding.elementId,
|
||||||
@@ -944,6 +962,8 @@ export const bindOrUnbindBindingElements = (
|
|||||||
bindOrUnbindBindingElement(
|
bindOrUnbindBindingElement(
|
||||||
arrow,
|
arrow,
|
||||||
new Map(), // No dragging points in this case
|
new Map(), // No dragging points in this case
|
||||||
|
Infinity,
|
||||||
|
Infinity,
|
||||||
scene,
|
scene,
|
||||||
appState,
|
appState,
|
||||||
);
|
);
|
||||||
@@ -1146,7 +1166,14 @@ export const updateBindings = (
|
|||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
if (isArrowElement(latestElement)) {
|
if (isArrowElement(latestElement)) {
|
||||||
bindOrUnbindBindingElement(latestElement, new Map(), scene, appState);
|
bindOrUnbindBindingElement(
|
||||||
|
latestElement,
|
||||||
|
new Map(),
|
||||||
|
Infinity,
|
||||||
|
Infinity,
|
||||||
|
scene,
|
||||||
|
appState,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
updateBoundElements(latestElement, scene, {
|
updateBoundElements(latestElement, scene, {
|
||||||
...options,
|
...options,
|
||||||
|
|||||||
@@ -343,6 +343,8 @@ export class LinearElementEditor {
|
|||||||
[idx],
|
[idx],
|
||||||
deltaX,
|
deltaX,
|
||||||
deltaY,
|
deltaY,
|
||||||
|
scenePointerX,
|
||||||
|
scenePointerY,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
element,
|
element,
|
||||||
elements,
|
elements,
|
||||||
@@ -498,7 +500,6 @@ export class LinearElementEditor {
|
|||||||
width + pivotPoint[0],
|
width + pivotPoint[0],
|
||||||
height + pivotPoint[1],
|
height + pivotPoint[1],
|
||||||
);
|
);
|
||||||
|
|
||||||
deltaX = target[0] - draggingPoint[0];
|
deltaX = target[0] - draggingPoint[0];
|
||||||
deltaY = target[1] - draggingPoint[1];
|
deltaY = target[1] - draggingPoint[1];
|
||||||
} else {
|
} else {
|
||||||
@@ -519,6 +520,8 @@ export class LinearElementEditor {
|
|||||||
selectedPointsIndices,
|
selectedPointsIndices,
|
||||||
deltaX,
|
deltaX,
|
||||||
deltaY,
|
deltaY,
|
||||||
|
scenePointerX,
|
||||||
|
scenePointerY,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
element,
|
element,
|
||||||
elements,
|
elements,
|
||||||
@@ -2066,6 +2069,8 @@ const pointDraggingUpdates = (
|
|||||||
selectedPointsIndices: readonly number[],
|
selectedPointsIndices: readonly number[],
|
||||||
deltaX: number,
|
deltaX: number,
|
||||||
deltaY: number,
|
deltaY: number,
|
||||||
|
scenePointerX: number,
|
||||||
|
scenePointerY: number,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
element: NonDeleted<ExcalidrawLinearElement>,
|
element: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||||
@@ -2106,6 +2111,8 @@ const pointDraggingUpdates = (
|
|||||||
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
|
const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
|
||||||
element,
|
element,
|
||||||
naiveDraggingPoints,
|
naiveDraggingPoints,
|
||||||
|
scenePointerX,
|
||||||
|
scenePointerY,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
app.state,
|
app.state,
|
||||||
@@ -2228,10 +2235,15 @@ const pointDraggingUpdates = (
|
|||||||
// We need to use a custom intersector to ensure that if there is a big "jump"
|
// 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
|
// in the arrow's position, we can position it with outline avoidance
|
||||||
// pixel-perfectly and avoid "dancing" arrows.
|
// pixel-perfectly and avoid "dancing" arrows.
|
||||||
const customIntersector =
|
// NOTE: Direction matters here, so we create two intersectors
|
||||||
|
const startCustomIntersector =
|
||||||
start.focusPoint && end.focusPoint
|
start.focusPoint && end.focusPoint
|
||||||
? lineSegment(start.focusPoint, end.focusPoint)
|
? lineSegment(start.focusPoint, end.focusPoint)
|
||||||
: undefined;
|
: 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
|
// Needed to handle a special case where an existing arrow is dragged over
|
||||||
// the same element it is bound to on the other side
|
// the same element it is bound to on the other side
|
||||||
@@ -2268,7 +2280,7 @@ const pointDraggingUpdates = (
|
|||||||
nextArrow.endBinding,
|
nextArrow.endBinding,
|
||||||
endBindable,
|
endBindable,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
customIntersector,
|
endCustomIntersector,
|
||||||
) || nextArrow.points[nextArrow.points.length - 1]
|
) || nextArrow.points[nextArrow.points.length - 1]
|
||||||
: nextArrow.points[nextArrow.points.length - 1];
|
: nextArrow.points[nextArrow.points.length - 1];
|
||||||
|
|
||||||
@@ -2299,7 +2311,7 @@ const pointDraggingUpdates = (
|
|||||||
nextArrow.startBinding,
|
nextArrow.startBinding,
|
||||||
startBindable,
|
startBindable,
|
||||||
elementsMap,
|
elementsMap,
|
||||||
customIntersector,
|
startCustomIntersector,
|
||||||
) || nextArrow.points[0]
|
) || nextArrow.points[0]
|
||||||
: nextArrow.points[0];
|
: nextArrow.points[0];
|
||||||
|
|
||||||
|
|||||||
@@ -103,11 +103,19 @@ export const actionFinalize = register<FormData>({
|
|||||||
return map;
|
return map;
|
||||||
}, new Map()) ?? new Map();
|
}, new Map()) ?? new Map();
|
||||||
|
|
||||||
bindOrUnbindBindingElement(element, draggedPoints, scene, appState, {
|
bindOrUnbindBindingElement(
|
||||||
newArrow,
|
element,
|
||||||
altKey: event.altKey,
|
draggedPoints,
|
||||||
angleLocked: shouldRotateWithDiscreteAngle(event),
|
sceneCoords.x,
|
||||||
});
|
sceneCoords.y,
|
||||||
|
scene,
|
||||||
|
appState,
|
||||||
|
{
|
||||||
|
newArrow,
|
||||||
|
altKey: event.altKey,
|
||||||
|
angleLocked: shouldRotateWithDiscreteAngle(event),
|
||||||
|
},
|
||||||
|
);
|
||||||
} else if (isLineElement(element)) {
|
} else if (isLineElement(element)) {
|
||||||
if (
|
if (
|
||||||
appState.selectedLinearElement?.isEditing &&
|
appState.selectedLinearElement?.isEditing &&
|
||||||
|
|||||||
@@ -8617,6 +8617,8 @@ class App extends React.Component<AppProps, AppState> {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
]),
|
]),
|
||||||
|
point[0],
|
||||||
|
point[1],
|
||||||
this.scene,
|
this.scene,
|
||||||
this.state,
|
this.state,
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user