@excalidraw/excalidraw 0.17.1-7500-ac247a0 → 0.17.1-b7babe5
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 +56 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-2W5GQUR4.js → chunk-6NMK7JTV.js} +13 -6
- package/dist/browser/dev/excalidraw-assets-dev/chunk-6NMK7JTV.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/chunk-CX3RATXT.js +20324 -0
- package/dist/browser/dev/excalidraw-assets-dev/chunk-CX3RATXT.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js → en-BZY7JRTM.js} +4 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-5TVMINCA.js → image-CVN3YKRW.js} +2 -4
- package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css +6 -0
- package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/roundRect-T5BX56ZF.js +161 -0
- package/dist/browser/dev/excalidraw-assets-dev/roundRect-T5BX56ZF.js.map +7 -0
- package/dist/browser/dev/index.css +189 -129
- package/dist/browser/dev/index.css.map +3 -3
- package/dist/browser/dev/index.js +34964 -37
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/chunk-VJAIK3AX.js +55 -0
- package/dist/browser/prod/excalidraw-assets/chunk-YYO5DFUW.js +11 -0
- package/dist/browser/prod/excalidraw-assets/en-O2YCQM2W.js +1 -0
- package/dist/browser/prod/excalidraw-assets/image-6FKY54X5.js +1 -0
- package/dist/browser/prod/excalidraw-assets/image-X66R2EM5.css +1 -0
- package/dist/browser/prod/excalidraw-assets/roundRect-2ACQK4DA.js +1 -0
- package/dist/browser/prod/index.css +1 -1
- package/dist/browser/prod/index.js +203 -1
- package/dist/{prod/en-RLIAOBCI.json → dev/en-EY7E2L5O.json} +10 -5
- package/dist/dev/index.css +189 -129
- package/dist/dev/index.css.map +3 -3
- package/dist/dev/index.js +38702 -39409
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionAddToLibrary.d.ts +15 -15
- package/dist/excalidraw/actions/actionAlign.d.ts +6 -6
- package/dist/excalidraw/actions/actionAlign.js +2 -1
- package/dist/excalidraw/actions/actionBoundText.d.ts +10 -10
- package/dist/excalidraw/actions/actionBoundText.js +8 -8
- package/dist/excalidraw/actions/actionCanvas.d.ts +58 -58
- package/dist/excalidraw/actions/actionClipboard.d.ts +34 -34
- package/dist/excalidraw/actions/actionClipboard.js +9 -2
- package/dist/excalidraw/actions/actionDeleteSelected.d.ts +15 -15
- package/dist/excalidraw/actions/actionDeleteSelected.js +3 -2
- package/dist/excalidraw/actions/actionDistribute.d.ts +2 -2
- package/dist/excalidraw/actions/actionDistribute.js +1 -1
- package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +1 -1
- package/dist/excalidraw/actions/actionDuplicateSelection.js +4 -3
- package/dist/excalidraw/actions/actionElementLock.d.ts +10 -10
- package/dist/excalidraw/actions/actionExport.d.ts +43 -43
- package/dist/excalidraw/actions/actionExport.js +4 -4
- package/dist/excalidraw/actions/actionFinalize.d.ts +9 -9
- package/dist/excalidraw/actions/actionFinalize.js +7 -6
- package/dist/excalidraw/actions/actionFlip.d.ts +2 -2
- package/dist/excalidraw/actions/actionFlip.js +11 -11
- package/dist/excalidraw/actions/actionFrame.d.ts +16 -16
- package/dist/excalidraw/actions/actionFrame.js +1 -1
- package/dist/excalidraw/actions/actionGroup.d.ts +10 -10
- package/dist/excalidraw/actions/actionGroup.js +3 -2
- package/dist/excalidraw/actions/actionLinearEditor.d.ts +5 -5
- package/dist/excalidraw/actions/actionLinearEditor.js +1 -1
- package/dist/excalidraw/{element/Hyperlink.d.ts → actions/actionLink.d.ts} +29 -51
- package/dist/excalidraw/actions/actionLink.js +40 -0
- package/dist/excalidraw/actions/actionMenu.d.ts +13 -13
- package/dist/excalidraw/actions/actionNavigate.d.ts +10 -10
- package/dist/excalidraw/actions/actionNavigate.js +1 -1
- package/dist/excalidraw/actions/actionProperties.d.ts +77 -77
- package/dist/excalidraw/actions/actionProperties.js +32 -27
- package/dist/excalidraw/actions/actionSelectAll.d.ts +5 -5
- package/dist/excalidraw/actions/actionSelectAll.js +1 -1
- package/dist/excalidraw/actions/actionStyles.d.ts +7 -7
- package/dist/excalidraw/actions/actionStyles.js +4 -4
- package/dist/excalidraw/actions/actionToggleGridMode.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleStats.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleViewMode.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleZenMode.d.ts +5 -5
- package/dist/excalidraw/actions/index.d.ts +1 -1
- package/dist/excalidraw/actions/index.js +1 -1
- package/dist/excalidraw/actions/manager.js +2 -1
- package/dist/excalidraw/align.d.ts +2 -2
- package/dist/excalidraw/align.js +2 -2
- package/dist/excalidraw/animated-trail.d.ts +33 -0
- package/dist/excalidraw/animated-trail.js +96 -0
- package/dist/excalidraw/animation-frame-handler.d.ts +16 -0
- package/dist/excalidraw/animation-frame-handler.js +55 -0
- package/dist/excalidraw/appState.d.ts +1 -1
- package/dist/excalidraw/appState.js +1 -3
- package/dist/excalidraw/clipboard.js +5 -5
- package/dist/excalidraw/components/Actions.d.ts +3 -3
- package/dist/excalidraw/components/Actions.js +18 -7
- package/dist/excalidraw/components/App.d.ts +23 -16
- package/dist/excalidraw/components/App.js +387 -272
- package/dist/excalidraw/components/Button.d.ts +1 -1
- package/dist/excalidraw/components/FilledButton.d.ts +2 -2
- package/dist/excalidraw/components/FilledButton.js +27 -3
- package/dist/excalidraw/components/FollowMode/FollowMode.js +1 -1
- package/dist/excalidraw/components/ImageExportDialog.d.ts +2 -1
- package/dist/excalidraw/components/ImageExportDialog.js +17 -13
- package/dist/excalidraw/components/JSONExportDialog.js +1 -1
- package/dist/excalidraw/components/{LaserTool/LaserPointerButton.d.ts → LaserPointerButton.d.ts} +1 -1
- package/dist/excalidraw/components/{LaserTool/LaserPointerButton.js → LaserPointerButton.js} +2 -2
- package/dist/excalidraw/components/LayerUI.js +3 -3
- package/dist/excalidraw/components/MobileMenu.js +1 -1
- package/dist/excalidraw/components/ProjectName.d.ts +0 -1
- package/dist/excalidraw/components/ProjectName.js +1 -1
- package/dist/excalidraw/components/PublishLibrary.js +1 -1
- package/dist/excalidraw/components/SVGLayer.d.ts +8 -0
- package/dist/excalidraw/components/SVGLayer.js +20 -0
- package/dist/excalidraw/components/ShareableLinkDialog.js +10 -10
- package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +1 -1
- package/dist/excalidraw/components/Stack.d.ts +2 -2
- package/dist/excalidraw/components/TTDDialog/common.js +10 -1
- package/dist/excalidraw/components/TextField.d.ts +5 -2
- package/dist/excalidraw/components/TextField.js +6 -3
- package/dist/excalidraw/components/Toast.d.ts +3 -2
- package/dist/excalidraw/components/Toast.js +2 -2
- package/dist/excalidraw/components/ToolButton.js +2 -1
- package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +2 -2
- package/dist/excalidraw/components/canvases/InteractiveCanvas.js +6 -5
- package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +4 -3
- package/dist/excalidraw/components/canvases/StaticCanvas.js +7 -5
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuContent.js +22 -2
- package/dist/excalidraw/components/hyperlink/Hyperlink.d.ts +19 -0
- package/dist/excalidraw/{element → components/hyperlink}/Hyperlink.js +40 -115
- package/dist/excalidraw/components/hyperlink/helpers.d.ts +7 -0
- package/dist/excalidraw/components/hyperlink/helpers.js +49 -0
- package/dist/excalidraw/components/icons.d.ts +2 -1
- package/dist/excalidraw/components/icons.js +2 -1
- package/dist/excalidraw/components/live-collaboration/LiveCollaborationTrigger.js +3 -2
- package/dist/excalidraw/components/main-menu/DefaultItems.js +5 -2
- package/dist/excalidraw/constants.d.ts +6 -0
- package/dist/excalidraw/constants.js +6 -0
- package/dist/excalidraw/data/blob.js +13 -14
- package/dist/excalidraw/data/filesystem.d.ts +1 -1
- package/dist/excalidraw/data/index.d.ts +2 -1
- package/dist/excalidraw/data/index.js +20 -16
- package/dist/excalidraw/data/json.d.ts +1 -1
- package/dist/excalidraw/data/json.js +5 -3
- package/dist/excalidraw/data/library.d.ts +60 -8
- package/dist/excalidraw/data/library.js +302 -33
- package/dist/excalidraw/data/resave.d.ts +1 -1
- package/dist/excalidraw/data/resave.js +2 -2
- package/dist/excalidraw/data/restore.js +8 -13
- package/dist/excalidraw/data/transform.js +13 -9
- package/dist/excalidraw/distribute.d.ts +2 -2
- package/dist/excalidraw/distribute.js +2 -2
- package/dist/excalidraw/element/ElementCanvasButtons.d.ts +3 -2
- package/dist/excalidraw/element/ElementCanvasButtons.js +4 -4
- package/dist/excalidraw/element/binding.d.ts +9 -9
- package/dist/excalidraw/element/binding.js +61 -59
- package/dist/excalidraw/element/bounds.d.ts +5 -5
- package/dist/excalidraw/element/bounds.js +29 -32
- package/dist/excalidraw/element/collision.d.ts +11 -11
- package/dist/excalidraw/element/collision.js +49 -46
- package/dist/excalidraw/element/containerCache.d.ts +11 -0
- package/dist/excalidraw/element/containerCache.js +14 -0
- package/dist/excalidraw/element/dragElements.js +10 -19
- package/dist/excalidraw/element/embeddable.d.ts +12 -13
- package/dist/excalidraw/element/embeddable.js +17 -27
- package/dist/excalidraw/element/image.js +1 -2
- package/dist/excalidraw/element/index.d.ts +8 -1
- package/dist/excalidraw/element/index.js +23 -1
- package/dist/excalidraw/element/linearElementEditor.d.ts +36 -36
- package/dist/excalidraw/element/linearElementEditor.js +79 -80
- package/dist/excalidraw/element/newElement.d.ts +4 -6
- package/dist/excalidraw/element/newElement.js +11 -16
- package/dist/excalidraw/element/resizeElements.d.ts +6 -6
- package/dist/excalidraw/element/resizeElements.js +40 -46
- package/dist/excalidraw/element/resizeTest.d.ts +3 -3
- package/dist/excalidraw/element/resizeTest.js +4 -4
- package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
- package/dist/excalidraw/element/sizeHelpers.js +2 -2
- package/dist/excalidraw/element/textElement.d.ts +34 -21
- package/dist/excalidraw/element/textElement.js +87 -111
- package/dist/excalidraw/element/textWysiwyg.d.ts +1 -6
- package/dist/excalidraw/element/textWysiwyg.js +15 -37
- package/dist/excalidraw/element/transformHandles.d.ts +4 -4
- package/dist/excalidraw/element/transformHandles.js +6 -6
- package/dist/excalidraw/element/typeChecks.js +4 -1
- package/dist/excalidraw/element/types.d.ts +24 -11
- package/dist/excalidraw/frame.d.ts +26 -20
- package/dist/excalidraw/frame.js +157 -84
- package/dist/excalidraw/groups.d.ts +3 -3
- package/dist/excalidraw/groups.js +11 -3
- package/dist/excalidraw/history.d.ts +1 -1
- package/dist/excalidraw/hooks/useLibraryItemSvg.js +1 -1
- package/dist/excalidraw/index.d.ts +9 -10
- package/dist/excalidraw/index.js +16 -12
- package/dist/excalidraw/laser-trails.d.ts +19 -0
- package/dist/excalidraw/laser-trails.js +95 -0
- package/dist/excalidraw/locales/en.json +10 -5
- package/dist/excalidraw/queue.d.ts +9 -0
- package/dist/excalidraw/queue.js +27 -0
- package/dist/excalidraw/reactUtils.d.ts +14 -0
- package/dist/excalidraw/reactUtils.js +45 -0
- package/dist/excalidraw/renderer/helpers.d.ts +13 -0
- package/dist/excalidraw/renderer/helpers.js +39 -0
- package/dist/excalidraw/renderer/interactiveScene.d.ts +20 -0
- package/dist/excalidraw/renderer/{renderScene.js → interactiveScene.js} +199 -474
- package/dist/excalidraw/renderer/renderElement.d.ts +6 -6
- package/dist/excalidraw/renderer/renderElement.js +54 -366
- package/dist/excalidraw/renderer/staticScene.d.ts +11 -0
- package/dist/excalidraw/renderer/staticScene.js +205 -0
- package/dist/excalidraw/renderer/staticSvgScene.d.ts +5 -0
- package/dist/excalidraw/renderer/staticSvgScene.js +385 -0
- package/dist/excalidraw/scene/Fonts.js +2 -1
- package/dist/excalidraw/scene/Renderer.d.ts +1 -1
- package/dist/excalidraw/scene/Renderer.js +32 -20
- package/dist/excalidraw/scene/Scene.d.ts +10 -9
- package/dist/excalidraw/scene/Scene.js +45 -21
- package/dist/excalidraw/scene/Shape.d.ts +3 -1
- package/dist/excalidraw/scene/Shape.js +7 -5
- package/dist/excalidraw/scene/ShapeCache.d.ts +2 -1
- package/dist/excalidraw/scene/ShapeCache.js +1 -0
- package/dist/excalidraw/scene/comparisons.js +2 -1
- package/dist/excalidraw/scene/export.d.ts +3 -0
- package/dist/excalidraw/scene/export.js +20 -40
- package/dist/excalidraw/scene/index.d.ts +0 -1
- package/dist/excalidraw/scene/index.js +0 -1
- package/dist/excalidraw/scene/scrollbars.d.ts +1 -1
- package/dist/excalidraw/scene/scrollbars.js +1 -1
- package/dist/excalidraw/scene/selection.d.ts +5 -5
- package/dist/excalidraw/scene/selection.js +16 -14
- package/dist/excalidraw/scene/types.d.ts +11 -5
- package/dist/excalidraw/snapping.d.ts +7 -7
- package/dist/excalidraw/snapping.js +21 -20
- package/dist/excalidraw/types.d.ts +16 -17
- package/dist/excalidraw/utility-types.d.ts +7 -0
- package/dist/excalidraw/utils.d.ts +21 -16
- package/dist/excalidraw/utils.js +43 -45
- package/dist/{dev/en-RLIAOBCI.json → prod/en-EY7E2L5O.json} +10 -5
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +42 -42
- package/dist/utils/bbox.d.ts +2 -2
- package/dist/utils/export.d.ts +3 -3
- package/dist/utils/export.js +3 -13
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +2 -2
- package/dist/utils/withinBounds.d.ts +1 -1
- package/dist/utils/withinBounds.js +5 -2
- package/package.json +4 -4
- package/dist/browser/dev/excalidraw-assets-dev/chunk-2W5GQUR4.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-KGZXLFLR.js +0 -53497
- package/dist/browser/dev/excalidraw-assets-dev/chunk-KGZXLFLR.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/image-3MFRCKYM.css +0 -5797
- package/dist/browser/dev/excalidraw-assets-dev/image-3MFRCKYM.css.map +0 -7
- package/dist/browser/prod/excalidraw-assets/chunk-4YN2HN3S.js +0 -257
- package/dist/browser/prod/excalidraw-assets/chunk-OWLL6VOG.js +0 -11
- package/dist/browser/prod/excalidraw-assets/en-ERQOR3OC.js +0 -1
- package/dist/browser/prod/excalidraw-assets/image-LTLHTTSE.js +0 -1
- package/dist/browser/prod/excalidraw-assets/image-QBL334OA.css +0 -1
- package/dist/excalidraw/components/LaserTool/LaserPathManager.d.ts +0 -28
- package/dist/excalidraw/components/LaserTool/LaserPathManager.js +0 -225
- package/dist/excalidraw/components/LaserTool/LaserTool.d.ts +0 -8
- package/dist/excalidraw/components/LaserTool/LaserTool.js +0 -15
- package/dist/excalidraw/renderer/renderScene.d.ts +0 -25
- package/dist/excalidraw/vite.config.d.mts +0 -2
- package/dist/excalidraw/vite.config.mjs +0 -13
- /package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js.map → en-BZY7JRTM.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-5TVMINCA.js.map → image-CVN3YKRW.js.map} +0 -0
|
@@ -6,10 +6,10 @@ import { rescalePoints } from "../points";
|
|
|
6
6
|
import { getBoundTextElement, getContainerElement } from "./textElement";
|
|
7
7
|
import { LinearElementEditor } from "./linearElementEditor";
|
|
8
8
|
import { ShapeCache } from "../scene/ShapeCache";
|
|
9
|
-
import
|
|
9
|
+
import { arrayToMap } from "../utils";
|
|
10
10
|
export class ElementBounds {
|
|
11
11
|
static boundsCache = new WeakMap();
|
|
12
|
-
static getBounds(element) {
|
|
12
|
+
static getBounds(element, elementsMap) {
|
|
13
13
|
const cachedBounds = ElementBounds.boundsCache.get(element);
|
|
14
14
|
if (cachedBounds?.version &&
|
|
15
15
|
cachedBounds.version === element.version &&
|
|
@@ -18,22 +18,16 @@ export class ElementBounds {
|
|
|
18
18
|
!isBoundToContainer(element)) {
|
|
19
19
|
return cachedBounds.bounds;
|
|
20
20
|
}
|
|
21
|
-
const bounds = ElementBounds.calculateBounds(element);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (shouldCache) {
|
|
27
|
-
ElementBounds.boundsCache.set(element, {
|
|
28
|
-
version: element.version,
|
|
29
|
-
bounds,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
21
|
+
const bounds = ElementBounds.calculateBounds(element, elementsMap);
|
|
22
|
+
ElementBounds.boundsCache.set(element, {
|
|
23
|
+
version: element.version,
|
|
24
|
+
bounds,
|
|
25
|
+
});
|
|
32
26
|
return bounds;
|
|
33
27
|
}
|
|
34
|
-
static calculateBounds(element) {
|
|
28
|
+
static calculateBounds(element, elementsMap) {
|
|
35
29
|
let bounds;
|
|
36
|
-
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element);
|
|
30
|
+
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element, elementsMap);
|
|
37
31
|
if (isFreeDrawElement(element)) {
|
|
38
32
|
const [minX, minY, maxX, maxY] = getBoundsFromPoints(element.points.map(([x, y]) => rotate(x, y, cx - element.x, cy - element.y, element.angle)));
|
|
39
33
|
return [
|
|
@@ -44,7 +38,7 @@ export class ElementBounds {
|
|
|
44
38
|
];
|
|
45
39
|
}
|
|
46
40
|
else if (isLinearElement(element)) {
|
|
47
|
-
bounds = getLinearElementRotatedBounds(element, cx, cy);
|
|
41
|
+
bounds = getLinearElementRotatedBounds(element, cx, cy, elementsMap);
|
|
48
42
|
}
|
|
49
43
|
else if (element.type === "diamond") {
|
|
50
44
|
const [x11, y11] = rotate(cx, y1, cx, cy, element.angle);
|
|
@@ -84,17 +78,19 @@ export class ElementBounds {
|
|
|
84
78
|
//
|
|
85
79
|
// If the element is created from right to left, the width is going to be negative
|
|
86
80
|
// This set of functions retrieves the absolute position of the 4 points.
|
|
87
|
-
export const getElementAbsoluteCoords = (element, includeBoundText = false) => {
|
|
81
|
+
export const getElementAbsoluteCoords = (element, elementsMap, includeBoundText = false) => {
|
|
88
82
|
if (isFreeDrawElement(element)) {
|
|
89
83
|
return getFreeDrawElementAbsoluteCoords(element);
|
|
90
84
|
}
|
|
91
85
|
else if (isLinearElement(element)) {
|
|
92
|
-
return LinearElementEditor.getElementAbsoluteCoords(element, includeBoundText);
|
|
86
|
+
return LinearElementEditor.getElementAbsoluteCoords(element, elementsMap, includeBoundText);
|
|
93
87
|
}
|
|
94
88
|
else if (isTextElement(element)) {
|
|
95
|
-
const container =
|
|
89
|
+
const container = elementsMap
|
|
90
|
+
? getContainerElement(element, elementsMap)
|
|
91
|
+
: null;
|
|
96
92
|
if (isArrowElement(container)) {
|
|
97
|
-
const coords = LinearElementEditor.getBoundTextElementPosition(container, element);
|
|
93
|
+
const coords = LinearElementEditor.getBoundTextElementPosition(container, element, elementsMap);
|
|
98
94
|
return [
|
|
99
95
|
coords.x,
|
|
100
96
|
coords.y,
|
|
@@ -119,8 +115,8 @@ export const getElementAbsoluteCoords = (element, includeBoundText = false) => {
|
|
|
119
115
|
* that can be used for visual collision detection (useful for frames)
|
|
120
116
|
* as opposed to bounding box collision detection
|
|
121
117
|
*/
|
|
122
|
-
export const getElementLineSegments = (element) => {
|
|
123
|
-
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element);
|
|
118
|
+
export const getElementLineSegments = (element, elementsMap) => {
|
|
119
|
+
const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element, elementsMap);
|
|
124
120
|
const center = [cx, cy];
|
|
125
121
|
if (isLinearElement(element) || isFreeDrawElement(element)) {
|
|
126
122
|
const segments = [];
|
|
@@ -459,14 +455,14 @@ const generateLinearElementShape = (element) => {
|
|
|
459
455
|
})();
|
|
460
456
|
return generator[method](element.points, options);
|
|
461
457
|
};
|
|
462
|
-
const getLinearElementRotatedBounds = (element, cx, cy) => {
|
|
458
|
+
const getLinearElementRotatedBounds = (element, cx, cy, elementsMap) => {
|
|
459
|
+
const boundTextElement = getBoundTextElement(element, elementsMap);
|
|
463
460
|
if (element.points.length < 2) {
|
|
464
461
|
const [pointX, pointY] = element.points[0];
|
|
465
462
|
const [x, y] = rotate(element.x + pointX, element.y + pointY, cx, cy, element.angle);
|
|
466
463
|
let coords = [x, y, x, y];
|
|
467
|
-
const boundTextElement = getBoundTextElement(element);
|
|
468
464
|
if (boundTextElement) {
|
|
469
|
-
const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, [x, y, x, y], boundTextElement);
|
|
465
|
+
const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, elementsMap, [x, y, x, y], boundTextElement);
|
|
470
466
|
coords = [
|
|
471
467
|
coordsWithBoundText[0],
|
|
472
468
|
coordsWithBoundText[1],
|
|
@@ -483,9 +479,8 @@ const getLinearElementRotatedBounds = (element, cx, cy) => {
|
|
|
483
479
|
const transformXY = (x, y) => rotate(element.x + x, element.y + y, cx, cy, element.angle);
|
|
484
480
|
const res = getMinMaxXYFromCurvePathOps(ops, transformXY);
|
|
485
481
|
let coords = [res[0], res[1], res[2], res[3]];
|
|
486
|
-
const boundTextElement = getBoundTextElement(element);
|
|
487
482
|
if (boundTextElement) {
|
|
488
|
-
const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, coords, boundTextElement);
|
|
483
|
+
const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, elementsMap, coords, boundTextElement);
|
|
489
484
|
coords = [
|
|
490
485
|
coordsWithBoundText[0],
|
|
491
486
|
coordsWithBoundText[1],
|
|
@@ -495,8 +490,8 @@ const getLinearElementRotatedBounds = (element, cx, cy) => {
|
|
|
495
490
|
}
|
|
496
491
|
return coords;
|
|
497
492
|
};
|
|
498
|
-
export const getElementBounds = (element) => {
|
|
499
|
-
return ElementBounds.getBounds(element);
|
|
493
|
+
export const getElementBounds = (element, elementsMap) => {
|
|
494
|
+
return ElementBounds.getBounds(element, elementsMap);
|
|
500
495
|
};
|
|
501
496
|
export const getCommonBounds = (elements) => {
|
|
502
497
|
if (!elements.length) {
|
|
@@ -506,8 +501,9 @@ export const getCommonBounds = (elements) => {
|
|
|
506
501
|
let maxX = -Infinity;
|
|
507
502
|
let minY = Infinity;
|
|
508
503
|
let maxY = -Infinity;
|
|
504
|
+
const elementsMap = arrayToMap(elements);
|
|
509
505
|
elements.forEach((element) => {
|
|
510
|
-
const [x1, y1, x2, y2] = getElementBounds(element);
|
|
506
|
+
const [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
|
|
511
507
|
minX = Math.min(minX, x1);
|
|
512
508
|
minY = Math.min(minY, y1);
|
|
513
509
|
maxX = Math.max(maxX, x2);
|
|
@@ -577,15 +573,16 @@ export const getClosestElementBounds = (elements, from) => {
|
|
|
577
573
|
}
|
|
578
574
|
let minDistance = Infinity;
|
|
579
575
|
let closestElement = elements[0];
|
|
576
|
+
const elementsMap = arrayToMap(elements);
|
|
580
577
|
elements.forEach((element) => {
|
|
581
|
-
const [x1, y1, x2, y2] = getElementBounds(element);
|
|
578
|
+
const [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
|
|
582
579
|
const distance = distance2d((x1 + x2) / 2, (y1 + y2) / 2, from.x, from.y);
|
|
583
580
|
if (distance < minDistance) {
|
|
584
581
|
minDistance = distance;
|
|
585
582
|
closestElement = element;
|
|
586
583
|
}
|
|
587
584
|
});
|
|
588
|
-
return getElementBounds(closestElement);
|
|
585
|
+
return getElementBounds(closestElement, elementsMap);
|
|
589
586
|
};
|
|
590
587
|
export const getCommonBoundingBox = (elements) => {
|
|
591
588
|
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import * as GA from "../ga";
|
|
2
|
-
import { NonDeletedExcalidrawElement, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawRectangleElement, ExcalidrawDiamondElement, ExcalidrawTextElement, ExcalidrawEllipseElement, NonDeleted, ExcalidrawImageElement, ExcalidrawFrameLikeElement, ExcalidrawIframeLikeElement } from "./types";
|
|
2
|
+
import { NonDeletedExcalidrawElement, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawRectangleElement, ExcalidrawDiamondElement, ExcalidrawTextElement, ExcalidrawEllipseElement, NonDeleted, ExcalidrawImageElement, ExcalidrawFrameLikeElement, ExcalidrawIframeLikeElement, ElementsMap } from "./types";
|
|
3
3
|
import { FrameNameBoundsCache, Point } from "../types";
|
|
4
4
|
import { AppState } from "../types";
|
|
5
|
-
export declare const hitTest: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number) => boolean;
|
|
6
|
-
export declare const isHittingElementBoundingBoxWithoutHittingElement: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number) => boolean;
|
|
7
|
-
export declare const isHittingElementNotConsideringBoundingBox: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache | null, point: readonly [number, number]) => boolean;
|
|
8
|
-
export declare const isPointHittingElementBoundingBox: (element: NonDeleted<ExcalidrawElement>, [x, y]: readonly [number, number], threshold: number, frameNameBoundsCache: FrameNameBoundsCache | null) => boolean;
|
|
5
|
+
export declare const hitTest: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number, elementsMap: ElementsMap) => boolean;
|
|
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
9
|
export declare const bindingBorderTest: (element: NonDeleted<ExcalidrawBindableElement>, { x, y }: {
|
|
10
10
|
x: number;
|
|
11
11
|
y: number;
|
|
12
|
-
}) => boolean;
|
|
12
|
+
}, elementsMap: ElementsMap) => boolean;
|
|
13
13
|
export declare const maxBindingGap: (element: ExcalidrawElement, elementWidth: number, elementHeight: number) => number;
|
|
14
|
-
export declare const distanceToBindableElement: (element: ExcalidrawBindableElement, point: readonly [number, number]) => number;
|
|
15
|
-
export declare const pointInAbsoluteCoords: (element: ExcalidrawElement, point: readonly [number, number]) => readonly [number, number];
|
|
16
|
-
export declare const determineFocusDistance: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number]) => number;
|
|
17
|
-
export declare const determineFocusPoint: (element: ExcalidrawBindableElement, focus: number, adjecentPoint: readonly [number, number]) => readonly [number, number];
|
|
18
|
-
export declare const intersectElementWithLine: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], gap
|
|
14
|
+
export declare const distanceToBindableElement: (element: ExcalidrawBindableElement, point: readonly [number, number], elementsMap: ElementsMap) => number;
|
|
15
|
+
export declare const pointInAbsoluteCoords: (element: ExcalidrawElement, elementsMap: ElementsMap, point: readonly [number, number]) => readonly [number, number];
|
|
16
|
+
export declare const determineFocusDistance: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], elementsMap: ElementsMap) => number;
|
|
17
|
+
export declare const determineFocusPoint: (element: ExcalidrawBindableElement, focus: number, adjecentPoint: readonly [number, number], elementsMap: ElementsMap) => readonly [number, number];
|
|
18
|
+
export declare const intersectElementWithLine: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], gap: number | undefined, elementsMap: ElementsMap) => Point[];
|
|
19
19
|
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[];
|
|
20
20
|
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];
|
|
21
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];
|
|
@@ -27,36 +27,36 @@ const isElementDraggableFromInside = (element) => {
|
|
|
27
27
|
}
|
|
28
28
|
return isDraggableFromInside || isImageElement(element);
|
|
29
29
|
};
|
|
30
|
-
export const hitTest = (element, appState, frameNameBoundsCache, x, y) => {
|
|
30
|
+
export const hitTest = (element, appState, frameNameBoundsCache, x, y, elementsMap) => {
|
|
31
31
|
// How many pixels off the shape boundary we still consider a hit
|
|
32
32
|
const threshold = 10 / appState.zoom.value;
|
|
33
33
|
const point = [x, y];
|
|
34
34
|
if (isElementSelected(appState, element) &&
|
|
35
35
|
shouldShowBoundingBox([element], appState)) {
|
|
36
|
-
return isPointHittingElementBoundingBox(element, point, threshold, frameNameBoundsCache);
|
|
36
|
+
return isPointHittingElementBoundingBox(element, elementsMap, point, threshold, frameNameBoundsCache);
|
|
37
37
|
}
|
|
38
|
-
const boundTextElement = getBoundTextElement(element);
|
|
38
|
+
const boundTextElement = getBoundTextElement(element, elementsMap);
|
|
39
39
|
if (boundTextElement) {
|
|
40
|
-
const isHittingBoundTextElement = hitTest(boundTextElement, appState, frameNameBoundsCache, x, y);
|
|
40
|
+
const isHittingBoundTextElement = hitTest(boundTextElement, appState, frameNameBoundsCache, x, y, elementsMap);
|
|
41
41
|
if (isHittingBoundTextElement) {
|
|
42
42
|
return true;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
return isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, point);
|
|
45
|
+
return isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, point, elementsMap);
|
|
46
46
|
};
|
|
47
|
-
export const isHittingElementBoundingBoxWithoutHittingElement = (element, appState, frameNameBoundsCache, x, y) => {
|
|
47
|
+
export const isHittingElementBoundingBoxWithoutHittingElement = (element, appState, frameNameBoundsCache, x, y, elementsMap) => {
|
|
48
48
|
const threshold = 10 / appState.zoom.value;
|
|
49
49
|
// So that bound text element hit is considered within bounding box of container even if its outside actual bounding box of element
|
|
50
50
|
// eg for linear elements text can be outside the element bounding box
|
|
51
|
-
const boundTextElement = getBoundTextElement(element);
|
|
51
|
+
const boundTextElement = getBoundTextElement(element, elementsMap);
|
|
52
52
|
if (boundTextElement &&
|
|
53
|
-
hitTest(boundTextElement, appState, frameNameBoundsCache, x, y)) {
|
|
53
|
+
hitTest(boundTextElement, appState, frameNameBoundsCache, x, y, elementsMap)) {
|
|
54
54
|
return false;
|
|
55
55
|
}
|
|
56
|
-
return (!isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, [x, y]) &&
|
|
57
|
-
isPointHittingElementBoundingBox(element, [x, y], threshold, frameNameBoundsCache));
|
|
56
|
+
return (!isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, [x, y], elementsMap) &&
|
|
57
|
+
isPointHittingElementBoundingBox(element, elementsMap, [x, y], threshold, frameNameBoundsCache));
|
|
58
58
|
};
|
|
59
|
-
export const isHittingElementNotConsideringBoundingBox = (element, appState, frameNameBoundsCache, point) => {
|
|
59
|
+
export const isHittingElementNotConsideringBoundingBox = (element, appState, frameNameBoundsCache, point, elementsMap) => {
|
|
60
60
|
const threshold = 10 / appState.zoom.value;
|
|
61
61
|
const check = isTextElement(element)
|
|
62
62
|
? isStrictlyInside
|
|
@@ -65,6 +65,7 @@ export const isHittingElementNotConsideringBoundingBox = (element, appState, fra
|
|
|
65
65
|
: isNearCheck;
|
|
66
66
|
return hitTestPointAgainstElement({
|
|
67
67
|
element,
|
|
68
|
+
elementsMap,
|
|
68
69
|
point,
|
|
69
70
|
threshold,
|
|
70
71
|
check,
|
|
@@ -72,7 +73,7 @@ export const isHittingElementNotConsideringBoundingBox = (element, appState, fra
|
|
|
72
73
|
});
|
|
73
74
|
};
|
|
74
75
|
const isElementSelected = (appState, element) => appState.selectedElementIds[element.id];
|
|
75
|
-
export const isPointHittingElementBoundingBox = (element, [x, y], threshold, frameNameBoundsCache) => {
|
|
76
|
+
export const isPointHittingElementBoundingBox = (element, elementsMap, [x, y], threshold, frameNameBoundsCache) => {
|
|
76
77
|
// frames needs be checked differently so as to be able to drag it
|
|
77
78
|
// by its frame, whether it has been selected or not
|
|
78
79
|
// this logic here is not ideal
|
|
@@ -80,13 +81,14 @@ export const isPointHittingElementBoundingBox = (element, [x, y], threshold, fra
|
|
|
80
81
|
if (isFrameLikeElement(element)) {
|
|
81
82
|
return hitTestPointAgainstElement({
|
|
82
83
|
element,
|
|
84
|
+
elementsMap,
|
|
83
85
|
point: [x, y],
|
|
84
86
|
threshold,
|
|
85
87
|
check: isInsideCheck,
|
|
86
88
|
frameNameBoundsCache,
|
|
87
89
|
});
|
|
88
90
|
}
|
|
89
|
-
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
91
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
90
92
|
const elementCenterX = (x1 + x2) / 2;
|
|
91
93
|
const elementCenterY = (y1 + y2) / 2;
|
|
92
94
|
// reverse rotate to take element's angle into account.
|
|
@@ -96,12 +98,13 @@ export const isPointHittingElementBoundingBox = (element, [x, y], threshold, fra
|
|
|
96
98
|
rotatedY > y1 - threshold &&
|
|
97
99
|
rotatedY < y2 + threshold);
|
|
98
100
|
};
|
|
99
|
-
export const bindingBorderTest = (element, { x, y }) => {
|
|
101
|
+
export const bindingBorderTest = (element, { x, y }, elementsMap) => {
|
|
100
102
|
const threshold = maxBindingGap(element, element.width, element.height);
|
|
101
103
|
const check = isOutsideCheck;
|
|
102
104
|
const point = [x, y];
|
|
103
105
|
return hitTestPointAgainstElement({
|
|
104
106
|
element,
|
|
107
|
+
elementsMap,
|
|
105
108
|
point,
|
|
106
109
|
threshold,
|
|
107
110
|
check,
|
|
@@ -124,13 +127,13 @@ const hitTestPointAgainstElement = (args) => {
|
|
|
124
127
|
case "text":
|
|
125
128
|
case "diamond":
|
|
126
129
|
case "ellipse":
|
|
127
|
-
const distance = distanceToBindableElement(args.element, args.point);
|
|
130
|
+
const distance = distanceToBindableElement(args.element, args.point, args.elementsMap);
|
|
128
131
|
return args.check(distance, args.threshold);
|
|
129
132
|
case "freedraw": {
|
|
130
|
-
if (!args.check(distanceToRectangle(args.element, args.point), args.threshold)) {
|
|
133
|
+
if (!args.check(distanceToRectangle(args.element, args.point, args.elementsMap), args.threshold)) {
|
|
131
134
|
return false;
|
|
132
135
|
}
|
|
133
|
-
return hitTestFreeDrawElement(args.element, args.point, args.threshold);
|
|
136
|
+
return hitTestFreeDrawElement(args.element, args.point, args.threshold, args.elementsMap);
|
|
134
137
|
}
|
|
135
138
|
case "arrow":
|
|
136
139
|
case "line":
|
|
@@ -141,7 +144,7 @@ const hitTestPointAgainstElement = (args) => {
|
|
|
141
144
|
case "frame":
|
|
142
145
|
case "magicframe": {
|
|
143
146
|
// check distance to frame element first
|
|
144
|
-
if (args.check(distanceToBindableElement(args.element, args.point), args.threshold)) {
|
|
147
|
+
if (args.check(distanceToBindableElement(args.element, args.point, args.elementsMap), args.threshold)) {
|
|
145
148
|
return true;
|
|
146
149
|
}
|
|
147
150
|
const frameNameBounds = args.frameNameBoundsCache?.get(args.element);
|
|
@@ -152,7 +155,7 @@ const hitTestPointAgainstElement = (args) => {
|
|
|
152
155
|
}
|
|
153
156
|
}
|
|
154
157
|
};
|
|
155
|
-
export const distanceToBindableElement = (element, point) => {
|
|
158
|
+
export const distanceToBindableElement = (element, point, elementsMap) => {
|
|
156
159
|
switch (element.type) {
|
|
157
160
|
case "rectangle":
|
|
158
161
|
case "image":
|
|
@@ -161,11 +164,11 @@ export const distanceToBindableElement = (element, point) => {
|
|
|
161
164
|
case "embeddable":
|
|
162
165
|
case "frame":
|
|
163
166
|
case "magicframe":
|
|
164
|
-
return distanceToRectangle(element, point);
|
|
167
|
+
return distanceToRectangle(element, point, elementsMap);
|
|
165
168
|
case "diamond":
|
|
166
|
-
return distanceToDiamond(element, point);
|
|
169
|
+
return distanceToDiamond(element, point, elementsMap);
|
|
167
170
|
case "ellipse":
|
|
168
|
-
return distanceToEllipse(element, point);
|
|
171
|
+
return distanceToEllipse(element, point, elementsMap);
|
|
169
172
|
}
|
|
170
173
|
};
|
|
171
174
|
const isStrictlyInside = (distance, threshold) => {
|
|
@@ -180,25 +183,25 @@ const isNearCheck = (distance, threshold) => {
|
|
|
180
183
|
const isOutsideCheck = (distance, threshold) => {
|
|
181
184
|
return 0 <= distance && distance < threshold;
|
|
182
185
|
};
|
|
183
|
-
const distanceToRectangle = (element, point) => {
|
|
184
|
-
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point);
|
|
186
|
+
const distanceToRectangle = (element, point, elementsMap) => {
|
|
187
|
+
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
|
|
185
188
|
return Math.max(GAPoint.distanceToLine(pointRel, GALine.equation(0, 1, -hheight)), GAPoint.distanceToLine(pointRel, GALine.equation(1, 0, -hwidth)));
|
|
186
189
|
};
|
|
187
190
|
const distanceToRectangleBox = (box, point) => {
|
|
188
191
|
const [, pointRel, hwidth, hheight] = pointRelativeToDivElement(point, box);
|
|
189
192
|
return Math.max(GAPoint.distanceToLine(pointRel, GALine.equation(0, 1, -hheight)), GAPoint.distanceToLine(pointRel, GALine.equation(1, 0, -hwidth)));
|
|
190
193
|
};
|
|
191
|
-
const distanceToDiamond = (element, point) => {
|
|
192
|
-
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point);
|
|
194
|
+
const distanceToDiamond = (element, point, elementsMap) => {
|
|
195
|
+
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
|
|
193
196
|
const side = GALine.equation(hheight, hwidth, -hheight * hwidth);
|
|
194
197
|
return GAPoint.distanceToLine(pointRel, side);
|
|
195
198
|
};
|
|
196
|
-
const distanceToEllipse = (element, point) => {
|
|
197
|
-
const [pointRel, tangent] = ellipseParamsForTest(element, point);
|
|
199
|
+
const distanceToEllipse = (element, point, elementsMap) => {
|
|
200
|
+
const [pointRel, tangent] = ellipseParamsForTest(element, point, elementsMap);
|
|
198
201
|
return -GALine.sign(tangent) * GAPoint.distanceToLine(pointRel, tangent);
|
|
199
202
|
};
|
|
200
|
-
const ellipseParamsForTest = (element, point) => {
|
|
201
|
-
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point);
|
|
203
|
+
const ellipseParamsForTest = (element, point, elementsMap) => {
|
|
204
|
+
const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
|
|
202
205
|
const [px, py] = GAPoint.toTuple(pointRel);
|
|
203
206
|
// We're working in positive quadrant, so start with `t = 45deg`, `tx=cos(t)`
|
|
204
207
|
let tx = 0.707;
|
|
@@ -228,7 +231,7 @@ const ellipseParamsForTest = (element, point) => {
|
|
|
228
231
|
const tangent = GALine.orthogonalThrough(pointRel, closestPoint);
|
|
229
232
|
return [pointRel, tangent];
|
|
230
233
|
};
|
|
231
|
-
const hitTestFreeDrawElement = (element, point, threshold) => {
|
|
234
|
+
const hitTestFreeDrawElement = (element, point, threshold, elementsMap) => {
|
|
232
235
|
// Check point-distance-to-line-segment for every segment in the
|
|
233
236
|
// element's points (its input points, not its outline points).
|
|
234
237
|
// This is... okay? It's plenty fast, but the GA library may
|
|
@@ -241,7 +244,7 @@ const hitTestFreeDrawElement = (element, point, threshold) => {
|
|
|
241
244
|
}
|
|
242
245
|
else {
|
|
243
246
|
// Counter-rotate the point around center before testing
|
|
244
|
-
const [minX, minY, maxX, maxY] = getElementAbsoluteCoords(element);
|
|
247
|
+
const [minX, minY, maxX, maxY] = getElementAbsoluteCoords(element, elementsMap);
|
|
245
248
|
const rotatedPoint = rotatePoint(point, [minX + (maxX - minX) / 2, minY + (maxY - minY) / 2], -element.angle);
|
|
246
249
|
x = rotatedPoint[0] - element.x;
|
|
247
250
|
y = rotatedPoint[1] - element.y;
|
|
@@ -285,7 +288,7 @@ const hitTestLinear = (args) => {
|
|
|
285
288
|
if (!ShapeCache.get(element)) {
|
|
286
289
|
return false;
|
|
287
290
|
}
|
|
288
|
-
const [point, pointAbs, hwidth, hheight] = pointRelativeToElement(args.element, args.point);
|
|
291
|
+
const [point, pointAbs, hwidth, hheight] = pointRelativeToElement(args.element, args.point, args.elementsMap);
|
|
289
292
|
const side1 = GALine.equation(0, 1, -hheight);
|
|
290
293
|
const side2 = GALine.equation(1, 0, -hwidth);
|
|
291
294
|
if (!isInsideCheck(GAPoint.distanceToLine(pointAbs, side1), threshold) ||
|
|
@@ -318,9 +321,9 @@ const hitTestLinear = (args) => {
|
|
|
318
321
|
// Rectangles, diamonds and ellipses are symmetrical over axes,
|
|
319
322
|
// and other elements have a rectangular boundary,
|
|
320
323
|
// so we only need to perform hit tests for the positive quadrant.
|
|
321
|
-
const pointRelativeToElement = (element, pointTuple) => {
|
|
324
|
+
const pointRelativeToElement = (element, pointTuple, elementsMap) => {
|
|
322
325
|
const point = GAPoint.from(pointTuple);
|
|
323
|
-
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
326
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
324
327
|
const center = coordsCenter(x1, y1, x2, y2);
|
|
325
328
|
// GA has angle orientation opposite to `rotate`
|
|
326
329
|
const rotate = GATransform.rotation(center, element.angle);
|
|
@@ -348,18 +351,18 @@ const pointRelativeToDivElement = (pointTuple, rectangle) => {
|
|
|
348
351
|
return [pointRelToPos, pointRelToCenterAbs, halfWidth, halfHeight];
|
|
349
352
|
};
|
|
350
353
|
// Returns point in absolute coordinates
|
|
351
|
-
export const pointInAbsoluteCoords = (element,
|
|
354
|
+
export const pointInAbsoluteCoords = (element, elementsMap,
|
|
352
355
|
// Point relative to the element position
|
|
353
356
|
point) => {
|
|
354
357
|
const [x, y] = point;
|
|
355
|
-
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
358
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
356
359
|
const cx = (x2 - x1) / 2;
|
|
357
360
|
const cy = (y2 - y1) / 2;
|
|
358
361
|
const [rotatedX, rotatedY] = rotate(x, y, cx, cy, element.angle);
|
|
359
362
|
return [element.x + rotatedX, element.y + rotatedY];
|
|
360
363
|
};
|
|
361
|
-
const relativizationToElementCenter = (element) => {
|
|
362
|
-
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
364
|
+
const relativizationToElementCenter = (element, elementsMap) => {
|
|
365
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
363
366
|
const center = coordsCenter(x1, y1, x2, y2);
|
|
364
367
|
// GA has angle orientation opposite to `rotate`
|
|
365
368
|
const rotate = GATransform.rotation(center, element.angle);
|
|
@@ -378,8 +381,8 @@ export const determineFocusDistance = (element,
|
|
|
378
381
|
// Point on the line, in absolute coordinates
|
|
379
382
|
a,
|
|
380
383
|
// Another point on the line, in absolute coordinates (closer to element)
|
|
381
|
-
b) => {
|
|
382
|
-
const relateToCenter = relativizationToElementCenter(element);
|
|
384
|
+
b, elementsMap) => {
|
|
385
|
+
const relateToCenter = relativizationToElementCenter(element, elementsMap);
|
|
383
386
|
const aRel = GATransform.apply(relateToCenter, GAPoint.from(a));
|
|
384
387
|
const bRel = GATransform.apply(relateToCenter, GAPoint.from(b));
|
|
385
388
|
const line = GALine.through(aRel, bRel);
|
|
@@ -414,13 +417,13 @@ b) => {
|
|
|
414
417
|
export const determineFocusPoint = (element,
|
|
415
418
|
// The oriented, relative distance from the center of `element` of the
|
|
416
419
|
// returned focusPoint
|
|
417
|
-
focus, adjecentPoint) => {
|
|
420
|
+
focus, adjecentPoint, elementsMap) => {
|
|
418
421
|
if (focus === 0) {
|
|
419
|
-
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
|
422
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
|
|
420
423
|
const center = coordsCenter(x1, y1, x2, y2);
|
|
421
424
|
return GAPoint.toTuple(center);
|
|
422
425
|
}
|
|
423
|
-
const relateToCenter = relativizationToElementCenter(element);
|
|
426
|
+
const relateToCenter = relativizationToElementCenter(element, elementsMap);
|
|
424
427
|
const adjecentPointRel = GATransform.apply(relateToCenter, GAPoint.from(adjecentPoint));
|
|
425
428
|
const reverseRelateToCenter = GA.reverse(relateToCenter);
|
|
426
429
|
let point;
|
|
@@ -449,8 +452,8 @@ a,
|
|
|
449
452
|
// Another point on the line, in absolute coordinates
|
|
450
453
|
b,
|
|
451
454
|
// If given, the element is inflated by this value
|
|
452
|
-
gap = 0) => {
|
|
453
|
-
const relateToCenter = relativizationToElementCenter(element);
|
|
455
|
+
gap = 0, elementsMap) => {
|
|
456
|
+
const relateToCenter = relativizationToElementCenter(element, elementsMap);
|
|
454
457
|
const aRel = GATransform.apply(relateToCenter, GAPoint.from(a));
|
|
455
458
|
const bRel = GATransform.apply(relateToCenter, GAPoint.from(b));
|
|
456
459
|
const line = GALine.through(aRel, bRel);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ExcalidrawTextContainer } from "./types";
|
|
2
|
+
export declare const originalContainerCache: {
|
|
3
|
+
[id: ExcalidrawTextContainer["id"]]: {
|
|
4
|
+
height: ExcalidrawTextContainer["height"];
|
|
5
|
+
} | undefined;
|
|
6
|
+
};
|
|
7
|
+
export declare const updateOriginalContainerCache: (id: ExcalidrawTextContainer["id"], height: ExcalidrawTextContainer["height"]) => {
|
|
8
|
+
height: ExcalidrawTextContainer["height"];
|
|
9
|
+
};
|
|
10
|
+
export declare const resetOriginalContainerCache: (id: ExcalidrawTextContainer["id"]) => void;
|
|
11
|
+
export declare const getOriginalContainerHeightFromCache: (id: ExcalidrawTextContainer["id"]) => number | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const originalContainerCache = {};
|
|
2
|
+
export const updateOriginalContainerCache = (id, height) => {
|
|
3
|
+
const data = originalContainerCache[id] || (originalContainerCache[id] = { height });
|
|
4
|
+
data.height = height;
|
|
5
|
+
return data;
|
|
6
|
+
};
|
|
7
|
+
export const resetOriginalContainerCache = (id) => {
|
|
8
|
+
if (originalContainerCache[id]) {
|
|
9
|
+
delete originalContainerCache[id];
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export const getOriginalContainerHeightFromCache = (id) => {
|
|
13
|
+
return originalContainerCache[id]?.height ?? null;
|
|
14
|
+
};
|
|
@@ -3,9 +3,8 @@ import { getCommonBounds } from "./bounds";
|
|
|
3
3
|
import { mutateElement } from "./mutateElement";
|
|
4
4
|
import { getPerfectElementSize } from "./sizeHelpers";
|
|
5
5
|
import { getBoundTextElement } from "./textElement";
|
|
6
|
-
import { isSelectedViaGroup } from "../groups";
|
|
7
6
|
import { getGridPoint } from "../math";
|
|
8
|
-
import { isArrowElement,
|
|
7
|
+
import { isArrowElement, isFrameLikeElement } from "./typeChecks";
|
|
9
8
|
export const dragSelectedElements = (pointerDownState, selectedElements, offset, appState, scene, snapOffset, gridSize) => {
|
|
10
9
|
// we do not want a frame and its elements to be selected at the same time
|
|
11
10
|
// but when it happens (due to some bug), we want to avoid updating element
|
|
@@ -15,33 +14,25 @@ export const dragSelectedElements = (pointerDownState, selectedElements, offset,
|
|
|
15
14
|
.filter((e) => isFrameLikeElement(e))
|
|
16
15
|
.map((f) => f.id);
|
|
17
16
|
if (frames.length > 0) {
|
|
18
|
-
const
|
|
19
|
-
.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
elementsInFrames.forEach((element) => elementsToUpdate.add(element));
|
|
17
|
+
for (const element of scene.getNonDeletedElements()) {
|
|
18
|
+
if (element.frameId !== null && frames.includes(element.frameId)) {
|
|
19
|
+
elementsToUpdate.add(element);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
24
22
|
}
|
|
25
23
|
const commonBounds = getCommonBounds(Array.from(elementsToUpdate).map((el) => pointerDownState.originalElements.get(el.id) ?? el));
|
|
26
24
|
const adjustedOffset = calculateOffset(commonBounds, offset, snapOffset, gridSize);
|
|
27
25
|
elementsToUpdate.forEach((element) => {
|
|
28
26
|
updateElementCoords(pointerDownState, element, adjustedOffset);
|
|
29
|
-
// update coords of bound text only if we're dragging the container directly
|
|
30
|
-
// (we don't drag the group that it's part of)
|
|
31
27
|
if (
|
|
32
|
-
//
|
|
33
|
-
!isArrowElement(element)
|
|
34
|
-
|
|
35
|
-
// (perf optim so we don't check `isSelectedViaGroup()` in every case)
|
|
36
|
-
(!element.groupIds.length ||
|
|
37
|
-
// container is part of a group, but we're dragging the container directly
|
|
38
|
-
(appState.editingGroupId && !isSelectedViaGroup(appState, element)))) {
|
|
39
|
-
const textElement = getBoundTextElement(element);
|
|
28
|
+
// skip arrow labels since we calculate its position during render
|
|
29
|
+
!isArrowElement(element)) {
|
|
30
|
+
const textElement = getBoundTextElement(element, scene.getNonDeletedElementsMap());
|
|
40
31
|
if (textElement) {
|
|
41
32
|
updateElementCoords(pointerDownState, textElement, adjustedOffset);
|
|
42
33
|
}
|
|
43
34
|
}
|
|
44
|
-
updateBoundElements(element, {
|
|
35
|
+
updateBoundElements(element, scene.getElementsMapIncludingDeleted(), {
|
|
45
36
|
simultaneouslyUpdated: Array.from(elementsToUpdate),
|
|
46
37
|
});
|
|
47
38
|
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { ExcalidrawProps } from "../types";
|
|
3
|
-
import { ExcalidrawElement, ExcalidrawIframeLikeElement, IframeData
|
|
3
|
+
import { ExcalidrawElement, ExcalidrawIframeLikeElement, IframeData } from "./types";
|
|
4
4
|
export declare const createSrcDoc: (body: string) => string;
|
|
5
5
|
export declare const getEmbedLink: (link: string | null | undefined) => IframeData | null;
|
|
6
|
-
export declare const isIframeLikeOrItsLabel: (element: NonDeletedExcalidrawElement) => Boolean;
|
|
7
6
|
export declare const createPlaceholderEmbeddableLabel: (element: ExcalidrawIframeLikeElement) => ExcalidrawElement;
|
|
8
7
|
export declare const actionSetEmbeddableAsActiveTool: {
|
|
9
8
|
name: "setEmbeddableAsActiveTool";
|
|
@@ -26,13 +25,13 @@ export declare const actionSetEmbeddableAsActiveTool: {
|
|
|
26
25
|
isLoading: boolean;
|
|
27
26
|
errorMessage: import("react").ReactNode;
|
|
28
27
|
activeEmbeddable: {
|
|
29
|
-
element: NonDeletedExcalidrawElement;
|
|
30
|
-
state: "
|
|
28
|
+
element: import("./types").NonDeletedExcalidrawElement;
|
|
29
|
+
state: "hover" | "active";
|
|
31
30
|
} | null;
|
|
32
|
-
draggingElement: NonDeletedExcalidrawElement | null;
|
|
33
|
-
resizingElement: NonDeletedExcalidrawElement | null;
|
|
31
|
+
draggingElement: import("./types").NonDeletedExcalidrawElement | null;
|
|
32
|
+
resizingElement: import("./types").NonDeletedExcalidrawElement | null;
|
|
34
33
|
multiElement: import("./types").NonDeleted<import("./types").ExcalidrawLinearElement> | null;
|
|
35
|
-
selectionElement: NonDeletedExcalidrawElement | null;
|
|
34
|
+
selectionElement: import("./types").NonDeletedExcalidrawElement | null;
|
|
36
35
|
isBindingEnabled: boolean;
|
|
37
36
|
startBoundElement: import("./types").NonDeleted<import("./types").ExcalidrawBindableElement> | null;
|
|
38
37
|
suggestedBindings: import("./binding").SuggestedBinding[];
|
|
@@ -45,7 +44,7 @@ export declare const actionSetEmbeddableAsActiveTool: {
|
|
|
45
44
|
};
|
|
46
45
|
editingFrame: string | null;
|
|
47
46
|
elementsToHighlight: import("./types").NonDeleted<ExcalidrawElement>[] | null;
|
|
48
|
-
editingElement: NonDeletedExcalidrawElement | null;
|
|
47
|
+
editingElement: import("./types").NonDeletedExcalidrawElement | null;
|
|
49
48
|
editingLinearElement: import("./linearElementEditor").LinearElementEditor | null;
|
|
50
49
|
penMode: boolean;
|
|
51
50
|
penDetected: boolean;
|
|
@@ -71,7 +70,7 @@ export declare const actionSetEmbeddableAsActiveTool: {
|
|
|
71
70
|
scrollY: number;
|
|
72
71
|
cursorButton: "up" | "down";
|
|
73
72
|
scrolledOutside: boolean;
|
|
74
|
-
name: string;
|
|
73
|
+
name: string | null;
|
|
75
74
|
isResizing: boolean;
|
|
76
75
|
isRotating: boolean;
|
|
77
76
|
zoom: Readonly<{
|
|
@@ -84,14 +83,14 @@ export declare const actionSetEmbeddableAsActiveTool: {
|
|
|
84
83
|
tab?: string | undefined;
|
|
85
84
|
} | null;
|
|
86
85
|
openDialog: {
|
|
87
|
-
name: "
|
|
86
|
+
name: "imageExport" | "help" | "jsonExport";
|
|
88
87
|
} | {
|
|
89
88
|
name: "settings";
|
|
90
89
|
source: "settings" | "tool" | "generation";
|
|
91
90
|
tab: "text-to-diagram" | "diagram-to-code";
|
|
92
91
|
} | {
|
|
93
92
|
name: "ttd";
|
|
94
|
-
tab: "
|
|
93
|
+
tab: "text-to-diagram" | "mermaid";
|
|
95
94
|
} | null;
|
|
96
95
|
defaultSidebarDockedPreference: boolean;
|
|
97
96
|
lastPointerDownWith: import("./types").PointerType;
|
|
@@ -148,7 +147,7 @@ export declare const actionSetEmbeddableAsActiveTool: {
|
|
|
148
147
|
data: import("../charts").Spreadsheet;
|
|
149
148
|
};
|
|
150
149
|
pendingImageElementId: string | null;
|
|
151
|
-
showHyperlinkPopup: false | "
|
|
150
|
+
showHyperlinkPopup: false | "info" | "editor";
|
|
152
151
|
selectedLinearElement: import("./linearElementEditor").LinearElementEditor | null;
|
|
153
152
|
snapLines: readonly import("../snapping").SnapLine[];
|
|
154
153
|
originSnapOffset: {
|
|
@@ -164,5 +163,5 @@ export declare const actionSetEmbeddableAsActiveTool: {
|
|
|
164
163
|
} & {
|
|
165
164
|
keyTest?: undefined;
|
|
166
165
|
};
|
|
167
|
-
export declare const
|
|
166
|
+
export declare const maybeParseEmbedSrc: (str: string) => string;
|
|
168
167
|
export declare const embeddableURLValidator: (url: string | null | undefined, validateEmbeddable: ExcalidrawProps["validateEmbeddable"]) => boolean;
|