mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-25 18:31:15 +02:00
fix:More precise element nesting check
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { KEYS, arrayToMap, invariant, isTransparent } from "@excalidraw/common";
|
||||
|
||||
import { isElementInsideBBox } from "@excalidraw/utils";
|
||||
import {
|
||||
lineSegment,
|
||||
pointFrom,
|
||||
@@ -31,6 +30,7 @@ import {
|
||||
getAllHoveredElementAtPoint,
|
||||
getHoveredElementForBinding,
|
||||
intersectElementWithLineSegment,
|
||||
isBindableElementInsideOtherBindable,
|
||||
isPointInElement,
|
||||
} from "./collision";
|
||||
import { distanceToElement } from "./distance";
|
||||
@@ -351,7 +351,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
// We are hovering another element with the end point
|
||||
const isNested =
|
||||
hit &&
|
||||
isElementInsideBBox(otherElement, getElementBounds(hit, elementsMap));
|
||||
isBindableElementInsideOtherBindable(otherElement, hit, elementsMap);
|
||||
let current: BindingStrategy;
|
||||
if (hit) {
|
||||
const isInsideBinding =
|
||||
@@ -424,7 +424,7 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
|
||||
const isNested =
|
||||
hit &&
|
||||
oppositeElement &&
|
||||
isElementInsideBBox(oppositeElement, getElementBounds(hit, elementsMap));
|
||||
isBindableElementInsideOtherBindable(oppositeElement, hit, elementsMap);
|
||||
|
||||
// If the global bind mode is in free binding mode, just bind
|
||||
// where the pointer is and keep the other end intact
|
||||
@@ -1267,7 +1267,7 @@ export const updateBoundPoint = (
|
||||
compareElementArea(bindableElement, otherBindableElement) < 0;
|
||||
const isIntersecting = otherBounds && doBoundsIntersect(bounds, otherBounds);
|
||||
// const isNested =
|
||||
// otherBindableElement && isElementInsideBBox(otherBindableElement, bounds);
|
||||
// otherBindableElement && isBindableElementInsideOtherBindable(otherBindableElement, bindableElement);
|
||||
const isNested = isIntersecting && isLargerThanOther;
|
||||
|
||||
const maybeOutlineGlobal =
|
||||
|
@@ -34,6 +34,7 @@ import {
|
||||
elementCenterPoint,
|
||||
getCenterForBounds,
|
||||
getCubicBezierCurveBound,
|
||||
getDiamondPoints,
|
||||
getElementBounds,
|
||||
} from "./bounds";
|
||||
import {
|
||||
@@ -657,3 +658,57 @@ export const isPointInElement = (
|
||||
|
||||
return intersections.length % 2 === 1;
|
||||
};
|
||||
|
||||
export const isBindableElementInsideOtherBindable = (
|
||||
innerElement: ExcalidrawBindableElement,
|
||||
outerElement: ExcalidrawBindableElement,
|
||||
elementsMap: ElementsMap,
|
||||
): boolean => {
|
||||
// Get corner points of the inner element based on its type
|
||||
const getCornerPoints = (element: ExcalidrawElement): GlobalPoint[] => {
|
||||
const { x, y, width, height, angle } = element;
|
||||
const center = elementCenterPoint(element, elementsMap);
|
||||
|
||||
if (element.type === "diamond") {
|
||||
// Diamond has 4 corner points at the middle of each side
|
||||
const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] =
|
||||
getDiamondPoints(element);
|
||||
const corners: GlobalPoint[] = [
|
||||
pointFrom(x + topX, y + topY), // top
|
||||
pointFrom(x + rightX, y + rightY), // right
|
||||
pointFrom(x + bottomX, y + bottomY), // bottom
|
||||
pointFrom(x + leftX, y + leftY), // left
|
||||
];
|
||||
return corners.map((corner) => pointRotateRads(corner, center, angle));
|
||||
}
|
||||
if (element.type === "ellipse") {
|
||||
// For ellipse, test points at the extremes (top, right, bottom, left)
|
||||
const cx = x + width / 2;
|
||||
const cy = y + height / 2;
|
||||
const rx = width / 2;
|
||||
const ry = height / 2;
|
||||
const corners: GlobalPoint[] = [
|
||||
pointFrom(cx, cy - ry), // top
|
||||
pointFrom(cx + rx, cy), // right
|
||||
pointFrom(cx, cy + ry), // bottom
|
||||
pointFrom(cx - rx, cy), // left
|
||||
];
|
||||
return corners.map((corner) => pointRotateRads(corner, center, angle));
|
||||
}
|
||||
// Rectangle and other rectangular shapes (image, text, etc.)
|
||||
const corners: GlobalPoint[] = [
|
||||
pointFrom(x, y), // top-left
|
||||
pointFrom(x + width, y), // top-right
|
||||
pointFrom(x + width, y + height), // bottom-right
|
||||
pointFrom(x, y + height), // bottom-left
|
||||
];
|
||||
return corners.map((corner) => pointRotateRads(corner, center, angle));
|
||||
};
|
||||
|
||||
const innerCorners = getCornerPoints(innerElement);
|
||||
|
||||
// Check if all corner points of the inner element are inside the outer element
|
||||
return innerCorners.every((corner) =>
|
||||
isPointInElement(corner, outerElement, elementsMap),
|
||||
);
|
||||
};
|
||||
|
Reference in New Issue
Block a user