mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Inline binding logic fix
This commit is contained in:
parent
a79eb06939
commit
4efa6f69e5
5 changed files with 65 additions and 42 deletions
|
@ -223,7 +223,7 @@ const bindOrUnbindLinearElementEdge = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOriginalBindingsIfStillCloseToArrowEnds = (
|
export const getOriginalBindingsIfStillCloseToArrowEnds = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
zoom?: AppState["zoom"],
|
zoom?: AppState["zoom"],
|
||||||
|
@ -418,10 +418,47 @@ export const getSuggestedBindingsForArrows = (
|
||||||
export const maybeBindLinearElement = (
|
export const maybeBindLinearElement = (
|
||||||
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
linearElement: NonDeleted<ExcalidrawLinearElement>,
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
pointerCoords: { x: number; y: number },
|
|
||||||
elementsMap: NonDeletedSceneElementsMap,
|
elementsMap: NonDeletedSceneElementsMap,
|
||||||
elements: readonly NonDeletedExcalidrawElement[],
|
elements: readonly NonDeletedExcalidrawElement[],
|
||||||
): void => {
|
): void => {
|
||||||
|
const start = tupleToCoors(
|
||||||
|
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||||
|
linearElement,
|
||||||
|
0,
|
||||||
|
elementsMap,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const end = tupleToCoors(
|
||||||
|
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
||||||
|
linearElement,
|
||||||
|
-1,
|
||||||
|
elementsMap,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const otherHoveredElement = getHoveredElementForBinding(
|
||||||
|
start,
|
||||||
|
elements,
|
||||||
|
elementsMap,
|
||||||
|
appState.zoom,
|
||||||
|
isElbowArrow(linearElement),
|
||||||
|
isElbowArrow(linearElement),
|
||||||
|
);
|
||||||
|
|
||||||
|
const hoveredElement = getHoveredElementForBinding(
|
||||||
|
end,
|
||||||
|
elements,
|
||||||
|
elementsMap,
|
||||||
|
appState.zoom,
|
||||||
|
isElbowArrow(linearElement),
|
||||||
|
isElbowArrow(linearElement),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inside the same element there is no binding to the shape
|
||||||
|
if (hoveredElement === otherHoveredElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (appState.startBoundElement != null) {
|
if (appState.startBoundElement != null) {
|
||||||
bindLinearElement(
|
bindLinearElement(
|
||||||
linearElement,
|
linearElement,
|
||||||
|
@ -431,15 +468,6 @@ export const maybeBindLinearElement = (
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hoveredElement = getHoveredElementForBinding(
|
|
||||||
pointerCoords,
|
|
||||||
elements,
|
|
||||||
elementsMap,
|
|
||||||
appState.zoom,
|
|
||||||
isElbowArrow(linearElement),
|
|
||||||
isElbowArrow(linearElement),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (hoveredElement !== null) {
|
if (hoveredElement !== null) {
|
||||||
if (
|
if (
|
||||||
!isLinearElementSimpleAndAlreadyBoundOnOppositeEdge(
|
!isLinearElementSimpleAndAlreadyBoundOnOppositeEdge(
|
||||||
|
|
|
@ -50,7 +50,6 @@ import { isBindableElement } from "./typeChecks";
|
||||||
import {
|
import {
|
||||||
type ExcalidrawElbowArrowElement,
|
type ExcalidrawElbowArrowElement,
|
||||||
type NonDeletedSceneElementsMap,
|
type NonDeletedSceneElementsMap,
|
||||||
type SceneElementsMap,
|
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
import { aabbForElement, pointInsideBounds } from "./shapes";
|
import { aabbForElement, pointInsideBounds } from "./shapes";
|
||||||
|
@ -1237,6 +1236,14 @@ const getElbowArrowData = (
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
) || null;
|
) || null;
|
||||||
|
|
||||||
|
// Inside the same element there is no binding to the shape
|
||||||
|
if (hoveredStartElement === hoveredEndElement) {
|
||||||
|
hoveredStartElement = null;
|
||||||
|
hoveredEndElement = null;
|
||||||
|
arrow.startBinding = null;
|
||||||
|
arrow.endBinding = null;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hoveredStartElement = arrow.startBinding
|
hoveredStartElement = arrow.startBinding
|
||||||
? getBindableElementForId(arrow.startBinding.elementId, elementsMap) ||
|
? getBindableElementForId(arrow.startBinding.elementId, elementsMap) ||
|
||||||
|
@ -1278,14 +1285,12 @@ const getElbowArrowData = (
|
||||||
const startHeading = getBindPointHeading(
|
const startHeading = getBindPointHeading(
|
||||||
startGlobalPoint,
|
startGlobalPoint,
|
||||||
endGlobalPoint,
|
endGlobalPoint,
|
||||||
elementsMap,
|
|
||||||
hoveredStartElement,
|
hoveredStartElement,
|
||||||
origStartGlobalPoint,
|
origStartGlobalPoint,
|
||||||
);
|
);
|
||||||
const endHeading = getBindPointHeading(
|
const endHeading = getBindPointHeading(
|
||||||
endGlobalPoint,
|
endGlobalPoint,
|
||||||
startGlobalPoint,
|
startGlobalPoint,
|
||||||
elementsMap,
|
|
||||||
hoveredEndElement,
|
hoveredEndElement,
|
||||||
origEndGlobalPoint,
|
origEndGlobalPoint,
|
||||||
);
|
);
|
||||||
|
@ -2257,7 +2262,6 @@ const getGlobalPoint = (
|
||||||
const getBindPointHeading = (
|
const getBindPointHeading = (
|
||||||
p: GlobalPoint,
|
p: GlobalPoint,
|
||||||
otherPoint: GlobalPoint,
|
otherPoint: GlobalPoint,
|
||||||
elementsMap: NonDeletedSceneElementsMap | SceneElementsMap,
|
|
||||||
hoveredElement: ExcalidrawBindableElement | null | undefined,
|
hoveredElement: ExcalidrawBindableElement | null | undefined,
|
||||||
origPoint: GlobalPoint,
|
origPoint: GlobalPoint,
|
||||||
): Heading =>
|
): Heading =>
|
||||||
|
|
|
@ -10,6 +10,8 @@ import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
||||||
import { UI, Pointer, Keyboard } from "@excalidraw/excalidraw/tests/helpers/ui";
|
import { UI, Pointer, Keyboard } from "@excalidraw/excalidraw/tests/helpers/ui";
|
||||||
import { fireEvent, render } from "@excalidraw/excalidraw/tests/test-utils";
|
import { fireEvent, render } from "@excalidraw/excalidraw/tests/test-utils";
|
||||||
|
|
||||||
|
import "@excalidraw/utils/test-utils";
|
||||||
|
|
||||||
import { getTransformHandles } from "../src/transformHandles";
|
import { getTransformHandles } from "../src/transformHandles";
|
||||||
|
|
||||||
const { h } = window;
|
const { h } = window;
|
||||||
|
@ -510,7 +512,7 @@ describe("element binding", () => {
|
||||||
"allow non-binding simple (complex) arrow creation while start and end" +
|
"allow non-binding simple (complex) arrow creation while start and end" +
|
||||||
" points are in the same shape",
|
" points are in the same shape",
|
||||||
() => {
|
() => {
|
||||||
UI.createElement("rectangle", {
|
const rect = UI.createElement("rectangle", {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 100,
|
width: 100,
|
||||||
|
@ -526,9 +528,10 @@ describe("element binding", () => {
|
||||||
|
|
||||||
expect(arrow.startBinding).toBe(null);
|
expect(arrow.startBinding).toBe(null);
|
||||||
expect(arrow.endBinding).toBe(null);
|
expect(arrow.endBinding).toBe(null);
|
||||||
|
expect(rect.boundElements).toEqual(null);
|
||||||
expect(arrow.points).toCloselyEqualPoints([
|
expect(arrow.points).toCloselyEqualPoints([
|
||||||
[0, 0],
|
[0, 0],
|
||||||
[95, 95],
|
[92.2855, 92.2855],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const rect2 = API.createElement({
|
const rect2 = API.createElement({
|
||||||
|
@ -552,32 +555,35 @@ describe("element binding", () => {
|
||||||
|
|
||||||
expect(arrow2.startBinding).toBe(null);
|
expect(arrow2.startBinding).toBe(null);
|
||||||
expect(arrow2.endBinding).toBe(null);
|
expect(arrow2.endBinding).toBe(null);
|
||||||
|
expect(rect2.boundElements).toEqual(null);
|
||||||
expect(arrow2.points).toCloselyEqualPoints([
|
expect(arrow2.points).toCloselyEqualPoints([
|
||||||
[0, 0],
|
[0, 0],
|
||||||
[95, 95],
|
[92.2855, 92.2855],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
UI.createElement("rectangle", {
|
const rect3 = UI.createElement("rectangle", {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 300,
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 100,
|
height: 100,
|
||||||
});
|
});
|
||||||
|
|
||||||
const arrow3 = UI.createElement("arrow", {
|
const arrow3 = UI.createElement("arrow", {
|
||||||
x: 5,
|
x: 10,
|
||||||
y: 5,
|
y: 310,
|
||||||
height: 95,
|
height: 85,
|
||||||
width: 95,
|
width: 84,
|
||||||
elbowed: true,
|
elbowed: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(arrow3.startBinding).toBe(null);
|
expect(arrow3.startBinding).toBe(null);
|
||||||
expect(arrow3.endBinding).toBe(null);
|
expect(arrow3.endBinding).toBe(null);
|
||||||
|
expect(rect3.boundElements).toEqual(null);
|
||||||
expect(arrow3.points).toCloselyEqualPoints([
|
expect(arrow3.points).toCloselyEqualPoints([
|
||||||
[0, 0],
|
[0, 0],
|
||||||
[45, 45],
|
[0, 42.5],
|
||||||
[95, 95],
|
[84, 42.5],
|
||||||
|
[84, 85],
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
isLinearElement,
|
isLinearElement,
|
||||||
} from "@excalidraw/element/typeChecks";
|
} from "@excalidraw/element/typeChecks";
|
||||||
|
|
||||||
import { KEYS, arrayToMap, updateActiveTool } from "@excalidraw/common";
|
import { KEYS, updateActiveTool } from "@excalidraw/common";
|
||||||
import { isPathALoop } from "@excalidraw/element/shapes";
|
import { isPathALoop } from "@excalidraw/element/shapes";
|
||||||
|
|
||||||
import { isInvisiblySmallElement } from "@excalidraw/element/sizeHelpers";
|
import { isInvisiblySmallElement } from "@excalidraw/element/sizeHelpers";
|
||||||
|
@ -153,15 +153,9 @@ export const actionFinalize = register({
|
||||||
!isLoop &&
|
!isLoop &&
|
||||||
multiPointElement.points.length > 1
|
multiPointElement.points.length > 1
|
||||||
) {
|
) {
|
||||||
const [x, y] = LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
|
||||||
multiPointElement,
|
|
||||||
-1,
|
|
||||||
arrayToMap(elements),
|
|
||||||
);
|
|
||||||
maybeBindLinearElement(
|
maybeBindLinearElement(
|
||||||
multiPointElement,
|
multiPointElement,
|
||||||
appState,
|
appState,
|
||||||
{ x, y },
|
|
||||||
elementsMap,
|
elementsMap,
|
||||||
elements,
|
elements,
|
||||||
);
|
);
|
||||||
|
|
|
@ -2770,7 +2770,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
this.updateEmbeddables();
|
this.updateEmbeddables();
|
||||||
const elements = this.scene.getElementsIncludingDeleted();
|
const elements = this.scene.getElementsIncludingDeleted();
|
||||||
const elementsMap = this.scene.getElementsMapIncludingDeleted();
|
const elementsMap = this.scene.getElementsMapIncludingDeleted();
|
||||||
const nonDeletedElementsMap = this.scene.getNonDeletedElementsMap();
|
|
||||||
|
|
||||||
if (!this.state.showWelcomeScreen && !elements.length) {
|
if (!this.state.showWelcomeScreen && !elements.length) {
|
||||||
this.setState({ showWelcomeScreen: true });
|
this.setState({ showWelcomeScreen: true });
|
||||||
|
@ -2927,13 +2926,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
maybeBindLinearElement(
|
maybeBindLinearElement(
|
||||||
multiElement,
|
multiElement,
|
||||||
this.state,
|
this.state,
|
||||||
tupleToCoors(
|
|
||||||
LinearElementEditor.getPointAtIndexGlobalCoordinates(
|
|
||||||
multiElement,
|
|
||||||
-1,
|
|
||||||
nonDeletedElementsMap,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
);
|
);
|
||||||
|
@ -9174,7 +9166,6 @@ class App extends React.Component<AppProps, AppState> {
|
||||||
maybeBindLinearElement(
|
maybeBindLinearElement(
|
||||||
newElement,
|
newElement,
|
||||||
this.state,
|
this.state,
|
||||||
pointerCoords,
|
|
||||||
this.scene.getNonDeletedElementsMap(),
|
this.scene.getNonDeletedElementsMap(),
|
||||||
this.scene.getNonDeletedElements(),
|
this.scene.getNonDeletedElements(),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue