fix: Add back transparency check for bindables

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