|
@@ -185,6 +185,7 @@ import type {
|
|
|
MagicGenerationData,
|
|
|
ExcalidrawNonSelectionElement,
|
|
|
ExcalidrawArrowElement,
|
|
|
+ NonDeletedSceneElementsMap,
|
|
|
} from "../element/types";
|
|
|
import { getCenter, getDistance } from "../gesture";
|
|
|
import {
|
|
@@ -259,6 +260,7 @@ import type {
|
|
|
ElementsPendingErasure,
|
|
|
GenerateDiagramToCode,
|
|
|
NullableGridSize,
|
|
|
+ Offsets,
|
|
|
} from "../types";
|
|
|
import {
|
|
|
debounce,
|
|
@@ -286,6 +288,7 @@ import {
|
|
|
getDateTime,
|
|
|
isShallowEqual,
|
|
|
arrayToMap,
|
|
|
+ toBrandedType,
|
|
|
} from "../utils";
|
|
|
import {
|
|
|
createSrcDoc,
|
|
@@ -434,14 +437,15 @@ import { actionTextAutoResize } from "../actions/actionTextAutoResize";
|
|
|
import { getVisibleSceneBounds } from "../element/bounds";
|
|
|
import { isMaybeMermaidDefinition } from "../mermaid";
|
|
|
import NewElementCanvas from "./canvases/NewElementCanvas";
|
|
|
-import { mutateElbowArrow } from "../element/routing";
|
|
|
+import { mutateElbowArrow, updateElbowArrow } from "../element/routing";
|
|
|
import {
|
|
|
FlowChartCreator,
|
|
|
FlowChartNavigator,
|
|
|
getLinkDirectionFromKey,
|
|
|
} from "../element/flowchart";
|
|
|
+import { searchItemInFocusAtom } from "./SearchMenu";
|
|
|
import type { LocalPoint, Radians } from "../../math";
|
|
|
-import { clamp, point, pointDistance, vector } from "../../math";
|
|
|
+import { clamp, pointFrom, pointDistance, vector } from "../../math";
|
|
|
import { cropElement } from "../element/cropElement";
|
|
|
|
|
|
const AppContext = React.createContext<AppClassProperties>(null!);
|
|
@@ -549,6 +553,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
public scene: Scene;
|
|
|
public fonts: Fonts;
|
|
|
public renderer: Renderer;
|
|
|
+ public visibleElements: readonly NonDeletedExcalidrawElement[];
|
|
|
private resizeObserver: ResizeObserver | undefined;
|
|
|
private nearestScrollableContainer: HTMLElement | Document | undefined;
|
|
|
public library: AppClassProperties["library"];
|
|
@@ -556,7 +561,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
public id: string;
|
|
|
private store: Store;
|
|
|
private history: History;
|
|
|
- private excalidrawContainerValue: {
|
|
|
+ public excalidrawContainerValue: {
|
|
|
container: HTMLDivElement | null;
|
|
|
id: string;
|
|
|
};
|
|
@@ -684,6 +689,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.canvas = document.createElement("canvas");
|
|
|
this.rc = rough.canvas(this.canvas);
|
|
|
this.renderer = new Renderer(this.scene);
|
|
|
+ this.visibleElements = [];
|
|
|
|
|
|
this.store = new Store();
|
|
|
this.history = new History();
|
|
@@ -1482,6 +1488,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
newElementId: this.state.newElement?.id,
|
|
|
pendingImageElementId: this.state.pendingImageElementId,
|
|
|
});
|
|
|
+ this.visibleElements = visibleElements;
|
|
|
|
|
|
const allElementsMap = this.scene.getNonDeletedElementsMap();
|
|
|
|
|
@@ -2297,6 +2304,9 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
storeAction: StoreAction.UPDATE,
|
|
|
});
|
|
|
|
|
|
+ // clear the shape and image cache so that any images in initialData
|
|
|
+ // can be loaded fresh
|
|
|
+ this.clearImageShapeCache();
|
|
|
// FontFaceSet loadingdone event we listen on may not always
|
|
|
// fire (looking at you Safari), so on init we manually load all
|
|
|
// fonts and rerender scene text elements once done. This also
|
|
@@ -2362,6 +2372,16 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
return false;
|
|
|
};
|
|
|
|
|
|
+ private clearImageShapeCache(filesMap?: BinaryFiles) {
|
|
|
+ const files = filesMap ?? this.files;
|
|
|
+ this.scene.getNonDeletedElements().forEach((element) => {
|
|
|
+ if (isInitializedImageElement(element) && files[element.fileId]) {
|
|
|
+ this.imageCache.delete(element.fileId);
|
|
|
+ ShapeCache.delete(element);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
public async componentDidMount() {
|
|
|
this.unmounted = false;
|
|
|
this.excalidrawContainerValue.container =
|
|
@@ -3093,7 +3113,45 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
retainSeed?: boolean;
|
|
|
fitToContent?: boolean;
|
|
|
}) => {
|
|
|
- const elements = restoreElements(opts.elements, null, undefined);
|
|
|
+ let elements = opts.elements.map((el, _, elements) => {
|
|
|
+ if (isElbowArrow(el)) {
|
|
|
+ const startEndElements = [
|
|
|
+ el.startBinding &&
|
|
|
+ elements.find((l) => l.id === el.startBinding?.elementId),
|
|
|
+ el.endBinding &&
|
|
|
+ elements.find((l) => l.id === el.endBinding?.elementId),
|
|
|
+ ];
|
|
|
+ const startBinding = startEndElements[0] ? el.startBinding : null;
|
|
|
+ const endBinding = startEndElements[1] ? el.endBinding : null;
|
|
|
+ return {
|
|
|
+ ...el,
|
|
|
+ ...updateElbowArrow(
|
|
|
+ {
|
|
|
+ ...el,
|
|
|
+ startBinding,
|
|
|
+ endBinding,
|
|
|
+ },
|
|
|
+ toBrandedType<NonDeletedSceneElementsMap>(
|
|
|
+ new Map(
|
|
|
+ startEndElements
|
|
|
+ .filter((x) => x != null)
|
|
|
+ .map(
|
|
|
+ (el) =>
|
|
|
+ [el!.id, el] as [
|
|
|
+ string,
|
|
|
+ Ordered<NonDeletedExcalidrawElement>,
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ [el.points[0], el.points[el.points.length - 1]],
|
|
|
+ ),
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ return el;
|
|
|
+ });
|
|
|
+ elements = restoreElements(elements, null, undefined);
|
|
|
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
|
|
|
|
|
|
const elementsCenterX = distance(minX, maxX) / 2;
|
|
@@ -3217,6 +3275,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
if (opts.fitToContent) {
|
|
|
this.scrollToContent(newElements, {
|
|
|
fitToContent: true,
|
|
|
+ canvasOffsets: this.getEditorUIOffsets(),
|
|
|
});
|
|
|
}
|
|
|
};
|
|
@@ -3529,7 +3588,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
target:
|
|
|
| ExcalidrawElement
|
|
|
| readonly ExcalidrawElement[] = this.scene.getNonDeletedElements(),
|
|
|
- opts?:
|
|
|
+ opts?: (
|
|
|
| {
|
|
|
fitToContent?: boolean;
|
|
|
fitToViewport?: never;
|
|
@@ -3546,7 +3605,12 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
viewportZoomFactor?: number;
|
|
|
animate?: boolean;
|
|
|
duration?: number;
|
|
|
- },
|
|
|
+ }
|
|
|
+ ) & {
|
|
|
+ minZoom?: number;
|
|
|
+ maxZoom?: number;
|
|
|
+ canvasOffsets?: Offsets;
|
|
|
+ },
|
|
|
) => {
|
|
|
this.cancelInProgressAnimation?.();
|
|
|
|
|
@@ -3559,10 +3623,13 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
if (opts?.fitToContent || opts?.fitToViewport) {
|
|
|
const { appState } = zoomToFit({
|
|
|
+ canvasOffsets: opts.canvasOffsets,
|
|
|
targetElements,
|
|
|
appState: this.state,
|
|
|
fitToViewport: !!opts?.fitToViewport,
|
|
|
viewportZoomFactor: opts?.viewportZoomFactor,
|
|
|
+ minZoom: opts?.minZoom,
|
|
|
+ maxZoom: opts?.maxZoom,
|
|
|
});
|
|
|
zoom = appState.zoom;
|
|
|
scrollX = appState.scrollX;
|
|
@@ -3676,15 +3743,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
|
|
|
this.files = { ...this.files, ...Object.fromEntries(filesMap) };
|
|
|
|
|
|
- this.scene.getNonDeletedElements().forEach((element) => {
|
|
|
- if (
|
|
|
- isInitializedImageElement(element) &&
|
|
|
- filesMap.has(element.fileId)
|
|
|
- ) {
|
|
|
- this.imageCache.delete(element.fileId);
|
|
|
- ShapeCache.delete(element);
|
|
|
- }
|
|
|
- });
|
|
|
+ this.clearImageShapeCache(Object.fromEntries(filesMap));
|
|
|
this.scene.triggerUpdate();
|
|
|
|
|
|
this.addNewImagesToImageCache();
|
|
@@ -3798,40 +3857,42 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
},
|
|
|
);
|
|
|
|
|
|
- private getEditorUIOffsets = (): {
|
|
|
- top: number;
|
|
|
- right: number;
|
|
|
- bottom: number;
|
|
|
- left: number;
|
|
|
- } => {
|
|
|
+ public getEditorUIOffsets = (): Offsets => {
|
|
|
const toolbarBottom =
|
|
|
this.excalidrawContainerRef?.current
|
|
|
?.querySelector(".App-toolbar")
|
|
|
?.getBoundingClientRect()?.bottom ?? 0;
|
|
|
- const sidebarWidth = Math.max(
|
|
|
- this.excalidrawContainerRef?.current
|
|
|
- ?.querySelector(".default-sidebar")
|
|
|
- ?.getBoundingClientRect()?.width ?? 0,
|
|
|
- );
|
|
|
- const propertiesPanelWidth = Math.max(
|
|
|
- this.excalidrawContainerRef?.current
|
|
|
- ?.querySelector(".App-menu__left")
|
|
|
- ?.getBoundingClientRect()?.width ?? 0,
|
|
|
- 0,
|
|
|
- );
|
|
|
+ const sidebarRect = this.excalidrawContainerRef?.current
|
|
|
+ ?.querySelector(".sidebar")
|
|
|
+ ?.getBoundingClientRect();
|
|
|
+ const propertiesPanelRect = this.excalidrawContainerRef?.current
|
|
|
+ ?.querySelector(".App-menu__left")
|
|
|
+ ?.getBoundingClientRect();
|
|
|
+
|
|
|
+ const PADDING = 16;
|
|
|
|
|
|
return getLanguage().rtl
|
|
|
? {
|
|
|
- top: toolbarBottom,
|
|
|
- right: propertiesPanelWidth,
|
|
|
- bottom: 0,
|
|
|
- left: sidebarWidth,
|
|
|
+ top: toolbarBottom + PADDING,
|
|
|
+ right:
|
|
|
+ Math.max(
|
|
|
+ this.state.width -
|
|
|
+ (propertiesPanelRect?.left ?? this.state.width),
|
|
|
+ 0,
|
|
|
+ ) + PADDING,
|
|
|
+ bottom: PADDING,
|
|
|
+ left: Math.max(sidebarRect?.right ?? 0, 0) + PADDING,
|
|
|
}
|
|
|
: {
|
|
|
- top: toolbarBottom,
|
|
|
- right: sidebarWidth,
|
|
|
- bottom: 0,
|
|
|
- left: propertiesPanelWidth,
|
|
|
+ top: toolbarBottom + PADDING,
|
|
|
+ right: Math.max(
|
|
|
+ this.state.width -
|
|
|
+ (sidebarRect?.left ?? this.state.width) +
|
|
|
+ PADDING,
|
|
|
+ 0,
|
|
|
+ ),
|
|
|
+ bottom: PADDING,
|
|
|
+ left: Math.max(propertiesPanelRect?.right ?? 0, 0) + PADDING,
|
|
|
};
|
|
|
};
|
|
|
|
|
@@ -3938,7 +3999,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
animate: true,
|
|
|
duration: 300,
|
|
|
fitToContent: true,
|
|
|
- viewportZoomFactor: 0.8,
|
|
|
+ canvasOffsets: this.getEditorUIOffsets(),
|
|
|
});
|
|
|
}
|
|
|
|
|
@@ -3994,6 +4055,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.scrollToContent(nextNode, {
|
|
|
animate: true,
|
|
|
duration: 300,
|
|
|
+ canvasOffsets: this.getEditorUIOffsets(),
|
|
|
});
|
|
|
}
|
|
|
}
|
|
@@ -4426,6 +4488,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.scrollToContent(firstNode, {
|
|
|
animate: true,
|
|
|
duration: 300,
|
|
|
+ canvasOffsets: this.getEditorUIOffsets(),
|
|
|
});
|
|
|
}
|
|
|
}
|
|
@@ -4871,7 +4934,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.getElementHitThreshold(),
|
|
|
);
|
|
|
|
|
|
- return isPointInShape(point(x, y), selectionShape);
|
|
|
+ return isPointInShape(pointFrom(x, y), selectionShape);
|
|
|
}
|
|
|
|
|
|
// take bound text element into consideration for hit collision as well
|
|
@@ -5247,7 +5310,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
element,
|
|
|
this.scene.getNonDeletedElementsMap(),
|
|
|
this.state,
|
|
|
- point(scenePointer.x, scenePointer.y),
|
|
|
+ pointFrom(scenePointer.x, scenePointer.y),
|
|
|
this.device.editor.isMobile,
|
|
|
)
|
|
|
);
|
|
@@ -5259,11 +5322,14 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
isTouchScreen: boolean,
|
|
|
) => {
|
|
|
const draggedDistance = pointDistance(
|
|
|
- point(
|
|
|
+ pointFrom(
|
|
|
this.lastPointerDownEvent!.clientX,
|
|
|
this.lastPointerDownEvent!.clientY,
|
|
|
),
|
|
|
- point(this.lastPointerUpEvent!.clientX, this.lastPointerUpEvent!.clientY),
|
|
|
+ pointFrom(
|
|
|
+ this.lastPointerUpEvent!.clientX,
|
|
|
+ this.lastPointerUpEvent!.clientY,
|
|
|
+ ),
|
|
|
);
|
|
|
if (
|
|
|
!this.hitLinkElement ||
|
|
@@ -5282,7 +5348,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.hitLinkElement,
|
|
|
elementsMap,
|
|
|
this.state,
|
|
|
- point(lastPointerDownCoords.x, lastPointerDownCoords.y),
|
|
|
+ pointFrom(lastPointerDownCoords.x, lastPointerDownCoords.y),
|
|
|
this.device.editor.isMobile,
|
|
|
);
|
|
|
const lastPointerUpCoords = viewportCoordsToSceneCoords(
|
|
@@ -5293,7 +5359,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.hitLinkElement,
|
|
|
elementsMap,
|
|
|
this.state,
|
|
|
- point(lastPointerUpCoords.x, lastPointerUpCoords.y),
|
|
|
+ pointFrom(lastPointerUpCoords.x, lastPointerUpCoords.y),
|
|
|
this.device.editor.isMobile,
|
|
|
);
|
|
|
if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {
|
|
@@ -5543,7 +5609,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
// threshold, add a point
|
|
|
if (
|
|
|
pointDistance(
|
|
|
- point(scenePointerX - rx, scenePointerY - ry),
|
|
|
+ pointFrom(scenePointerX - rx, scenePointerY - ry),
|
|
|
lastPoint,
|
|
|
) >= LINE_CONFIRM_THRESHOLD
|
|
|
) {
|
|
@@ -5552,7 +5618,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
{
|
|
|
points: [
|
|
|
...points,
|
|
|
- point<LocalPoint>(scenePointerX - rx, scenePointerY - ry),
|
|
|
+ pointFrom<LocalPoint>(scenePointerX - rx, scenePointerY - ry),
|
|
|
],
|
|
|
},
|
|
|
false,
|
|
@@ -5566,7 +5632,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
points.length > 2 &&
|
|
|
lastCommittedPoint &&
|
|
|
pointDistance(
|
|
|
- point(scenePointerX - rx, scenePointerY - ry),
|
|
|
+ pointFrom(scenePointerX - rx, scenePointerY - ry),
|
|
|
lastCommittedPoint,
|
|
|
) < LINE_CONFIRM_THRESHOLD
|
|
|
) {
|
|
@@ -5614,7 +5680,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.scene.getNonDeletedElementsMap(),
|
|
|
[
|
|
|
...points.slice(0, -1),
|
|
|
- point<LocalPoint>(
|
|
|
+ pointFrom<LocalPoint>(
|
|
|
lastCommittedX + dxFromLastCommitted,
|
|
|
lastCommittedY + dyFromLastCommitted,
|
|
|
),
|
|
@@ -5633,7 +5699,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
{
|
|
|
points: [
|
|
|
...points.slice(0, -1),
|
|
|
- point<LocalPoint>(
|
|
|
+ pointFrom<LocalPoint>(
|
|
|
lastCommittedX + dxFromLastCommitted,
|
|
|
lastCommittedY + dyFromLastCommitted,
|
|
|
),
|
|
@@ -5862,8 +5928,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
};
|
|
|
|
|
|
const distance = pointDistance(
|
|
|
- point(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y),
|
|
|
- point(scenePointer.x, scenePointer.y),
|
|
|
+ pointFrom(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y),
|
|
|
+ pointFrom(scenePointer.x, scenePointer.y),
|
|
|
);
|
|
|
const threshold = this.getElementHitThreshold();
|
|
|
const p = { ...pointerDownState.lastCoords };
|
|
@@ -6010,6 +6076,16 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.maybeCleanupAfterMissingPointerUp(event.nativeEvent);
|
|
|
this.maybeUnfollowRemoteUser();
|
|
|
|
|
|
+ if (this.state.searchMatches) {
|
|
|
+ this.setState((state) => ({
|
|
|
+ searchMatches: state.searchMatches.map((searchMatch) => ({
|
|
|
+ ...searchMatch,
|
|
|
+ focus: false,
|
|
|
+ })),
|
|
|
+ }));
|
|
|
+ jotaiStore.set(searchItemInFocusAtom, null);
|
|
|
+ }
|
|
|
+
|
|
|
// since contextMenu options are potentially evaluated on each render,
|
|
|
// and an contextMenu action may depend on selection state, we must
|
|
|
// close the contextMenu before we update the selection on pointerDown
|
|
@@ -6365,7 +6441,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.hitLinkElement,
|
|
|
this.scene.getNonDeletedElementsMap(),
|
|
|
this.state,
|
|
|
- point(scenePointer.x, scenePointer.y),
|
|
|
+ pointFrom(scenePointer.x, scenePointer.y),
|
|
|
)
|
|
|
) {
|
|
|
this.handleEmbeddableCenterClick(this.hitLinkElement);
|
|
@@ -6438,8 +6514,16 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
}
|
|
|
isPanning = true;
|
|
|
|
|
|
+ // due to event.preventDefault below, container wouldn't get focus
|
|
|
+ // automatically
|
|
|
+ this.focusContainer();
|
|
|
+
|
|
|
+ // preventing defualt while text editing messes with cursor/focus
|
|
|
if (!this.state.editingTextElement) {
|
|
|
- // preventing defualt while text editing messes with cursor/focus
|
|
|
+ // necessary to prevent browser from scrolling the page if excalidraw
|
|
|
+ // not full-page #4489
|
|
|
+ //
|
|
|
+ // as such, the above is broken when panning canvas while in wysiwyg
|
|
|
event.preventDefault();
|
|
|
}
|
|
|
|
|
@@ -7068,7 +7152,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
simulatePressure,
|
|
|
locked: false,
|
|
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
|
|
- points: [point<LocalPoint>(0, 0)],
|
|
|
+ points: [pointFrom<LocalPoint>(0, 0)],
|
|
|
pressures: simulatePressure ? [] : [event.pressure],
|
|
|
});
|
|
|
|
|
@@ -7277,7 +7361,10 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
multiElement.points.length > 1 &&
|
|
|
lastCommittedPoint &&
|
|
|
pointDistance(
|
|
|
- point(pointerDownState.origin.x - rx, pointerDownState.origin.y - ry),
|
|
|
+ pointFrom(
|
|
|
+ pointerDownState.origin.x - rx,
|
|
|
+ pointerDownState.origin.y - ry,
|
|
|
+ ),
|
|
|
lastCommittedPoint,
|
|
|
) < LINE_CONFIRM_THRESHOLD
|
|
|
) {
|
|
@@ -7379,7 +7466,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
};
|
|
|
});
|
|
|
mutateElement(element, {
|
|
|
- points: [...element.points, point<LocalPoint>(0, 0)],
|
|
|
+ points: [...element.points, pointFrom<LocalPoint>(0, 0)],
|
|
|
});
|
|
|
const boundElement = getHoveredElementForBinding(
|
|
|
pointerDownState.origin,
|
|
@@ -7635,8 +7722,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
) {
|
|
|
if (
|
|
|
pointDistance(
|
|
|
- point(pointerCoords.x, pointerCoords.y),
|
|
|
- point(pointerDownState.origin.x, pointerDownState.origin.y),
|
|
|
+ pointFrom(pointerCoords.x, pointerCoords.y),
|
|
|
+ pointFrom(pointerDownState.origin.x, pointerDownState.origin.y),
|
|
|
) < DRAGGING_THRESHOLD
|
|
|
) {
|
|
|
return;
|
|
@@ -8031,7 +8118,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
mutateElement(
|
|
|
newElement,
|
|
|
{
|
|
|
- points: [...points, point<LocalPoint>(dx, dy)],
|
|
|
+ points: [...points, pointFrom<LocalPoint>(dx, dy)],
|
|
|
pressures,
|
|
|
},
|
|
|
false,
|
|
@@ -8060,7 +8147,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
mutateElement(
|
|
|
newElement,
|
|
|
{
|
|
|
- points: [...points, point<LocalPoint>(dx, dy)],
|
|
|
+ points: [...points, pointFrom<LocalPoint>(dx, dy)],
|
|
|
},
|
|
|
false,
|
|
|
);
|
|
@@ -8068,7 +8155,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
mutateElbowArrow(
|
|
|
newElement,
|
|
|
elementsMap,
|
|
|
- [...points.slice(0, -1), point<LocalPoint>(dx, dy)],
|
|
|
+ [...points.slice(0, -1), pointFrom<LocalPoint>(dx, dy)],
|
|
|
vector(0, 0),
|
|
|
undefined,
|
|
|
{
|
|
@@ -8080,7 +8167,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
mutateElement(
|
|
|
newElement,
|
|
|
{
|
|
|
- points: [...points.slice(0, -1), point<LocalPoint>(dx, dy)],
|
|
|
+ points: [...points.slice(0, -1), pointFrom<LocalPoint>(dx, dy)],
|
|
|
},
|
|
|
false,
|
|
|
);
|
|
@@ -8394,9 +8481,9 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
: [...newElement.pressures, childEvent.pressure];
|
|
|
|
|
|
mutateElement(newElement, {
|
|
|
- points: [...points, point<LocalPoint>(dx, dy)],
|
|
|
+ points: [...points, pointFrom<LocalPoint>(dx, dy)],
|
|
|
pressures,
|
|
|
- lastCommittedPoint: point<LocalPoint>(dx, dy),
|
|
|
+ lastCommittedPoint: pointFrom<LocalPoint>(dx, dy),
|
|
|
});
|
|
|
|
|
|
this.actionManager.executeAction(actionFinalize);
|
|
@@ -8443,7 +8530,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
mutateElement(newElement, {
|
|
|
points: [
|
|
|
...newElement.points,
|
|
|
- point<LocalPoint>(
|
|
|
+ pointFrom<LocalPoint>(
|
|
|
pointerCoords.x - newElement.x,
|
|
|
pointerCoords.y - newElement.y,
|
|
|
),
|
|
@@ -8771,8 +8858,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
|
this.eraserTrail.endPath();
|
|
|
|
|
|
const draggedDistance = pointDistance(
|
|
|
- point(pointerStart.clientX, pointerStart.clientY),
|
|
|
- point(pointerEnd.clientX, pointerEnd.clientY),
|
|
|
+ pointFrom(pointerStart.clientX, pointerStart.clientY),
|
|
|
+ pointFrom(pointerEnd.clientX, pointerEnd.clientY),
|
|
|
);
|
|
|
|
|
|
if (draggedDistance === 0) {
|