@excalidraw/excalidraw 0.17.1-1d71f84 → 0.17.1-4689a6b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-AK7SWNLN.js → chunk-23CKV3WP.js} +4 -2
- package/dist/browser/dev/excalidraw-assets-dev/chunk-23CKV3WP.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-RWZVJAQU.js → chunk-7D5BMEAB.js} +2227 -1976
- package/dist/browser/dev/excalidraw-assets-dev/chunk-7D5BMEAB.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-5TCZHGGJ.js → en-W7TECCRB.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-EDKQZH7Z.js → image-JKT6GXZD.js} +2 -2
- package/dist/browser/dev/index.css +20 -0
- package/dist/browser/dev/index.css.map +2 -2
- package/dist/browser/dev/index.js +770 -585
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/chunk-DWOM5R6H.js +55 -0
- package/dist/browser/prod/excalidraw-assets/{chunk-CTYINSWT.js → chunk-SK23VHAR.js} +2 -2
- package/dist/browser/prod/excalidraw-assets/{en-LROPV2RN.js → en-SMMH575S.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/image-WDEQS5RL.js +1 -0
- package/dist/browser/prod/index.css +1 -1
- package/dist/browser/prod/index.js +22 -22
- package/dist/{prod/en-II4GK66F.json → dev/en-CVBEBUBY.json} +3 -1
- package/dist/dev/index.css +20 -0
- package/dist/dev/index.css.map +2 -2
- package/dist/dev/index.js +2383 -2074
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionBoundText.js +4 -1
- package/dist/excalidraw/actions/actionCanvas.js +3 -1
- package/dist/excalidraw/actions/actionDuplicateSelection.js +4 -0
- package/dist/excalidraw/actions/actionExport.d.ts +1 -1
- package/dist/excalidraw/actions/actionFinalize.d.ts +1 -1
- package/dist/excalidraw/actions/actionFinalize.js +3 -3
- package/dist/excalidraw/actions/actionFlip.d.ts +3 -3
- package/dist/excalidraw/actions/actionFlip.js +6 -6
- package/dist/excalidraw/actions/actionGroup.js +4 -2
- package/dist/excalidraw/actions/actionHistory.js +3 -0
- package/dist/excalidraw/actions/actionZindex.d.ts +11 -11
- package/dist/excalidraw/actions/shortcuts.js +1 -1
- package/dist/excalidraw/analytics.js +1 -1
- package/dist/excalidraw/components/App.d.ts +13 -3
- package/dist/excalidraw/components/App.js +212 -83
- package/dist/excalidraw/components/CommandPalette/CommandPalette.js +24 -10
- package/dist/excalidraw/components/DarkModeToggle.js +3 -1
- package/dist/excalidraw/components/HelpDialog.js +8 -6
- package/dist/excalidraw/components/RadioGroup.d.ts +2 -1
- package/dist/excalidraw/components/RadioGroup.js +1 -1
- package/dist/excalidraw/components/TTDDialog/MermaidToExcalidraw.js +6 -2
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.d.ts +18 -0
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.js +9 -0
- package/dist/excalidraw/components/hyperlink/Hyperlink.js +3 -3
- package/dist/excalidraw/components/hyperlink/helpers.js +2 -3
- package/dist/excalidraw/components/icons.d.ts +3 -0
- package/dist/excalidraw/components/icons.js +5 -1
- package/dist/excalidraw/components/main-menu/DefaultItems.d.ts +12 -2
- package/dist/excalidraw/components/main-menu/DefaultItems.js +38 -7
- package/dist/excalidraw/constants.d.ts +0 -3
- package/dist/excalidraw/constants.js +0 -3
- package/dist/excalidraw/data/magic.js +2 -1
- package/dist/excalidraw/data/reconcile.d.ts +6 -0
- package/dist/excalidraw/data/reconcile.js +49 -0
- package/dist/excalidraw/data/restore.d.ts +3 -3
- package/dist/excalidraw/data/restore.js +5 -6
- package/dist/excalidraw/data/transform.d.ts +1 -1
- package/dist/excalidraw/data/transform.js +12 -3
- package/dist/excalidraw/element/binding.d.ts +22 -9
- package/dist/excalidraw/element/binding.js +403 -26
- package/dist/excalidraw/element/bounds.d.ts +0 -1
- package/dist/excalidraw/element/bounds.js +0 -3
- package/dist/excalidraw/element/collision.d.ts +14 -19
- package/dist/excalidraw/element/collision.js +36 -713
- package/dist/excalidraw/element/embeddable.js +18 -43
- package/dist/excalidraw/element/index.d.ts +0 -1
- package/dist/excalidraw/element/index.js +0 -1
- package/dist/excalidraw/element/linearElementEditor.d.ts +10 -10
- package/dist/excalidraw/element/linearElementEditor.js +6 -4
- package/dist/excalidraw/element/newElement.d.ts +1 -1
- package/dist/excalidraw/element/newElement.js +2 -1
- package/dist/excalidraw/element/textElement.d.ts +0 -1
- package/dist/excalidraw/element/textElement.js +0 -30
- package/dist/excalidraw/element/types.d.ts +17 -2
- package/dist/excalidraw/errors.d.ts +3 -0
- package/dist/excalidraw/errors.js +3 -0
- package/dist/excalidraw/fractionalIndex.d.ts +40 -0
- package/dist/excalidraw/fractionalIndex.js +241 -0
- package/dist/excalidraw/frame.d.ts +1 -1
- package/dist/excalidraw/hooks/useCreatePortalContainer.js +2 -1
- package/dist/excalidraw/locales/en.json +3 -1
- package/dist/excalidraw/renderer/helpers.js +2 -2
- package/dist/excalidraw/renderer/interactiveScene.js +1 -1
- package/dist/excalidraw/renderer/renderElement.js +3 -3
- package/dist/excalidraw/renderer/renderSnaps.js +2 -1
- package/dist/excalidraw/scene/Scene.d.ts +7 -6
- package/dist/excalidraw/scene/Scene.js +28 -13
- package/dist/excalidraw/scene/export.js +4 -3
- package/dist/excalidraw/types.d.ts +4 -3
- package/dist/excalidraw/utils.d.ts +1 -0
- package/dist/excalidraw/utils.js +1 -0
- package/dist/excalidraw/zindex.d.ts +2 -2
- package/dist/excalidraw/zindex.js +9 -13
- package/dist/{dev/en-II4GK66F.json → prod/en-CVBEBUBY.json} +3 -1
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +36 -36
- package/dist/utils/collision.d.ts +4 -0
- package/dist/utils/collision.js +48 -0
- package/dist/utils/geometry/geometry.d.ts +71 -0
- package/dist/utils/geometry/geometry.js +674 -0
- package/dist/utils/geometry/shape.d.ts +55 -0
- package/dist/utils/geometry/shape.js +149 -0
- package/package.json +2 -1
- package/dist/browser/dev/excalidraw-assets-dev/chunk-AK7SWNLN.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-RWZVJAQU.js.map +0 -7
- package/dist/browser/prod/excalidraw-assets/chunk-LL4GORAM.js +0 -55
- package/dist/browser/prod/excalidraw-assets/image-EFCJDJH3.js +0 -1
- /package/dist/browser/dev/excalidraw-assets-dev/{en-5TCZHGGJ.js.map → en-W7TECCRB.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-EDKQZH7Z.js.map → image-JKT6GXZD.js.map} +0 -0
|
@@ -15,12 +15,12 @@ import { APP_NAME, CURSOR_TYPE, DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT, DEFAULT_VERTI
|
|
|
15
15
|
import { exportCanvas, loadFromBlob } from "../data";
|
|
16
16
|
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
|
|
17
17
|
import { restore, restoreElements } from "../data/restore";
|
|
18
|
-
import { dragNewElement, dragSelectedElements, duplicateElement, getCommonBounds, getCursorForResizingElement, getDragOffsetXY, getElementWithTransformHandleType, getNormalizedDimensions, getResizeArrowDirection, getResizeOffsetXY, getLockedLinearCursorAlignSize, getTransformHandleTypeFromCoords,
|
|
18
|
+
import { dragNewElement, dragSelectedElements, duplicateElement, getCommonBounds, getCursorForResizingElement, getDragOffsetXY, getElementWithTransformHandleType, getNormalizedDimensions, getResizeArrowDirection, getResizeOffsetXY, getLockedLinearCursorAlignSize, getTransformHandleTypeFromCoords, isInvisiblySmallElement, isNonDeletedElement, isTextElement, newElement, newLinearElement, newTextElement, newImageElement, transformElements, updateTextElement, redrawTextBoundingBox, getElementAbsoluteCoords, } from "../element";
|
|
19
19
|
import { bindOrUnbindLinearElement, bindOrUnbindSelectedElements, fixBindingsAfterDeletion, fixBindingsAfterDuplication, getEligibleElementsForBinding, getHoveredElementForBinding, isBindingEnabled, isLinearElementSimpleAndAlreadyBound, maybeBindLinearElement, shouldEnableBindingForPointerEvent, unbindLinearElements, updateBoundElements, } from "../element/binding";
|
|
20
20
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
|
21
21
|
import { mutateElement, newElementWith } from "../element/mutateElement";
|
|
22
22
|
import { deepCopyElement, duplicateElements, newFrameElement, newFreeDrawElement, newEmbeddableElement, newMagicFrameElement, newIframeElement, } from "../element/newElement";
|
|
23
|
-
import { hasBoundTextElement, isArrowElement, isBindingElement, isBindingElementType, isBoundToContainer, isFrameLikeElement, isImageElement, isEmbeddableElement, isInitializedImageElement, isLinearElement, isLinearElementType, isUsingAdaptiveRadius, isFrameElement, isIframeElement, isIframeLikeElement, isMagicFrameElement, } from "../element/typeChecks";
|
|
23
|
+
import { hasBoundTextElement, isArrowElement, isBindingElement, isBindingElementType, isBoundToContainer, isFrameLikeElement, isImageElement, isEmbeddableElement, isInitializedImageElement, isLinearElement, isLinearElementType, isUsingAdaptiveRadius, isFrameElement, isIframeElement, isIframeLikeElement, isMagicFrameElement, isTextBindableContainer, } from "../element/typeChecks";
|
|
24
24
|
import { getCenter, getDistance } from "../gesture";
|
|
25
25
|
import { editGroupForSelectedElement, getElementsInGroup, getSelectedGroupIdForElement, getSelectedGroupIds, isElementInGroup, isSelectedViaGroup, selectGroupsForSelectedElements, } from "../groups";
|
|
26
26
|
import History from "../history";
|
|
@@ -28,11 +28,13 @@ import { defaultLang, getLanguage, languages, setLanguage, t } from "../i18n";
|
|
|
28
28
|
import { CODES, shouldResizeFromCenter, shouldMaintainAspectRatio, shouldRotateWithDiscreteAngle, isArrowKey, KEYS, } from "../keys";
|
|
29
29
|
import { isElementInViewport } from "../element/sizeHelpers";
|
|
30
30
|
import { distance2d, getCornerRadius, getGridPoint, isPathALoop, } from "../math";
|
|
31
|
-
import { calculateScrollCenter,
|
|
31
|
+
import { calculateScrollCenter, getElementsWithinSelection, getNormalizedZoom, getSelectedElements, hasBackground, isSomeElementSelected, } from "../scene";
|
|
32
32
|
import Scene from "../scene/Scene";
|
|
33
33
|
import { getStateForZoom } from "../scene/zoom";
|
|
34
34
|
import { findShapeByKey } from "../shapes";
|
|
35
|
-
import {
|
|
35
|
+
import { getClosedCurveShape, getCurveShape, getEllipseShape, getFreedrawShape, getPolygonShape, } from "../../utils/geometry/shape";
|
|
36
|
+
import { isPointInShape } from "../../utils/collision";
|
|
37
|
+
import { debounce, distance, getFontString, getNearestScrollableContainer, isInputLike, isToolIcon, isWritableElement, sceneCoordsToViewportCoords, tupleToCoors, viewportCoordsToSceneCoords, wrapEvent, updateObject, updateActiveTool, getShortcutKey, isTransparent, easeToValuesRAF, muteFSAbortError, isTestEnv, easeOut, arrayToMap, updateStable, addEventListener, normalizeEOL, getDateTime, } from "../utils";
|
|
36
38
|
import { createSrcDoc, embeddableURLValidator, maybeParseEmbedSrc, getEmbedLink, } from "../element/embeddable";
|
|
37
39
|
import { ContextMenu, CONTEXT_MENU_SEPARATOR, } from "./ContextMenu";
|
|
38
40
|
import LayerUI from "./LayerUI";
|
|
@@ -42,8 +44,7 @@ import { dataURLToFile, generateIdFromFile, getDataURL, getFileFromEvent, ImageU
|
|
|
42
44
|
import { getInitializedImageElements, loadHTMLImageElement, normalizeSVG, updateImageCache as _updateImageCache, } from "../element/image";
|
|
43
45
|
import throttle from "lodash.throttle";
|
|
44
46
|
import { fileOpen } from "../data/filesystem";
|
|
45
|
-
import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx,
|
|
46
|
-
import { isHittingElementNotConsideringBoundingBox } from "../element/collision";
|
|
47
|
+
import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx, isMeasureTextSupported, isValidTextContainer, } from "../element/textElement";
|
|
47
48
|
import { showHyperlinkTooltip, hideHyperlinkToolip, Hyperlink, } from "../components/hyperlink/Hyperlink";
|
|
48
49
|
import { isLocalLink, normalizeLink, toValidURL } from "../data/url";
|
|
49
50
|
import { shouldShowBoundingBox } from "../element/transformHandles";
|
|
@@ -82,8 +83,10 @@ import { AnimatedTrail } from "../animated-trail";
|
|
|
82
83
|
import { LaserTrails } from "../laser-trails";
|
|
83
84
|
import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
|
|
84
85
|
import { getRenderOpacity } from "../renderer/renderElement";
|
|
86
|
+
import { hitElementBoundText, hitElementBoundingBox, hitElementBoundingBoxOnly, hitElementItself, shouldTestInside, } from "../element/collision";
|
|
85
87
|
import { textWysiwyg } from "../element/textWysiwyg";
|
|
86
88
|
import { isOverScrollBars } from "../scene/scrollbars";
|
|
89
|
+
import { syncInvalidIndices, syncMovedIndices } from "../fractionalIndex";
|
|
87
90
|
import { isPointHittingLink, isPointHittingLinkIcon, } from "./hyperlink/helpers";
|
|
88
91
|
import { getShortcutFromShortcutName } from "../actions/shortcuts";
|
|
89
92
|
const AppContext = React.createContext(null);
|
|
@@ -495,7 +498,7 @@ class App extends React.Component {
|
|
|
495
498
|
html, body {
|
|
496
499
|
width: 100%;
|
|
497
500
|
height: 100%;
|
|
498
|
-
color: ${this.state.theme ===
|
|
501
|
+
color: ${this.state.theme === THEME.DARK ? "white" : "black"};
|
|
499
502
|
}
|
|
500
503
|
body {
|
|
501
504
|
display: flex;
|
|
@@ -650,7 +653,7 @@ class App extends React.Component {
|
|
|
650
653
|
? src.srcdoc(this.state.theme)
|
|
651
654
|
: undefined, src: src?.type !== "document" ? src?.link ?? "" : undefined,
|
|
652
655
|
// https://stackoverflow.com/q/18470015
|
|
653
|
-
scrolling: "no", referrerPolicy: "no-referrer-when-downgrade", title: "Excalidraw Embedded Content", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture", allowFullScreen: true, sandbox: "allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads
|
|
656
|
+
scrolling: "no", referrerPolicy: "no-referrer-when-downgrade", title: "Excalidraw Embedded Content", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture", allowFullScreen: true, sandbox: `${src?.sandbox?.allowSameOrigin ? "allow-same-origin" : ""} allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads` })) })] }) }, el.id));
|
|
654
657
|
}) }));
|
|
655
658
|
}
|
|
656
659
|
getFrameNameDOMId = (frameElement) => {
|
|
@@ -692,7 +695,7 @@ class App extends React.Component {
|
|
|
692
695
|
if (!this.state.frameRendering.enabled || !this.state.frameRendering.name) {
|
|
693
696
|
return null;
|
|
694
697
|
}
|
|
695
|
-
const isDarkTheme = this.state.theme ===
|
|
698
|
+
const isDarkTheme = this.state.theme === THEME.DARK;
|
|
696
699
|
let frameIndex = 0;
|
|
697
700
|
let magicFrameIndex = 0;
|
|
698
701
|
return this.scene.getNonDeletedFramesLikes().map((f) => {
|
|
@@ -1122,7 +1125,7 @@ class App extends React.Component {
|
|
|
1122
1125
|
opacity: 100,
|
|
1123
1126
|
locked: false,
|
|
1124
1127
|
});
|
|
1125
|
-
this.scene.
|
|
1128
|
+
this.scene.insertElement(frame);
|
|
1126
1129
|
for (const child of selectedElements) {
|
|
1127
1130
|
mutateElement(child, { frameId: frame.id });
|
|
1128
1131
|
}
|
|
@@ -1608,7 +1611,7 @@ class App extends React.Component {
|
|
|
1608
1611
|
gridSize: this.props.gridModeEnabled ? GRID_SIZE : null,
|
|
1609
1612
|
});
|
|
1610
1613
|
}
|
|
1611
|
-
this.excalidrawContainerRef.current?.classList.toggle("theme--dark", this.state.theme ===
|
|
1614
|
+
this.excalidrawContainerRef.current?.classList.toggle("theme--dark", this.state.theme === THEME.DARK);
|
|
1612
1615
|
if (this.state.editingLinearElement &&
|
|
1613
1616
|
!this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {
|
|
1614
1617
|
// defer so that the commitToHistory flag isn't reset via current update
|
|
@@ -1636,7 +1639,7 @@ class App extends React.Component {
|
|
|
1636
1639
|
multiElement != null &&
|
|
1637
1640
|
isBindingEnabled(this.state) &&
|
|
1638
1641
|
isBindingElement(multiElement, false)) {
|
|
1639
|
-
maybeBindLinearElement(multiElement, this.state,
|
|
1642
|
+
maybeBindLinearElement(multiElement, this.state, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, elementsMap)), this);
|
|
1640
1643
|
}
|
|
1641
1644
|
this.history.record(this.state, elements);
|
|
1642
1645
|
// Do not notify consumers if we're still loading the scene. Among other
|
|
@@ -1894,16 +1897,15 @@ class App extends React.Component {
|
|
|
1894
1897
|
}), {
|
|
1895
1898
|
randomizeSeed: !opts.retainSeed,
|
|
1896
1899
|
});
|
|
1897
|
-
const
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
];
|
|
1900
|
+
const prevElements = this.scene.getElementsIncludingDeleted();
|
|
1901
|
+
const nextElements = [...prevElements, ...newElements];
|
|
1902
|
+
syncMovedIndices(nextElements, arrayToMap(newElements));
|
|
1901
1903
|
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({ x, y });
|
|
1902
1904
|
if (topLayerFrame) {
|
|
1903
1905
|
const eligibleElements = filterElementsEligibleAsFrameChildren(newElements, topLayerFrame);
|
|
1904
|
-
addElementsToFrame(
|
|
1906
|
+
addElementsToFrame(nextElements, eligibleElements, topLayerFrame);
|
|
1905
1907
|
}
|
|
1906
|
-
this.scene.replaceAllElements(
|
|
1908
|
+
this.scene.replaceAllElements(nextElements);
|
|
1907
1909
|
newElements.forEach((newElement) => {
|
|
1908
1910
|
if (isTextElement(newElement) && isBoundToContainer(newElement)) {
|
|
1909
1911
|
const container = getContainerElement(newElement, this.scene.getElementsMapIncludingDeleted());
|
|
@@ -2071,16 +2073,7 @@ class App extends React.Component {
|
|
|
2071
2073
|
if (textElements.length === 0) {
|
|
2072
2074
|
return;
|
|
2073
2075
|
}
|
|
2074
|
-
|
|
2075
|
-
if (frameId) {
|
|
2076
|
-
this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));
|
|
2077
|
-
}
|
|
2078
|
-
else {
|
|
2079
|
-
this.scene.replaceAllElements([
|
|
2080
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
2081
|
-
...textElements,
|
|
2082
|
-
]);
|
|
2083
|
-
}
|
|
2076
|
+
this.scene.insertElements(textElements);
|
|
2084
2077
|
this.setState({
|
|
2085
2078
|
selectedElementIds: makeNextSelectedElementIds(Object.fromEntries(textElements.map((el) => [el.id, true])), this.state),
|
|
2086
2079
|
});
|
|
@@ -2355,8 +2348,7 @@ class App extends React.Component {
|
|
|
2355
2348
|
!event.altKey) {
|
|
2356
2349
|
this.setToast({
|
|
2357
2350
|
message: t("commandPalette.shortcutHint", {
|
|
2358
|
-
|
|
2359
|
-
shortcutTwo: getShortcutFromShortcutName("commandPalette", 1),
|
|
2351
|
+
shortcut: getShortcutFromShortcutName("commandPalette"),
|
|
2360
2352
|
}),
|
|
2361
2353
|
});
|
|
2362
2354
|
event.preventDefault();
|
|
@@ -2605,7 +2597,7 @@ class App extends React.Component {
|
|
|
2605
2597
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
2606
2598
|
const elementsMap = this.scene.getNonDeletedElementsMap();
|
|
2607
2599
|
isBindingEnabled(this.state)
|
|
2608
|
-
? bindOrUnbindSelectedElements(selectedElements, this
|
|
2600
|
+
? bindOrUnbindSelectedElements(selectedElements, this)
|
|
2609
2601
|
: unbindLinearElements(selectedElements, elementsMap);
|
|
2610
2602
|
this.setState({ suggestedBindings: [] });
|
|
2611
2603
|
}
|
|
@@ -2835,6 +2827,57 @@ class App extends React.Component {
|
|
|
2835
2827
|
}
|
|
2836
2828
|
return null;
|
|
2837
2829
|
}
|
|
2830
|
+
/**
|
|
2831
|
+
* get the pure geometric shape of an excalidraw element
|
|
2832
|
+
* which is then used for hit detection
|
|
2833
|
+
*/
|
|
2834
|
+
getElementShape(element) {
|
|
2835
|
+
switch (element.type) {
|
|
2836
|
+
case "rectangle":
|
|
2837
|
+
case "diamond":
|
|
2838
|
+
case "frame":
|
|
2839
|
+
case "magicframe":
|
|
2840
|
+
case "embeddable":
|
|
2841
|
+
case "image":
|
|
2842
|
+
case "iframe":
|
|
2843
|
+
case "text":
|
|
2844
|
+
case "selection":
|
|
2845
|
+
return getPolygonShape(element);
|
|
2846
|
+
case "arrow":
|
|
2847
|
+
case "line": {
|
|
2848
|
+
const roughShape = ShapeCache.get(element)?.[0] ??
|
|
2849
|
+
ShapeCache.generateElementShape(element, null)[0];
|
|
2850
|
+
const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
|
|
2851
|
+
return shouldTestInside(element)
|
|
2852
|
+
? getClosedCurveShape(element, roughShape, [element.x, element.y], element.angle, [cx, cy])
|
|
2853
|
+
: getCurveShape(roughShape, [element.x, element.y], element.angle, [
|
|
2854
|
+
cx,
|
|
2855
|
+
cy,
|
|
2856
|
+
]);
|
|
2857
|
+
}
|
|
2858
|
+
case "ellipse":
|
|
2859
|
+
return getEllipseShape(element);
|
|
2860
|
+
case "freedraw": {
|
|
2861
|
+
const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
|
|
2862
|
+
return getFreedrawShape(element, [cx, cy], shouldTestInside(element));
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
getBoundTextShape(element) {
|
|
2867
|
+
const boundTextElement = getBoundTextElement(element, this.scene.getNonDeletedElementsMap());
|
|
2868
|
+
if (boundTextElement) {
|
|
2869
|
+
if (element.type === "arrow") {
|
|
2870
|
+
return this.getElementShape({
|
|
2871
|
+
...boundTextElement,
|
|
2872
|
+
// arrow's bound text accurate position is not stored in the element's property
|
|
2873
|
+
// but rather calculated and returned from the following static method
|
|
2874
|
+
...LinearElementEditor.getBoundTextElementPosition(element, boundTextElement, this.scene.getNonDeletedElementsMap()),
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2877
|
+
return this.getElementShape(boundTextElement);
|
|
2878
|
+
}
|
|
2879
|
+
return null;
|
|
2880
|
+
}
|
|
2838
2881
|
getElementAtPosition(x, y, opts) {
|
|
2839
2882
|
const allHitElements = this.getElementsAtPosition(x, y, opts?.includeBoundTextElement, opts?.includeLockedElements);
|
|
2840
2883
|
if (allHitElements.length > 1) {
|
|
@@ -2848,9 +2891,9 @@ class App extends React.Component {
|
|
|
2848
2891
|
const elementWithHighestZIndex = allHitElements[allHitElements.length - 1];
|
|
2849
2892
|
// If we're hitting element with highest z-index only on its bounding box
|
|
2850
2893
|
// while also hitting other element figure, the latter should be considered.
|
|
2851
|
-
return
|
|
2852
|
-
?
|
|
2853
|
-
:
|
|
2894
|
+
return isPointInShape([x, y], this.getElementShape(elementWithHighestZIndex))
|
|
2895
|
+
? elementWithHighestZIndex
|
|
2896
|
+
: allHitElements[allHitElements.length - 2];
|
|
2854
2897
|
}
|
|
2855
2898
|
if (allHitElements.length === 1) {
|
|
2856
2899
|
return allHitElements[0];
|
|
@@ -2858,15 +2901,17 @@ class App extends React.Component {
|
|
|
2858
2901
|
return null;
|
|
2859
2902
|
}
|
|
2860
2903
|
getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {
|
|
2861
|
-
const
|
|
2904
|
+
const iframeLikes = [];
|
|
2905
|
+
const elementsMap = this.scene.getNonDeletedElementsMap();
|
|
2906
|
+
const elements = (includeBoundTextElement && includeLockedElements
|
|
2862
2907
|
? this.scene.getNonDeletedElements()
|
|
2863
2908
|
: this.scene
|
|
2864
2909
|
.getNonDeletedElements()
|
|
2865
2910
|
.filter((element) => (includeLockedElements || !element.locked) &&
|
|
2866
2911
|
(includeBoundTextElement ||
|
|
2867
|
-
!(isTextElement(element) && element.containerId)))
|
|
2868
|
-
|
|
2869
|
-
|
|
2912
|
+
!(isTextElement(element) && element.containerId))))
|
|
2913
|
+
.filter((el) => this.hitElement(x, y, el))
|
|
2914
|
+
.filter((element) => {
|
|
2870
2915
|
// hitting a frame's element from outside the frame is not considered a hit
|
|
2871
2916
|
const containingFrame = getContainingFrame(element, elementsMap);
|
|
2872
2917
|
return containingFrame &&
|
|
@@ -2874,8 +2919,80 @@ class App extends React.Component {
|
|
|
2874
2919
|
this.state.frameRendering.clip
|
|
2875
2920
|
? isCursorInFrame({ x, y }, containingFrame, elementsMap)
|
|
2876
2921
|
: true;
|
|
2922
|
+
})
|
|
2923
|
+
.filter((el) => {
|
|
2924
|
+
// The parameter elements comes ordered from lower z-index to higher.
|
|
2925
|
+
// We want to preserve that order on the returned array.
|
|
2926
|
+
// Exception being embeddables which should be on top of everything else in
|
|
2927
|
+
// terms of hit testing.
|
|
2928
|
+
if (isIframeElement(el)) {
|
|
2929
|
+
iframeLikes.push(el);
|
|
2930
|
+
return false;
|
|
2931
|
+
}
|
|
2932
|
+
return true;
|
|
2933
|
+
})
|
|
2934
|
+
.concat(iframeLikes);
|
|
2935
|
+
return elements;
|
|
2936
|
+
}
|
|
2937
|
+
getHitThreshold() {
|
|
2938
|
+
return 10 / this.state.zoom.value;
|
|
2939
|
+
}
|
|
2940
|
+
hitElement(x, y, element, considerBoundingBox = true) {
|
|
2941
|
+
// if the element is selected, then hit test is done against its bounding box
|
|
2942
|
+
if (considerBoundingBox &&
|
|
2943
|
+
this.state.selectedElementIds[element.id] &&
|
|
2944
|
+
shouldShowBoundingBox([element], this.state)) {
|
|
2945
|
+
return hitElementBoundingBox(x, y, element, this.scene.getNonDeletedElementsMap(), this.getHitThreshold());
|
|
2946
|
+
}
|
|
2947
|
+
// take bound text element into consideration for hit collision as well
|
|
2948
|
+
const hitBoundTextOfElement = hitElementBoundText(x, y, this.getBoundTextShape(element));
|
|
2949
|
+
if (hitBoundTextOfElement) {
|
|
2950
|
+
return true;
|
|
2951
|
+
}
|
|
2952
|
+
return hitElementItself({
|
|
2953
|
+
x,
|
|
2954
|
+
y,
|
|
2955
|
+
element,
|
|
2956
|
+
shape: this.getElementShape(element),
|
|
2957
|
+
threshold: this.getHitThreshold(),
|
|
2958
|
+
frameNameBound: isFrameLikeElement(element)
|
|
2959
|
+
? this.frameNameBoundsCache.get(element)
|
|
2960
|
+
: null,
|
|
2877
2961
|
});
|
|
2878
2962
|
}
|
|
2963
|
+
getTextBindableContainerAtPosition(x, y) {
|
|
2964
|
+
const elements = this.scene.getNonDeletedElements();
|
|
2965
|
+
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
2966
|
+
if (selectedElements.length === 1) {
|
|
2967
|
+
return isTextBindableContainer(selectedElements[0], false)
|
|
2968
|
+
? selectedElements[0]
|
|
2969
|
+
: null;
|
|
2970
|
+
}
|
|
2971
|
+
let hitElement = null;
|
|
2972
|
+
// We need to do hit testing from front (end of the array) to back (beginning of the array)
|
|
2973
|
+
for (let index = elements.length - 1; index >= 0; --index) {
|
|
2974
|
+
if (elements[index].isDeleted) {
|
|
2975
|
+
continue;
|
|
2976
|
+
}
|
|
2977
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(elements[index], this.scene.getNonDeletedElementsMap());
|
|
2978
|
+
if (isArrowElement(elements[index]) &&
|
|
2979
|
+
hitElementItself({
|
|
2980
|
+
x,
|
|
2981
|
+
y,
|
|
2982
|
+
element: elements[index],
|
|
2983
|
+
shape: this.getElementShape(elements[index]),
|
|
2984
|
+
threshold: this.getHitThreshold(),
|
|
2985
|
+
})) {
|
|
2986
|
+
hitElement = elements[index];
|
|
2987
|
+
break;
|
|
2988
|
+
}
|
|
2989
|
+
else if (x1 < x && x < x2 && y1 < y && y < y2) {
|
|
2990
|
+
hitElement = elements[index];
|
|
2991
|
+
break;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
return isTextBindableContainer(hitElement, false) ? hitElement : null;
|
|
2995
|
+
}
|
|
2879
2996
|
startTextEditing = ({ sceneX, sceneY, insertAtParentCenter = true, container, }) => {
|
|
2880
2997
|
let shouldBindToContainer = false;
|
|
2881
2998
|
let parentCenterPosition = insertAtParentCenter &&
|
|
@@ -2974,7 +3091,7 @@ class App extends React.Component {
|
|
|
2974
3091
|
this.scene.insertElementAtIndex(element, containerIndex + 1);
|
|
2975
3092
|
}
|
|
2976
3093
|
else {
|
|
2977
|
-
this.scene.
|
|
3094
|
+
this.scene.insertElement(element);
|
|
2978
3095
|
}
|
|
2979
3096
|
}
|
|
2980
3097
|
this.setState({
|
|
@@ -3033,11 +3150,17 @@ class App extends React.Component {
|
|
|
3033
3150
|
});
|
|
3034
3151
|
return;
|
|
3035
3152
|
}
|
|
3036
|
-
const container =
|
|
3153
|
+
const container = this.getTextBindableContainerAtPosition(sceneX, sceneY);
|
|
3037
3154
|
if (container) {
|
|
3038
3155
|
if (hasBoundTextElement(container) ||
|
|
3039
3156
|
!isTransparent(container.backgroundColor) ||
|
|
3040
|
-
|
|
3157
|
+
hitElementItself({
|
|
3158
|
+
x: sceneX,
|
|
3159
|
+
y: sceneY,
|
|
3160
|
+
element: container,
|
|
3161
|
+
shape: this.getElementShape(container),
|
|
3162
|
+
threshold: this.getHitThreshold(),
|
|
3163
|
+
})) {
|
|
3041
3164
|
const midPoint = getContainerCenter(container, this.state, this.scene.getNonDeletedElementsMap());
|
|
3042
3165
|
sceneX = midPoint.x;
|
|
3043
3166
|
sceneY = midPoint.y;
|
|
@@ -3092,7 +3215,7 @@ class App extends React.Component {
|
|
|
3092
3215
|
}
|
|
3093
3216
|
if (!customEvent?.defaultPrevented) {
|
|
3094
3217
|
const target = isLocalLink(url) ? "_self" : "_blank";
|
|
3095
|
-
const newWindow = window.open(undefined, target
|
|
3218
|
+
const newWindow = window.open(undefined, target);
|
|
3096
3219
|
// https://mathiasbynens.github.io/rel-noopener/
|
|
3097
3220
|
if (newWindow) {
|
|
3098
3221
|
newWindow.opener = null;
|
|
@@ -3420,7 +3543,7 @@ class App extends React.Component {
|
|
|
3420
3543
|
}
|
|
3421
3544
|
};
|
|
3422
3545
|
const distance = distance2d(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);
|
|
3423
|
-
const threshold =
|
|
3546
|
+
const threshold = this.getHitThreshold();
|
|
3424
3547
|
const point = { ...pointerDownState.lastCoords };
|
|
3425
3548
|
let samplingInterval = 0;
|
|
3426
3549
|
while (samplingInterval <= distance) {
|
|
@@ -3466,14 +3589,18 @@ class App extends React.Component {
|
|
|
3466
3589
|
handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {
|
|
3467
3590
|
const elementsMap = this.scene.getNonDeletedElementsMap();
|
|
3468
3591
|
const element = LinearElementEditor.getElement(linearElementEditor.elementId, elementsMap);
|
|
3469
|
-
const boundTextElement = getBoundTextElement(element, elementsMap);
|
|
3470
3592
|
if (!element) {
|
|
3471
3593
|
return;
|
|
3472
3594
|
}
|
|
3473
3595
|
if (this.state.selectedLinearElement) {
|
|
3474
3596
|
let hoverPointIndex = -1;
|
|
3475
3597
|
let segmentMidPointHoveredCoords = null;
|
|
3476
|
-
if (
|
|
3598
|
+
if (hitElementItself({
|
|
3599
|
+
x: scenePointerX,
|
|
3600
|
+
y: scenePointerY,
|
|
3601
|
+
element,
|
|
3602
|
+
shape: this.getElementShape(element),
|
|
3603
|
+
})) {
|
|
3477
3604
|
hoverPointIndex = LinearElementEditor.getPointIndexUnderCursor(element, elementsMap, this.state.zoom, scenePointerX, scenePointerY);
|
|
3478
3605
|
segmentMidPointHoveredCoords =
|
|
3479
3606
|
LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, { x: scenePointerX, y: scenePointerY }, this.state, this.scene.getNonDeletedElementsMap());
|
|
@@ -3484,12 +3611,7 @@ class App extends React.Component {
|
|
|
3484
3611
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
|
|
3485
3612
|
}
|
|
3486
3613
|
}
|
|
3487
|
-
else if (
|
|
3488
|
-
isHittingElementBoundingBoxWithoutHittingElement(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY, elementsMap)) {
|
|
3489
|
-
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
|
|
3490
|
-
}
|
|
3491
|
-
else if (boundTextElement &&
|
|
3492
|
-
hitTest(boundTextElement, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY, this.scene.getNonDeletedElementsMap())) {
|
|
3614
|
+
else if (this.hitElement(scenePointerX, scenePointerY, element)) {
|
|
3493
3615
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
|
|
3494
3616
|
}
|
|
3495
3617
|
if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {
|
|
@@ -4020,7 +4142,7 @@ class App extends React.Component {
|
|
|
4020
4142
|
else {
|
|
4021
4143
|
if (this.state.selectedLinearElement) {
|
|
4022
4144
|
const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;
|
|
4023
|
-
const ret = LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor, this
|
|
4145
|
+
const ret = LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor, this);
|
|
4024
4146
|
if (ret.hitElement) {
|
|
4025
4147
|
pointerDownState.hit.element = ret.hitElement;
|
|
4026
4148
|
}
|
|
@@ -4181,7 +4303,7 @@ class App extends React.Component {
|
|
|
4181
4303
|
return false;
|
|
4182
4304
|
}
|
|
4183
4305
|
// How many pixels off the shape boundary we still consider a hit
|
|
4184
|
-
const threshold =
|
|
4306
|
+
const threshold = this.getHitThreshold();
|
|
4185
4307
|
const [x1, y1, x2, y2] = getCommonBounds(selectedElements);
|
|
4186
4308
|
return (point.x > x1 - threshold &&
|
|
4187
4309
|
point.x < x2 + threshold &&
|
|
@@ -4201,7 +4323,7 @@ class App extends React.Component {
|
|
|
4201
4323
|
includeBoundTextElement: true,
|
|
4202
4324
|
});
|
|
4203
4325
|
// FIXME
|
|
4204
|
-
let container =
|
|
4326
|
+
let container = this.getTextBindableContainerAtPosition(sceneX, sceneY);
|
|
4205
4327
|
if (hasBoundTextElement(element)) {
|
|
4206
4328
|
container = element;
|
|
4207
4329
|
sceneX = element.x + element.width / 2;
|
|
@@ -4259,8 +4381,8 @@ class App extends React.Component {
|
|
|
4259
4381
|
points: [[0, 0]],
|
|
4260
4382
|
pressures,
|
|
4261
4383
|
});
|
|
4262
|
-
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this
|
|
4263
|
-
this.scene.
|
|
4384
|
+
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
|
|
4385
|
+
this.scene.insertElement(element);
|
|
4264
4386
|
this.setState({
|
|
4265
4387
|
draggingElement: element,
|
|
4266
4388
|
editingElement: element,
|
|
@@ -4288,10 +4410,7 @@ class App extends React.Component {
|
|
|
4288
4410
|
width,
|
|
4289
4411
|
height,
|
|
4290
4412
|
});
|
|
4291
|
-
this.scene.
|
|
4292
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
4293
|
-
element,
|
|
4294
|
-
]);
|
|
4413
|
+
this.scene.insertElement(element);
|
|
4295
4414
|
return element;
|
|
4296
4415
|
};
|
|
4297
4416
|
//create rectangle element with youtube top left on nearest grid point width / hight 640/360
|
|
@@ -4326,10 +4445,7 @@ class App extends React.Component {
|
|
|
4326
4445
|
height: embedLink.intrinsicSize.h,
|
|
4327
4446
|
link,
|
|
4328
4447
|
});
|
|
4329
|
-
this.scene.
|
|
4330
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
4331
|
-
element,
|
|
4332
|
-
]);
|
|
4448
|
+
this.scene.insertElement(element);
|
|
4333
4449
|
return element;
|
|
4334
4450
|
};
|
|
4335
4451
|
createImageElement = ({ sceneX, sceneY, addToFrameUnderCursor = true, }) => {
|
|
@@ -4437,8 +4553,8 @@ class App extends React.Component {
|
|
|
4437
4553
|
mutateElement(element, {
|
|
4438
4554
|
points: [...element.points, [0, 0]],
|
|
4439
4555
|
});
|
|
4440
|
-
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this
|
|
4441
|
-
this.scene.
|
|
4556
|
+
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
|
|
4557
|
+
this.scene.insertElement(element);
|
|
4442
4558
|
this.setState({
|
|
4443
4559
|
draggingElement: element,
|
|
4444
4560
|
editingElement: element,
|
|
@@ -4498,7 +4614,7 @@ class App extends React.Component {
|
|
|
4498
4614
|
});
|
|
4499
4615
|
}
|
|
4500
4616
|
else {
|
|
4501
|
-
this.scene.
|
|
4617
|
+
this.scene.insertElement(element);
|
|
4502
4618
|
this.setState({
|
|
4503
4619
|
multiElement: null,
|
|
4504
4620
|
draggingElement: element,
|
|
@@ -4520,10 +4636,7 @@ class App extends React.Component {
|
|
|
4520
4636
|
const frame = type === TOOL_TYPE.magicframe
|
|
4521
4637
|
? newMagicFrameElement(constructorOpts)
|
|
4522
4638
|
: newFrameElement(constructorOpts);
|
|
4523
|
-
this.scene.
|
|
4524
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
4525
|
-
frame,
|
|
4526
|
-
]);
|
|
4639
|
+
this.scene.insertElement(frame);
|
|
4527
4640
|
this.setState({
|
|
4528
4641
|
multiElement: null,
|
|
4529
4642
|
draggingElement: frame,
|
|
@@ -4781,6 +4894,7 @@ class App extends React.Component {
|
|
|
4781
4894
|
}
|
|
4782
4895
|
}
|
|
4783
4896
|
const nextSceneElements = [...nextElements, ...elementsToAppend];
|
|
4897
|
+
syncMovedIndices(nextSceneElements, arrayToMap(elementsToAppend));
|
|
4784
4898
|
bindTextToShapeAfterDuplication(nextElements, elementsToAppend, oldIdToDuplicatedId);
|
|
4785
4899
|
fixBindingsAfterDuplication(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, "duplicatesServeAsOld");
|
|
4786
4900
|
bindElementsToFramesAfterDuplication(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);
|
|
@@ -4972,7 +5086,7 @@ class App extends React.Component {
|
|
|
4972
5086
|
this.actionManager.executeAction(actionFinalize);
|
|
4973
5087
|
}
|
|
4974
5088
|
else {
|
|
4975
|
-
const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this
|
|
5089
|
+
const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this);
|
|
4976
5090
|
if (editingLinearElement !== this.state.editingLinearElement) {
|
|
4977
5091
|
this.setState({
|
|
4978
5092
|
editingLinearElement,
|
|
@@ -4991,7 +5105,7 @@ class App extends React.Component {
|
|
|
4991
5105
|
}
|
|
4992
5106
|
}
|
|
4993
5107
|
else {
|
|
4994
|
-
const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this
|
|
5108
|
+
const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this);
|
|
4995
5109
|
const { startBindingElement, endBindingElement } = linearElementEditor;
|
|
4996
5110
|
const element = this.scene.getElement(linearElementEditor.elementId);
|
|
4997
5111
|
if (isBindingElement(element)) {
|
|
@@ -5083,7 +5197,7 @@ class App extends React.Component {
|
|
|
5083
5197
|
else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
|
5084
5198
|
if (isBindingEnabled(this.state) &&
|
|
5085
5199
|
isBindingElement(draggingElement, false)) {
|
|
5086
|
-
maybeBindLinearElement(draggingElement, this.state,
|
|
5200
|
+
maybeBindLinearElement(draggingElement, this.state, pointerCoords, this);
|
|
5087
5201
|
}
|
|
5088
5202
|
this.setState({ suggestedBindings: [], startBoundElement: null });
|
|
5089
5203
|
if (!activeTool.locked) {
|
|
@@ -5357,10 +5471,23 @@ class App extends React.Component {
|
|
|
5357
5471
|
}));
|
|
5358
5472
|
}
|
|
5359
5473
|
}
|
|
5360
|
-
if (
|
|
5474
|
+
if (
|
|
5475
|
+
// not dragged
|
|
5476
|
+
!pointerDownState.drag.hasOccurred &&
|
|
5477
|
+
// not resized
|
|
5361
5478
|
!this.state.isResizing &&
|
|
5479
|
+
// only hitting the bounding box of the previous hit element
|
|
5362
5480
|
((hitElement &&
|
|
5363
|
-
|
|
5481
|
+
hitElementBoundingBoxOnly({
|
|
5482
|
+
x: pointerDownState.origin.x,
|
|
5483
|
+
y: pointerDownState.origin.y,
|
|
5484
|
+
element: hitElement,
|
|
5485
|
+
shape: this.getElementShape(hitElement),
|
|
5486
|
+
threshold: this.getHitThreshold(),
|
|
5487
|
+
frameNameBound: isFrameLikeElement(hitElement)
|
|
5488
|
+
? this.frameNameBoundsCache.get(hitElement)
|
|
5489
|
+
: null,
|
|
5490
|
+
}, elementsMap)) ||
|
|
5364
5491
|
(!hitElement &&
|
|
5365
5492
|
pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements))) {
|
|
5366
5493
|
if (this.state.editingLinearElement) {
|
|
@@ -5375,6 +5502,8 @@ class App extends React.Component {
|
|
|
5375
5502
|
activeEmbeddable: null,
|
|
5376
5503
|
});
|
|
5377
5504
|
}
|
|
5505
|
+
// reset cursor
|
|
5506
|
+
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
|
5378
5507
|
return;
|
|
5379
5508
|
}
|
|
5380
5509
|
if (!activeTool.locked &&
|
|
@@ -5397,8 +5526,8 @@ class App extends React.Component {
|
|
|
5397
5526
|
}
|
|
5398
5527
|
if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {
|
|
5399
5528
|
isBindingEnabled(this.state)
|
|
5400
|
-
? bindOrUnbindSelectedElements(this.scene.getSelectedElements(this.state), this
|
|
5401
|
-
: unbindLinearElements(this.scene.
|
|
5529
|
+
? bindOrUnbindSelectedElements(this.scene.getSelectedElements(this.state), this)
|
|
5530
|
+
: unbindLinearElements(this.scene.getNonDeletedElements(), elementsMap);
|
|
5402
5531
|
}
|
|
5403
5532
|
if (activeTool.type === "laser") {
|
|
5404
5533
|
this.laserTrails.endPath();
|
|
@@ -5552,7 +5681,7 @@ class App extends React.Component {
|
|
|
5552
5681
|
this.setState({ errorMessage: t("errors.imageToolNotSupported") });
|
|
5553
5682
|
return;
|
|
5554
5683
|
}
|
|
5555
|
-
this.scene.
|
|
5684
|
+
this.scene.insertElement(imageElement);
|
|
5556
5685
|
try {
|
|
5557
5686
|
return await this.initializeImage({
|
|
5558
5687
|
imageFile,
|
|
@@ -5741,7 +5870,7 @@ class App extends React.Component {
|
|
|
5741
5870
|
}
|
|
5742
5871
|
};
|
|
5743
5872
|
maybeSuggestBindingAtCursor = (pointerCoords) => {
|
|
5744
|
-
const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this
|
|
5873
|
+
const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this);
|
|
5745
5874
|
this.setState({
|
|
5746
5875
|
suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : [],
|
|
5747
5876
|
});
|
|
@@ -5756,7 +5885,7 @@ class App extends React.Component {
|
|
|
5756
5885
|
return;
|
|
5757
5886
|
}
|
|
5758
5887
|
const suggestedBindings = pointerCoords.reduce((acc, coords) => {
|
|
5759
|
-
const hoveredBindableElement = getHoveredElementForBinding(coords, this
|
|
5888
|
+
const hoveredBindableElement = getHoveredElementForBinding(coords, this);
|
|
5760
5889
|
if (hoveredBindableElement != null &&
|
|
5761
5890
|
!isLinearElementSimpleAndAlreadyBound(linearElement, oppositeBindingBoundElement?.id, hoveredBindableElement)) {
|
|
5762
5891
|
acc.push(hoveredBindableElement);
|
|
@@ -5769,7 +5898,7 @@ class App extends React.Component {
|
|
|
5769
5898
|
if (selectedElements.length > 50) {
|
|
5770
5899
|
return;
|
|
5771
5900
|
}
|
|
5772
|
-
const suggestedBindings = getEligibleElementsForBinding(selectedElements, this
|
|
5901
|
+
const suggestedBindings = getEligibleElementsForBinding(selectedElements, this);
|
|
5773
5902
|
this.setState({ suggestedBindings });
|
|
5774
5903
|
}
|
|
5775
5904
|
clearSelection(hitElement) {
|
|
@@ -6321,7 +6450,7 @@ export const createTestHook = () => {
|
|
|
6321
6450
|
return this.app?.scene.getElementsIncludingDeleted();
|
|
6322
6451
|
},
|
|
6323
6452
|
set(elements) {
|
|
6324
|
-
return this.app?.scene.replaceAllElements(elements);
|
|
6453
|
+
return this.app?.scene.replaceAllElements(syncInvalidIndices(elements));
|
|
6325
6454
|
},
|
|
6326
6455
|
},
|
|
6327
6456
|
});
|