@excalidraw/excalidraw 0.17.1-c0b80a0 → 0.17.1-c329470
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/dist/browser/dev/excalidraw-assets-dev/{chunk-JGDL4H2X.js → chunk-3DLVY5XU.js} +8272 -6864
- package/dist/browser/dev/excalidraw-assets-dev/chunk-3DLVY5XU.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-V7NFEZA6.js → chunk-NOAEU4NM.js} +9 -2
- package/dist/browser/dev/excalidraw-assets-dev/chunk-NOAEU4NM.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-ZSVWGT55.js → en-7IBTMWBG.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-RJG3J34Y.js → image-N5AC7SEK.js} +2 -6
- package/dist/browser/dev/index.css +85 -50
- package/dist/browser/dev/index.css.map +3 -3
- package/dist/browser/dev/index.js +4375 -3766
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/{chunk-LDVEIXGO.js → chunk-7CSIPVOW.js} +2 -2
- package/dist/browser/prod/excalidraw-assets/chunk-TX3BU7T2.js +47 -0
- package/dist/browser/prod/excalidraw-assets/{en-UPNEHLDS.js → en-LOGQBETY.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/image-3V4U7GZE.js +1 -0
- package/dist/browser/prod/index.css +1 -1
- package/dist/browser/prod/index.js +40 -40
- package/dist/dev/index.css +85 -50
- package/dist/dev/index.css.map +3 -3
- package/dist/dev/index.js +8688 -6706
- package/dist/dev/index.js.map +4 -4
- package/dist/{prod/locales/en-ZXYG7GCR.json → dev/locales/en-V6KXFSCK.json} +8 -1
- package/dist/excalidraw/actions/actionAlign.d.ts +7 -6
- package/dist/excalidraw/actions/actionAlign.js +14 -14
- package/dist/excalidraw/actions/actionClipboard.d.ts +7 -3
- package/dist/excalidraw/actions/actionDeleteSelected.d.ts +7 -3
- package/dist/excalidraw/actions/actionDeleteSelected.js +103 -34
- package/dist/excalidraw/actions/actionDuplicateSelection.js +105 -95
- package/dist/excalidraw/actions/actionFlip.js +16 -7
- package/dist/excalidraw/actions/actionFrame.d.ts +493 -0
- package/dist/excalidraw/actions/actionFrame.js +45 -2
- package/dist/excalidraw/actions/actionGroup.js +6 -4
- package/dist/excalidraw/actions/actionProperties.js +145 -116
- package/dist/excalidraw/actions/actionSelectAll.js +4 -3
- package/dist/excalidraw/actions/shortcuts.d.ts +1 -1
- package/dist/excalidraw/actions/shortcuts.js +1 -0
- package/dist/excalidraw/actions/types.d.ts +1 -1
- package/dist/excalidraw/align.d.ts +2 -1
- package/dist/excalidraw/align.js +15 -6
- package/dist/excalidraw/clipboard.d.ts +27 -5
- package/dist/excalidraw/clipboard.js +55 -28
- package/dist/excalidraw/components/Actions.d.ts +2 -1
- package/dist/excalidraw/components/Actions.js +4 -2
- package/dist/excalidraw/components/ActiveConfirmDialog.d.ts +1 -1
- package/dist/excalidraw/components/ActiveConfirmDialog.js +2 -3
- package/dist/excalidraw/components/App.d.ts +1 -0
- package/dist/excalidraw/components/App.js +216 -111
- package/dist/excalidraw/components/ColorPicker/ColorInput.js +2 -3
- package/dist/excalidraw/components/ColorPicker/ColorPicker.js +2 -3
- package/dist/excalidraw/components/ColorPicker/CustomColorList.js +1 -1
- package/dist/excalidraw/components/ColorPicker/Picker.js +1 -1
- package/dist/excalidraw/components/ColorPicker/PickerColorList.js +1 -1
- package/dist/excalidraw/components/ColorPicker/ShadeList.js +1 -1
- package/dist/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +1 -1
- package/dist/excalidraw/components/ColorPicker/colorPickerUtils.js +1 -1
- package/dist/excalidraw/components/CommandPalette/CommandPalette.js +3 -3
- package/dist/excalidraw/components/ConfirmDialog.js +17 -5
- package/dist/excalidraw/components/Dialog.js +2 -3
- package/dist/excalidraw/components/EyeDropper.d.ts +1 -1
- package/dist/excalidraw/components/EyeDropper.js +1 -1
- package/dist/excalidraw/components/IconPicker.d.ts +2 -2
- package/dist/excalidraw/components/IconPicker.js +56 -53
- package/dist/excalidraw/components/LayerUI.js +6 -6
- package/dist/excalidraw/components/LibraryMenu.d.ts +2 -16
- package/dist/excalidraw/components/LibraryMenu.js +70 -28
- package/dist/excalidraw/components/LibraryMenuHeaderContent.js +4 -5
- package/dist/excalidraw/components/MobileMenu.js +1 -1
- package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirm.js +2 -3
- package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.d.ts +1 -1
- package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.js +2 -3
- package/dist/excalidraw/components/Range.d.ts +9 -0
- package/dist/excalidraw/components/Range.js +24 -0
- package/dist/excalidraw/components/SearchMenu.d.ts +1 -1
- package/dist/excalidraw/components/SearchMenu.js +3 -4
- package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +1 -1
- package/dist/excalidraw/components/Sidebar/Sidebar.js +2 -3
- package/dist/excalidraw/components/Stats/Collapsible.d.ts +2 -1
- package/dist/excalidraw/components/Stats/Collapsible.js +2 -2
- package/dist/excalidraw/components/Stats/Dimension.js +94 -8
- package/dist/excalidraw/components/Stats/MultiDimension.js +8 -5
- package/dist/excalidraw/components/Stats/Position.js +63 -3
- package/dist/excalidraw/components/Stats/index.js +21 -4
- package/dist/excalidraw/components/Stats/utils.d.ts +1 -1
- package/dist/excalidraw/components/Stats/utils.js +2 -55
- package/dist/excalidraw/components/TTDDialog/TTDDialog.js +1 -1
- package/dist/excalidraw/components/ToolButton.js +4 -9
- package/dist/excalidraw/components/hoc/withInternalFallback.js +3 -3
- package/dist/excalidraw/components/hyperlink/Hyperlink.js +6 -12
- package/dist/excalidraw/components/icons.d.ts +9 -0
- package/dist/excalidraw/components/icons.js +4 -4
- package/dist/excalidraw/components/main-menu/DefaultItems.js +2 -3
- package/dist/excalidraw/constants.d.ts +5 -1
- package/dist/excalidraw/constants.js +9 -1
- package/dist/excalidraw/context/tunnels.d.ts +2 -1
- package/dist/excalidraw/context/tunnels.js +3 -1
- package/dist/excalidraw/data/blob.d.ts +1 -0
- package/dist/excalidraw/data/blob.js +7 -3
- package/dist/excalidraw/data/filesystem.d.ts +2 -1
- package/dist/excalidraw/data/filesystem.js +1 -0
- package/dist/excalidraw/data/image.d.ts +0 -6
- package/dist/excalidraw/data/image.js +1 -43
- package/dist/excalidraw/data/index.js +6 -6
- package/dist/excalidraw/data/library.d.ts +9 -3
- package/dist/excalidraw/data/library.js +43 -6
- package/dist/excalidraw/data/restore.js +26 -8
- package/dist/excalidraw/data/url.d.ts +0 -1
- package/dist/excalidraw/data/url.js +2 -4
- package/dist/excalidraw/editor-jotai.d.ts +56 -0
- package/dist/excalidraw/editor-jotai.js +8 -0
- package/dist/excalidraw/element/binding.d.ts +9 -6
- package/dist/excalidraw/element/binding.js +124 -44
- package/dist/excalidraw/element/bounds.js +10 -0
- package/dist/excalidraw/element/cropElement.d.ts +5 -0
- package/dist/excalidraw/element/cropElement.js +28 -1
- package/dist/excalidraw/element/dragElements.js +13 -7
- package/dist/excalidraw/element/elbowArrow.d.ts +16 -0
- package/dist/excalidraw/element/elbowArrow.js +1268 -0
- package/dist/excalidraw/element/embeddable.js +4 -5
- package/dist/excalidraw/element/flowchart.d.ts +1 -1
- package/dist/excalidraw/element/flowchart.js +25 -9
- package/dist/excalidraw/element/heading.d.ts +5 -1
- package/dist/excalidraw/element/heading.js +5 -1
- package/dist/excalidraw/element/image.js +19 -5
- package/dist/excalidraw/element/linearElementEditor.d.ts +9 -10
- package/dist/excalidraw/element/linearElementEditor.js +97 -38
- package/dist/excalidraw/element/mutateElement.d.ts +3 -1
- package/dist/excalidraw/element/mutateElement.js +31 -4
- package/dist/excalidraw/element/newElement.d.ts +8 -12
- package/dist/excalidraw/element/newElement.js +36 -21
- package/dist/excalidraw/element/resizeElements.d.ts +20 -5
- package/dist/excalidraw/element/resizeElements.js +593 -361
- package/dist/excalidraw/element/sortElements.js +1 -4
- package/dist/excalidraw/element/types.d.ts +23 -1
- package/dist/excalidraw/fonts/Fonts.d.ts +0 -16
- package/dist/excalidraw/fonts/Fonts.js +6 -31
- package/dist/excalidraw/frame.d.ts +11 -5
- package/dist/excalidraw/frame.js +146 -35
- package/dist/excalidraw/groups.js +3 -0
- package/dist/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
- package/dist/excalidraw/hooks/useLibraryItemSvg.js +2 -3
- package/dist/excalidraw/hooks/useScrollPosition.js +1 -1
- package/dist/excalidraw/i18n.js +3 -4
- package/dist/excalidraw/index.js +3 -4
- package/dist/excalidraw/locales/en.json +8 -1
- package/dist/excalidraw/renderer/interactiveScene.js +43 -32
- package/dist/excalidraw/renderer/staticScene.js +6 -4
- package/dist/excalidraw/renderer/staticSvgScene.js +1 -1
- package/dist/excalidraw/scene/Shape.js +40 -17
- package/dist/excalidraw/scene/comparisons.d.ts +0 -477
- package/dist/excalidraw/scene/comparisons.js +0 -37
- package/dist/excalidraw/scene/export.d.ts +7 -0
- package/dist/excalidraw/scene/export.js +107 -43
- package/dist/excalidraw/scene/index.d.ts +1 -1
- package/dist/excalidraw/scene/index.js +1 -1
- package/dist/excalidraw/scene/selection.js +4 -1
- package/dist/excalidraw/types.d.ts +15 -0
- package/dist/excalidraw/utility-types.d.ts +1 -0
- package/dist/excalidraw/utils.d.ts +8 -1
- package/dist/excalidraw/utils.js +9 -0
- package/dist/excalidraw/visualdebug.d.ts +8 -1
- package/dist/excalidraw/visualdebug.js +3 -0
- package/dist/math/line.d.ts +19 -0
- package/dist/math/line.js +32 -3
- package/dist/math/point.d.ts +10 -0
- package/dist/math/point.js +12 -1
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +29 -44
- package/dist/{dev/locales/en-ZXYG7GCR.json → prod/locales/en-V6KXFSCK.json} +8 -1
- package/package.json +5 -2
- package/dist/browser/dev/excalidraw-assets-dev/chunk-JGDL4H2X.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-V7NFEZA6.js.map +0 -7
- package/dist/browser/prod/excalidraw-assets/chunk-S2XKB3DE.js +0 -62
- package/dist/browser/prod/excalidraw-assets/image-OFI2YYMP.js +0 -1
- package/dist/excalidraw/element/routing.d.ts +0 -12
- package/dist/excalidraw/element/routing.js +0 -642
- package/dist/excalidraw/jotai.d.ts +0 -34
- package/dist/excalidraw/jotai.js +0 -18
- /package/dist/browser/dev/excalidraw-assets-dev/{en-ZSVWGT55.js.map → en-7IBTMWBG.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-RJG3J34Y.js.map → image-N5AC7SEK.js.map} +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { register } from "../actions/register";
|
|
2
2
|
import { FONT_FAMILY, VERTICAL_ALIGN } from "../constants";
|
|
3
|
-
import { getFontString, updateActiveTool } from "../utils";
|
|
3
|
+
import { escapeDoubleQuotes, getFontString, updateActiveTool } from "../utils";
|
|
4
4
|
import { setCursorForShape } from "../cursor";
|
|
5
5
|
import { newTextElement } from "./newElement";
|
|
6
6
|
import { wrapText } from "./textWrapping";
|
|
7
7
|
import { isIframeElement } from "./typeChecks";
|
|
8
|
-
import { sanitizeHTMLAttribute } from "../data/url";
|
|
9
8
|
import { StoreAction } from "../store";
|
|
10
9
|
const embeddedLinkCache = new Map();
|
|
11
10
|
const RE_YOUTUBE = /^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)(?:\?t=|&t=|\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\s]*$/;
|
|
@@ -162,7 +161,7 @@ export const getEmbedLink = (link) => {
|
|
|
162
161
|
// Note that we don't attempt to parse the username as it can consist of
|
|
163
162
|
// non-latin1 characters, and the username in the url can be set to anything
|
|
164
163
|
// without affecting the embed.
|
|
165
|
-
const safeURL =
|
|
164
|
+
const safeURL = escapeDoubleQuotes(`https://twitter.com/x/status/${postId}`);
|
|
166
165
|
const ret = {
|
|
167
166
|
type: "document",
|
|
168
167
|
srcdoc: (theme) => createSrcDoc(`<blockquote class="twitter-tweet" data-dnt="true" data-theme="${theme}"><a href="${safeURL}"></a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>`),
|
|
@@ -174,7 +173,7 @@ export const getEmbedLink = (link) => {
|
|
|
174
173
|
}
|
|
175
174
|
if (RE_REDDIT.test(link)) {
|
|
176
175
|
const [, page, postId, title] = link.match(RE_REDDIT);
|
|
177
|
-
const safeURL =
|
|
176
|
+
const safeURL = escapeDoubleQuotes(`https://reddit.com/r/${page}/comments/${postId}/${title}`);
|
|
178
177
|
const ret = {
|
|
179
178
|
type: "document",
|
|
180
179
|
srcdoc: (theme) => createSrcDoc(`<blockquote class="reddit-embed-bq" data-embed-theme="${theme}"><a href="${safeURL}"></a><br></blockquote><script async="" src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>`),
|
|
@@ -186,7 +185,7 @@ export const getEmbedLink = (link) => {
|
|
|
186
185
|
}
|
|
187
186
|
if (RE_GH_GIST.test(link)) {
|
|
188
187
|
const [, user, gistId] = link.match(RE_GH_GIST);
|
|
189
|
-
const safeURL =
|
|
188
|
+
const safeURL = escapeDoubleQuotes(`https://gist.github.com/${user}/${gistId}`);
|
|
190
189
|
const ret = {
|
|
191
190
|
type: "document",
|
|
192
191
|
srcdoc: () => createSrcDoc(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ElementsMap, type ExcalidrawBindableElement, type ExcalidrawElement, type ExcalidrawFlowchartNodeElement } from "./types";
|
|
2
2
|
import type { AppState, PendingExcalidrawElements } from "../types";
|
|
3
3
|
type LinkDirection = "up" | "right" | "down" | "left";
|
|
4
4
|
export declare const getLinkDirectionFromKey: (key: string) => LinkDirection;
|
|
@@ -6,9 +6,10 @@ import { KEYS } from "../keys";
|
|
|
6
6
|
import { mutateElement } from "./mutateElement";
|
|
7
7
|
import { elementOverlapsWithFrame, elementsAreInFrameBounds } from "../frame";
|
|
8
8
|
import { isBindableElement, isElbowArrow, isFrameElement, isFlowchartNodeElement, } from "./typeChecks";
|
|
9
|
-
import { invariant } from "../utils";
|
|
9
|
+
import { invariant, toBrandedType } from "../utils";
|
|
10
10
|
import { pointFrom } from "../../math";
|
|
11
11
|
import { aabbForElement } from "../shapes";
|
|
12
|
+
import { updateElbowArrowPoints } from "./elbowArrow";
|
|
12
13
|
const VERTICAL_OFFSET = 100;
|
|
13
14
|
const HORIZONTAL_OFFSET = 100;
|
|
14
15
|
export const getLinkDirectionFromKey = (key) => {
|
|
@@ -158,6 +159,9 @@ const addNewNode = (element, elementsMap, appState, direction) => {
|
|
|
158
159
|
backgroundColor: element.backgroundColor,
|
|
159
160
|
strokeColor: element.strokeColor,
|
|
160
161
|
strokeWidth: element.strokeWidth,
|
|
162
|
+
opacity: element.opacity,
|
|
163
|
+
fillStyle: element.fillStyle,
|
|
164
|
+
strokeStyle: element.strokeStyle,
|
|
161
165
|
});
|
|
162
166
|
invariant(isFlowchartNodeElement(nextNode), "not an ExcalidrawFlowchartNodeElement");
|
|
163
167
|
const bindingArrow = createBindingArrow(element, nextNode, elementsMap, direction, appState);
|
|
@@ -208,6 +212,9 @@ export const addNewNodes = (startNode, elementsMap, appState, direction, numberO
|
|
|
208
212
|
backgroundColor: startNode.backgroundColor,
|
|
209
213
|
strokeColor: startNode.strokeColor,
|
|
210
214
|
strokeWidth: startNode.strokeWidth,
|
|
215
|
+
opacity: startNode.opacity,
|
|
216
|
+
fillStyle: startNode.fillStyle,
|
|
217
|
+
strokeStyle: startNode.strokeStyle,
|
|
211
218
|
});
|
|
212
219
|
invariant(isFlowchartNodeElement(nextNode), "not an ExcalidrawFlowchartNodeElement");
|
|
213
220
|
const bindingArrow = createBindingArrow(startNode, nextNode, elementsMap, direction, appState);
|
|
@@ -270,11 +277,13 @@ const createBindingArrow = (startBindingElement, endBindingElement, elementsMap,
|
|
|
270
277
|
type: "arrow",
|
|
271
278
|
x: startX,
|
|
272
279
|
y: startY,
|
|
273
|
-
startArrowhead:
|
|
280
|
+
startArrowhead: null,
|
|
274
281
|
endArrowhead: appState.currentItemEndArrowhead,
|
|
275
|
-
strokeColor:
|
|
276
|
-
strokeStyle:
|
|
277
|
-
strokeWidth:
|
|
282
|
+
strokeColor: startBindingElement.strokeColor,
|
|
283
|
+
strokeStyle: startBindingElement.strokeStyle,
|
|
284
|
+
strokeWidth: startBindingElement.strokeWidth,
|
|
285
|
+
opacity: startBindingElement.opacity,
|
|
286
|
+
roughness: startBindingElement.roughness,
|
|
278
287
|
points: [pointFrom(0, 0), pointFrom(endX, endY)],
|
|
279
288
|
elbowed: true,
|
|
280
289
|
});
|
|
@@ -289,10 +298,17 @@ const createBindingArrow = (startBindingElement, endBindingElement, elementsMap,
|
|
|
289
298
|
index: 1,
|
|
290
299
|
point: bindingArrow.points[1],
|
|
291
300
|
},
|
|
292
|
-
]
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
301
|
+
]);
|
|
302
|
+
const update = updateElbowArrowPoints(bindingArrow, toBrandedType(new Map([
|
|
303
|
+
...elementsMap.entries(),
|
|
304
|
+
[startBindingElement.id, startBindingElement],
|
|
305
|
+
[endBindingElement.id, endBindingElement],
|
|
306
|
+
[bindingArrow.id, bindingArrow],
|
|
307
|
+
])), { points: bindingArrow.points });
|
|
308
|
+
return {
|
|
309
|
+
...bindingArrow,
|
|
310
|
+
...update,
|
|
311
|
+
};
|
|
296
312
|
};
|
|
297
313
|
export class FlowChartNavigator {
|
|
298
314
|
isExploring = false;
|
|
@@ -7,6 +7,10 @@ export declare const HEADING_UP: Heading;
|
|
|
7
7
|
export type Heading = [1, 0] | [0, 1] | [-1, 0] | [0, -1];
|
|
8
8
|
export declare const headingForDiamond: <Point extends GlobalPoint | LocalPoint>(a: Point, b: Point) => Heading;
|
|
9
9
|
export declare const vectorToHeading: (vec: Vector) => Heading;
|
|
10
|
+
export declare const headingForPoint: <P extends GlobalPoint | LocalPoint>(p: P, o: P) => Heading;
|
|
11
|
+
export declare const headingForPointIsHorizontal: <P extends GlobalPoint | LocalPoint>(p: P, o: P) => boolean;
|
|
10
12
|
export declare const compareHeading: (a: Heading, b: Heading) => boolean;
|
|
11
|
-
export declare const
|
|
13
|
+
export declare const headingIsHorizontal: (a: Heading) => boolean;
|
|
14
|
+
export declare const headingIsVertical: (a: Heading) => boolean;
|
|
15
|
+
export declare const headingForPointFromElement: <Point extends GlobalPoint | LocalPoint>(element: Readonly<ExcalidrawBindableElement>, aabb: readonly [minX: number, minY: number, maxX: number, maxY: number], p: Readonly<Point>) => Heading;
|
|
12
16
|
export declare const flipHeading: (h: Heading) => Heading;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pointFrom, pointRotateRads, pointScaleFromOrigin, radiansToDegrees, triangleIncludesPoint, } from "../../math";
|
|
1
|
+
import { pointFrom, pointRotateRads, pointScaleFromOrigin, radiansToDegrees, triangleIncludesPoint, vectorFromPoint, } from "../../math";
|
|
2
2
|
import { getCenterForBounds } from "./bounds";
|
|
3
3
|
export const HEADING_RIGHT = [1, 0];
|
|
4
4
|
export const HEADING_DOWN = [0, 1];
|
|
@@ -32,7 +32,11 @@ export const vectorToHeading = (vec) => {
|
|
|
32
32
|
}
|
|
33
33
|
return HEADING_UP;
|
|
34
34
|
};
|
|
35
|
+
export const headingForPoint = (p, o) => vectorToHeading(vectorFromPoint(p, o));
|
|
36
|
+
export const headingForPointIsHorizontal = (p, o) => headingIsHorizontal(headingForPoint(p, o));
|
|
35
37
|
export const compareHeading = (a, b) => a[0] === b[0] && a[1] === b[1];
|
|
38
|
+
export const headingIsHorizontal = (a) => compareHeading(a, HEADING_RIGHT) || compareHeading(a, HEADING_LEFT);
|
|
39
|
+
export const headingIsVertical = (a) => !headingIsHorizontal(a);
|
|
36
40
|
// Gets the heading for the point by creating a bounding box around the rotated
|
|
37
41
|
// close fitting bounding box, then creating 4 search cones around the center of
|
|
38
42
|
// the external bbox.
|
|
@@ -72,12 +72,22 @@ export const normalizeSVG = (SVGString) => {
|
|
|
72
72
|
if (!svg.hasAttribute("xmlns")) {
|
|
73
73
|
svg.setAttribute("xmlns", SVG_NS);
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
let width = svg.getAttribute("width");
|
|
76
|
+
let height = svg.getAttribute("height");
|
|
77
|
+
// Do not use % or auto values for width/height
|
|
78
|
+
// to avoid scaling issues when rendering at different sizes/zoom levels
|
|
79
|
+
if (width?.includes("%") || width === "auto") {
|
|
80
|
+
width = null;
|
|
81
|
+
}
|
|
82
|
+
if (height?.includes("%") || height === "auto") {
|
|
83
|
+
height = null;
|
|
84
|
+
}
|
|
85
|
+
const viewBox = svg.getAttribute("viewBox");
|
|
86
|
+
if (!width || !height) {
|
|
87
|
+
width = width || "50";
|
|
88
|
+
height = height || "50";
|
|
79
89
|
if (viewBox) {
|
|
80
|
-
const match = viewBox.match(/\d+ +\d+ +(\d+) +(\d+)/);
|
|
90
|
+
const match = viewBox.match(/\d+ +\d+ +(\d+(?:\.\d+)?) +(\d+(?:\.\d+)?)/);
|
|
81
91
|
if (match) {
|
|
82
92
|
[, width, height] = match;
|
|
83
93
|
}
|
|
@@ -85,6 +95,10 @@ export const normalizeSVG = (SVGString) => {
|
|
|
85
95
|
svg.setAttribute("width", width);
|
|
86
96
|
svg.setAttribute("height", height);
|
|
87
97
|
}
|
|
98
|
+
// Make sure viewBox is set
|
|
99
|
+
if (!viewBox) {
|
|
100
|
+
svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
101
|
+
}
|
|
88
102
|
return svg.outerHTML;
|
|
89
103
|
}
|
|
90
104
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import type { NonDeleted, ExcalidrawLinearElement, ExcalidrawElement, PointBinding, ExcalidrawBindableElement, ExcalidrawTextElementWithContainer, ElementsMap, NonDeletedSceneElementsMap,
|
|
2
|
+
import type { NonDeleted, ExcalidrawLinearElement, ExcalidrawElement, PointBinding, ExcalidrawBindableElement, ExcalidrawTextElementWithContainer, ElementsMap, NonDeletedSceneElementsMap, SceneElementsMap, ExcalidrawElbowArrowElement } from "./types";
|
|
3
3
|
import type { Bounds } from "./bounds";
|
|
4
|
-
import type { AppState, PointerCoords, InteractiveCanvasAppState, AppClassProperties, NullableGridSize } from "../types";
|
|
4
|
+
import type { AppState, PointerCoords, InteractiveCanvasAppState, AppClassProperties, NullableGridSize, Zoom } from "../types";
|
|
5
5
|
import type { Store } from "../store";
|
|
6
6
|
import type Scene from "../scene/Scene";
|
|
7
7
|
import { type GlobalPoint, type LocalPoint } from "../../math";
|
|
@@ -49,7 +49,7 @@ export declare class LinearElementEditor {
|
|
|
49
49
|
* @param id the `elementId` from the instance of this class (so that we can
|
|
50
50
|
* statically guarantee this method returns an ExcalidrawLinearElement)
|
|
51
51
|
*/
|
|
52
|
-
static getElement(id: InstanceType<typeof LinearElementEditor>["elementId"], elementsMap: ElementsMap):
|
|
52
|
+
static getElement<T extends ExcalidrawLinearElement>(id: InstanceType<typeof LinearElementEditor>["elementId"], elementsMap: ElementsMap): T | null;
|
|
53
53
|
static handleBoxSelection(event: PointerEvent, appState: AppState, setState: React.Component<any, AppState>["setState"], elementsMap: NonDeletedSceneElementsMap): false | undefined;
|
|
54
54
|
/** @returns whether point was dragged */
|
|
55
55
|
static handlePointDragging(event: PointerEvent, app: AppClassProperties, scenePointerX: number, scenePointerY: number, maybeSuggestBinding: (element: NonDeleted<ExcalidrawLinearElement>, pointSceneCoords: {
|
|
@@ -63,7 +63,7 @@ export declare class LinearElementEditor {
|
|
|
63
63
|
x: number;
|
|
64
64
|
y: number;
|
|
65
65
|
}, appState: AppState, elementsMap: ElementsMap) => GlobalPoint | null;
|
|
66
|
-
static isSegmentTooShort(element: NonDeleted<ExcalidrawLinearElement>, startPoint:
|
|
66
|
+
static isSegmentTooShort<P extends GlobalPoint | LocalPoint>(element: NonDeleted<ExcalidrawLinearElement>, startPoint: P, endPoint: P, index: number, zoom: Zoom): boolean;
|
|
67
67
|
static getSegmentMidPoint(element: NonDeleted<ExcalidrawLinearElement>, startPoint: GlobalPoint, endPoint: GlobalPoint, endPointIndex: number, elementsMap: ElementsMap): GlobalPoint;
|
|
68
68
|
static getSegmentMidPointIndex(linearElementEditor: LinearElementEditor, appState: AppState, midPoint: GlobalPoint, elementsMap: ElementsMap): number;
|
|
69
69
|
static handlePointerDown(event: React.PointerEvent<HTMLElement>, app: AppClassProperties, store: Store, scenePointer: {
|
|
@@ -97,20 +97,17 @@ export declare class LinearElementEditor {
|
|
|
97
97
|
};
|
|
98
98
|
static normalizePoints(element: NonDeleted<ExcalidrawLinearElement>): void;
|
|
99
99
|
static duplicateSelectedPoints(appState: AppState, elementsMap: NonDeletedSceneElementsMap | SceneElementsMap): AppState;
|
|
100
|
-
static deletePoints(element: NonDeleted<ExcalidrawLinearElement>, pointIndices: readonly number[]
|
|
100
|
+
static deletePoints(element: NonDeleted<ExcalidrawLinearElement>, pointIndices: readonly number[]): void;
|
|
101
101
|
static addPoints(element: NonDeleted<ExcalidrawLinearElement>, targetPoints: {
|
|
102
102
|
point: LocalPoint;
|
|
103
|
-
}[]
|
|
103
|
+
}[]): void;
|
|
104
104
|
static movePoints(element: NonDeleted<ExcalidrawLinearElement>, targetPoints: {
|
|
105
105
|
index: number;
|
|
106
106
|
point: LocalPoint;
|
|
107
107
|
isDragging?: boolean;
|
|
108
|
-
}[],
|
|
108
|
+
}[], otherUpdates?: {
|
|
109
109
|
startBinding?: PointBinding | null;
|
|
110
110
|
endBinding?: PointBinding | null;
|
|
111
|
-
}, options?: {
|
|
112
|
-
changedElements?: Map<string, OrderedExcalidrawElement>;
|
|
113
|
-
isDragging?: boolean;
|
|
114
111
|
}): void;
|
|
115
112
|
static shouldAddMidpoint(linearElementEditor: LinearElementEditor, pointerCoords: PointerCoords, appState: AppState, elementsMap: ElementsMap): boolean;
|
|
116
113
|
static addMidpoint(linearElementEditor: LinearElementEditor, pointerCoords: PointerCoords, app: AppClassProperties, snapToGrid: boolean, elementsMap: ElementsMap): {
|
|
@@ -125,5 +122,7 @@ export declare class LinearElementEditor {
|
|
|
125
122
|
};
|
|
126
123
|
static getMinMaxXYWithBoundText: (element: ExcalidrawLinearElement, elementsMap: ElementsMap, elementBounds: Bounds, boundTextElement: ExcalidrawTextElementWithContainer) => [number, number, number, number, number, number];
|
|
127
124
|
static getElementAbsoluteCoords: (element: ExcalidrawLinearElement, elementsMap: ElementsMap, includeBoundText?: boolean) => [number, number, number, number, number, number];
|
|
125
|
+
static moveFixedSegment(linearElement: LinearElementEditor, index: number, x: number, y: number, elementsMap: ElementsMap): LinearElementEditor;
|
|
126
|
+
static deleteFixedSegment(element: ExcalidrawElbowArrowElement, index: number): void;
|
|
128
127
|
}
|
|
129
128
|
export {};
|
|
@@ -2,16 +2,16 @@ import { getElementAbsoluteCoords, getLockedLinearCursorAlignSize } from ".";
|
|
|
2
2
|
import { getCurvePathOps, getElementPointsCoords, getMinMaxXYFromCurvePathOps, } from "./bounds";
|
|
3
3
|
import { mutateElement } from "./mutateElement";
|
|
4
4
|
import { bindOrUnbindLinearElement, getHoveredElementForBinding, isBindingEnabled, } from "./binding";
|
|
5
|
-
import { invariant,
|
|
5
|
+
import { invariant, tupleToCoors } from "../utils";
|
|
6
6
|
import { isBindingElement, isElbowArrow, isFixedPointBinding, } from "./typeChecks";
|
|
7
7
|
import { KEYS, shouldRotateWithDiscreteAngle } from "../keys";
|
|
8
8
|
import { getBoundTextElement, handleBindTextResize } from "./textElement";
|
|
9
9
|
import { DRAGGING_THRESHOLD } from "../constants";
|
|
10
10
|
import { ShapeCache } from "../scene/ShapeCache";
|
|
11
|
-
import {
|
|
12
|
-
import { pointCenter, pointFrom, pointRotateRads, pointsEqual, vector, pointDistance, } from "../../math";
|
|
11
|
+
import { pointCenter, pointFrom, pointRotateRads, pointsEqual, vector, pointDistance, pointTranslate, vectorFromPoint, } from "../../math";
|
|
13
12
|
import { getBezierCurveLength, getBezierXY, getControlPointsForBezierCurve, isPathALoop, mapIntervalToBezierT, } from "../shapes";
|
|
14
13
|
import { getGridPoint } from "../snapping";
|
|
14
|
+
import { headingIsHorizontal, vectorToHeading } from "./heading";
|
|
15
15
|
const editorMidPointsCache = { version: null, points: [], zoom: null };
|
|
16
16
|
export class LinearElementEditor {
|
|
17
17
|
elementId;
|
|
@@ -151,7 +151,7 @@ export class LinearElementEditor {
|
|
|
151
151
|
point: pointFrom(width + referencePoint[0], height + referencePoint[1]),
|
|
152
152
|
isDragging: selectedIndex === lastClickedPoint,
|
|
153
153
|
},
|
|
154
|
-
]
|
|
154
|
+
]);
|
|
155
155
|
}
|
|
156
156
|
else {
|
|
157
157
|
const newDraggingPointPosition = LinearElementEditor.createPointAt(element, elementsMap, scenePointerX - linearElementEditor.pointerOffset.x, scenePointerY - linearElementEditor.pointerOffset.y, event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize());
|
|
@@ -166,7 +166,7 @@ export class LinearElementEditor {
|
|
|
166
166
|
point: newPointPosition,
|
|
167
167
|
isDragging: pointIndex === lastClickedPoint,
|
|
168
168
|
};
|
|
169
|
-
})
|
|
169
|
+
}));
|
|
170
170
|
}
|
|
171
171
|
const boundTextElement = getBoundTextElement(element, elementsMap);
|
|
172
172
|
if (boundTextElement) {
|
|
@@ -212,10 +212,10 @@ export class LinearElementEditor {
|
|
|
212
212
|
? element.points[element.points.length - 1]
|
|
213
213
|
: element.points[0],
|
|
214
214
|
},
|
|
215
|
-
]
|
|
215
|
+
]);
|
|
216
216
|
}
|
|
217
217
|
const bindingElement = isBindingEnabled(appState)
|
|
218
|
-
? getHoveredElementForBinding(tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(element, selectedPoint, elementsMap)), elements, elementsMap)
|
|
218
|
+
? getHoveredElementForBinding(tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(element, selectedPoint, elementsMap)), elements, elementsMap, appState.zoom, isElbowArrow(element), isElbowArrow(element))
|
|
219
219
|
: null;
|
|
220
220
|
bindings[selectedPoint === 0 ? "startBindingElement" : "endBindingElement"] = bindingElement;
|
|
221
221
|
}
|
|
@@ -244,7 +244,8 @@ export class LinearElementEditor {
|
|
|
244
244
|
static getEditorMidPoints = (element, elementsMap, appState) => {
|
|
245
245
|
const boundText = getBoundTextElement(element, elementsMap);
|
|
246
246
|
// Since its not needed outside editor unless 2 pointer lines or bound text
|
|
247
|
-
if (!
|
|
247
|
+
if (!isElbowArrow(element) &&
|
|
248
|
+
!appState.editingLinearElement &&
|
|
248
249
|
element.points.length > 2 &&
|
|
249
250
|
!boundText) {
|
|
250
251
|
return [];
|
|
@@ -261,7 +262,7 @@ export class LinearElementEditor {
|
|
|
261
262
|
let index = 0;
|
|
262
263
|
const midpoints = [];
|
|
263
264
|
while (index < points.length - 1) {
|
|
264
|
-
if (LinearElementEditor.isSegmentTooShort(element, element.points[index], element.points[index + 1], appState.zoom)) {
|
|
265
|
+
if (LinearElementEditor.isSegmentTooShort(element, element.points[index], element.points[index + 1], index, appState.zoom)) {
|
|
265
266
|
midpoints.push(null);
|
|
266
267
|
index++;
|
|
267
268
|
continue;
|
|
@@ -281,14 +282,16 @@ export class LinearElementEditor {
|
|
|
281
282
|
return null;
|
|
282
283
|
}
|
|
283
284
|
const clickedPointIndex = LinearElementEditor.getPointIndexUnderCursor(element, elementsMap, appState.zoom, scenePointer.x, scenePointer.y);
|
|
284
|
-
if (clickedPointIndex >= 0) {
|
|
285
|
+
if (!isElbowArrow(element) && clickedPointIndex >= 0) {
|
|
285
286
|
return null;
|
|
286
287
|
}
|
|
287
288
|
const points = LinearElementEditor.getPointsGlobalCoordinates(element, elementsMap);
|
|
288
|
-
if (points.length >= 3 &&
|
|
289
|
+
if (points.length >= 3 &&
|
|
290
|
+
!appState.editingLinearElement &&
|
|
291
|
+
!isElbowArrow(element)) {
|
|
289
292
|
return null;
|
|
290
293
|
}
|
|
291
|
-
const threshold = LinearElementEditor.POINT_HANDLE_SIZE / appState.zoom.value;
|
|
294
|
+
const threshold = (LinearElementEditor.POINT_HANDLE_SIZE + 1) / appState.zoom.value;
|
|
292
295
|
const existingSegmentMidpointHitCoords = linearElementEditor.segmentMidPointHoveredCoords;
|
|
293
296
|
if (existingSegmentMidpointHitCoords) {
|
|
294
297
|
const distance = pointDistance(pointFrom(existingSegmentMidpointHitCoords[0], existingSegmentMidpointHitCoords[1]), pointFrom(scenePointer.x, scenePointer.y));
|
|
@@ -300,7 +303,7 @@ export class LinearElementEditor {
|
|
|
300
303
|
const midPoints = LinearElementEditor.getEditorMidPoints(element, elementsMap, appState);
|
|
301
304
|
while (index < midPoints.length) {
|
|
302
305
|
if (midPoints[index] !== null) {
|
|
303
|
-
const distance = pointDistance(
|
|
306
|
+
const distance = pointDistance(midPoints[index], pointFrom(scenePointer.x, scenePointer.y));
|
|
304
307
|
if (distance <= threshold) {
|
|
305
308
|
return midPoints[index];
|
|
306
309
|
}
|
|
@@ -309,8 +312,15 @@ export class LinearElementEditor {
|
|
|
309
312
|
}
|
|
310
313
|
return null;
|
|
311
314
|
};
|
|
312
|
-
static isSegmentTooShort(element, startPoint, endPoint, zoom) {
|
|
313
|
-
|
|
315
|
+
static isSegmentTooShort(element, startPoint, endPoint, index, zoom) {
|
|
316
|
+
if (isElbowArrow(element)) {
|
|
317
|
+
if (index >= 0 && index < element.points.length) {
|
|
318
|
+
return (pointDistance(startPoint, endPoint) * zoom.value <
|
|
319
|
+
LinearElementEditor.POINT_HANDLE_SIZE / 2);
|
|
320
|
+
}
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
let distance = pointDistance(startPoint, endPoint);
|
|
314
324
|
if (element.points.length > 2 && element.roundness) {
|
|
315
325
|
distance = getBezierCurveLength(element, endPoint);
|
|
316
326
|
}
|
|
@@ -364,9 +374,8 @@ export class LinearElementEditor {
|
|
|
364
374
|
if (segmentMidpoint) {
|
|
365
375
|
segmentMidpointIndex = LinearElementEditor.getSegmentMidPointIndex(linearElementEditor, appState, segmentMidpoint, elementsMap);
|
|
366
376
|
}
|
|
367
|
-
if (event.altKey && appState.editingLinearElement) {
|
|
368
|
-
if (linearElementEditor.lastUncommittedPoint == null
|
|
369
|
-
!isElbowArrow(element)) {
|
|
377
|
+
else if (event.altKey && appState.editingLinearElement) {
|
|
378
|
+
if (linearElementEditor.lastUncommittedPoint == null) {
|
|
370
379
|
mutateElement(element, {
|
|
371
380
|
points: [
|
|
372
381
|
...element.points,
|
|
@@ -391,7 +400,7 @@ export class LinearElementEditor {
|
|
|
391
400
|
},
|
|
392
401
|
selectedPointsIndices: [element.points.length - 1],
|
|
393
402
|
lastUncommittedPoint: null,
|
|
394
|
-
endBindingElement: getHoveredElementForBinding(scenePointer, elements, elementsMap),
|
|
403
|
+
endBindingElement: getHoveredElementForBinding(scenePointer, elements, elementsMap, app.state.zoom, linearElementEditor.elbowed),
|
|
395
404
|
};
|
|
396
405
|
ret.didAddPoint = true;
|
|
397
406
|
return ret;
|
|
@@ -473,7 +482,7 @@ export class LinearElementEditor {
|
|
|
473
482
|
const lastPoint = points[points.length - 1];
|
|
474
483
|
if (!event.altKey) {
|
|
475
484
|
if (lastPoint === lastUncommittedPoint) {
|
|
476
|
-
LinearElementEditor.deletePoints(element, [points.length - 1]
|
|
485
|
+
LinearElementEditor.deletePoints(element, [points.length - 1]);
|
|
477
486
|
}
|
|
478
487
|
return {
|
|
479
488
|
...appState.editingLinearElement,
|
|
@@ -497,10 +506,10 @@ export class LinearElementEditor {
|
|
|
497
506
|
index: element.points.length - 1,
|
|
498
507
|
point: newPoint,
|
|
499
508
|
},
|
|
500
|
-
]
|
|
509
|
+
]);
|
|
501
510
|
}
|
|
502
511
|
else {
|
|
503
|
-
LinearElementEditor.addPoints(element, [{ point: newPoint }]
|
|
512
|
+
LinearElementEditor.addPoints(element, [{ point: newPoint }]);
|
|
504
513
|
}
|
|
505
514
|
return {
|
|
506
515
|
...appState.editingLinearElement,
|
|
@@ -633,7 +642,7 @@ export class LinearElementEditor {
|
|
|
633
642
|
index: element.points.length - 1,
|
|
634
643
|
point: pointFrom(lastPoint[0] + 30, lastPoint[1] + 30),
|
|
635
644
|
},
|
|
636
|
-
]
|
|
645
|
+
]);
|
|
637
646
|
}
|
|
638
647
|
return {
|
|
639
648
|
...appState,
|
|
@@ -643,7 +652,7 @@ export class LinearElementEditor {
|
|
|
643
652
|
},
|
|
644
653
|
};
|
|
645
654
|
}
|
|
646
|
-
static deletePoints(element, pointIndices
|
|
655
|
+
static deletePoints(element, pointIndices) {
|
|
647
656
|
let offsetX = 0;
|
|
648
657
|
let offsetY = 0;
|
|
649
658
|
const isDeletingOriginPoint = pointIndices.includes(0);
|
|
@@ -666,15 +675,15 @@ export class LinearElementEditor {
|
|
|
666
675
|
}
|
|
667
676
|
return acc;
|
|
668
677
|
}, []);
|
|
669
|
-
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY
|
|
678
|
+
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY);
|
|
670
679
|
}
|
|
671
|
-
static addPoints(element, targetPoints
|
|
680
|
+
static addPoints(element, targetPoints) {
|
|
672
681
|
const offsetX = 0;
|
|
673
682
|
const offsetY = 0;
|
|
674
683
|
const nextPoints = [...element.points, ...targetPoints.map((x) => x.point)];
|
|
675
|
-
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY
|
|
684
|
+
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY);
|
|
676
685
|
}
|
|
677
|
-
static movePoints(element, targetPoints,
|
|
686
|
+
static movePoints(element, targetPoints, otherUpdates) {
|
|
678
687
|
const { points } = element;
|
|
679
688
|
// in case we're moving start point, instead of modifying its position
|
|
680
689
|
// which would break the invariant of it being at [0,0], we move
|
|
@@ -702,9 +711,8 @@ export class LinearElementEditor {
|
|
|
702
711
|
}
|
|
703
712
|
return offsetX || offsetY ? pointFrom(p[0] - offsetX, p[1] - offsetY) : p;
|
|
704
713
|
});
|
|
705
|
-
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY,
|
|
714
|
+
LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY, otherUpdates, {
|
|
706
715
|
isDragging: targetPoints.reduce((dragging, targetPoint) => dragging || targetPoint.isDragging === true, false),
|
|
707
|
-
changedElements: options?.changedElements,
|
|
708
716
|
});
|
|
709
717
|
}
|
|
710
718
|
static shouldAddMidpoint(linearElementEditor, pointerCoords, appState, elementsMap) {
|
|
@@ -761,27 +769,27 @@ export class LinearElementEditor {
|
|
|
761
769
|
ret.selectedPointsIndices = [segmentMidpoint.index];
|
|
762
770
|
return ret;
|
|
763
771
|
}
|
|
764
|
-
static _updatePoints(element, nextPoints, offsetX, offsetY,
|
|
772
|
+
static _updatePoints(element, nextPoints, offsetX, offsetY, otherUpdates, options) {
|
|
765
773
|
if (isElbowArrow(element)) {
|
|
766
|
-
const
|
|
774
|
+
const updates = {};
|
|
767
775
|
if (otherUpdates?.startBinding !== undefined) {
|
|
768
|
-
|
|
776
|
+
updates.startBinding =
|
|
769
777
|
otherUpdates.startBinding !== null &&
|
|
770
778
|
isFixedPointBinding(otherUpdates.startBinding)
|
|
771
779
|
? otherUpdates.startBinding
|
|
772
780
|
: null;
|
|
773
781
|
}
|
|
774
782
|
if (otherUpdates?.endBinding !== undefined) {
|
|
775
|
-
|
|
783
|
+
updates.endBinding =
|
|
776
784
|
otherUpdates.endBinding !== null &&
|
|
777
785
|
isFixedPointBinding(otherUpdates.endBinding)
|
|
778
786
|
? otherUpdates.endBinding
|
|
779
787
|
: null;
|
|
780
788
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
789
|
+
updates.points = Array.from(nextPoints);
|
|
790
|
+
updates.points[0] = pointTranslate(updates.points[0], vector(offsetX, offsetY));
|
|
791
|
+
updates.points[updates.points.length - 1] = pointTranslate(updates.points[updates.points.length - 1], vector(offsetX, offsetY));
|
|
792
|
+
mutateElement(element, updates, true, {
|
|
785
793
|
isDragging: options?.isDragging,
|
|
786
794
|
});
|
|
787
795
|
}
|
|
@@ -927,6 +935,57 @@ export class LinearElementEditor {
|
|
|
927
935
|
}
|
|
928
936
|
return coords;
|
|
929
937
|
};
|
|
938
|
+
static moveFixedSegment(linearElement, index, x, y, elementsMap) {
|
|
939
|
+
const element = LinearElementEditor.getElement(linearElement.elementId, elementsMap);
|
|
940
|
+
if (!element || !isElbowArrow(element)) {
|
|
941
|
+
return linearElement;
|
|
942
|
+
}
|
|
943
|
+
if (index && index > 0 && index < element.points.length) {
|
|
944
|
+
const isHorizontal = headingIsHorizontal(vectorToHeading(vectorFromPoint(element.points[index], element.points[index - 1])));
|
|
945
|
+
const fixedSegments = (element.fixedSegments ?? []).reduce((segments, s) => {
|
|
946
|
+
segments[s.index] = s;
|
|
947
|
+
return segments;
|
|
948
|
+
}, {});
|
|
949
|
+
fixedSegments[index] = {
|
|
950
|
+
index,
|
|
951
|
+
start: pointFrom(!isHorizontal ? x - element.x : element.points[index - 1][0], isHorizontal ? y - element.y : element.points[index - 1][1]),
|
|
952
|
+
end: pointFrom(!isHorizontal ? x - element.x : element.points[index][0], isHorizontal ? y - element.y : element.points[index][1]),
|
|
953
|
+
};
|
|
954
|
+
const nextFixedSegments = Object.values(fixedSegments).sort((a, b) => a.index - b.index);
|
|
955
|
+
const offset = nextFixedSegments
|
|
956
|
+
.map((segment) => segment.index)
|
|
957
|
+
.reduce((count, idx) => (idx < index ? count + 1 : count), 0);
|
|
958
|
+
mutateElement(element, {
|
|
959
|
+
fixedSegments: nextFixedSegments,
|
|
960
|
+
});
|
|
961
|
+
const point = pointFrom(element.x +
|
|
962
|
+
(element.fixedSegments[offset].start[0] +
|
|
963
|
+
element.fixedSegments[offset].end[0]) /
|
|
964
|
+
2, element.y +
|
|
965
|
+
(element.fixedSegments[offset].start[1] +
|
|
966
|
+
element.fixedSegments[offset].end[1]) /
|
|
967
|
+
2);
|
|
968
|
+
return {
|
|
969
|
+
...linearElement,
|
|
970
|
+
segmentMidPointHoveredCoords: point,
|
|
971
|
+
pointerDownState: {
|
|
972
|
+
...linearElement.pointerDownState,
|
|
973
|
+
segmentMidpoint: {
|
|
974
|
+
added: false,
|
|
975
|
+
index: element.fixedSegments[offset].index,
|
|
976
|
+
value: point,
|
|
977
|
+
},
|
|
978
|
+
},
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
return linearElement;
|
|
982
|
+
}
|
|
983
|
+
static deleteFixedSegment(element, index) {
|
|
984
|
+
mutateElement(element, {
|
|
985
|
+
fixedSegments: element.fixedSegments?.filter((segment) => segment.index !== index),
|
|
986
|
+
});
|
|
987
|
+
mutateElement(element, {}, true);
|
|
988
|
+
}
|
|
930
989
|
}
|
|
931
990
|
const normalizeSelectedPoints = (points) => {
|
|
932
991
|
let nextPoints = [
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ExcalidrawElement } from "./types";
|
|
2
2
|
import type { Mutable } from "../utility-types";
|
|
3
3
|
export type ElementUpdate<TElement extends ExcalidrawElement> = Omit<Partial<TElement>, "id" | "version" | "versionNonce" | "updated">;
|
|
4
|
-
export declare const mutateElement: <TElement extends Mutable<ExcalidrawElement>>(element: TElement, updates: ElementUpdate<TElement>, informMutation?: boolean
|
|
4
|
+
export declare const mutateElement: <TElement extends Mutable<ExcalidrawElement>>(element: TElement, updates: ElementUpdate<TElement>, informMutation?: boolean, options?: {
|
|
5
|
+
isDragging?: boolean;
|
|
6
|
+
}) => TElement;
|
|
5
7
|
export declare const newElementWith: <TElement extends ExcalidrawElement>(element: TElement, updates: ElementUpdate<TElement>, force?: boolean) => TElement;
|
|
6
8
|
/**
|
|
7
9
|
* Mutates element, bumping `version`, `versionNonce`, and `updated`.
|
|
@@ -1,18 +1,45 @@
|
|
|
1
1
|
import Scene from "../scene/Scene";
|
|
2
2
|
import { getSizeFromPoints } from "../points";
|
|
3
3
|
import { randomInteger } from "../random";
|
|
4
|
-
import { getUpdatedTimestamp } from "../utils";
|
|
4
|
+
import { getUpdatedTimestamp, toBrandedType } from "../utils";
|
|
5
5
|
import { ShapeCache } from "../scene/ShapeCache";
|
|
6
|
+
import { isElbowArrow } from "./typeChecks";
|
|
7
|
+
import { updateElbowArrowPoints } from "./elbowArrow";
|
|
6
8
|
// This function tracks updates of text elements for the purposes for collaboration.
|
|
7
9
|
// The version is used to compare updates when more than one user is working in
|
|
8
10
|
// the same drawing. Note: this will trigger the component to update. Make sure you
|
|
9
11
|
// are calling it either from a React event handler or within unstable_batchedUpdates().
|
|
10
|
-
export const mutateElement = (element, updates, informMutation = true) => {
|
|
12
|
+
export const mutateElement = (element, updates, informMutation = true, options) => {
|
|
11
13
|
let didChange = false;
|
|
12
14
|
// casting to any because can't use `in` operator
|
|
13
15
|
// (see https://github.com/microsoft/TypeScript/issues/21732)
|
|
14
|
-
const { points, fileId } = updates;
|
|
15
|
-
if (
|
|
16
|
+
const { points, fixedSegments, fileId, startBinding, endBinding } = updates;
|
|
17
|
+
if (isElbowArrow(element) &&
|
|
18
|
+
(Object.keys(updates).length === 0 || // normalization case
|
|
19
|
+
typeof points !== "undefined" || // repositioning
|
|
20
|
+
typeof fixedSegments !== "undefined" || // segment fixing
|
|
21
|
+
typeof startBinding !== "undefined" ||
|
|
22
|
+
typeof endBinding !== "undefined") // manual binding to element
|
|
23
|
+
) {
|
|
24
|
+
const elementsMap = toBrandedType(Scene.getScene(element)?.getNonDeletedElementsMap() ?? new Map());
|
|
25
|
+
updates = {
|
|
26
|
+
...updates,
|
|
27
|
+
angle: 0,
|
|
28
|
+
...updateElbowArrowPoints({
|
|
29
|
+
...element,
|
|
30
|
+
x: updates.x || element.x,
|
|
31
|
+
y: updates.y || element.y,
|
|
32
|
+
}, elementsMap, {
|
|
33
|
+
fixedSegments,
|
|
34
|
+
points,
|
|
35
|
+
startBinding,
|
|
36
|
+
endBinding,
|
|
37
|
+
}, {
|
|
38
|
+
isDragging: options?.isDragging,
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
else if (typeof points !== "undefined") {
|
|
16
43
|
updates = { ...getSizeFromPoints(points), ...updates };
|
|
17
44
|
}
|
|
18
45
|
for (const key in updates) {
|