confirm arrow on doubleclick (#949)

* confirm arrow on double click

* change hint

* fix cursor not updating on click
This commit is contained in:
David Luzar 2020-03-18 16:43:06 +01:00 committed by GitHub
parent 254a0753ff
commit b7da524538
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 95 additions and 16 deletions

View File

@ -18,12 +18,15 @@ 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") {
mutateElement(appState.multiElement, { const { points, lastCommittedPoint } = appState.multiElement;
points: appState.multiElement.points.slice( if (
0, !lastCommittedPoint ||
appState.multiElement.points.length - 1, points[points.length - 1] !== lastCommittedPoint
), ) {
}); mutateElement(appState.multiElement, {
points: appState.multiElement.points.slice(0, -1),
});
}
} }
if (isInvisiblySmallElement(appState.multiElement)) { if (isInvisiblySmallElement(appState.multiElement)) {
newElements = newElements.slice(0, -1); newElements = newElements.slice(0, -1);

View File

@ -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)

View File

@ -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;
mutateElement(multiElement, { const { points, lastCommittedPoint } = multiElement;
points: [...points.slice(0, -1), [x - originX, y - originY]], 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, {
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,

View File

@ -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,

View File

@ -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,
}; };
} }

View File

@ -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";

View File

@ -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": {