mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-12 20:10:09 +02:00
@@ -35,10 +35,8 @@ import {
|
||||
import {
|
||||
bindingBorderTest,
|
||||
getHoveredElementForBinding,
|
||||
getHoveredElementForBindingAndIfItsPrecise,
|
||||
hitElementItself,
|
||||
intersectElementWithLineSegment,
|
||||
maxBindingDistanceFromOutline,
|
||||
} from "./collision";
|
||||
import { distanceToElement } from "./distance";
|
||||
import {
|
||||
@@ -114,7 +112,6 @@ export type BindingStrategy =
|
||||
};
|
||||
|
||||
export const FIXED_BINDING_DISTANCE = 5;
|
||||
export const BINDING_HIGHLIGHT_THICKNESS = 10;
|
||||
|
||||
export const shouldEnableBindingForPointerEvent = (
|
||||
event: React.PointerEvent<HTMLElement>,
|
||||
@@ -202,7 +199,6 @@ const bindOrUnbindBindingElementEdge = (
|
||||
const getOriginalBindingsIfStillCloseToBindingEnds = (
|
||||
linearElement: NonDeleted<ExcalidrawArrowElement>,
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
zoom?: AppState["zoom"],
|
||||
): (NonDeleted<ExcalidrawElement> | null)[] =>
|
||||
(["start", "end"] as const).map((edge) => {
|
||||
const coors = tupleToCoors(
|
||||
@@ -224,7 +220,6 @@ const getOriginalBindingsIfStillCloseToBindingEnds = (
|
||||
element,
|
||||
pointFrom<GlobalPoint>(coors.x, coors.y),
|
||||
elementsMap,
|
||||
zoom,
|
||||
)
|
||||
) {
|
||||
return element;
|
||||
@@ -328,30 +323,16 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
draggingPoints.get(startDragged ? startIdx : endIdx)!.point,
|
||||
elementsMap,
|
||||
);
|
||||
const { hovered, hit } = getHoveredElementForBindingAndIfItsPrecise(
|
||||
point,
|
||||
elements,
|
||||
elementsMap,
|
||||
appState.zoom,
|
||||
true,
|
||||
);
|
||||
const hit = getHoveredElementForBinding(point, elements, elementsMap);
|
||||
|
||||
// With new arrows this handles the binding at arrow creation
|
||||
if (startDragged) {
|
||||
if (hovered) {
|
||||
if (hit) {
|
||||
start = {
|
||||
element: hovered,
|
||||
mode: "inside",
|
||||
focusPoint: point,
|
||||
};
|
||||
} else {
|
||||
start = {
|
||||
element: hovered,
|
||||
mode: "orbit",
|
||||
focusPoint: point,
|
||||
};
|
||||
}
|
||||
if (hit) {
|
||||
start = {
|
||||
element: hit,
|
||||
mode: "inside",
|
||||
focusPoint: point,
|
||||
};
|
||||
} else {
|
||||
start = { mode: null };
|
||||
}
|
||||
@@ -365,41 +346,24 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
appState?.selectedLinearElement?.pointerDownState.arrowOriginalStartPoint;
|
||||
|
||||
// Inside -> inside binding
|
||||
if (hovered && hit && arrow.startBinding?.elementId === hovered.id) {
|
||||
if (hit && arrow.startBinding?.elementId === hit.id) {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
hovered.x + hovered.width / 2,
|
||||
hovered.y + hovered.height / 2,
|
||||
hit.x + hit.width / 2,
|
||||
hit.y + hit.height / 2,
|
||||
);
|
||||
|
||||
return {
|
||||
start: {
|
||||
mode: "inside",
|
||||
element: hovered,
|
||||
element: hit,
|
||||
focusPoint: arrowOriginalStartPoint ?? center,
|
||||
},
|
||||
end: { mode: "inside", element: hovered, focusPoint: point },
|
||||
};
|
||||
}
|
||||
|
||||
// Inside -> orbit binding
|
||||
if (hovered && !hit && arrow.startBinding?.elementId === hovered.id) {
|
||||
const center = pointFrom<GlobalPoint>(
|
||||
hovered.x + hovered.width / 2,
|
||||
hovered.y + hovered.height / 2,
|
||||
);
|
||||
|
||||
return {
|
||||
start: {
|
||||
mode: globalBindMode === "inside" ? "inside" : "orbit",
|
||||
element: hovered,
|
||||
focusPoint: arrowOriginalStartPoint ?? center,
|
||||
},
|
||||
end: { mode: null },
|
||||
end: { mode: "inside", element: hit, focusPoint: point },
|
||||
};
|
||||
}
|
||||
|
||||
// Inside -> outside binding
|
||||
if (arrow.startBinding && arrow.startBinding.elementId !== hovered?.id) {
|
||||
if (arrow.startBinding && arrow.startBinding.elementId !== hit?.id) {
|
||||
const otherElement = elementsMap.get(
|
||||
arrow.startBinding.elementId,
|
||||
) as ExcalidrawBindableElement;
|
||||
@@ -423,14 +387,14 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
|
||||
// We are hovering another element with the end point
|
||||
let current: BindingStrategy;
|
||||
if (hovered) {
|
||||
if (hit) {
|
||||
const isInsideBinding = globalBindMode === "inside";
|
||||
current = {
|
||||
mode: isInsideBinding ? "inside" : "orbit",
|
||||
element: hovered,
|
||||
element: hit,
|
||||
focusPoint: isInsideBinding
|
||||
? point
|
||||
: snapToCenter(hovered, elementsMap, point),
|
||||
: snapToCenter(hit, elementsMap, point),
|
||||
};
|
||||
} else {
|
||||
current = { mode: null };
|
||||
@@ -444,13 +408,13 @@ const bindingStrategyForNewSimpleArrowEndpointDragging = (
|
||||
|
||||
// No start binding
|
||||
if (!arrow.startBinding) {
|
||||
if (hovered) {
|
||||
if (hit) {
|
||||
const isInsideBinding =
|
||||
globalBindMode === "inside" || isAlwaysInsideBinding(hovered);
|
||||
globalBindMode === "inside" || isAlwaysInsideBinding(hit);
|
||||
|
||||
end = {
|
||||
mode: isInsideBinding ? "inside" : "orbit",
|
||||
element: hovered,
|
||||
element: hit,
|
||||
focusPoint: point,
|
||||
};
|
||||
} else {
|
||||
@@ -471,7 +435,6 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
|
||||
oppositeBinding: FixedPointBinding | null,
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||
zoom: AppState["zoom"],
|
||||
globalBindMode?: AppState["bindMode"],
|
||||
opts?: {
|
||||
newArrow?: boolean;
|
||||
@@ -481,23 +444,14 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
|
||||
let current: BindingStrategy = { mode: undefined };
|
||||
let other: BindingStrategy = { mode: undefined };
|
||||
|
||||
const { hovered, hit } = getHoveredElementForBindingAndIfItsPrecise(
|
||||
point,
|
||||
elements,
|
||||
elementsMap,
|
||||
zoom,
|
||||
true,
|
||||
);
|
||||
const hit = getHoveredElementForBinding(point, elements, elementsMap);
|
||||
|
||||
// If the global bind mode is in free binding mode, just bind
|
||||
// where the pointer is and keep the other end intact
|
||||
if (
|
||||
globalBindMode === "inside" ||
|
||||
(hovered && isAlwaysInsideBinding(hovered))
|
||||
) {
|
||||
current = hovered
|
||||
if (globalBindMode === "inside" || (hit && isAlwaysInsideBinding(hit))) {
|
||||
current = hit
|
||||
? {
|
||||
element: hovered,
|
||||
element: hit,
|
||||
focusPoint: point,
|
||||
mode: "inside",
|
||||
}
|
||||
@@ -508,90 +462,58 @@ const bindingStrategyForSimpleArrowEndpointDragging = (
|
||||
|
||||
// Dragged point is outside of any bindable element
|
||||
// so we break any existing binding
|
||||
if (!hovered) {
|
||||
if (!hit) {
|
||||
return { current: { mode: null }, other };
|
||||
}
|
||||
|
||||
// Dragged point is on the binding gap of a bindable element
|
||||
if (!hit) {
|
||||
// If the opposite binding (if exists) is on the same element
|
||||
if (oppositeBinding) {
|
||||
if (oppositeBinding.elementId === hovered.id) {
|
||||
return { current: { mode: null }, other };
|
||||
}
|
||||
// The opposite binding is on a different element
|
||||
// eslint-disable-next-line no-else-return
|
||||
else {
|
||||
current = {
|
||||
element: hovered,
|
||||
mode: "orbit",
|
||||
focusPoint: opts?.newArrow
|
||||
? pointFrom<GlobalPoint>(
|
||||
hovered.x + hovered.width / 2,
|
||||
hovered.y + hovered.height / 2,
|
||||
)
|
||||
: point,
|
||||
};
|
||||
|
||||
return { current, other };
|
||||
}
|
||||
}
|
||||
|
||||
// No opposite binding or the opposite binding is on a different element
|
||||
current = { element: hovered, mode: "orbit", focusPoint: point };
|
||||
}
|
||||
// The dragged point is inside the hovered bindable element
|
||||
else {
|
||||
// The opposite binding is on the same element
|
||||
// eslint-disable-next-line no-lonely-if
|
||||
if (oppositeBinding) {
|
||||
if (oppositeBinding.elementId === hovered.id) {
|
||||
// The opposite binding is on the binding gap of the same element
|
||||
if (oppositeBinding.mode !== "inside") {
|
||||
current = { element: hovered, mode: "orbit", focusPoint: point };
|
||||
other = { mode: null };
|
||||
|
||||
return { current, other };
|
||||
}
|
||||
// The opposite binding is inside the same element
|
||||
// eslint-disable-next-line no-else-return
|
||||
else {
|
||||
current = { element: hovered, mode: "inside", focusPoint: point };
|
||||
// The opposite binding is on the same element
|
||||
// eslint-disable-next-line no-lonely-if
|
||||
if (oppositeBinding) {
|
||||
if (oppositeBinding.elementId === hit.id) {
|
||||
// The opposite binding is on the binding gap of the same element
|
||||
if (oppositeBinding.mode !== "inside") {
|
||||
current = { element: hit, mode: "orbit", focusPoint: point };
|
||||
other = { mode: null };
|
||||
|
||||
return { current, other };
|
||||
}
|
||||
return { current, other };
|
||||
}
|
||||
// The opposite binding is on a different element
|
||||
// The opposite binding is inside the same element
|
||||
// eslint-disable-next-line no-else-return
|
||||
else {
|
||||
current = {
|
||||
element: hovered,
|
||||
mode: "orbit",
|
||||
focusPoint: opts?.newArrow
|
||||
? pointFrom<GlobalPoint>(
|
||||
hovered.x + hovered.width / 2,
|
||||
hovered.y + hovered.height / 2,
|
||||
)
|
||||
: point,
|
||||
};
|
||||
current = { element: hit, mode: "inside", focusPoint: point };
|
||||
|
||||
return { current, other };
|
||||
}
|
||||
}
|
||||
// The opposite binding is on a different element or no binding
|
||||
// The opposite binding is on a different element
|
||||
// eslint-disable-next-line no-else-return
|
||||
else {
|
||||
current = {
|
||||
element: hovered,
|
||||
element: hit,
|
||||
mode: "orbit",
|
||||
focusPoint: opts?.newArrow
|
||||
? pointFrom<GlobalPoint>(
|
||||
hovered.x + hovered.width / 2,
|
||||
hovered.y + hovered.height / 2,
|
||||
hit.x + hit.width / 2,
|
||||
hit.y + hit.height / 2,
|
||||
)
|
||||
: point,
|
||||
};
|
||||
|
||||
return { current, other };
|
||||
}
|
||||
}
|
||||
// The opposite binding is on a different element or no binding
|
||||
else {
|
||||
current = {
|
||||
element: hit,
|
||||
mode: "orbit",
|
||||
focusPoint: opts?.newArrow
|
||||
? pointFrom<GlobalPoint>(hit.x + hit.width / 2, hit.y + hit.height / 2)
|
||||
: point,
|
||||
};
|
||||
}
|
||||
|
||||
// Must return as only one endpoint is dragged, therefore
|
||||
// the end binding strategy might accidentally gets overriden
|
||||
@@ -654,7 +576,6 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
|
||||
p,
|
||||
elements,
|
||||
elementsMap,
|
||||
appState.zoom,
|
||||
);
|
||||
const current: BindingStrategy = hoveredElement
|
||||
? {
|
||||
@@ -702,7 +623,6 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
|
||||
arrow.endBinding,
|
||||
elementsMap,
|
||||
elements,
|
||||
appState.zoom,
|
||||
globalBindMode,
|
||||
opts,
|
||||
);
|
||||
@@ -724,7 +644,6 @@ export const getBindingStrategyForDraggingBindingElementEndpoints = (
|
||||
arrow.startBinding,
|
||||
elementsMap,
|
||||
elements,
|
||||
appState.zoom,
|
||||
globalBindMode,
|
||||
opts,
|
||||
);
|
||||
@@ -753,7 +672,6 @@ export const bindOrUnbindBindingElements = (
|
||||
export const getSuggestedBindingsForBindingElements = (
|
||||
selectedElements: NonDeleted<ExcalidrawElement>[],
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
zoom: AppState["zoom"],
|
||||
): SuggestedBinding[] => {
|
||||
// HOT PATH: Bail out if selected elements list is too large
|
||||
if (selectedElements.length > 50) {
|
||||
@@ -764,11 +682,7 @@ export const getSuggestedBindingsForBindingElements = (
|
||||
selectedElements
|
||||
.filter(isArrowElement)
|
||||
.flatMap((element) =>
|
||||
getOriginalBindingsIfStillCloseToBindingEnds(
|
||||
element,
|
||||
elementsMap,
|
||||
zoom,
|
||||
),
|
||||
getOriginalBindingsIfStillCloseToBindingEnds(element, elementsMap),
|
||||
)
|
||||
.filter(
|
||||
(element): element is NonDeleted<ExcalidrawBindableElement> =>
|
||||
@@ -790,7 +704,6 @@ export const maybeSuggestBindingsForBindingElementAtCoords = (
|
||||
linearElement: NonDeleted<ExcalidrawArrowElement>,
|
||||
startOrEndOrBoth: "start" | "end" | "both",
|
||||
scene: Scene,
|
||||
zoom: AppState["zoom"],
|
||||
): ExcalidrawBindableElement[] => {
|
||||
const startCoords = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
linearElement,
|
||||
@@ -806,13 +719,11 @@ export const maybeSuggestBindingsForBindingElementAtCoords = (
|
||||
startCoords,
|
||||
scene.getNonDeletedElements(),
|
||||
scene.getNonDeletedElementsMap(),
|
||||
zoom,
|
||||
);
|
||||
const endHovered = getHoveredElementForBinding(
|
||||
endCoords,
|
||||
scene.getNonDeletedElements(),
|
||||
scene.getNonDeletedElementsMap(),
|
||||
zoom,
|
||||
);
|
||||
|
||||
const suggestedBindings = [];
|
||||
@@ -1080,7 +991,6 @@ export const getHeadingForElbowArrowSnap = (
|
||||
aabb: Bounds | undefined | null,
|
||||
origPoint: GlobalPoint,
|
||||
elementsMap: ElementsMap,
|
||||
zoom?: AppState["zoom"],
|
||||
): Heading => {
|
||||
const otherPointHeading = vectorToHeading(vectorFromPoint(otherPoint, p));
|
||||
|
||||
@@ -1089,14 +999,8 @@ export const getHeadingForElbowArrowSnap = (
|
||||
}
|
||||
|
||||
const d = distanceToElement(bindableElement, elementsMap, origPoint);
|
||||
const bindDistance = maxBindingDistanceFromOutline(
|
||||
bindableElement,
|
||||
bindableElement.width,
|
||||
bindableElement.height,
|
||||
zoom,
|
||||
);
|
||||
|
||||
const distance = d > bindDistance ? null : d;
|
||||
const distance = d > 0 ? null : d;
|
||||
|
||||
if (!distance) {
|
||||
return vectorToHeading(
|
||||
|
@@ -25,7 +25,7 @@ import type {
|
||||
Radians,
|
||||
} from "@excalidraw/math";
|
||||
|
||||
import type { AppState, FrameNameBounds } from "@excalidraw/excalidraw/types";
|
||||
import type { FrameNameBounds } from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { isPathALoop } from "./utils";
|
||||
import {
|
||||
@@ -58,8 +58,6 @@ import { LinearElementEditor } from "./linearElementEditor";
|
||||
|
||||
import { distanceToElement } from "./distance";
|
||||
|
||||
import { BINDING_HIGHLIGHT_THICKNESS, FIXED_BINDING_DISTANCE } from "./binding";
|
||||
|
||||
import type {
|
||||
ElementsMap,
|
||||
ExcalidrawBindableElement,
|
||||
@@ -206,40 +204,12 @@ export const hitElementBoundText = (
|
||||
return isPointInElement(point, boundTextElement, elementsMap);
|
||||
};
|
||||
|
||||
export const maxBindingDistanceFromOutline = (
|
||||
element: ExcalidrawElement,
|
||||
elementWidth: number,
|
||||
elementHeight: number,
|
||||
zoom?: AppState["zoom"],
|
||||
): number => {
|
||||
const zoomValue = zoom?.value && zoom.value < 1 ? zoom.value : 1;
|
||||
|
||||
// Aligns diamonds with rectangles
|
||||
const shapeRatio = element.type === "diamond" ? 1 / Math.sqrt(2) : 1;
|
||||
const smallerDimension = shapeRatio * Math.min(elementWidth, elementHeight);
|
||||
|
||||
return Math.max(
|
||||
16,
|
||||
// bigger bindable boundary for bigger elements
|
||||
Math.min(0.25 * smallerDimension, 32),
|
||||
// keep in sync with the zoomed highlight
|
||||
BINDING_HIGHLIGHT_THICKNESS / zoomValue + FIXED_BINDING_DISTANCE,
|
||||
);
|
||||
};
|
||||
|
||||
export const bindingBorderTest = (
|
||||
element: NonDeleted<ExcalidrawBindableElement>,
|
||||
[x, y]: Readonly<GlobalPoint>,
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
zoom?: AppState["zoom"],
|
||||
): boolean => {
|
||||
const p = pointFrom<GlobalPoint>(x, y);
|
||||
const threshold = maxBindingDistanceFromOutline(
|
||||
element,
|
||||
element.width,
|
||||
element.height,
|
||||
zoom,
|
||||
);
|
||||
const shouldTestInside =
|
||||
// disable fullshape snapping for frame elements so we
|
||||
// can bind to frame children
|
||||
@@ -247,12 +217,7 @@ export const bindingBorderTest = (
|
||||
|
||||
// PERF: Run a cheap test to see if the binding element
|
||||
// is even close to the element
|
||||
const bounds = [
|
||||
x - threshold,
|
||||
y - threshold,
|
||||
x + threshold,
|
||||
y + threshold,
|
||||
] as Bounds;
|
||||
const bounds = [x - 1, y - 1, x + 1, y + 1] as Bounds;
|
||||
const elementBounds = getElementBounds(element, elementsMap);
|
||||
if (!doBoundsIntersect(bounds, elementBounds)) {
|
||||
return false;
|
||||
@@ -267,15 +232,14 @@ export const bindingBorderTest = (
|
||||
const distance = distanceToElement(element, elementsMap, p);
|
||||
|
||||
return shouldTestInside
|
||||
? intersections.length === 0 || distance <= threshold
|
||||
: intersections.length > 0 && distance <= threshold;
|
||||
? intersections.length === 0
|
||||
: intersections.length > 0 && distance <= 1;
|
||||
};
|
||||
|
||||
export const getHoveredElementForBinding = (
|
||||
point: Readonly<GlobalPoint>,
|
||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
zoom?: AppState["zoom"],
|
||||
): NonDeleted<ExcalidrawBindableElement> | null => {
|
||||
const candidateElements: NonDeleted<ExcalidrawBindableElement>[] = [];
|
||||
// We need to to hit testing from front (end of the array) to back (beginning of the array)
|
||||
@@ -291,7 +255,7 @@ export const getHoveredElementForBinding = (
|
||||
|
||||
if (
|
||||
isBindableElement(element, false) &&
|
||||
bindingBorderTest(element, point, elementsMap, zoom)
|
||||
bindingBorderTest(element, point, elementsMap)
|
||||
) {
|
||||
candidateElements.push(element);
|
||||
}
|
||||
@@ -313,36 +277,6 @@ export const getHoveredElementForBinding = (
|
||||
.pop() as NonDeleted<ExcalidrawBindableElement>;
|
||||
};
|
||||
|
||||
export const getHoveredElementForBindingAndIfItsPrecise = (
|
||||
point: GlobalPoint,
|
||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
zoom: AppState["zoom"],
|
||||
shouldTestInside: boolean = true,
|
||||
): {
|
||||
hovered: NonDeleted<ExcalidrawBindableElement> | null;
|
||||
hit: boolean;
|
||||
} => {
|
||||
const hoveredElement = getHoveredElementForBinding(
|
||||
point,
|
||||
elements,
|
||||
elementsMap,
|
||||
zoom,
|
||||
);
|
||||
// TODO: Optimize this to avoid recalculating the point - element distance
|
||||
const hit =
|
||||
!!hoveredElement &&
|
||||
hitElementItself({
|
||||
element: hoveredElement,
|
||||
elementsMap,
|
||||
point,
|
||||
threshold: 0,
|
||||
overrideShouldTestInside: shouldTestInside,
|
||||
});
|
||||
|
||||
return { hovered: hoveredElement, hit };
|
||||
};
|
||||
|
||||
/**
|
||||
* Intersect a line with an element for binding test
|
||||
*
|
||||
|
@@ -1194,19 +1194,9 @@ const getElbowArrowData = (
|
||||
if (options?.isDragging) {
|
||||
const elements = Array.from(elementsMap.values());
|
||||
hoveredStartElement =
|
||||
getHoveredElement(
|
||||
origStartGlobalPoint,
|
||||
elementsMap,
|
||||
elements,
|
||||
options?.zoom,
|
||||
) || null;
|
||||
getHoveredElement(origStartGlobalPoint, elementsMap, elements) || null;
|
||||
hoveredEndElement =
|
||||
getHoveredElement(
|
||||
origEndGlobalPoint,
|
||||
elementsMap,
|
||||
elements,
|
||||
options?.zoom,
|
||||
) || null;
|
||||
getHoveredElement(origEndGlobalPoint, elementsMap, elements) || null;
|
||||
} else {
|
||||
hoveredStartElement = arrow.startBinding
|
||||
? getBindableElementForId(arrow.startBinding.elementId, elementsMap) ||
|
||||
@@ -2249,9 +2239,8 @@ const getHoveredElement = (
|
||||
origPoint: GlobalPoint,
|
||||
elementsMap: NonDeletedSceneElementsMap,
|
||||
elements: readonly Ordered<NonDeletedExcalidrawElement>[],
|
||||
zoom?: AppState["zoom"],
|
||||
) => {
|
||||
return getHoveredElementForBinding(origPoint, elements, elementsMap, zoom);
|
||||
return getHoveredElementForBinding(origPoint, elements, elementsMap);
|
||||
};
|
||||
|
||||
const gridAddressesEqual = (a: GridAddress, b: GridAddress): boolean =>
|
||||
|
@@ -465,7 +465,6 @@ export class LinearElementEditor {
|
||||
? "start"
|
||||
: "end",
|
||||
app.scene,
|
||||
app.state.zoom,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2001,7 +2000,6 @@ const pointDraggingUpdates = (
|
||||
newGlobalPointPosition,
|
||||
elements,
|
||||
elementsMap,
|
||||
app.state.zoom,
|
||||
);
|
||||
const otherGlobalPoint =
|
||||
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||
@@ -2011,12 +2009,7 @@ const pointDraggingUpdates = (
|
||||
);
|
||||
const otherPointInsideElement =
|
||||
!!hoveredElement &&
|
||||
!!bindingBorderTest(
|
||||
hoveredElement,
|
||||
otherGlobalPoint,
|
||||
elementsMap,
|
||||
app.state.zoom,
|
||||
);
|
||||
!!bindingBorderTest(hoveredElement, otherGlobalPoint, elementsMap);
|
||||
|
||||
if (
|
||||
isBindingEnabled(app.state) &&
|
||||
|
@@ -4513,7 +4513,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
(element) => element.id !== elbowArrow?.id || step !== 0,
|
||||
),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
),
|
||||
});
|
||||
|
||||
@@ -4742,7 +4741,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
pointFrom<GlobalPoint>(scenePointer.x, scenePointer.y),
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
if (hoveredElement && !this.bindModeHandler) {
|
||||
@@ -6074,7 +6072,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
newElement,
|
||||
"end",
|
||||
this.scene,
|
||||
this.state.zoom,
|
||||
),
|
||||
});
|
||||
} else {
|
||||
@@ -6179,7 +6176,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
pointFrom<GlobalPoint>(scenePointerX, scenePointerY),
|
||||
this.scene.getNonDeletedElements(),
|
||||
elementsMap,
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
// Timed bind mode handler for arrow elements
|
||||
@@ -7967,7 +7963,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
),
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
this.setState({
|
||||
@@ -8173,7 +8168,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
lastGlobalPoint,
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
// clicking inside commit zone → finalize arrow
|
||||
@@ -8294,7 +8288,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
point,
|
||||
this.scene.getNonDeletedElements(),
|
||||
elementsMap,
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
this.scene.mutateElement(element, {
|
||||
@@ -8740,7 +8733,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
|
||||
this.scene.getNonDeletedElements(),
|
||||
elementsMap,
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
// Timed bind mode handler for arrow elements
|
||||
@@ -9117,7 +9109,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
suggestedBindings: getSuggestedBindingsForBindingElements(
|
||||
selectedElements,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
),
|
||||
});
|
||||
}
|
||||
@@ -9427,7 +9418,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
newElement,
|
||||
"end",
|
||||
this.scene,
|
||||
this.state.zoom,
|
||||
),
|
||||
});
|
||||
}
|
||||
@@ -10978,7 +10968,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
pointFrom<GlobalPoint>(pointerCoords.x, pointerCoords.y),
|
||||
this.scene.getNonDeletedElements(),
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
);
|
||||
this.setState({
|
||||
suggestedBindings:
|
||||
@@ -11601,7 +11590,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||
const suggestedBindings = getSuggestedBindingsForBindingElements(
|
||||
selectedElements,
|
||||
this.scene.getNonDeletedElementsMap(),
|
||||
this.state.zoom,
|
||||
);
|
||||
|
||||
const elementsToHighlight = new Set<ExcalidrawElement>();
|
||||
|
@@ -16,10 +16,7 @@ import {
|
||||
throttleRAF,
|
||||
} from "@excalidraw/common";
|
||||
|
||||
import {
|
||||
FIXED_BINDING_DISTANCE,
|
||||
maxBindingDistanceFromOutline,
|
||||
} from "@excalidraw/element";
|
||||
import { FIXED_BINDING_DISTANCE } from "@excalidraw/element";
|
||||
import { LinearElementEditor } from "@excalidraw/element";
|
||||
import {
|
||||
getOmitSidesForDevice,
|
||||
@@ -197,12 +194,7 @@ const renderBindingHighlightForBindableElement = (
|
||||
elementsMap: ElementsMap,
|
||||
zoom: InteractiveCanvasAppState["zoom"],
|
||||
) => {
|
||||
const padding = maxBindingDistanceFromOutline(
|
||||
element,
|
||||
element.width,
|
||||
element.height,
|
||||
zoom,
|
||||
);
|
||||
const padding = 5;
|
||||
|
||||
context.fillStyle = "rgba(0,0,0,.05)";
|
||||
|
||||
@@ -251,14 +243,9 @@ const renderBindingHighlightForSuggestedPointBinding = (
|
||||
elementsMap: ElementsMap,
|
||||
zoom: InteractiveCanvasAppState["zoom"],
|
||||
) => {
|
||||
const [element, startOrEnd, bindableElement] = suggestedBinding;
|
||||
const [element, startOrEnd] = suggestedBinding;
|
||||
|
||||
const threshold = maxBindingDistanceFromOutline(
|
||||
bindableElement,
|
||||
bindableElement.width,
|
||||
bindableElement.height,
|
||||
zoom,
|
||||
);
|
||||
const threshold = 0;
|
||||
|
||||
context.strokeStyle = "rgba(0,0,0,0)";
|
||||
context.fillStyle = "rgba(0,0,0,.05)";
|
||||
|
Reference in New Issue
Block a user