confirm arrow on doubleclick (#949)
* confirm arrow on double click * change hint * fix cursor not updating on click
This commit is contained in:
parent
254a0753ff
commit
b7da524538
@ -18,13 +18,16 @@ export const actionFinalize = register({
|
|||||||
if (appState.multiElement) {
|
if (appState.multiElement) {
|
||||||
// pen and mouse have hover
|
// pen and mouse have hover
|
||||||
if (appState.lastPointerDownWith !== "touch") {
|
if (appState.lastPointerDownWith !== "touch") {
|
||||||
|
const { points, lastCommittedPoint } = appState.multiElement;
|
||||||
|
if (
|
||||||
|
!lastCommittedPoint ||
|
||||||
|
points[points.length - 1] !== lastCommittedPoint
|
||||||
|
) {
|
||||||
mutateElement(appState.multiElement, {
|
mutateElement(appState.multiElement, {
|
||||||
points: appState.multiElement.points.slice(
|
points: appState.multiElement.points.slice(0, -1),
|
||||||
0,
|
|
||||||
appState.multiElement.points.length - 1,
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (isInvisiblySmallElement(appState.multiElement)) {
|
if (isInvisiblySmallElement(appState.multiElement)) {
|
||||||
newElements = newElements.slice(0, -1);
|
newElements = newElements.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,16 @@ export class ActionManager implements ActionsManagerInterface {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
executeAction(action: Action) {
|
||||||
|
const commitToHistory =
|
||||||
|
action.commitToHistory &&
|
||||||
|
action.commitToHistory(this.getAppState(), this.getElements());
|
||||||
|
this.updater(
|
||||||
|
action.perform(this.getElements(), this.getAppState(), null),
|
||||||
|
commitToHistory,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getContextMenuItems(actionFilter: ActionFilterFn = action => action) {
|
getContextMenuItems(actionFilter: ActionFilterFn = action => action) {
|
||||||
return Object.values(this.actions)
|
return Object.values(this.actions)
|
||||||
.filter(actionFilter)
|
.filter(actionFilter)
|
||||||
|
@ -92,6 +92,7 @@ import {
|
|||||||
POINTER_BUTTON,
|
POINTER_BUTTON,
|
||||||
DRAGGING_THRESHOLD,
|
DRAGGING_THRESHOLD,
|
||||||
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
TEXT_TO_CENTER_SNAP_THRESHOLD,
|
||||||
|
ARROW_CONFIRM_THRESHOLD,
|
||||||
} from "../constants";
|
} from "../constants";
|
||||||
import { LayerUI } from "./LayerUI";
|
import { LayerUI } from "./LayerUI";
|
||||||
import { ScrollBars } from "../scene/types";
|
import { ScrollBars } from "../scene/types";
|
||||||
@ -102,6 +103,7 @@ import { unstable_batchedUpdates } from "react-dom";
|
|||||||
import { SceneStateCallbackRemover } from "../scene/globalScene";
|
import { SceneStateCallbackRemover } from "../scene/globalScene";
|
||||||
import { isLinearElement } from "../element/typeChecks";
|
import { isLinearElement } from "../element/typeChecks";
|
||||||
import { rescalePoints } from "../points";
|
import { rescalePoints } from "../points";
|
||||||
|
import { actionFinalize } from "../actions";
|
||||||
|
|
||||||
function withBatchedUpdates<
|
function withBatchedUpdates<
|
||||||
TFunction extends ((event: any) => void) | (() => void)
|
TFunction extends ((event: any) => void) | (() => void)
|
||||||
@ -1122,13 +1124,52 @@ export class App extends React.Component<any, AppState> {
|
|||||||
);
|
);
|
||||||
if (this.state.multiElement) {
|
if (this.state.multiElement) {
|
||||||
const { multiElement } = this.state;
|
const { multiElement } = this.state;
|
||||||
const originX = multiElement.x;
|
const { x: rx, y: ry } = multiElement;
|
||||||
const originY = multiElement.y;
|
|
||||||
const points = multiElement.points;
|
|
||||||
|
|
||||||
|
const { points, lastCommittedPoint } = multiElement;
|
||||||
|
const lastPoint = points[points.length - 1];
|
||||||
|
|
||||||
|
setCursorForShape(this.state.elementType);
|
||||||
|
|
||||||
|
if (lastPoint === lastCommittedPoint) {
|
||||||
|
// if we haven't yet created a temp point and we're beyond commit-zone
|
||||||
|
// threshold, add a point
|
||||||
|
if (
|
||||||
|
distance2d(x - rx, y - ry, lastPoint[0], lastPoint[1]) >=
|
||||||
|
ARROW_CONFIRM_THRESHOLD
|
||||||
|
) {
|
||||||
mutateElement(multiElement, {
|
mutateElement(multiElement, {
|
||||||
points: [...points.slice(0, -1), [x - originX, y - originY]],
|
points: [...points, [x - rx, y - ry]],
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||||
|
// in this branch, we're inside the commit zone, and no uncommitted
|
||||||
|
// point exists. Thus do nothing (don't add/remove points).
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// cursor moved inside commit zone, and there's uncommitted point,
|
||||||
|
// thus remove it
|
||||||
|
if (
|
||||||
|
points.length > 2 &&
|
||||||
|
lastCommittedPoint &&
|
||||||
|
distance2d(
|
||||||
|
x - rx,
|
||||||
|
y - ry,
|
||||||
|
lastCommittedPoint[0],
|
||||||
|
lastCommittedPoint[1],
|
||||||
|
) < ARROW_CONFIRM_THRESHOLD
|
||||||
|
) {
|
||||||
|
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||||
|
mutateElement(multiElement, {
|
||||||
|
points: points.slice(0, -1),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// update last uncommitted point
|
||||||
|
mutateElement(multiElement, {
|
||||||
|
points: [...points.slice(0, -1), [x - rx, y - ry]],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1505,16 +1546,36 @@ export class App extends React.Component<any, AppState> {
|
|||||||
) {
|
) {
|
||||||
if (this.state.multiElement) {
|
if (this.state.multiElement) {
|
||||||
const { multiElement } = this.state;
|
const { multiElement } = this.state;
|
||||||
const { x: rx, y: ry } = multiElement;
|
|
||||||
|
const { x: rx, y: ry, lastCommittedPoint } = multiElement;
|
||||||
|
|
||||||
|
// clicking inside commit zone → finalize arrow
|
||||||
|
if (
|
||||||
|
multiElement.points.length > 1 &&
|
||||||
|
lastCommittedPoint &&
|
||||||
|
distance2d(
|
||||||
|
x - rx,
|
||||||
|
y - ry,
|
||||||
|
lastCommittedPoint[0],
|
||||||
|
lastCommittedPoint[1],
|
||||||
|
) < ARROW_CONFIRM_THRESHOLD
|
||||||
|
) {
|
||||||
|
this.actionManager.executeAction(actionFinalize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.setState(prevState => ({
|
this.setState(prevState => ({
|
||||||
selectedElementIds: {
|
selectedElementIds: {
|
||||||
...prevState.selectedElementIds,
|
...prevState.selectedElementIds,
|
||||||
[multiElement.id]: true,
|
[multiElement.id]: true,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
// clicking outside commit zone → update reference for last committed
|
||||||
|
// point
|
||||||
mutateElement(multiElement, {
|
mutateElement(multiElement, {
|
||||||
points: [...multiElement.points, [x - rx, y - ry]],
|
lastCommittedPoint:
|
||||||
|
multiElement.points[multiElement.points.length - 1],
|
||||||
});
|
});
|
||||||
|
document.documentElement.style.cursor = CURSOR_TYPE.POINTER;
|
||||||
} else {
|
} else {
|
||||||
const element = newLinearElement({
|
const element = newLinearElement({
|
||||||
type: this.state.elementType,
|
type: this.state.elementType,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export const DRAGGING_THRESHOLD = 10; // 10px
|
export const DRAGGING_THRESHOLD = 10; // 10px
|
||||||
|
export const ARROW_CONFIRM_THRESHOLD = 10; // 10px
|
||||||
export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5;
|
export const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5;
|
||||||
export const ELEMENT_TRANSLATE_AMOUNT = 1;
|
export const ELEMENT_TRANSLATE_AMOUNT = 1;
|
||||||
export const TEXT_TO_CENTER_SNAP_THRESHOLD = 30;
|
export const TEXT_TO_CENTER_SNAP_THRESHOLD = 30;
|
||||||
@ -6,6 +7,7 @@ export const CURSOR_TYPE = {
|
|||||||
TEXT: "text",
|
TEXT: "text",
|
||||||
CROSSHAIR: "crosshair",
|
CROSSHAIR: "crosshair",
|
||||||
GRABBING: "grabbing",
|
GRABBING: "grabbing",
|
||||||
|
POINTER: "pointer",
|
||||||
};
|
};
|
||||||
export const POINTER_BUTTON = {
|
export const POINTER_BUTTON = {
|
||||||
MAIN: 0,
|
MAIN: 0,
|
||||||
|
@ -91,12 +91,14 @@ export function newTextElement(
|
|||||||
|
|
||||||
export function newLinearElement(
|
export function newLinearElement(
|
||||||
opts: {
|
opts: {
|
||||||
type: "arrow" | "line";
|
type: ExcalidrawLinearElement["type"];
|
||||||
|
lastCommittedPoint?: ExcalidrawLinearElement["lastCommittedPoint"];
|
||||||
} & ElementConstructorOpts,
|
} & ElementConstructorOpts,
|
||||||
): ExcalidrawLinearElement {
|
): ExcalidrawLinearElement {
|
||||||
return {
|
return {
|
||||||
..._newElementBase<ExcalidrawLinearElement>(opts.type, opts),
|
..._newElementBase<ExcalidrawLinearElement>(opts.type, opts),
|
||||||
points: [],
|
points: [],
|
||||||
|
lastCommittedPoint: opts.lastCommittedPoint || null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ export type ExcalidrawLinearElement = _ExcalidrawElementBase &
|
|||||||
Readonly<{
|
Readonly<{
|
||||||
type: "arrow" | "line";
|
type: "arrow" | "line";
|
||||||
points: Point[];
|
points: Point[];
|
||||||
|
lastCommittedPoint?: Point | null;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type PointerType = "mouse" | "pen" | "touch";
|
export type PointerType = "mouse" | "pen" | "touch";
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
},
|
},
|
||||||
"hints": {
|
"hints": {
|
||||||
"linearElement": "Click to start multiple points, drag for single line",
|
"linearElement": "Click to start multiple points, drag for single line",
|
||||||
"linearElementMulti": "Press Escape or Enter to finish",
|
"linearElementMulti": "Click on last point or press Escape or Enter to finish",
|
||||||
"resize": "You can constraint proportions by holding SHIFT while resizing"
|
"resize": "You can constraint proportions by holding SHIFT while resizing"
|
||||||
},
|
},
|
||||||
"errorSplash": {
|
"errorSplash": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user