From 9e49c9254b4740613917cdcff5651d3e2b0c9d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20Tolm=C3=A1cs?= Date: Thu, 6 Feb 2025 14:45:49 +0100 Subject: [PATCH] fix: IFrame and elbow arrow interaction fix (#9101) --- packages/excalidraw/element/binding.ts | 50 ++++++++++++++++++++-- packages/excalidraw/scene/comparisons.ts | 53 ------------------------ packages/excalidraw/scene/index.ts | 2 - 3 files changed, 46 insertions(+), 59 deletions(-) diff --git a/packages/excalidraw/element/binding.ts b/packages/excalidraw/element/binding.ts index 5b45d982b1..fa5b461819 100644 --- a/packages/excalidraw/element/binding.ts +++ b/packages/excalidraw/element/binding.ts @@ -32,7 +32,6 @@ import type { Bounds } from "./bounds"; import { getCenterForBounds, getElementAbsoluteCoords } from "./bounds"; import type { AppState } from "../types"; import { isPointOnShape } from "../../utils/collision"; -import { getElementAtPosition } from "../scene"; import { isArrowElement, isBindableElement, @@ -79,7 +78,6 @@ import { clamp, } from "../../math"; import { segmentIntersectRectangleElement } from "../../utils/geometry/shape"; -import { getElementsAtPosition } from "../scene/comparisons"; export type SuggestedBinding = | NonDeleted @@ -568,7 +566,7 @@ export const getHoveredElementForBinding = ( ): NonDeleted | null => { if (considerAllElements) { let cullRest = false; - const candidateElements = getElementsAtPosition( + const candidateElements = getAllElementsAtPositionForBinding( elements, (element) => isBindableElement(element, false) && @@ -622,7 +620,7 @@ export const getHoveredElementForBinding = ( .pop() as NonDeleted; } - const hoveredElement = getElementAtPosition( + const hoveredElement = getElementAtPositionForBinding( elements, (element) => isBindableElement(element, false) && @@ -641,6 +639,50 @@ export const getHoveredElementForBinding = ( return hoveredElement as NonDeleted | null; }; +const getElementAtPositionForBinding = ( + elements: readonly NonDeletedExcalidrawElement[], + isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean, +) => { + let hitElement = null; + // 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 + // with higher z-index + for (let index = elements.length - 1; index >= 0; --index) { + const element = elements[index]; + if (element.isDeleted) { + continue; + } + if (isAtPositionFn(element)) { + hitElement = element; + break; + } + } + + return hitElement; +}; + +const getAllElementsAtPositionForBinding = ( + elements: readonly NonDeletedExcalidrawElement[], + isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean, +) => { + const elementsAtPosition: NonDeletedExcalidrawElement[] = []; + // 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 + // with higher z-index + for (let index = elements.length - 1; index >= 0; --index) { + const element = elements[index]; + if (element.isDeleted) { + continue; + } + + if (isAtPositionFn(element)) { + elementsAtPosition.push(element); + } + } + + return elementsAtPosition; +}; + const calculateFocusAndGap = ( linearElement: NonDeleted, hoveredElement: ExcalidrawBindableElement, diff --git a/packages/excalidraw/scene/comparisons.ts b/packages/excalidraw/scene/comparisons.ts index 47561fdf9f..9af3e66cb6 100644 --- a/packages/excalidraw/scene/comparisons.ts +++ b/packages/excalidraw/scene/comparisons.ts @@ -1,8 +1,3 @@ -import { isIframeElement } from "../element/typeChecks"; -import type { - ExcalidrawIframeElement, - NonDeletedExcalidrawElement, -} from "../element/types"; import type { ElementOrToolType } from "../types"; export const hasBackground = (type: ElementOrToolType) => @@ -47,51 +42,3 @@ export const canChangeRoundness = (type: ElementOrToolType) => export const toolIsArrow = (type: ElementOrToolType) => type === "arrow"; export const canHaveArrowheads = (type: ElementOrToolType) => type === "arrow"; - -export const getElementAtPosition = ( - elements: readonly NonDeletedExcalidrawElement[], - isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean, -) => { - let hitElement = null; - // 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 - // with higher z-index - for (let index = elements.length - 1; index >= 0; --index) { - const element = elements[index]; - if (element.isDeleted) { - continue; - } - if (isAtPositionFn(element)) { - hitElement = element; - break; - } - } - - return hitElement; -}; - -export const getElementsAtPosition = ( - elements: readonly NonDeletedExcalidrawElement[], - isAtPositionFn: (element: NonDeletedExcalidrawElement) => boolean, -) => { - const iframeLikes: ExcalidrawIframeElement[] = []; - const elementsAtPosition: NonDeletedExcalidrawElement[] = []; - // 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 - // with higher z-index - for (let index = elements.length - 1; index >= 0; --index) { - const element = elements[index]; - if (element.isDeleted) { - continue; - } - if (isIframeElement(element)) { - iframeLikes.push(element); - continue; - } - if (isAtPositionFn(element)) { - elementsAtPosition.push(element); - } - } - - return elementsAtPosition.concat(iframeLikes); -}; diff --git a/packages/excalidraw/scene/index.ts b/packages/excalidraw/scene/index.ts index 0f8b7ad857..1c0b795f1d 100644 --- a/packages/excalidraw/scene/index.ts +++ b/packages/excalidraw/scene/index.ts @@ -12,8 +12,6 @@ export { hasStrokeStyle, canHaveArrowheads, canChangeRoundness, - getElementAtPosition, - getElementsAtPosition, } from "./comparisons"; export { getNormalizedZoom,