From a8338cdb5a3b58a80fa19da1c6ec294f4dabdbb7 Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Fri, 11 Apr 2025 21:08:55 +0200 Subject: [PATCH] More adaptive elbow dongle offset --- packages/element/src/binding.ts | 1 + packages/element/src/elbowArrow.ts | 42 ++++++++++++++++++++++++++++-- packages/element/src/shapes.ts | 9 +++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/packages/element/src/binding.ts b/packages/element/src/binding.ts index 5c32e8c81d..0ef3fda544 100644 --- a/packages/element/src/binding.ts +++ b/packages/element/src/binding.ts @@ -981,6 +981,7 @@ export const bindPointToSnapToElementOutline = ( otherPoint, ), ), + 0.1, )[0]; } else { intersection = intersectElementWithLineSegment( diff --git a/packages/element/src/elbowArrow.ts b/packages/element/src/elbowArrow.ts index 503d2f02fd..8e502d2833 100644 --- a/packages/element/src/elbowArrow.ts +++ b/packages/element/src/elbowArrow.ts @@ -53,7 +53,7 @@ import { type SceneElementsMap, } from "./types"; -import { aabbForElement, pointInsideBounds } from "./shapes"; +import { aabbForElement, aabbForPoints, pointInsideBounds } from "./shapes"; import type { Bounds } from "./bounds"; import type { Heading } from "./heading"; @@ -108,7 +108,30 @@ type ElbowArrowData = { }; const DEDUP_TRESHOLD = 1; -export const BASE_PADDING = 40; + +const calculatePadding = ( + aabb: Bounds, + startHeading: Heading, + endHeading: Heading, +) => { + const width = aabb[2] - aabb[0]; + const height = aabb[3] - aabb[1]; + const size = Math.max(width, height); + + return compareHeading(startHeading, flipHeading(endHeading)) || size > 50 + ? 40 + : Math.min( + Math.max( + headingIsHorizontal(startHeading) ? width / 2 - 1 : height / 2 - 1, + 10, + ), + Math.max( + headingIsHorizontal(endHeading) ? width / 2 - 1 : height / 2 - 1, + 10, + ), + 40, + ); +}; const handleSegmentRenormalization = ( arrow: ExcalidrawElbowArrowElement, @@ -464,6 +487,11 @@ const handleSegmentMove = ( hoveredStartElement: ExcalidrawBindableElement | null, hoveredEndElement: ExcalidrawBindableElement | null, ): ElementUpdate => { + const BASE_PADDING = calculatePadding( + aabbForElement(arrow), + startHeading, + endHeading, + ); const activelyModifiedSegmentIdx = fixedSegments .map((segment, i) => { if ( @@ -708,6 +736,11 @@ const handleEndpointDrag = ( hoveredStartElement: ExcalidrawBindableElement | null, hoveredEndElement: ExcalidrawBindableElement | null, ) => { + const BASE_PADDING = calculatePadding( + aabbForPoints([startGlobalPoint, endGlobalPoint]), + startHeading, + endHeading, + ); let startIsSpecial = arrow.startIsSpecial ?? null; let endIsSpecial = arrow.endIsSpecial ?? null; const globalUpdatedPoints = updatedPoints.map((p, i) => @@ -1298,6 +1331,11 @@ const getElbowArrowData = ( endGlobalPoint[0] + 2, endGlobalPoint[1] + 2, ] as Bounds; + const BASE_PADDING = calculatePadding( + aabbForPoints([startGlobalPoint, endGlobalPoint]), + startHeading, + endHeading, + ); const startElementBounds = hoveredStartElement ? aabbForElement( hoveredStartElement, diff --git a/packages/element/src/shapes.ts b/packages/element/src/shapes.ts index 96542c5385..29afb17c29 100644 --- a/packages/element/src/shapes.ts +++ b/packages/element/src/shapes.ts @@ -282,6 +282,15 @@ export const mapIntervalToBezierT =

( ); }; +export const aabbForPoints = ( + points: Point[], +): Bounds => [ + Math.min(...points.map((point) => point[0])), + Math.min(...points.map((point) => point[1])), + Math.max(...points.map((point) => point[0])), + Math.max(...points.map((point) => point[1])), +]; + /** * Get the axis-aligned bounding box for a given element */