@excalidraw/excalidraw 0.17.1-1d71f84 → 0.17.1-4689a6b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-AK7SWNLN.js → chunk-23CKV3WP.js} +4 -2
- package/dist/browser/dev/excalidraw-assets-dev/chunk-23CKV3WP.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-RWZVJAQU.js → chunk-7D5BMEAB.js} +2227 -1976
- package/dist/browser/dev/excalidraw-assets-dev/chunk-7D5BMEAB.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-5TCZHGGJ.js → en-W7TECCRB.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-EDKQZH7Z.js → image-JKT6GXZD.js} +2 -2
- package/dist/browser/dev/index.css +20 -0
- package/dist/browser/dev/index.css.map +2 -2
- package/dist/browser/dev/index.js +770 -585
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/chunk-DWOM5R6H.js +55 -0
- package/dist/browser/prod/excalidraw-assets/{chunk-CTYINSWT.js → chunk-SK23VHAR.js} +2 -2
- package/dist/browser/prod/excalidraw-assets/{en-LROPV2RN.js → en-SMMH575S.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/image-WDEQS5RL.js +1 -0
- package/dist/browser/prod/index.css +1 -1
- package/dist/browser/prod/index.js +22 -22
- package/dist/{prod/en-II4GK66F.json → dev/en-CVBEBUBY.json} +3 -1
- package/dist/dev/index.css +20 -0
- package/dist/dev/index.css.map +2 -2
- package/dist/dev/index.js +2383 -2074
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionBoundText.js +4 -1
- package/dist/excalidraw/actions/actionCanvas.js +3 -1
- package/dist/excalidraw/actions/actionDuplicateSelection.js +4 -0
- package/dist/excalidraw/actions/actionExport.d.ts +1 -1
- package/dist/excalidraw/actions/actionFinalize.d.ts +1 -1
- package/dist/excalidraw/actions/actionFinalize.js +3 -3
- package/dist/excalidraw/actions/actionFlip.d.ts +3 -3
- package/dist/excalidraw/actions/actionFlip.js +6 -6
- package/dist/excalidraw/actions/actionGroup.js +4 -2
- package/dist/excalidraw/actions/actionHistory.js +3 -0
- package/dist/excalidraw/actions/actionZindex.d.ts +11 -11
- package/dist/excalidraw/actions/shortcuts.js +1 -1
- package/dist/excalidraw/analytics.js +1 -1
- package/dist/excalidraw/components/App.d.ts +13 -3
- package/dist/excalidraw/components/App.js +212 -83
- package/dist/excalidraw/components/CommandPalette/CommandPalette.js +24 -10
- package/dist/excalidraw/components/DarkModeToggle.js +3 -1
- package/dist/excalidraw/components/HelpDialog.js +8 -6
- package/dist/excalidraw/components/RadioGroup.d.ts +2 -1
- package/dist/excalidraw/components/RadioGroup.js +1 -1
- package/dist/excalidraw/components/TTDDialog/MermaidToExcalidraw.js +6 -2
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.d.ts +18 -0
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.js +9 -0
- package/dist/excalidraw/components/hyperlink/Hyperlink.js +3 -3
- package/dist/excalidraw/components/hyperlink/helpers.js +2 -3
- package/dist/excalidraw/components/icons.d.ts +3 -0
- package/dist/excalidraw/components/icons.js +5 -1
- package/dist/excalidraw/components/main-menu/DefaultItems.d.ts +12 -2
- package/dist/excalidraw/components/main-menu/DefaultItems.js +38 -7
- package/dist/excalidraw/constants.d.ts +0 -3
- package/dist/excalidraw/constants.js +0 -3
- package/dist/excalidraw/data/magic.js +2 -1
- package/dist/excalidraw/data/reconcile.d.ts +6 -0
- package/dist/excalidraw/data/reconcile.js +49 -0
- package/dist/excalidraw/data/restore.d.ts +3 -3
- package/dist/excalidraw/data/restore.js +5 -6
- package/dist/excalidraw/data/transform.d.ts +1 -1
- package/dist/excalidraw/data/transform.js +12 -3
- package/dist/excalidraw/element/binding.d.ts +22 -9
- package/dist/excalidraw/element/binding.js +403 -26
- package/dist/excalidraw/element/bounds.d.ts +0 -1
- package/dist/excalidraw/element/bounds.js +0 -3
- package/dist/excalidraw/element/collision.d.ts +14 -19
- package/dist/excalidraw/element/collision.js +36 -713
- package/dist/excalidraw/element/embeddable.js +18 -43
- package/dist/excalidraw/element/index.d.ts +0 -1
- package/dist/excalidraw/element/index.js +0 -1
- package/dist/excalidraw/element/linearElementEditor.d.ts +10 -10
- package/dist/excalidraw/element/linearElementEditor.js +6 -4
- package/dist/excalidraw/element/newElement.d.ts +1 -1
- package/dist/excalidraw/element/newElement.js +2 -1
- package/dist/excalidraw/element/textElement.d.ts +0 -1
- package/dist/excalidraw/element/textElement.js +0 -30
- package/dist/excalidraw/element/types.d.ts +17 -2
- package/dist/excalidraw/errors.d.ts +3 -0
- package/dist/excalidraw/errors.js +3 -0
- package/dist/excalidraw/fractionalIndex.d.ts +40 -0
- package/dist/excalidraw/fractionalIndex.js +241 -0
- package/dist/excalidraw/frame.d.ts +1 -1
- package/dist/excalidraw/hooks/useCreatePortalContainer.js +2 -1
- package/dist/excalidraw/locales/en.json +3 -1
- package/dist/excalidraw/renderer/helpers.js +2 -2
- package/dist/excalidraw/renderer/interactiveScene.js +1 -1
- package/dist/excalidraw/renderer/renderElement.js +3 -3
- package/dist/excalidraw/renderer/renderSnaps.js +2 -1
- package/dist/excalidraw/scene/Scene.d.ts +7 -6
- package/dist/excalidraw/scene/Scene.js +28 -13
- package/dist/excalidraw/scene/export.js +4 -3
- package/dist/excalidraw/types.d.ts +4 -3
- package/dist/excalidraw/utils.d.ts +1 -0
- package/dist/excalidraw/utils.js +1 -0
- package/dist/excalidraw/zindex.d.ts +2 -2
- package/dist/excalidraw/zindex.js +9 -13
- package/dist/{dev/en-II4GK66F.json → prod/en-CVBEBUBY.json} +3 -1
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +36 -36
- package/dist/utils/collision.d.ts +4 -0
- package/dist/utils/collision.js +48 -0
- package/dist/utils/geometry/geometry.d.ts +71 -0
- package/dist/utils/geometry/geometry.js +674 -0
- package/dist/utils/geometry/shape.d.ts +55 -0
- package/dist/utils/geometry/shape.js +149 -0
- package/package.json +2 -1
- package/dist/browser/dev/excalidraw-assets-dev/chunk-AK7SWNLN.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-RWZVJAQU.js.map +0 -7
- package/dist/browser/prod/excalidraw-assets/chunk-LL4GORAM.js +0 -55
- package/dist/browser/prod/excalidraw-assets/image-EFCJDJH3.js +0 -1
- /package/dist/browser/dev/excalidraw-assets-dev/{en-5TCZHGGJ.js.map → en-W7TECCRB.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-EDKQZH7Z.js.map → image-JKT6GXZD.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import * as GA from "../ga";
|
|
2
|
+
import { ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawRectangleElement, ExcalidrawDiamondElement, ExcalidrawTextElement, ExcalidrawEllipseElement, ExcalidrawImageElement, ExcalidrawFrameLikeElement, ExcalidrawIframeLikeElement, NonDeleted, ExcalidrawLinearElement, NonDeletedExcalidrawElement, ElementsMap, NonDeletedSceneElementsMap } from "./types";
|
|
3
|
+
import { AppClassProperties, AppState, Point } from "../types";
|
|
4
4
|
export type SuggestedBinding = NonDeleted<ExcalidrawBindableElement> | SuggestedPointBinding;
|
|
5
5
|
export type SuggestedPointBinding = [
|
|
6
6
|
NonDeleted<ExcalidrawLinearElement>,
|
|
@@ -10,18 +10,18 @@ export type SuggestedPointBinding = [
|
|
|
10
10
|
export declare const shouldEnableBindingForPointerEvent: (event: React.PointerEvent<HTMLElement>) => boolean;
|
|
11
11
|
export declare const isBindingEnabled: (appState: AppState) => boolean;
|
|
12
12
|
export declare const bindOrUnbindLinearElement: (linearElement: NonDeleted<ExcalidrawLinearElement>, startBindingElement: ExcalidrawBindableElement | null | "keep", endBindingElement: ExcalidrawBindableElement | null | "keep", elementsMap: NonDeletedSceneElementsMap) => void;
|
|
13
|
-
export declare const bindOrUnbindSelectedElements: (selectedElements: NonDeleted<ExcalidrawElement>[],
|
|
14
|
-
export declare const maybeBindLinearElement: (linearElement: NonDeleted<ExcalidrawLinearElement>, appState: AppState,
|
|
13
|
+
export declare const bindOrUnbindSelectedElements: (selectedElements: NonDeleted<ExcalidrawElement>[], app: AppClassProperties) => void;
|
|
14
|
+
export declare const maybeBindLinearElement: (linearElement: NonDeleted<ExcalidrawLinearElement>, appState: AppState, pointerCoords: {
|
|
15
15
|
x: number;
|
|
16
16
|
y: number;
|
|
17
|
-
},
|
|
17
|
+
}, app: AppClassProperties) => void;
|
|
18
18
|
export declare const bindLinearElement: (linearElement: NonDeleted<ExcalidrawLinearElement>, hoveredElement: ExcalidrawBindableElement, startOrEnd: "start" | "end", elementsMap: NonDeletedSceneElementsMap) => void;
|
|
19
19
|
export declare const isLinearElementSimpleAndAlreadyBound: (linearElement: NonDeleted<ExcalidrawLinearElement>, alreadyBoundToId: ExcalidrawBindableElement["id"] | undefined, bindableElement: ExcalidrawBindableElement) => boolean;
|
|
20
|
-
export declare const unbindLinearElements: (elements: NonDeleted<ExcalidrawElement>[], elementsMap: NonDeletedSceneElementsMap) => void;
|
|
20
|
+
export declare const unbindLinearElements: (elements: readonly NonDeleted<ExcalidrawElement>[], elementsMap: NonDeletedSceneElementsMap) => void;
|
|
21
21
|
export declare const getHoveredElementForBinding: (pointerCoords: {
|
|
22
22
|
x: number;
|
|
23
23
|
y: number;
|
|
24
|
-
},
|
|
24
|
+
}, app: AppClassProperties) => NonDeleted<ExcalidrawBindableElement> | null;
|
|
25
25
|
export declare const updateBoundElements: (changedElement: NonDeletedExcalidrawElement, elementsMap: ElementsMap, options?: {
|
|
26
26
|
simultaneouslyUpdated?: readonly ExcalidrawElement[];
|
|
27
27
|
newSize?: {
|
|
@@ -29,6 +29,19 @@ export declare const updateBoundElements: (changedElement: NonDeletedExcalidrawE
|
|
|
29
29
|
height: number;
|
|
30
30
|
};
|
|
31
31
|
}) => void;
|
|
32
|
-
export declare const getEligibleElementsForBinding: (selectedElements: NonDeleted<ExcalidrawElement>[],
|
|
32
|
+
export declare const getEligibleElementsForBinding: (selectedElements: NonDeleted<ExcalidrawElement>[], app: AppClassProperties) => SuggestedBinding[];
|
|
33
33
|
export declare const fixBindingsAfterDuplication: (sceneElements: readonly ExcalidrawElement[], oldElements: readonly ExcalidrawElement[], oldIdToDuplicatedId: Map<ExcalidrawElement["id"], ExcalidrawElement["id"]>, duplicatesServeAsOld?: "duplicatesServeAsOld" | undefined) => void;
|
|
34
34
|
export declare const fixBindingsAfterDeletion: (sceneElements: readonly ExcalidrawElement[], deletedElements: readonly ExcalidrawElement[]) => void;
|
|
35
|
+
export declare const bindingBorderTest: (element: NonDeleted<ExcalidrawBindableElement>, { x, y }: {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
}, app: AppClassProperties) => boolean;
|
|
39
|
+
export declare const maxBindingGap: (element: ExcalidrawElement, elementWidth: number, elementHeight: number) => number;
|
|
40
|
+
export declare const distanceToBindableElement: (element: ExcalidrawBindableElement, point: readonly [number, number], elementsMap: ElementsMap) => number;
|
|
41
|
+
export declare const distanceToEllipse: (element: ExcalidrawEllipseElement, point: readonly [number, number], elementsMap: ElementsMap) => number;
|
|
42
|
+
export declare const determineFocusDistance: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], elementsMap: ElementsMap) => number;
|
|
43
|
+
export declare const determineFocusPoint: (element: ExcalidrawBindableElement, focus: number, adjecentPoint: readonly [number, number], elementsMap: ElementsMap) => readonly [number, number];
|
|
44
|
+
export declare const intersectElementWithLine: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], gap: number | undefined, elementsMap: ElementsMap) => Point[];
|
|
45
|
+
export declare const getCircleIntersections: (center: readonly [number, number, number, number, number, number, number, number], radius: number, line: readonly [number, number, number, number, number, number, number, number]) => GA.Point[];
|
|
46
|
+
export declare const findFocusPointForEllipse: (ellipse: ExcalidrawEllipseElement, relativeDistance: number, point: readonly [number, number, number, number, number, number, number, number]) => readonly [number, number, number, number, number, number, number, number];
|
|
47
|
+
export declare const findFocusPointForRectangulars: (element: ExcalidrawRectangleElement | ExcalidrawImageElement | ExcalidrawDiamondElement | ExcalidrawTextElement | ExcalidrawIframeLikeElement | ExcalidrawFrameLikeElement, relativeDistance: number, point: readonly [number, number, number, number, number, number, number, number]) => readonly [number, number, number, number, number, number, number, number];
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import * as GA from "../ga";
|
|
2
|
+
import * as GAPoint from "../gapoints";
|
|
3
|
+
import * as GADirection from "../gadirections";
|
|
4
|
+
import * as GALine from "../galines";
|
|
5
|
+
import * as GATransform from "../gatransforms";
|
|
6
|
+
import { getElementAbsoluteCoords } from "./bounds";
|
|
7
|
+
import { isPointOnShape } from "../../utils/collision";
|
|
1
8
|
import { getElementAtPosition } from "../scene";
|
|
2
9
|
import { isBindableElement, isBindingElement, isLinearElement, } from "./typeChecks";
|
|
3
|
-
import { bindingBorderTest, distanceToBindableElement, maxBindingGap, determineFocusDistance, intersectElementWithLine, determineFocusPoint, } from "./collision";
|
|
4
10
|
import { mutateElement } from "./mutateElement";
|
|
5
11
|
import Scene from "../scene/Scene";
|
|
6
12
|
import { LinearElementEditor } from "./linearElementEditor";
|
|
@@ -61,27 +67,27 @@ unboundFromElementIds, elementsMap) => {
|
|
|
61
67
|
}
|
|
62
68
|
}
|
|
63
69
|
};
|
|
64
|
-
export const bindOrUnbindSelectedElements = (selectedElements,
|
|
70
|
+
export const bindOrUnbindSelectedElements = (selectedElements, app) => {
|
|
65
71
|
selectedElements.forEach((selectedElement) => {
|
|
66
72
|
if (isBindingElement(selectedElement)) {
|
|
67
|
-
bindOrUnbindLinearElement(selectedElement, getElligibleElementForBindingElement(selectedElement, "start",
|
|
73
|
+
bindOrUnbindLinearElement(selectedElement, getElligibleElementForBindingElement(selectedElement, "start", app), getElligibleElementForBindingElement(selectedElement, "end", app), app.scene.getNonDeletedElementsMap());
|
|
68
74
|
}
|
|
69
75
|
else if (isBindableElement(selectedElement)) {
|
|
70
|
-
maybeBindBindableElement(selectedElement,
|
|
76
|
+
maybeBindBindableElement(selectedElement, app.scene.getNonDeletedElementsMap(), app);
|
|
71
77
|
}
|
|
72
78
|
});
|
|
73
79
|
};
|
|
74
|
-
const maybeBindBindableElement = (bindableElement, elementsMap) => {
|
|
75
|
-
getElligibleElementsForBindableElementAndWhere(bindableElement,
|
|
80
|
+
const maybeBindBindableElement = (bindableElement, elementsMap, app) => {
|
|
81
|
+
getElligibleElementsForBindableElementAndWhere(bindableElement, app).forEach(([linearElement, where]) => bindOrUnbindLinearElement(linearElement, where === "end" ? "keep" : bindableElement, where === "start" ? "keep" : bindableElement, elementsMap));
|
|
76
82
|
};
|
|
77
|
-
export const maybeBindLinearElement = (linearElement, appState,
|
|
83
|
+
export const maybeBindLinearElement = (linearElement, appState, pointerCoords, app) => {
|
|
78
84
|
if (appState.startBoundElement != null) {
|
|
79
|
-
bindLinearElement(linearElement, appState.startBoundElement, "start",
|
|
85
|
+
bindLinearElement(linearElement, appState.startBoundElement, "start", app.scene.getNonDeletedElementsMap());
|
|
80
86
|
}
|
|
81
|
-
const hoveredElement = getHoveredElementForBinding(pointerCoords,
|
|
87
|
+
const hoveredElement = getHoveredElementForBinding(pointerCoords, app);
|
|
82
88
|
if (hoveredElement != null &&
|
|
83
89
|
!isLinearElementSimpleAndAlreadyBoundOnOppositeEdge(linearElement, hoveredElement, "end")) {
|
|
84
|
-
bindLinearElement(linearElement, hoveredElement, "end",
|
|
90
|
+
bindLinearElement(linearElement, hoveredElement, "end", app.scene.getNonDeletedElementsMap());
|
|
85
91
|
}
|
|
86
92
|
};
|
|
87
93
|
export const bindLinearElement = (linearElement, hoveredElement, startOrEnd, elementsMap) => {
|
|
@@ -125,9 +131,9 @@ const unbindLinearElement = (linearElement, startOrEnd) => {
|
|
|
125
131
|
mutateElement(linearElement, { [field]: null });
|
|
126
132
|
return binding.elementId;
|
|
127
133
|
};
|
|
128
|
-
export const getHoveredElementForBinding = (pointerCoords,
|
|
129
|
-
const hoveredElement = getElementAtPosition(
|
|
130
|
-
bindingBorderTest(element, pointerCoords,
|
|
134
|
+
export const getHoveredElementForBinding = (pointerCoords, app) => {
|
|
135
|
+
const hoveredElement = getElementAtPosition(app.scene.getNonDeletedElements(), (element) => isBindableElement(element, false) &&
|
|
136
|
+
bindingBorderTest(element, pointerCoords, app));
|
|
131
137
|
return hoveredElement;
|
|
132
138
|
};
|
|
133
139
|
const calculateFocusAndGap = (linearElement, hoveredElement, startOrEnd, elementsMap) => {
|
|
@@ -237,28 +243,28 @@ const maybeCalculateNewGapWhenScaling = (changedElement, currentBinding, newSize
|
|
|
237
243
|
return { elementId, gap: newGap, focus };
|
|
238
244
|
};
|
|
239
245
|
// TODO: this is a bottleneck, optimise
|
|
240
|
-
export const getEligibleElementsForBinding = (selectedElements,
|
|
246
|
+
export const getEligibleElementsForBinding = (selectedElements, app) => {
|
|
241
247
|
const includedElementIds = new Set(selectedElements.map(({ id }) => id));
|
|
242
248
|
return selectedElements.flatMap((selectedElement) => isBindingElement(selectedElement, false)
|
|
243
|
-
? getElligibleElementsForBindingElement(selectedElement,
|
|
249
|
+
? getElligibleElementsForBindingElement(selectedElement, app).filter((element) => !includedElementIds.has(element.id))
|
|
244
250
|
: isBindableElement(selectedElement, false)
|
|
245
|
-
? getElligibleElementsForBindableElementAndWhere(selectedElement,
|
|
251
|
+
? getElligibleElementsForBindableElementAndWhere(selectedElement, app).filter((binding) => !includedElementIds.has(binding[0].id))
|
|
246
252
|
: []);
|
|
247
253
|
};
|
|
248
|
-
const getElligibleElementsForBindingElement = (linearElement,
|
|
254
|
+
const getElligibleElementsForBindingElement = (linearElement, app) => {
|
|
249
255
|
return [
|
|
250
|
-
getElligibleElementForBindingElement(linearElement, "start",
|
|
251
|
-
getElligibleElementForBindingElement(linearElement, "end",
|
|
256
|
+
getElligibleElementForBindingElement(linearElement, "start", app),
|
|
257
|
+
getElligibleElementForBindingElement(linearElement, "end", app),
|
|
252
258
|
].filter((element) => element != null);
|
|
253
259
|
};
|
|
254
|
-
const getElligibleElementForBindingElement = (linearElement, startOrEnd,
|
|
255
|
-
return getHoveredElementForBinding(getLinearElementEdgeCoors(linearElement, startOrEnd,
|
|
260
|
+
const getElligibleElementForBindingElement = (linearElement, startOrEnd, app) => {
|
|
261
|
+
return getHoveredElementForBinding(getLinearElementEdgeCoors(linearElement, startOrEnd, app.scene.getNonDeletedElementsMap()), app);
|
|
256
262
|
};
|
|
257
263
|
const getLinearElementEdgeCoors = (linearElement, startOrEnd, elementsMap) => {
|
|
258
264
|
const index = startOrEnd === "start" ? 0 : -1;
|
|
259
265
|
return tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(linearElement, index, elementsMap));
|
|
260
266
|
};
|
|
261
|
-
const getElligibleElementsForBindableElementAndWhere = (bindableElement,
|
|
267
|
+
const getElligibleElementsForBindableElementAndWhere = (bindableElement, app) => {
|
|
262
268
|
const scene = Scene.getScene(bindableElement);
|
|
263
269
|
return scene
|
|
264
270
|
.getNonDeletedElements()
|
|
@@ -266,8 +272,8 @@ const getElligibleElementsForBindableElementAndWhere = (bindableElement, element
|
|
|
266
272
|
if (!isBindingElement(element, false)) {
|
|
267
273
|
return null;
|
|
268
274
|
}
|
|
269
|
-
const canBindStart = isLinearElementEligibleForNewBindingByBindable(element, "start", bindableElement,
|
|
270
|
-
const canBindEnd = isLinearElementEligibleForNewBindingByBindable(element, "end", bindableElement,
|
|
275
|
+
const canBindStart = isLinearElementEligibleForNewBindingByBindable(element, "start", bindableElement, scene.getNonDeletedElementsMap(), app);
|
|
276
|
+
const canBindEnd = isLinearElementEligibleForNewBindingByBindable(element, "end", bindableElement, scene.getNonDeletedElementsMap(), app);
|
|
271
277
|
if (!canBindStart && !canBindEnd) {
|
|
272
278
|
return null;
|
|
273
279
|
}
|
|
@@ -279,11 +285,11 @@ const getElligibleElementsForBindableElementAndWhere = (bindableElement, element
|
|
|
279
285
|
})
|
|
280
286
|
.filter((maybeElement) => maybeElement != null);
|
|
281
287
|
};
|
|
282
|
-
const isLinearElementEligibleForNewBindingByBindable = (linearElement, startOrEnd, bindableElement, elementsMap) => {
|
|
288
|
+
const isLinearElementEligibleForNewBindingByBindable = (linearElement, startOrEnd, bindableElement, elementsMap, app) => {
|
|
283
289
|
const existingBinding = linearElement[startOrEnd === "start" ? "startBinding" : "endBinding"];
|
|
284
290
|
return (existingBinding == null &&
|
|
285
291
|
!isLinearElementSimpleAndAlreadyBoundOnOppositeEdge(linearElement, bindableElement, startOrEnd) &&
|
|
286
|
-
bindingBorderTest(bindableElement, getLinearElementEdgeCoors(linearElement, startOrEnd, elementsMap),
|
|
292
|
+
bindingBorderTest(bindableElement, getLinearElementEdgeCoors(linearElement, startOrEnd, elementsMap), app));
|
|
287
293
|
};
|
|
288
294
|
// We need to:
|
|
289
295
|
// 1: Update elements not selected to point to duplicated elements
|
|
@@ -412,3 +418,374 @@ const newBoundElementsAfterDeletion = (boundElements, deletedElementIds) => {
|
|
|
412
418
|
}
|
|
413
419
|
return boundElements.filter((ele) => !deletedElementIds.has(ele.id));
|
|
414
420
|
};
|
|
421
|
+
export const bindingBorderTest = (element, { x, y }, app) => {
|
|
422
|
+
const threshold = maxBindingGap(element, element.width, element.height);
|
|
423
|
+
const shape = app.getElementShape(element);
|
|
424
|
+
return isPointOnShape([x, y], shape, threshold);
|
|
425
|
+
};
|
|
426
|
+
export const maxBindingGap = (element, elementWidth, elementHeight) => {
|
|
427
|
+
// Aligns diamonds with rectangles
|
|
428
|
+
const shapeRatio = element.type === "diamond" ? 1 / Math.sqrt(2) : 1;
|
|
429
|
+
const smallerDimension = shapeRatio * Math.min(elementWidth, elementHeight);
|
|
430
|
+
// We make the bindable boundary bigger for bigger elements
|
|
431
|
+
return Math.max(16, Math.min(0.25 * smallerDimension, 32));
|
|
432
|
+
};
|
|
433
|
+
export const distanceToBindableElement = (element, point, elementsMap) => {
|
|
434
|
+
switch (element.type) {
|
|
435
|
+
case "rectangle":
|
|
436
|
+
case "image":
|
|
437
|
+
case "text":
|
|
438
|
+
case "iframe":
|
|
439
|
+
case "embeddable":
|
|
440
|
+
case "frame":
|
|
441
|
+
case "magicframe":
|
|
442
|
+
return distanceToRectangle(element, point, elementsMap);
|
|
443
|
+
case "diamond":
|
|
444
|
+
return distanceToDiamond(element, point, elementsMap);
|
|
445
|
+
case "ellipse":
|
|
446
|
+
return distanceToEllipse(element, point, elementsMap);
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
const distanceToRectangle = (element, point, elementsMap) => {
|
|
450
|
+
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
|
|
451
|
+
return Math.max(GAPoint.distanceToLine(pointRel, GALine.equation(0, 1, -hheight)), GAPoint.distanceToLine(pointRel, GALine.equation(1, 0, -hwidth)));
|
|
452
|
+
};
|
|
453
|
+
const distanceToDiamond = (element, point, elementsMap) => {
|
|
454
|
+
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
|
|
455
|
+
const side = GALine.equation(hheight, hwidth, -hheight * hwidth);
|
|
456
|
+
return GAPoint.distanceToLine(pointRel, side);
|
|
457
|
+
};
|
|
458
|
+
export const distanceToEllipse = (element, point, elementsMap) => {
|
|
459
|
+
const [pointRel, tangent] = ellipseParamsForTest(element, point, elementsMap);
|
|
460
|
+
return -GALine.sign(tangent) * GAPoint.distanceToLine(pointRel, tangent);
|
|
461
|
+
};
|
|
462
|
+
const ellipseParamsForTest = (element, point, elementsMap) => {
|
|
463
|
+
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
|
|
464
|
+
const [px, py] = GAPoint.toTuple(pointRel);
|
|
465
|
+
// We're working in positive quadrant, so start with `t = 45deg`, `tx=cos(t)`
|
|
466
|
+
let tx = 0.707;
|
|
467
|
+
let ty = 0.707;
|
|
468
|
+
const a = hwidth;
|
|
469
|
+
const b = hheight;
|
|
470
|
+
// This is a numerical method to find the params tx, ty at which
|
|
471
|
+
// the ellipse has the closest point to the given point
|
|
472
|
+
[0, 1, 2, 3].forEach((_) => {
|
|
473
|
+
const xx = a * tx;
|
|
474
|
+
const yy = b * ty;
|
|
475
|
+
const ex = ((a * a - b * b) * tx ** 3) / a;
|
|
476
|
+
const ey = ((b * b - a * a) * ty ** 3) / b;
|
|
477
|
+
const rx = xx - ex;
|
|
478
|
+
const ry = yy - ey;
|
|
479
|
+
const qx = px - ex;
|
|
480
|
+
const qy = py - ey;
|
|
481
|
+
const r = Math.hypot(ry, rx);
|
|
482
|
+
const q = Math.hypot(qy, qx);
|
|
483
|
+
tx = Math.min(1, Math.max(0, ((qx * r) / q + ex) / a));
|
|
484
|
+
ty = Math.min(1, Math.max(0, ((qy * r) / q + ey) / b));
|
|
485
|
+
const t = Math.hypot(ty, tx);
|
|
486
|
+
tx /= t;
|
|
487
|
+
ty /= t;
|
|
488
|
+
});
|
|
489
|
+
const closestPoint = GA.point(a * tx, b * ty);
|
|
490
|
+
const tangent = GALine.orthogonalThrough(pointRel, closestPoint);
|
|
491
|
+
return [pointRel, tangent];
|
|
492
|
+
};
|
|
493
|
+
// Returns:
|
|
494
|
+
// 1. the point relative to the elements (x, y) position
|
|
495
|
+
// 2. the point relative to the element's center with positive (x, y)
|
|
496
|
+
// 3. half element width
|
|
497
|
+
// 4. half element height
|
|
498
|
+
//
|
|
499
|
+
// Note that for linear elements the (x, y) position is not at the
|
|
500
|
+
// top right corner of their boundary.
|
|
501
|
+
//
|
|
502
|
+
// Rectangles, diamonds and ellipses are symmetrical over axes,
|
|
503
|
+
// and other elements have a rectangular boundary,
|
|
504
|
+
// so we only need to perform hit tests for the positive quadrant.
|
|
505
|
+
const pointRelativeToElement = (element, pointTuple, elementsMap) => {
|
|
506
|
+
const point = GAPoint.from(pointTuple);
|
|
507
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
508
|
+
const center = coordsCenter(x1, y1, x2, y2);
|
|
509
|
+
// GA has angle orientation opposite to `rotate`
|
|
510
|
+
const rotate = GATransform.rotation(center, element.angle);
|
|
511
|
+
const pointRotated = GATransform.apply(rotate, point);
|
|
512
|
+
const pointRelToCenter = GA.sub(pointRotated, GADirection.from(center));
|
|
513
|
+
const pointRelToCenterAbs = GAPoint.abs(pointRelToCenter);
|
|
514
|
+
const elementPos = GA.offset(element.x, element.y);
|
|
515
|
+
const pointRelToPos = GA.sub(pointRotated, elementPos);
|
|
516
|
+
const halfWidth = (x2 - x1) / 2;
|
|
517
|
+
const halfHeight = (y2 - y1) / 2;
|
|
518
|
+
return [pointRelToPos, pointRelToCenterAbs, halfWidth, halfHeight];
|
|
519
|
+
};
|
|
520
|
+
const relativizationToElementCenter = (element, elementsMap) => {
|
|
521
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
522
|
+
const center = coordsCenter(x1, y1, x2, y2);
|
|
523
|
+
// GA has angle orientation opposite to `rotate`
|
|
524
|
+
const rotate = GATransform.rotation(center, element.angle);
|
|
525
|
+
const translate = GA.reverse(GATransform.translation(GADirection.from(center)));
|
|
526
|
+
return GATransform.compose(rotate, translate);
|
|
527
|
+
};
|
|
528
|
+
const coordsCenter = (x1, y1, x2, y2) => {
|
|
529
|
+
return GA.point((x1 + x2) / 2, (y1 + y2) / 2);
|
|
530
|
+
};
|
|
531
|
+
// The focus distance is the oriented ratio between the size of
|
|
532
|
+
// the `element` and the "focus image" of the element on which
|
|
533
|
+
// all focus points lie, so it's a number between -1 and 1.
|
|
534
|
+
// The line going through `a` and `b` is a tangent to the "focus image"
|
|
535
|
+
// of the element.
|
|
536
|
+
export const determineFocusDistance = (element,
|
|
537
|
+
// Point on the line, in absolute coordinates
|
|
538
|
+
a,
|
|
539
|
+
// Another point on the line, in absolute coordinates (closer to element)
|
|
540
|
+
b, elementsMap) => {
|
|
541
|
+
const relateToCenter = relativizationToElementCenter(element, elementsMap);
|
|
542
|
+
const aRel = GATransform.apply(relateToCenter, GAPoint.from(a));
|
|
543
|
+
const bRel = GATransform.apply(relateToCenter, GAPoint.from(b));
|
|
544
|
+
const line = GALine.through(aRel, bRel);
|
|
545
|
+
const q = element.height / element.width;
|
|
546
|
+
const hwidth = element.width / 2;
|
|
547
|
+
const hheight = element.height / 2;
|
|
548
|
+
const n = line[2];
|
|
549
|
+
const m = line[3];
|
|
550
|
+
const c = line[1];
|
|
551
|
+
const mabs = Math.abs(m);
|
|
552
|
+
const nabs = Math.abs(n);
|
|
553
|
+
let ret;
|
|
554
|
+
switch (element.type) {
|
|
555
|
+
case "rectangle":
|
|
556
|
+
case "image":
|
|
557
|
+
case "text":
|
|
558
|
+
case "iframe":
|
|
559
|
+
case "embeddable":
|
|
560
|
+
case "frame":
|
|
561
|
+
case "magicframe":
|
|
562
|
+
ret = c / (hwidth * (nabs + q * mabs));
|
|
563
|
+
break;
|
|
564
|
+
case "diamond":
|
|
565
|
+
ret = mabs < nabs ? c / (nabs * hwidth) : c / (mabs * hheight);
|
|
566
|
+
break;
|
|
567
|
+
case "ellipse":
|
|
568
|
+
ret = c / (hwidth * Math.sqrt(n ** 2 + q ** 2 * m ** 2));
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
return ret || 0;
|
|
572
|
+
};
|
|
573
|
+
export const determineFocusPoint = (element,
|
|
574
|
+
// The oriented, relative distance from the center of `element` of the
|
|
575
|
+
// returned focusPoint
|
|
576
|
+
focus, adjecentPoint, elementsMap) => {
|
|
577
|
+
if (focus === 0) {
|
|
578
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
579
|
+
const center = coordsCenter(x1, y1, x2, y2);
|
|
580
|
+
return GAPoint.toTuple(center);
|
|
581
|
+
}
|
|
582
|
+
const relateToCenter = relativizationToElementCenter(element, elementsMap);
|
|
583
|
+
const adjecentPointRel = GATransform.apply(relateToCenter, GAPoint.from(adjecentPoint));
|
|
584
|
+
const reverseRelateToCenter = GA.reverse(relateToCenter);
|
|
585
|
+
let point;
|
|
586
|
+
switch (element.type) {
|
|
587
|
+
case "rectangle":
|
|
588
|
+
case "image":
|
|
589
|
+
case "text":
|
|
590
|
+
case "diamond":
|
|
591
|
+
case "iframe":
|
|
592
|
+
case "embeddable":
|
|
593
|
+
case "frame":
|
|
594
|
+
case "magicframe":
|
|
595
|
+
point = findFocusPointForRectangulars(element, focus, adjecentPointRel);
|
|
596
|
+
break;
|
|
597
|
+
case "ellipse":
|
|
598
|
+
point = findFocusPointForEllipse(element, focus, adjecentPointRel);
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
return GAPoint.toTuple(GATransform.apply(reverseRelateToCenter, point));
|
|
602
|
+
};
|
|
603
|
+
// Returns 2 or 0 intersection points between line going through `a` and `b`
|
|
604
|
+
// and the `element`, in ascending order of distance from `a`.
|
|
605
|
+
export const intersectElementWithLine = (element,
|
|
606
|
+
// Point on the line, in absolute coordinates
|
|
607
|
+
a,
|
|
608
|
+
// Another point on the line, in absolute coordinates
|
|
609
|
+
b,
|
|
610
|
+
// If given, the element is inflated by this value
|
|
611
|
+
gap = 0, elementsMap) => {
|
|
612
|
+
const relateToCenter = relativizationToElementCenter(element, elementsMap);
|
|
613
|
+
const aRel = GATransform.apply(relateToCenter, GAPoint.from(a));
|
|
614
|
+
const bRel = GATransform.apply(relateToCenter, GAPoint.from(b));
|
|
615
|
+
const line = GALine.through(aRel, bRel);
|
|
616
|
+
const reverseRelateToCenter = GA.reverse(relateToCenter);
|
|
617
|
+
const intersections = getSortedElementLineIntersections(element, line, aRel, gap);
|
|
618
|
+
return intersections.map((point) => GAPoint.toTuple(GATransform.apply(reverseRelateToCenter, point)));
|
|
619
|
+
};
|
|
620
|
+
const getSortedElementLineIntersections = (element,
|
|
621
|
+
// Relative to element center
|
|
622
|
+
line,
|
|
623
|
+
// Relative to element center
|
|
624
|
+
nearPoint, gap = 0) => {
|
|
625
|
+
let intersections;
|
|
626
|
+
switch (element.type) {
|
|
627
|
+
case "rectangle":
|
|
628
|
+
case "image":
|
|
629
|
+
case "text":
|
|
630
|
+
case "diamond":
|
|
631
|
+
case "iframe":
|
|
632
|
+
case "embeddable":
|
|
633
|
+
case "frame":
|
|
634
|
+
case "magicframe":
|
|
635
|
+
const corners = getCorners(element);
|
|
636
|
+
intersections = corners
|
|
637
|
+
.flatMap((point, i) => {
|
|
638
|
+
const edge = [point, corners[(i + 1) % 4]];
|
|
639
|
+
return intersectSegment(line, offsetSegment(edge, gap));
|
|
640
|
+
})
|
|
641
|
+
.concat(corners.flatMap((point) => getCircleIntersections(point, gap, line)));
|
|
642
|
+
break;
|
|
643
|
+
case "ellipse":
|
|
644
|
+
intersections = getEllipseIntersections(element, gap, line);
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
if (intersections.length < 2) {
|
|
648
|
+
// Ignore the "edge" case of only intersecting with a single corner
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
const sortedIntersections = intersections.sort((i1, i2) => GAPoint.distance(i1, nearPoint) - GAPoint.distance(i2, nearPoint));
|
|
652
|
+
return [
|
|
653
|
+
sortedIntersections[0],
|
|
654
|
+
sortedIntersections[sortedIntersections.length - 1],
|
|
655
|
+
];
|
|
656
|
+
};
|
|
657
|
+
const getCorners = (element, scale = 1) => {
|
|
658
|
+
const hx = (scale * element.width) / 2;
|
|
659
|
+
const hy = (scale * element.height) / 2;
|
|
660
|
+
switch (element.type) {
|
|
661
|
+
case "rectangle":
|
|
662
|
+
case "image":
|
|
663
|
+
case "text":
|
|
664
|
+
case "iframe":
|
|
665
|
+
case "embeddable":
|
|
666
|
+
case "frame":
|
|
667
|
+
case "magicframe":
|
|
668
|
+
return [
|
|
669
|
+
GA.point(hx, hy),
|
|
670
|
+
GA.point(hx, -hy),
|
|
671
|
+
GA.point(-hx, -hy),
|
|
672
|
+
GA.point(-hx, hy),
|
|
673
|
+
];
|
|
674
|
+
case "diamond":
|
|
675
|
+
return [
|
|
676
|
+
GA.point(0, hy),
|
|
677
|
+
GA.point(hx, 0),
|
|
678
|
+
GA.point(0, -hy),
|
|
679
|
+
GA.point(-hx, 0),
|
|
680
|
+
];
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
// Returns intersection of `line` with `segment`, with `segment` moved by
|
|
684
|
+
// `gap` in its polar direction.
|
|
685
|
+
// If intersection coincides with second segment point returns empty array.
|
|
686
|
+
const intersectSegment = (line, segment) => {
|
|
687
|
+
const [a, b] = segment;
|
|
688
|
+
const aDist = GAPoint.distanceToLine(a, line);
|
|
689
|
+
const bDist = GAPoint.distanceToLine(b, line);
|
|
690
|
+
if (aDist * bDist >= 0) {
|
|
691
|
+
// The intersection is outside segment `(a, b)`
|
|
692
|
+
return [];
|
|
693
|
+
}
|
|
694
|
+
return [GAPoint.intersect(line, GALine.through(a, b))];
|
|
695
|
+
};
|
|
696
|
+
const offsetSegment = (segment, distance) => {
|
|
697
|
+
const [a, b] = segment;
|
|
698
|
+
const offset = GATransform.translationOrthogonal(GADirection.fromTo(a, b), distance);
|
|
699
|
+
return [GATransform.apply(offset, a), GATransform.apply(offset, b)];
|
|
700
|
+
};
|
|
701
|
+
const getEllipseIntersections = (element, gap, line) => {
|
|
702
|
+
const a = element.width / 2 + gap;
|
|
703
|
+
const b = element.height / 2 + gap;
|
|
704
|
+
const m = line[2];
|
|
705
|
+
const n = line[3];
|
|
706
|
+
const c = line[1];
|
|
707
|
+
const squares = a * a * m * m + b * b * n * n;
|
|
708
|
+
const discr = squares - c * c;
|
|
709
|
+
if (squares === 0 || discr <= 0) {
|
|
710
|
+
return [];
|
|
711
|
+
}
|
|
712
|
+
const discrRoot = Math.sqrt(discr);
|
|
713
|
+
const xn = -a * a * m * c;
|
|
714
|
+
const yn = -b * b * n * c;
|
|
715
|
+
return [
|
|
716
|
+
GA.point((xn + a * b * n * discrRoot) / squares, (yn - a * b * m * discrRoot) / squares),
|
|
717
|
+
GA.point((xn - a * b * n * discrRoot) / squares, (yn + a * b * m * discrRoot) / squares),
|
|
718
|
+
];
|
|
719
|
+
};
|
|
720
|
+
export const getCircleIntersections = (center, radius, line) => {
|
|
721
|
+
if (radius === 0) {
|
|
722
|
+
return GAPoint.distanceToLine(line, center) === 0 ? [center] : [];
|
|
723
|
+
}
|
|
724
|
+
const m = line[2];
|
|
725
|
+
const n = line[3];
|
|
726
|
+
const c = line[1];
|
|
727
|
+
const [a, b] = GAPoint.toTuple(center);
|
|
728
|
+
const r = radius;
|
|
729
|
+
const squares = m * m + n * n;
|
|
730
|
+
const discr = r * r * squares - (m * a + n * b + c) ** 2;
|
|
731
|
+
if (squares === 0 || discr <= 0) {
|
|
732
|
+
return [];
|
|
733
|
+
}
|
|
734
|
+
const discrRoot = Math.sqrt(discr);
|
|
735
|
+
const xn = a * n * n - b * m * n - m * c;
|
|
736
|
+
const yn = b * m * m - a * m * n - n * c;
|
|
737
|
+
return [
|
|
738
|
+
GA.point((xn + n * discrRoot) / squares, (yn - m * discrRoot) / squares),
|
|
739
|
+
GA.point((xn - n * discrRoot) / squares, (yn + m * discrRoot) / squares),
|
|
740
|
+
];
|
|
741
|
+
};
|
|
742
|
+
// The focus point is the tangent point of the "focus image" of the
|
|
743
|
+
// `element`, where the tangent goes through `point`.
|
|
744
|
+
export const findFocusPointForEllipse = (ellipse,
|
|
745
|
+
// Between -1 and 1 (not 0) the relative size of the "focus image" of
|
|
746
|
+
// the element on which the focus point lies
|
|
747
|
+
relativeDistance,
|
|
748
|
+
// The point for which we're trying to find the focus point, relative
|
|
749
|
+
// to the ellipse center.
|
|
750
|
+
point) => {
|
|
751
|
+
const relativeDistanceAbs = Math.abs(relativeDistance);
|
|
752
|
+
const a = (ellipse.width * relativeDistanceAbs) / 2;
|
|
753
|
+
const b = (ellipse.height * relativeDistanceAbs) / 2;
|
|
754
|
+
const orientation = Math.sign(relativeDistance);
|
|
755
|
+
const [px, pyo] = GAPoint.toTuple(point);
|
|
756
|
+
// The calculation below can't handle py = 0
|
|
757
|
+
const py = pyo === 0 ? 0.0001 : pyo;
|
|
758
|
+
const squares = px ** 2 * b ** 2 + py ** 2 * a ** 2;
|
|
759
|
+
// Tangent mx + ny + 1 = 0
|
|
760
|
+
const m = (-px * b ** 2 +
|
|
761
|
+
orientation * py * Math.sqrt(Math.max(0, squares - a ** 2 * b ** 2))) /
|
|
762
|
+
squares;
|
|
763
|
+
let n = (-m * px - 1) / py;
|
|
764
|
+
if (n === 0) {
|
|
765
|
+
// if zero {-0, 0}, fall back to a same-sign value in the similar range
|
|
766
|
+
n = (Object.is(n, -0) ? -1 : 1) * 0.01;
|
|
767
|
+
}
|
|
768
|
+
const x = -(a ** 2 * m) / (n ** 2 * b ** 2 + m ** 2 * a ** 2);
|
|
769
|
+
return GA.point(x, (-m * x - 1) / n);
|
|
770
|
+
};
|
|
771
|
+
export const findFocusPointForRectangulars = (element,
|
|
772
|
+
// Between -1 and 1 for how far away should the focus point be relative
|
|
773
|
+
// to the size of the element. Sign determines orientation.
|
|
774
|
+
relativeDistance,
|
|
775
|
+
// The point for which we're trying to find the focus point, relative
|
|
776
|
+
// to the element center.
|
|
777
|
+
point) => {
|
|
778
|
+
const relativeDistanceAbs = Math.abs(relativeDistance);
|
|
779
|
+
const orientation = Math.sign(relativeDistance);
|
|
780
|
+
const corners = getCorners(element, relativeDistanceAbs);
|
|
781
|
+
let maxDistance = 0;
|
|
782
|
+
let tangentPoint = null;
|
|
783
|
+
corners.forEach((corner) => {
|
|
784
|
+
const distance = orientation * GALine.through(point, corner)[1];
|
|
785
|
+
if (distance > maxDistance) {
|
|
786
|
+
maxDistance = distance;
|
|
787
|
+
tangentPoint = corner;
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
return tangentPoint;
|
|
791
|
+
};
|
|
@@ -36,7 +36,6 @@ export declare const getElementLineSegments: (element: ExcalidrawElement, elemen
|
|
|
36
36
|
* Rectangle here means any rectangular frame, not an excalidraw element.
|
|
37
37
|
*/
|
|
38
38
|
export declare const getRectangleBoxAbsoluteCoords: (boxSceneCoords: RectangleBox) => number[];
|
|
39
|
-
export declare const pointRelativeTo: (element: ExcalidrawElement, absoluteCoords: readonly [number, number]) => readonly [number, number];
|
|
40
39
|
export declare const getDiamondPoints: (element: ExcalidrawElement) => number[];
|
|
41
40
|
export declare const getCurvePathOps: (shape: Drawable) => Op[];
|
|
42
41
|
export declare const getMinMaxXYFromCurvePathOps: (ops: Op[], transformXY?: ((x: number, y: number) => [number, number]) | undefined) => Bounds;
|
|
@@ -192,9 +192,6 @@ export const getRectangleBoxAbsoluteCoords = (boxSceneCoords) => {
|
|
|
192
192
|
boxSceneCoords.y + boxSceneCoords.height / 2,
|
|
193
193
|
];
|
|
194
194
|
};
|
|
195
|
-
export const pointRelativeTo = (element, absoluteCoords) => {
|
|
196
|
-
return [absoluteCoords[0] - element.x, absoluteCoords[1] - element.y];
|
|
197
|
-
};
|
|
198
195
|
export const getDiamondPoints = (element) => {
|
|
199
196
|
// Here we add +1 to avoid these numbers to be 0
|
|
200
197
|
// otherwise rough.js will throw an error complaining about it
|
|
@@ -1,21 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
export declare const isHittingElementBoundingBoxWithoutHittingElement: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number, elementsMap: ElementsMap) => boolean;
|
|
7
|
-
export declare const isHittingElementNotConsideringBoundingBox: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache | null, point: readonly [number, number], elementsMap: ElementsMap) => boolean;
|
|
8
|
-
export declare const isPointHittingElementBoundingBox: (element: NonDeleted<ExcalidrawElement>, elementsMap: ElementsMap, [x, y]: readonly [number, number], threshold: number, frameNameBoundsCache: FrameNameBoundsCache | null) => boolean;
|
|
9
|
-
export declare const bindingBorderTest: (element: NonDeleted<ExcalidrawBindableElement>, { x, y }: {
|
|
1
|
+
import { ElementsMap, ExcalidrawElement } from "./types";
|
|
2
|
+
import { FrameNameBounds } from "../types";
|
|
3
|
+
import { GeometricShape } from "../../utils/geometry/shape";
|
|
4
|
+
export declare const shouldTestInside: (element: ExcalidrawElement) => boolean;
|
|
5
|
+
export type HitTestArgs = {
|
|
10
6
|
x: number;
|
|
11
7
|
y: number;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export declare const
|
|
18
|
-
export declare const
|
|
19
|
-
export declare const
|
|
20
|
-
export declare const
|
|
21
|
-
export declare const findFocusPointForRectangulars: (element: ExcalidrawRectangleElement | ExcalidrawImageElement | ExcalidrawDiamondElement | ExcalidrawTextElement | ExcalidrawIframeLikeElement | ExcalidrawFrameLikeElement, relativeDistance: number, point: readonly [number, number, number, number, number, number, number, number]) => readonly [number, number, number, number, number, number, number, number];
|
|
8
|
+
element: ExcalidrawElement;
|
|
9
|
+
shape: GeometricShape;
|
|
10
|
+
threshold?: number;
|
|
11
|
+
frameNameBound?: FrameNameBounds | null;
|
|
12
|
+
};
|
|
13
|
+
export declare const hitElementItself: ({ x, y, element, shape, threshold, frameNameBound, }: HitTestArgs) => boolean;
|
|
14
|
+
export declare const hitElementBoundingBox: (x: number, y: number, element: ExcalidrawElement, elementsMap: ElementsMap, tolerance?: number) => boolean;
|
|
15
|
+
export declare const hitElementBoundingBoxOnly: (hitArgs: HitTestArgs, elementsMap: ElementsMap) => boolean;
|
|
16
|
+
export declare const hitElementBoundText: (x: number, y: number, textShape: GeometricShape | null) => boolean | null;
|