mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-21 00:10:33 +02:00
feat: Nested shapes handling
Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
@@ -32,6 +32,7 @@ import {
|
||||
getElementBounds,
|
||||
} from "./bounds";
|
||||
import {
|
||||
getAllHoveredElementAtPoint,
|
||||
getHoveredElementForBinding,
|
||||
hitElementItself,
|
||||
intersectElementWithLineSegment,
|
||||
@@ -301,6 +302,54 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
};
|
||||
}
|
||||
|
||||
// Check and handle nested shapes
|
||||
if (arrow.startBinding) {
|
||||
const otherElement = elementsMap.get(
|
||||
arrow.startBinding.elementId,
|
||||
) as ExcalidrawBindableElement;
|
||||
invariant(otherElement, "Other element must be in the elements map");
|
||||
const startFocusElements = getAllHoveredElementAtPoint(
|
||||
getGlobalFixedPointForBindableElement(
|
||||
arrow.startBinding.fixedPoint,
|
||||
otherElement,
|
||||
elementsMap,
|
||||
),
|
||||
elements,
|
||||
elementsMap,
|
||||
);
|
||||
const startHoverElements = getAllHoveredElementAtPoint(
|
||||
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
arrow,
|
||||
0,
|
||||
elementsMap,
|
||||
),
|
||||
elements,
|
||||
elementsMap,
|
||||
);
|
||||
|
||||
if (
|
||||
hit &&
|
||||
otherElement.id !== hit.id &&
|
||||
(startHoverElements.find((el) => el.id === hit.id) ||
|
||||
startFocusElements.find((el) => el.id === hit.id))
|
||||
) {
|
||||
return {
|
||||
start: isMultiPoint
|
||||
? { mode: undefined }
|
||||
: {
|
||||
mode: "orbit",
|
||||
element: otherElement,
|
||||
focusPoint: snapToCenter(
|
||||
otherElement,
|
||||
elementsMap,
|
||||
origin ?? pointFrom<GlobalPoint>(arrow.x, arrow.y),
|
||||
),
|
||||
},
|
||||
end: { mode: "inside", element: hit, focusPoint: point },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Inside -> outside binding
|
||||
if (arrow.startBinding && arrow.startBinding.elementId !== hit?.id) {
|
||||
const otherElement = elementsMap.get(
|
||||
|
@@ -238,12 +238,12 @@ const bindingBorderTest = (
|
||||
: intersections.length > 0 && distance <= t;
|
||||
};
|
||||
|
||||
export const getHoveredElementForBinding = (
|
||||
export const getAllHoveredElementAtPoint = (
|
||||
point: Readonly<GlobalPoint>,
|
||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
toleranceFn?: (element: ExcalidrawBindableElement) => number,
|
||||
): NonDeleted<ExcalidrawBindableElement> | null => {
|
||||
): NonDeleted<ExcalidrawBindableElement>[] => {
|
||||
const candidateElements: NonDeleted<ExcalidrawBindableElement>[] = [];
|
||||
// We need to to hit testing from front (end of the array) to back (beginning of the array)
|
||||
// because array is ordered from lower z-index to highest and we want element z-index
|
||||
@@ -264,6 +264,22 @@ export const getHoveredElementForBinding = (
|
||||
}
|
||||
}
|
||||
|
||||
return candidateElements;
|
||||
};
|
||||
|
||||
export const getHoveredElementForBinding = (
|
||||
point: Readonly<GlobalPoint>,
|
||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
toleranceFn?: (element: ExcalidrawBindableElement) => number,
|
||||
): NonDeleted<ExcalidrawBindableElement> | null => {
|
||||
const candidateElements = getAllHoveredElementAtPoint(
|
||||
point,
|
||||
elements,
|
||||
elementsMap,
|
||||
toleranceFn,
|
||||
);
|
||||
|
||||
if (!candidateElements || candidateElements.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
Reference in New Issue
Block a user