feat: grid mode for line editing (#1984)

This commit is contained in:
Daishi Kato 2020-07-31 00:09:51 +09:00 committed by GitHub
parent c171fb4c7f
commit 818821c293
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 27 deletions

View File

@ -1883,6 +1883,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
scenePointerX, scenePointerX,
scenePointerY, scenePointerY,
this.state.editingLinearElement, this.state.editingLinearElement,
this.state.gridSize,
); );
if (editingLinearElement !== this.state.editingLinearElement) { if (editingLinearElement !== this.state.editingLinearElement) {
this.setState({ editingLinearElement }); this.setState({ editingLinearElement });
@ -2778,8 +2779,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
(appState) => this.setState(appState), (appState) => this.setState(appState),
x, x,
y, y,
pointerDownState.lastCoords.x,
pointerDownState.lastCoords.y,
); );
if (didDrag) { if (didDrag) {

View File

@ -3,7 +3,7 @@ import {
ExcalidrawLinearElement, ExcalidrawLinearElement,
ExcalidrawElement, ExcalidrawElement,
} from "./types"; } from "./types";
import { distance2d, rotate, isPathALoop } from "../math"; import { distance2d, rotate, isPathALoop, getGridPoint } from "../math";
import { getElementAbsoluteCoords } from "."; import { getElementAbsoluteCoords } from ".";
import { getElementPointsCoords } from "./bounds"; import { getElementPointsCoords } from "./bounds";
import { Point, AppState } from "../types"; import { Point, AppState } from "../types";
@ -20,6 +20,7 @@ export class LinearElementEditor {
/** whether you're dragging a point */ /** whether you're dragging a point */
public isDragging: boolean; public isDragging: boolean;
public lastUncommittedPoint: Point | null; public lastUncommittedPoint: Point | null;
public pointerOffset: { x: number; y: number };
constructor(element: NonDeleted<ExcalidrawLinearElement>, scene: Scene) { constructor(element: NonDeleted<ExcalidrawLinearElement>, scene: Scene) {
this.elementId = element.id as string & { this.elementId = element.id as string & {
@ -31,6 +32,7 @@ export class LinearElementEditor {
this.activePointIndex = null; this.activePointIndex = null;
this.lastUncommittedPoint = null; this.lastUncommittedPoint = null;
this.isDragging = false; this.isDragging = false;
this.pointerOffset = { x: 0, y: 0 };
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -57,8 +59,6 @@ export class LinearElementEditor {
setState: React.Component<any, AppState>["setState"], setState: React.Component<any, AppState>["setState"],
scenePointerX: number, scenePointerX: number,
scenePointerY: number, scenePointerY: number,
lastX: number,
lastY: number,
): boolean { ): boolean {
if (!appState.editingLinearElement) { if (!appState.editingLinearElement) {
return false; return false;
@ -80,18 +80,14 @@ export class LinearElementEditor {
}, },
}); });
} }
const [deltaX, deltaY] = rotate(
scenePointerX - lastX, const newPoint = LinearElementEditor.createPointAt(
scenePointerY - lastY, element,
0, scenePointerX - editingLinearElement.pointerOffset.x,
0, scenePointerY - editingLinearElement.pointerOffset.y,
-element.angle, appState.gridSize,
); );
const targetPoint = element.points[activePointIndex]; LinearElementEditor.movePoint(element, activePointIndex, newPoint);
LinearElementEditor.movePoint(element, activePointIndex, [
targetPoint[0] + deltaX,
targetPoint[1] + deltaY,
]);
return true; return true;
} }
return false; return false;
@ -120,14 +116,12 @@ export class LinearElementEditor {
: element.points[0], : element.points[0],
); );
} }
if (isDragging) {
return { return {
...editingLinearElement, ...editingLinearElement,
isDragging: false, isDragging: false,
pointerOffset: { x: 0, y: 0 },
}; };
} }
return editingLinearElement;
}
static handlePointerDown( static handlePointerDown(
event: React.PointerEvent<HTMLCanvasElement>, event: React.PointerEvent<HTMLCanvasElement>,
@ -165,6 +159,7 @@ export class LinearElementEditor {
element, element,
scenePointerX, scenePointerX,
scenePointerY, scenePointerY,
appState.gridSize,
), ),
], ],
}); });
@ -194,10 +189,29 @@ export class LinearElementEditor {
ret.hitElement = element; ret.hitElement = element;
} }
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const cx = (x1 + x2) / 2;
const cy = (y1 + y2) / 2;
const targetPoint =
clickedPointIndex > -1 &&
rotate(
element.x + element.points[clickedPointIndex][0],
element.y + element.points[clickedPointIndex][1],
cx,
cy,
element.angle,
);
setState({ setState({
editingLinearElement: { editingLinearElement: {
...appState.editingLinearElement, ...appState.editingLinearElement,
activePointIndex: clickedPointIndex > -1 ? clickedPointIndex : null, activePointIndex: clickedPointIndex > -1 ? clickedPointIndex : null,
pointerOffset: targetPoint
? {
x: scenePointerX - targetPoint[0],
y: scenePointerY - targetPoint[1],
}
: { x: 0, y: 0 },
}, },
}); });
return ret; return ret;
@ -208,6 +222,7 @@ export class LinearElementEditor {
scenePointerX: number, scenePointerX: number,
scenePointerY: number, scenePointerY: number,
editingLinearElement: LinearElementEditor, editingLinearElement: LinearElementEditor,
gridSize: number | null,
): LinearElementEditor { ): LinearElementEditor {
const { elementId, lastUncommittedPoint } = editingLinearElement; const { elementId, lastUncommittedPoint } = editingLinearElement;
const element = LinearElementEditor.getElement(elementId); const element = LinearElementEditor.getElement(elementId);
@ -227,8 +242,9 @@ export class LinearElementEditor {
const newPoint = LinearElementEditor.createPointAt( const newPoint = LinearElementEditor.createPointAt(
element, element,
scenePointerX, scenePointerX - editingLinearElement.pointerOffset.x,
scenePointerY, scenePointerY - editingLinearElement.pointerOffset.y,
gridSize,
); );
if (lastPoint === lastUncommittedPoint) { if (lastPoint === lastUncommittedPoint) {
@ -288,13 +304,15 @@ export class LinearElementEditor {
element: NonDeleted<ExcalidrawLinearElement>, element: NonDeleted<ExcalidrawLinearElement>,
scenePointerX: number, scenePointerX: number,
scenePointerY: number, scenePointerY: number,
gridSize: number | null,
): Point { ): Point {
const pointerOnGrid = getGridPoint(scenePointerX, scenePointerY, gridSize);
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element); const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const cx = (x1 + x2) / 2; const cx = (x1 + x2) / 2;
const cy = (y1 + y2) / 2; const cy = (y1 + y2) / 2;
const [rotatedX, rotatedY] = rotate( const [rotatedX, rotatedY] = rotate(
scenePointerX, pointerOnGrid[0],
scenePointerY, pointerOnGrid[1],
cx, cx,
cy, cy,
-element.angle, -element.angle,