|
@@ -54,13 +54,14 @@ import { renderScene } from "../renderer";
|
|
import { AppState, GestureEvent, Gesture } from "../types";
|
|
import { AppState, GestureEvent, Gesture } from "../types";
|
|
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
|
|
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
|
|
|
|
|
|
|
|
+import { distance2d, isPathALoop } from "../math";
|
|
|
|
+
|
|
import {
|
|
import {
|
|
isWritableElement,
|
|
isWritableElement,
|
|
isInputLike,
|
|
isInputLike,
|
|
isToolIcon,
|
|
isToolIcon,
|
|
debounce,
|
|
debounce,
|
|
distance,
|
|
distance,
|
|
- distance2d,
|
|
|
|
resetCursor,
|
|
resetCursor,
|
|
viewportCoordsToSceneCoords,
|
|
viewportCoordsToSceneCoords,
|
|
sceneCoordsToViewportCoords,
|
|
sceneCoordsToViewportCoords,
|
|
@@ -97,7 +98,7 @@ import {
|
|
POINTER_BUTTON,
|
|
POINTER_BUTTON,
|
|
DRAGGING_THRESHOLD,
|
|
DRAGGING_THRESHOLD,
|
|
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
|
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
|
- ARROW_CONFIRM_THRESHOLD,
|
|
|
|
|
|
+ LINE_CONFIRM_THRESHOLD,
|
|
} from "../constants";
|
|
} from "../constants";
|
|
import { LayerUI } from "./LayerUI";
|
|
import { LayerUI } from "./LayerUI";
|
|
import { ScrollBars, SceneState } from "../scene/types";
|
|
import { ScrollBars, SceneState } from "../scene/types";
|
|
@@ -1456,7 +1457,7 @@ export class App extends React.Component<any, AppState> {
|
|
// threshold, add a point
|
|
// threshold, add a point
|
|
if (
|
|
if (
|
|
distance2d(x - rx, y - ry, lastPoint[0], lastPoint[1]) >=
|
|
distance2d(x - rx, y - ry, lastPoint[0], lastPoint[1]) >=
|
|
- ARROW_CONFIRM_THRESHOLD
|
|
|
|
|
|
+ LINE_CONFIRM_THRESHOLD
|
|
) {
|
|
) {
|
|
mutateElement(multiElement, {
|
|
mutateElement(multiElement, {
|
|
points: [...points, [x - rx, y - ry]],
|
|
points: [...points, [x - rx, y - ry]],
|
|
@@ -1477,13 +1478,16 @@ export class App extends React.Component<any, AppState> {
|
|
y - ry,
|
|
y - ry,
|
|
lastCommittedPoint[0],
|
|
lastCommittedPoint[0],
|
|
lastCommittedPoint[1],
|
|
lastCommittedPoint[1],
|
|
- ) < ARROW_CONFIRM_THRESHOLD
|
|
|
|
|
|
+ ) < LINE_CONFIRM_THRESHOLD
|
|
) {
|
|
) {
|
|
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
|
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
|
mutateElement(multiElement, {
|
|
mutateElement(multiElement, {
|
|
points: points.slice(0, -1),
|
|
points: points.slice(0, -1),
|
|
});
|
|
});
|
|
} else {
|
|
} else {
|
|
|
|
+ if (isPathALoop(points)) {
|
|
|
|
+ document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
|
|
|
+ }
|
|
// update last uncommitted point
|
|
// update last uncommitted point
|
|
mutateElement(multiElement, {
|
|
mutateElement(multiElement, {
|
|
points: [...points.slice(0, -1), [x - rx, y - ry]],
|
|
points: [...points.slice(0, -1), [x - rx, y - ry]],
|
|
@@ -1875,6 +1879,16 @@ export class App extends React.Component<any, AppState> {
|
|
if (this.state.multiElement) {
|
|
if (this.state.multiElement) {
|
|
const { multiElement } = this.state;
|
|
const { multiElement } = this.state;
|
|
|
|
|
|
|
|
+ // finalize if completing a loop
|
|
|
|
+ if (multiElement.type === "line" && isPathALoop(multiElement.points)) {
|
|
|
|
+ mutateElement(multiElement, {
|
|
|
|
+ lastCommittedPoint:
|
|
|
|
+ multiElement.points[multiElement.points.length - 1],
|
|
|
|
+ });
|
|
|
|
+ this.actionManager.executeAction(actionFinalize);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
const { x: rx, y: ry, lastCommittedPoint } = multiElement;
|
|
const { x: rx, y: ry, lastCommittedPoint } = multiElement;
|
|
|
|
|
|
// clicking inside commit zone → finalize arrow
|
|
// clicking inside commit zone → finalize arrow
|
|
@@ -1886,11 +1900,12 @@ export class App extends React.Component<any, AppState> {
|
|
y - ry,
|
|
y - ry,
|
|
lastCommittedPoint[0],
|
|
lastCommittedPoint[0],
|
|
lastCommittedPoint[1],
|
|
lastCommittedPoint[1],
|
|
- ) < ARROW_CONFIRM_THRESHOLD
|
|
|
|
|
|
+ ) < LINE_CONFIRM_THRESHOLD
|
|
) {
|
|
) {
|
|
this.actionManager.executeAction(actionFinalize);
|
|
this.actionManager.executeAction(actionFinalize);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
+
|
|
this.setState((prevState) => ({
|
|
this.setState((prevState) => ({
|
|
selectedElementIds: {
|
|
selectedElementIds: {
|
|
...prevState.selectedElementIds,
|
|
...prevState.selectedElementIds,
|