mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-26 02:40:07 +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 { KEYS, arrayToMap, invariant, isTransparent } from "@excalidraw/common";
|
||||||
|
|
||||||
import { isElementInsideBBox } from "@excalidraw/utils";
|
|
||||||
import {
|
import {
|
||||||
lineSegment,
|
lineSegment,
|
||||||
pointFrom,
|
pointFrom,
|
||||||
@@ -31,6 +30,7 @@ import {
|
|||||||
getAllHoveredElementAtPoint,
|
getAllHoveredElementAtPoint,
|
||||||
getHoveredElementForBinding,
|
getHoveredElementForBinding,
|
||||||
intersectElementWithLineSegment,
|
intersectElementWithLineSegment,
|
||||||
|
isBindableElementInsideOtherBindable,
|
||||||
isPointInElement,
|
isPointInElement,
|
||||||
} from "./collision";
|
} from "./collision";
|
||||||
import { distanceToElement } from "./distance";
|
import { distanceToElement } from "./distance";
|
||||||
@@ -351,7 +351,7 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
|||||||
// We are hovering another element with the end point
|
// We are hovering another element with the end point
|
||||||
const isNested =
|
const isNested =
|
||||||
hit &&
|
hit &&
|
||||||
isElementInsideBBox(otherElement, getElementBounds(hit, elementsMap));
|
isBindableElementInsideOtherBindable(otherElement, hit, elementsMap);
|
||||||
let current: BindingStrategy;
|
let current: BindingStrategy;
|
||||||
if (hit) {
|
if (hit) {
|
||||||
const isInsideBinding =
|
const isInsideBinding =
|
||||||
@@ -424,7 +424,7 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
|
|||||||
const isNested =
|
const isNested =
|
||||||
hit &&
|
hit &&
|
||||||
oppositeElement &&
|
oppositeElement &&
|
||||||
isElementInsideBBox(oppositeElement, getElementBounds(hit, elementsMap));
|
isBindableElementInsideOtherBindable(oppositeElement, hit, elementsMap);
|
||||||
|
|
||||||
// If the global bind mode is in free binding mode, just bind
|
// If the global bind mode is in free binding mode, just bind
|
||||||
// where the pointer is and keep the other end intact
|
// where the pointer is and keep the other end intact
|
||||||
@@ -1267,7 +1267,7 @@ export const updateBoundPoint = (
|
|||||||
compareElementArea(bindableElement, otherBindableElement) < 0;
|
compareElementArea(bindableElement, otherBindableElement) < 0;
|
||||||
const isIntersecting = otherBounds && doBoundsIntersect(bounds, otherBounds);
|
const isIntersecting = otherBounds && doBoundsIntersect(bounds, otherBounds);
|
||||||
// const isNested =
|
// const isNested =
|
||||||
// otherBindableElement && isElementInsideBBox(otherBindableElement, bounds);
|
// otherBindableElement && isBindableElementInsideOtherBindable(otherBindableElement, bindableElement);
|
||||||
const isNested = isIntersecting && isLargerThanOther;
|
const isNested = isIntersecting && isLargerThanOther;
|
||||||
|
|
||||||
const maybeOutlineGlobal =
|
const maybeOutlineGlobal =
|
||||||
|
@@ -34,6 +34,7 @@ import {
|
|||||||
elementCenterPoint,
|
elementCenterPoint,
|
||||||
getCenterForBounds,
|
getCenterForBounds,
|
||||||
getCubicBezierCurveBound,
|
getCubicBezierCurveBound,
|
||||||
|
getDiamondPoints,
|
||||||
getElementBounds,
|
getElementBounds,
|
||||||
} from "./bounds";
|
} from "./bounds";
|
||||||
import {
|
import {
|
||||||
@@ -657,3 +658,57 @@ export const isPointInElement = (
|
|||||||
|
|
||||||
return intersections.length % 2 === 1;
|
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