Feature: Multi Point Arrows (#338)

* Add points to arrow on double click

* Use line generator instead of path to generate line segments

* Switch color of the circle when it is on an existing point in the segment

* Check point against both ends of the line segment to find collinearity

* Keep drawing the arrow based on mouse position until shape is changed

* Always select the arrow when in multi element mode

* Use curves instead of lines when drawing arrow points

* Add basic collision detection with some debug points

* Use roughjs shape when performing hit testing

* Draw proper handler rectangles for arrows

* Add argument to renderScene in export

* Globally resize all points on the arrow when bounds are resized

* Hide handler rectangles if an arrow has no size

- Allow continuing adding arrows when selected element is deleted

* Add dragging functionality to arrows

* Add SHIFT functionality to two point arrows

- Fix arrow positions when scrolling
- Revert the element back to selection when not in multi select mode

* Clean app state for export (JSON)

* Set curve options manually instead of using global options

- For some reason, this fixed the flickering issue in all shapes when arrows are rendered

* Set proper options for the arrow

* Increaase accuracy of hit testing arrows

- Additionally, skip testing if point is outside the domain of arrow and each curve

* Calculate bounding box of arrow based on roughjs curves

- Remove domain check per curve

* Change bounding box threshold to 10 and remove unnecessary code

* Fix handler rectangles for 2 and multi point arrows

- Fix margins of handler rectangles when using arrows
- Show handler rectangles in endpoints of 2-point arrows

* Remove unnecessary values from app state for export

* Use `resetTransform` instead of "retranslating" canvas space after each element rendering

* Allow resizing 2-point arrows

- Fix position of one of the handler rectangles

* refactor variable initialization

* Refactored to extract out mult-point generation to the abstracted function

* prevent dragging on arrow creation if under threshold

* Finalize selection during multi element mode when ENTER or ESC is clicked

* Set dragging element to null when finalizing

* Remove pathSegmentCircle from code

* Check if element is any "non-value" instead of NULL

* Show two points on any two point arrow and fix visibility of arrows during scroll

* Resume recording when done with drawing

- When deleting a multi select element, revert back to selection element type

* Resize arrow starting points perfectly

* Fix direction of arrow resize based for NW

* Resume recording history when there is more than one arrow

* Set dragging element to NULL when element is not locked

* Blur active element when finalizing

* Disable undo/redo for multielement, editingelement, and resizing element

- Allow undoing parts of the arrow

* Disable element visibility for arrow

* Use points array for arrow bounds when bezier curve shape is not available

Co-authored-by: David Luzar <luzar.david@gmail.com>
Co-authored-by: Preet <833927+pshihn@users.noreply.github.com>
This commit is contained in:
Gasim Gasimzada 2020-01-31 21:16:33 +04:00 committed by GitHub
parent 9a17abcb34
commit 16263e942b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 769 additions and 110 deletions

View file

@ -1,6 +1,6 @@
import { ExcalidrawElement } from "../element/types";
import { getDefaultAppState } from "../appState";
import { getDefaultAppState, cleanAppStateForExport } from "../appState";
import { AppState } from "../types";
import { ExportType, PreviousScene } from "./types";
@ -24,7 +24,7 @@ const BACKEND_GET = "https://json.excalidraw.com/api/v1/";
interface DataState {
elements: readonly ExcalidrawElement[];
appState: AppState;
appState: AppState | null;
selectedId?: number;
}
@ -36,10 +36,9 @@ export function serializeAsJSON(
{
type: "excalidraw",
version: 1,
appState: {
viewBackgroundColor: appState.viewBackgroundColor,
},
source: window.location.origin,
elements: elements.map(({ shape, isSelected, ...el }) => el),
appState: cleanAppStateForExport(appState),
},
null,
2,
@ -255,7 +254,7 @@ export async function exportCanvas(
function restore(
savedElements: readonly ExcalidrawElement[],
savedState: AppState,
savedState: AppState | null,
): DataState {
return {
elements: savedElements.map(element => ({
@ -291,7 +290,7 @@ export function restoreFromLocalStorage() {
let appState = null;
if (savedState) {
try {
appState = JSON.parse(savedState);
appState = JSON.parse(savedState) as AppState;
} catch (e) {
// Do nothing because appState is already null
}