mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
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:
parent
9a17abcb34
commit
16263e942b
19 changed files with 769 additions and 110 deletions
|
@ -1,5 +1,6 @@
|
|||
import { ExcalidrawElement } from "./types";
|
||||
import { SceneScroll } from "../scene/types";
|
||||
import { getArrowAbsoluteBounds } from "./bounds";
|
||||
|
||||
type Sides = "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se";
|
||||
|
||||
|
@ -7,18 +8,31 @@ export function handlerRectangles(
|
|||
element: ExcalidrawElement,
|
||||
{ scrollX, scrollY }: SceneScroll,
|
||||
) {
|
||||
const elementX1 = element.x;
|
||||
const elementX2 = element.x + element.width;
|
||||
const elementY1 = element.y;
|
||||
const elementY2 = element.y + element.height;
|
||||
let elementX2 = 0;
|
||||
let elementY2 = 0;
|
||||
let elementX1 = Infinity;
|
||||
let elementY1 = Infinity;
|
||||
let marginX = -8;
|
||||
let marginY = -8;
|
||||
|
||||
let minimumSize = 40;
|
||||
if (element.type === "arrow") {
|
||||
[elementX1, elementY1, elementX2, elementY2] = getArrowAbsoluteBounds(
|
||||
element,
|
||||
);
|
||||
} else {
|
||||
elementX1 = element.x;
|
||||
elementX2 = element.x + element.width;
|
||||
elementY1 = element.y;
|
||||
elementY2 = element.y + element.height;
|
||||
|
||||
marginX = element.width < 0 ? 8 : -8;
|
||||
marginY = element.height < 0 ? 8 : -8;
|
||||
}
|
||||
|
||||
const margin = 4;
|
||||
const minimumSize = 40;
|
||||
const handlers = {} as { [T in Sides]: number[] };
|
||||
|
||||
const marginX = element.width < 0 ? 8 : -8;
|
||||
const marginY = element.height < 0 ? 8 : -8;
|
||||
|
||||
if (Math.abs(elementX2 - elementX1) > minimumSize) {
|
||||
handlers["n"] = [
|
||||
elementX1 + (elementX2 - elementX1) / 2 + scrollX - 4,
|
||||
|
@ -76,11 +90,58 @@ export function handlerRectangles(
|
|||
8,
|
||||
]; // se
|
||||
|
||||
if (element.type === "arrow" || element.type === "line") {
|
||||
if (element.type === "line") {
|
||||
return {
|
||||
nw: handlers.nw,
|
||||
se: handlers.se,
|
||||
} as typeof handlers;
|
||||
} else if (element.type === "arrow") {
|
||||
if (element.points.length === 2) {
|
||||
// only check the last point because starting point is always (0,0)
|
||||
const [, p1] = element.points;
|
||||
|
||||
if (p1[0] === 0 || p1[1] === 0) {
|
||||
return {
|
||||
nw: handlers.nw,
|
||||
se: handlers.se,
|
||||
} as typeof handlers;
|
||||
}
|
||||
|
||||
if (p1[0] > 0 && p1[1] < 0) {
|
||||
return {
|
||||
ne: handlers.ne,
|
||||
sw: handlers.sw,
|
||||
} as typeof handlers;
|
||||
}
|
||||
|
||||
if (p1[0] > 0 && p1[1] > 0) {
|
||||
return {
|
||||
nw: handlers.nw,
|
||||
se: handlers.se,
|
||||
} as typeof handlers;
|
||||
}
|
||||
|
||||
if (p1[0] < 0 && p1[1] > 0) {
|
||||
return {
|
||||
ne: handlers.ne,
|
||||
sw: handlers.sw,
|
||||
} as typeof handlers;
|
||||
}
|
||||
|
||||
if (p1[0] < 0 && p1[1] < 0) {
|
||||
return {
|
||||
nw: handlers.nw,
|
||||
se: handlers.se,
|
||||
} as typeof handlers;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
n: handlers.n,
|
||||
s: handlers.s,
|
||||
w: handlers.w,
|
||||
e: handlers.e,
|
||||
} as typeof handlers;
|
||||
}
|
||||
|
||||
return handlers;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue