fix: IFrame and elbow arrow interaction fix (#9101)

This commit is contained in:
Márk Tolmács 2025-02-06 14:45:49 +01:00 committed by GitHub
parent b0c8c5f7a7
commit 9e49c9254b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 46 additions and 59 deletions

View file

@ -32,7 +32,6 @@ import type { Bounds } from "./bounds";
import { getCenterForBounds, getElementAbsoluteCoords } from "./bounds"; import { getCenterForBounds, getElementAbsoluteCoords } from "./bounds";
import type { AppState } from "../types"; import type { AppState } from "../types";
import { isPointOnShape } from "../../utils/collision"; import { isPointOnShape } from "../../utils/collision";
import { getElementAtPosition } from "../scene";
import { import {
isArrowElement, isArrowElement,
isBindableElement, isBindableElement,
@ -79,7 +78,6 @@ import {
clamp, clamp,
} from "../../math"; } from "../../math";
import { segmentIntersectRectangleElement } from "../../utils/geometry/shape"; import { segmentIntersectRectangleElement } from "../../utils/geometry/shape";
import { getElementsAtPosition } from "../scene/comparisons";
export type SuggestedBinding = export type SuggestedBinding =
| NonDeleted<ExcalidrawBindableElement> | NonDeleted<ExcalidrawBindableElement>
@ -568,7 +566,7 @@ export const getHoveredElementForBinding = (
): NonDeleted<ExcalidrawBindableElement> | null => { ): NonDeleted<ExcalidrawBindableElement> | null => {
if (considerAllElements) { if (considerAllElements) {
let cullRest = false; let cullRest = false;
const candidateElements = getElementsAtPosition( const candidateElements = getAllElementsAtPositionForBinding(
elements, elements,
(element) => (element) =>
isBindableElement(element, false) && isBindableElement(element, false) &&
@ -622,7 +620,7 @@ export const getHoveredElementForBinding = (
.pop() as NonDeleted<ExcalidrawBindableElement>; .pop() as NonDeleted<ExcalidrawBindableElement>;
} }
const hoveredElement = getElementAtPosition( const hoveredElement = getElementAtPositionForBinding(
elements, elements,
(element) => (element) =>
isBindableElement(element, false) && isBindableElement(element, false) &&
@ -641,6 +639,50 @@ export const getHoveredElementForBinding = (
return hoveredElement as NonDeleted<ExcalidrawBindableElement> | null; return hoveredElement as NonDeleted<ExcalidrawBindableElement> | 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 = ( const calculateFocusAndGap = (
linearElement: NonDeleted<ExcalidrawLinearElement>, linearElement: NonDeleted<ExcalidrawLinearElement>,
hoveredElement: ExcalidrawBindableElement, hoveredElement: ExcalidrawBindableElement,

View file

@ -1,8 +1,3 @@
import { isIframeElement } from "../element/typeChecks";
import type {
ExcalidrawIframeElement,
NonDeletedExcalidrawElement,
} from "../element/types";
import type { ElementOrToolType } from "../types"; import type { ElementOrToolType } from "../types";
export const hasBackground = (type: ElementOrToolType) => export const hasBackground = (type: ElementOrToolType) =>
@ -47,51 +42,3 @@ export const canChangeRoundness = (type: ElementOrToolType) =>
export const toolIsArrow = (type: ElementOrToolType) => type === "arrow"; export const toolIsArrow = (type: ElementOrToolType) => type === "arrow";
export const canHaveArrowheads = (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);
};

View file

@ -12,8 +12,6 @@ export {
hasStrokeStyle, hasStrokeStyle,
canHaveArrowheads, canHaveArrowheads,
canChangeRoundness, canChangeRoundness,
getElementAtPosition,
getElementsAtPosition,
} from "./comparisons"; } from "./comparisons";
export { export {
getNormalizedZoom, getNormalizedZoom,