fix: Add back transparency check for bindables

Signed-off-by: Mark Tolmacs <mark@lazycat.hu>
This commit is contained in:
Mark Tolmacs
2026-05-08 10:59:42 +00:00
parent d8e8d1aeda
commit 4e94b02375
5 changed files with 33 additions and 28 deletions
+1 -2
View File
@@ -10,7 +10,6 @@ import {
getBindingGap, getBindingGap,
getGlobalFixedPointForBindableElement, getGlobalFixedPointForBindableElement,
isBindingEnabled, isBindingEnabled,
maxBindingDistance_simple,
unbindBindingElement, unbindBindingElement,
updateBoundPoint, updateBoundPoint,
} from "../binding"; } from "../binding";
@@ -239,7 +238,7 @@ export const handleFocusPointDrag = (
point, point,
scene.getNonDeletedElements(), scene.getNonDeletedElements(),
elementsMap, elementsMap,
maxBindingDistance_simple(appState.zoom), appState.zoom,
); );
// Hovering a bindable element // Hovering a bindable element
+2 -2
View File
@@ -274,7 +274,7 @@ const bindingStrategyForElbowArrowEndpointDragging = (
globalPoint, globalPoint,
elements, elements,
elementsMap, elementsMap,
maxBindingDistance_simple(zoom), zoom,
); );
const current = hit const current = hit
@@ -705,7 +705,7 @@ const getBindingStrategyForDraggingBindingElementEndpoints_simple = (
globalPoint, globalPoint,
elements, elements,
elementsMap, elementsMap,
maxBindingDistance_simple(appState.zoom), appState.zoom,
); );
const pointInElement = const pointInElement =
hit && hit &&
+25 -17
View File
@@ -25,7 +25,7 @@ import type {
Radians, Radians,
} from "@excalidraw/math"; } from "@excalidraw/math";
import type { FrameNameBounds } from "@excalidraw/excalidraw/types"; import type { AppState, FrameNameBounds } from "@excalidraw/excalidraw/types";
import { isPathALoop } from "./utils"; import { isPathALoop } from "./utils";
import { import {
@@ -59,7 +59,7 @@ import { LinearElementEditor } from "./linearElementEditor";
import { distanceToElement } from "./distance"; import { distanceToElement } from "./distance";
import { getBindingGap } from "./binding"; import { getBindingGap, maxBindingDistance_simple } from "./binding";
import { hasBackground } from "./comparisons"; import { hasBackground } from "./comparisons";
@@ -253,7 +253,7 @@ export const hitElementBoundText = (
return isPointInElement(point, boundTextElement, elementsMap); return isPointInElement(point, boundTextElement, elementsMap);
}; };
const borderDistance = ( const bindableElementBorderDistanceIfClose = (
element: NonDeleted<ExcalidrawBindableElement>, element: NonDeleted<ExcalidrawBindableElement>,
point: GlobalPoint, point: GlobalPoint,
elementsMap: ElementsMap, elementsMap: ElementsMap,
@@ -339,12 +339,16 @@ export const getHoveredElementForBinding = (
point: Readonly<GlobalPoint>, point: Readonly<GlobalPoint>,
elements: readonly Ordered<NonDeletedExcalidrawElement>[], elements: readonly Ordered<NonDeletedExcalidrawElement>[],
elementsMap: NonDeletedSceneElementsMap, elementsMap: NonDeletedSceneElementsMap,
tolerance?: number, zoom?: AppState["zoom"],
): NonDeleted<ExcalidrawBindableElement> | null => { ): NonDeleted<ExcalidrawBindableElement> | null => {
const candidateElements: { type Candidate = {
element: NonDeleted<ExcalidrawBindableElement>; element: NonDeleted<ExcalidrawBindableElement>;
distance: number; distance: number;
}[] = []; overlapPercent?: number;
relativeArea?: number;
};
const candidates: Candidate[] = [];
for (let index = elements.length - 1; index >= 0; --index) { for (let index = elements.length - 1; index >= 0; --index) {
const element = elements[index]; const element = elements[index];
@@ -352,38 +356,42 @@ export const getHoveredElementForBinding = (
continue; continue;
} }
const distance = borderDistance( const maxDistance = maxBindingDistance_simple(zoom);
const distance = bindableElementBorderDistanceIfClose(
element, element,
point, point,
elementsMap, elementsMap,
tolerance ?? 0, maxDistance,
); );
const bindingGap = getBindingGap(element, arrow);
if (distance > -(tolerance ?? bindingGap)) { if (distance > -maxDistance) {
candidateElements.push({ element, distance }); candidates.push({ element, distance });
if (!isTransparent(element.backgroundColor) && distance >= 0) {
break;
}
} }
} }
if (candidateElements.length === 0) { if (candidates.length === 0) {
return null; return null;
} }
if (candidateElements.length === 1) { if (candidates.length === 1) {
return candidateElements[0].element; return candidates[0].element;
} }
const closestDistance = candidateElements.sort( const closestElements = candidates.sort(
(a, b) => Math.abs(a.distance) - Math.abs(b.distance), (a, b) => Math.abs(a.distance) - Math.abs(b.distance),
); );
const candidate = closestDistance[0]; const candidate = closestElements[0];
const [cx1, cy1, cx2, cy2] = getElementBounds(candidate.element, elementsMap); const [cx1, cy1, cx2, cy2] = getElementBounds(candidate.element, elementsMap);
const candidateArea = Math.max( const candidateArea = Math.max(
0.00001, 0.00001,
Math.abs(cx2 - cx1) * Math.abs(cy2 - cy1), Math.abs(cx2 - cx1) * Math.abs(cy2 - cy1),
); );
const overlaps = closestDistance const overlaps = closestElements
.map((c) => { .map((c) => {
if (c.element === candidate.element) { if (c.element === candidate.element) {
return { ...c, overlapPercent: 0, relativeArea: 1 }; return { ...c, overlapPercent: 0, relativeArea: 1 };
+1 -2
View File
@@ -30,7 +30,6 @@ import {
getHeadingForElbowArrowSnap, getHeadingForElbowArrowSnap,
getGlobalFixedPointForBindableElement, getGlobalFixedPointForBindableElement,
getBindingGap, getBindingGap,
maxBindingDistance_simple,
BASE_BINDING_GAP_ELBOW, BASE_BINDING_GAP_ELBOW,
} from "./binding"; } from "./binding";
import { distanceToElement } from "./distance"; import { distanceToElement } from "./distance";
@@ -2286,7 +2285,7 @@ const getHoveredElement = (
origPoint, origPoint,
elements, elements,
elementsMap, elementsMap,
maxBindingDistance_simple(zoom), zoom,
); );
}; };
+4 -5
View File
@@ -250,7 +250,6 @@ import {
getElementBounds, getElementBounds,
doBoundsIntersect, doBoundsIntersect,
isPointInElement, isPointInElement,
maxBindingDistance_simple,
convertToExcalidrawElements, convertToExcalidrawElements,
type ExcalidrawElementSkeleton, type ExcalidrawElementSkeleton,
getSnapOutlineMidPoint, getSnapOutlineMidPoint,
@@ -7092,7 +7091,7 @@ class App extends React.Component<AppProps, AppState> {
pointFrom<GlobalPoint>(scenePointerX, scenePointerY), pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
this.scene.getNonDeletedElements(), this.scene.getNonDeletedElements(),
elementsMap, elementsMap,
maxBindingDistance_simple(this.state.zoom), this.state.zoom,
); );
if (hoveredElement) { if (hoveredElement) {
this.setState({ this.setState({
@@ -7132,7 +7131,7 @@ class App extends React.Component<AppProps, AppState> {
pointFrom<GlobalPoint>(scenePointerX, scenePointerY), pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
this.scene.getNonDeletedElements(), this.scene.getNonDeletedElements(),
this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElementsMap(),
maxBindingDistance_simple(this.state.zoom), this.state.zoom,
); );
if (hoveredElement) { if (hoveredElement) {
this.actionManager.executeAction(actionFinalize, "ui", { this.actionManager.executeAction(actionFinalize, "ui", {
@@ -7284,7 +7283,7 @@ class App extends React.Component<AppProps, AppState> {
pointFrom<GlobalPoint>(scenePointerX, scenePointerY), pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
this.scene.getNonDeletedElements(), this.scene.getNonDeletedElements(),
this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElementsMap(),
maxBindingDistance_simple(this.state.zoom), this.state.zoom,
); );
const scenePointer = pointFrom<GlobalPoint>(scenePointerX, scenePointerY); const scenePointer = pointFrom<GlobalPoint>(scenePointerX, scenePointerY);
const elementsMap = this.scene.getNonDeletedElementsMap(); const elementsMap = this.scene.getNonDeletedElementsMap();
@@ -9893,7 +9892,7 @@ class App extends React.Component<AppProps, AppState> {
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y), pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
this.scene.getNonDeletedElements(), this.scene.getNonDeletedElements(),
elementsMap, elementsMap,
maxBindingDistance_simple(this.state.zoom), this.state.zoom,
); );
this.handleDelayedBindModeChange(element, hoveredElement); this.handleDelayedBindModeChange(element, hoveredElement);