From ece841326ba21f1a218760df6164ce373a9da07c Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Fri, 25 Apr 2025 14:25:40 +0200 Subject: [PATCH] Refine corner avoidance --- packages/element/src/binding.ts | 41 ++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/packages/element/src/binding.ts b/packages/element/src/binding.ts index 8a4ca3ee63..6e720e1820 100644 --- a/packages/element/src/binding.ts +++ b/packages/element/src/binding.ts @@ -45,6 +45,12 @@ import { import { intersectElementWithLineSegment } from "./collision"; import { distanceToBindableElement } from "./distance"; import { + compareHeading, + HEADING_DOWN, + HEADING_LEFT, + HEADING_RIGHT, + HEADING_UP, + headingForPoint, headingForPointFromElement, headingIsHorizontal, vectorToHeading, @@ -87,6 +93,7 @@ import type { SceneElementsMap, FixedPointBinding, } from "./types"; +import { debugDrawLine, debugDrawPoint } from "@excalidraw/utils/visualdebug"; export type SuggestedBinding = | NonDeleted @@ -1040,7 +1047,14 @@ export const avoidRectangularCorner = ( if (nonRotatedPoint[0] < element.x && nonRotatedPoint[1] < element.y) { // Top left - if (nonRotatedPoint[1] - element.y > -FIXED_BINDING_DISTANCE) { + const heading = headingForPoint( + nonRotatedPoint, + pointFrom(element.x, element.y), + ); + if ( + compareHeading(heading, HEADING_DOWN) || + compareHeading(heading, HEADING_LEFT) + ) { return pointRotateRads( pointFrom(element.x - FIXED_BINDING_DISTANCE, element.y), center, @@ -1057,7 +1071,14 @@ export const avoidRectangularCorner = ( nonRotatedPoint[1] > element.y + element.height ) { // Bottom left - if (nonRotatedPoint[0] - element.x > -FIXED_BINDING_DISTANCE) { + const heading = headingForPoint( + nonRotatedPoint, + pointFrom(element.x, element.y + element.height), + ); + if ( + compareHeading(heading, HEADING_DOWN) || + compareHeading(heading, HEADING_RIGHT) + ) { return pointRotateRads( pointFrom( element.x, @@ -1077,9 +1098,13 @@ export const avoidRectangularCorner = ( nonRotatedPoint[1] > element.y + element.height ) { // Bottom right + const heading = headingForPoint( + nonRotatedPoint, + pointFrom(element.x + element.width, element.y + element.height), + ); if ( - nonRotatedPoint[0] - element.x < - element.width + FIXED_BINDING_DISTANCE + compareHeading(heading, HEADING_DOWN) || + compareHeading(heading, HEADING_LEFT) ) { return pointRotateRads( pointFrom( @@ -1103,9 +1128,13 @@ export const avoidRectangularCorner = ( nonRotatedPoint[1] < element.y ) { // Top right + const heading = headingForPoint( + nonRotatedPoint, + pointFrom(element.x + element.width, element.y), + ); if ( - nonRotatedPoint[0] - element.x < - element.width + FIXED_BINDING_DISTANCE + compareHeading(heading, HEADING_UP) || + compareHeading(heading, HEADING_LEFT) ) { return pointRotateRads( pointFrom(