Implement line editing (#1616)

* implement line editing

* line editing with rotation

* ensure adding new points is disabled on point dragging

* fix hotkey replacement

* don't paint bounding box when creating new multipoint

* tweak points style, account for zoom and z-index

* don't persist editingLinearElement to localStorage

* don't mutate on noop points updates

* account for rotation when adding new point

* ensure clicking on points doesn't deselect element

* tweak history handling around editingline element

* update snapshots

* refactor pointerMove handling

* factor out point dragging

* factor out pointerDown

* improve positioning with rotation

* revert to use roughjs for calculating points bounds

* migrate from storing editingLinearElement.element to id

* make GlobalScene.getElement into O(1)

* use Alt for adding new points

* fix adding and deleting a point with rotation

* disable resize handlers & bounding box on line edit

Co-authored-by: daishi <daishi@axlight.com>
This commit is contained in:
David Luzar
2020-06-01 11:35:44 +02:00
committed by GitHub
parent db316f32e0
commit 14a66956d7
19 changed files with 1129 additions and 76 deletions

View File

@ -6,6 +6,8 @@ import { FlooredNumber, AppState } from "../types";
import {
ExcalidrawElement,
NonDeletedExcalidrawElement,
ExcalidrawLinearElement,
NonDeleted,
GroupId,
} from "../element/types";
import {
@ -28,6 +30,8 @@ import { getSelectedElements } from "../scene/selection";
import { renderElement, renderElementToSvg } from "./renderElement";
import colors from "../colors";
import { isLinearElement } from "../element/typeChecks";
import { LinearElementEditor } from "../element/linearElementEditor";
import {
isSelectedViaGroup,
getSelectedGroupIds,
@ -83,6 +87,41 @@ const strokeCircle = (
context.stroke();
};
const renderLinearPointHandles = (
context: CanvasRenderingContext2D,
appState: AppState,
sceneState: SceneState,
element: NonDeleted<ExcalidrawLinearElement>,
) => {
context.translate(sceneState.scrollX, sceneState.scrollY);
const origStrokeStyle = context.strokeStyle;
const lineWidth = context.lineWidth;
context.lineWidth = 1 / sceneState.zoom;
LinearElementEditor.getPointsGlobalCoordinates(element).forEach(
(point, idx) => {
context.strokeStyle = "red";
context.setLineDash([]);
context.fillStyle =
appState.editingLinearElement?.activePointIndex === idx
? "rgba(255, 127, 127, 0.9)"
: "rgba(255, 255, 255, 0.9)";
const { POINT_HANDLE_SIZE } = LinearElementEditor;
strokeCircle(
context,
point[0] - POINT_HANDLE_SIZE / 2 / sceneState.zoom,
point[1] - POINT_HANDLE_SIZE / 2 / sceneState.zoom,
POINT_HANDLE_SIZE / sceneState.zoom,
POINT_HANDLE_SIZE / sceneState.zoom,
);
},
);
context.setLineDash([]);
context.lineWidth = lineWidth;
context.translate(-sceneState.scrollX, -sceneState.scrollY);
context.strokeStyle = origStrokeStyle;
};
export const renderScene = (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
@ -153,9 +192,16 @@ export const renderScene = (
visibleElements.forEach((element) => {
renderElement(element, rc, context, renderOptimizations, sceneState);
if (
isLinearElement(element) &&
appState.editingLinearElement &&
appState.editingLinearElement.elementId === element.id
) {
renderLinearPointHandles(context, appState, sceneState, element);
}
});
// Pain selection element
// Paint selection element
if (selectionElement) {
renderElement(
selectionElement,
@ -167,7 +213,11 @@ export const renderScene = (
}
// Paint selected elements
if (renderSelection) {
if (
renderSelection &&
!appState.multiElement &&
!appState.editingLinearElement
) {
context.translate(sceneState.scrollX, sceneState.scrollY);
const selections = elements.reduce((acc, element) => {