From 73c940bcf697737eaf044876d739a64fb386e200 Mon Sep 17 00:00:00 2001 From: Mark Tolmacs Date: Sun, 10 May 2026 12:12:06 +0000 Subject: [PATCH] chore: Refactor binding gap calc Signed-off-by: Mark Tolmacs --- packages/element/src/arrows/focus.ts | 2 +- packages/element/src/binding.ts | 19 +- packages/element/src/collision.ts | 2 +- packages/element/src/elbowArrow.ts | 18 +- packages/element/src/utils.ts | 270 +++++++++--------- .../excalidraw/renderer/interactiveScene.ts | 90 ++---- .../tests/__snapshots__/history.test.tsx.snap | 116 ++++---- .../tests/__snapshots__/move.test.tsx.snap | 10 +- packages/excalidraw/tests/history.test.tsx | 20 +- packages/excalidraw/tests/move.test.tsx | 8 +- 10 files changed, 255 insertions(+), 300 deletions(-) diff --git a/packages/element/src/arrows/focus.ts b/packages/element/src/arrows/focus.ts index f5d6e64530..695c88d796 100644 --- a/packages/element/src/arrows/focus.ts +++ b/packages/element/src/arrows/focus.ts @@ -91,7 +91,7 @@ export const isFocusPointVisible = ( element: bindableElement, elementsMap, point: focusPoint, - threshold: getBindingGap(bindableElement, arrow), + threshold: getBindingGap(bindableElement), overrideShouldTestInside: true, }) ); diff --git a/packages/element/src/binding.ts b/packages/element/src/binding.ts index 07086b7514..a507c4fc2e 100644 --- a/packages/element/src/binding.ts +++ b/packages/element/src/binding.ts @@ -111,18 +111,13 @@ export type BindingStrategy = * IMPORTANT: currently must be > 0 (this also applies to the computed gap) */ export const BASE_BINDING_GAP = 5; -export const BASE_BINDING_GAP_ELBOW = 5; export const BASE_ARROW_MIN_LENGTH = 10; export const FOCUS_POINT_SIZE = 10 / 1.5; export const getBindingGap = ( bindTarget: ExcalidrawBindableElement, - opts: Pick, ): number => { - return ( - (opts.elbowed ? BASE_BINDING_GAP_ELBOW : BASE_BINDING_GAP) + - bindTarget.strokeWidth / 2 - ); + return BASE_BINDING_GAP + bindTarget.strokeWidth / 2; }; export const maxBindingDistance_simple = (zoom?: AppState["zoom"]): number => { @@ -1416,7 +1411,7 @@ export const bindPointToSnapToElementOutline = ( startOrEnd === "start" ? 1 : -2, elementsMap, ); - const bindingGap = getBindingGap(bindableElement, arrowElement); + const bindingGap = getBindingGap(bindableElement); const aabb = aabbForElement(bindableElement, elementsMap); const bindableCenter = getCenterForBounds(aabb); @@ -1477,7 +1472,7 @@ export const bindPointToSnapToElementOutline = ( bindableElement, elementsMap, anotherIntersector, - BASE_BINDING_GAP_ELBOW, + BASE_BINDING_GAP, ).sort(pointDistanceSq)[0]; } } else { @@ -1536,7 +1531,7 @@ export const avoidRectangularCorner = ( -bindTarget.angle as Radians, ); - const bindingGap = getBindingGap(bindTarget, arrowElement); + const bindingGap = getBindingGap(bindTarget); if (nonRotatedPoint[0] < bindTarget.x && nonRotatedPoint[1] < bindTarget.y) { // Top left @@ -1714,7 +1709,7 @@ export const updateBoundPoint = ( otherBindable, elementsMap, intersector, - getBindingGap(otherBindable, arrow), + getBindingGap(otherBindable), ).sort( (a, b) => pointDistanceSq(a, focusPoint) - pointDistanceSq(b, focusPoint), )[0]; @@ -1724,7 +1719,7 @@ export const updateBoundPoint = ( bindableElement, elementsMap, intersector, - getBindingGap(bindableElement, arrow), + getBindingGap(bindableElement), ).sort( (a, b) => pointDistanceSq(a, otherFocusPointOrArrowPoint) - @@ -1752,7 +1747,7 @@ export const updateBoundPoint = ( element: otherBindable, point: outlinePoint, elementsMap, - threshold: getBindingGap(otherBindable, arrow), + threshold: getBindingGap(otherBindable), overrideShouldTestInside: true, }) ) { diff --git a/packages/element/src/collision.ts b/packages/element/src/collision.ts index afa46c986b..8414bd4a55 100644 --- a/packages/element/src/collision.ts +++ b/packages/element/src/collision.ts @@ -316,7 +316,7 @@ export const getAllHoveredElementAtPoint = ( element, point, elementsMap, - threshold: tolerance ?? getBindingGap(element, arrow), + threshold: tolerance ?? getBindingGap(element), overrideShouldTestInside: true, }) ) { diff --git a/packages/element/src/elbowArrow.ts b/packages/element/src/elbowArrow.ts index c7429b2d12..fb6daa0c46 100644 --- a/packages/element/src/elbowArrow.ts +++ b/packages/element/src/elbowArrow.ts @@ -30,7 +30,7 @@ import { getHeadingForElbowArrowSnap, getGlobalFixedPointForBindableElement, getBindingGap, - BASE_BINDING_GAP_ELBOW, + BASE_BINDING_GAP, } from "./binding"; import { distanceToElement } from "./distance"; import { @@ -1311,8 +1311,8 @@ const getElbowArrowData = ( offsetFromHeading( startHeading, arrow.startArrowhead - ? getBindingGap(hoveredStartElement, { elbowed: true }) * 6 - : getBindingGap(hoveredStartElement, { elbowed: true }) * 2, + ? getBindingGap(hoveredStartElement) * 6 + : getBindingGap(hoveredStartElement) * 2, 1, ), ) @@ -1324,8 +1324,8 @@ const getElbowArrowData = ( offsetFromHeading( endHeading, arrow.endArrowhead - ? getBindingGap(hoveredEndElement, { elbowed: true }) * 6 - : getBindingGap(hoveredEndElement, { elbowed: true }) * 2, + ? getBindingGap(hoveredEndElement) * 6 + : getBindingGap(hoveredEndElement) * 2, 1, ), ) @@ -1372,8 +1372,8 @@ const getElbowArrowData = ( ? 0 : BASE_PADDING - (arrow.startArrowhead - ? BASE_BINDING_GAP_ELBOW * 6 - : BASE_BINDING_GAP_ELBOW * 2), + ? BASE_BINDING_GAP * 6 + : BASE_BINDING_GAP * 2), BASE_PADDING, ), boundsOverlap @@ -1388,8 +1388,8 @@ const getElbowArrowData = ( ? 0 : BASE_PADDING - (arrow.endArrowhead - ? BASE_BINDING_GAP_ELBOW * 6 - : BASE_BINDING_GAP_ELBOW * 2), + ? BASE_BINDING_GAP * 6 + : BASE_BINDING_GAP * 2), BASE_PADDING, ), boundsOverlap, diff --git a/packages/element/src/utils.ts b/packages/element/src/utils.ts index 30287c219f..58cc0f7668 100644 --- a/packages/element/src/utils.ts +++ b/packages/element/src/utils.ts @@ -588,104 +588,101 @@ const getDiagonalsForBindableElement = ( return [diagonalOne, diagonalTwo]; }; -export const getHighlightedMidpointIndex = ( - point: GlobalPoint, +const getSnappedMidpointIndexForElbowArrow = ( element: ExcalidrawBindableElement, - elementsMap: ElementsMap, - zoom: AppState["zoom"], - arrow: { elbowed: boolean }, -): number => { - const center = elementCenterPoint(element, elementsMap); - const TOLERANCE = 0.05; - const maxDistance = maxBindingDistance_simple(zoom) + element.strokeWidth / 2; + point: GlobalPoint, + center: GlobalPoint, + horizontalThreshold: number, + verticalThreshold: number, +) => { const { x, y, width, height, angle } = element; + const nonRotated = pointRotateRads(point, center, -angle as Radians); - // snap-to-center point is adaptive to element size, but we don't want to go - // above and below certain px distance - const verticalThreshold = clamp(TOLERANCE * height, 5, maxDistance); - const horizontalThreshold = clamp(TOLERANCE * width, 5, maxDistance); - - if (arrow.elbowed) { - const nonRotated = pointRotateRads(point, center, -angle as Radians); - - const bindingGap = getBindingGap(element, arrow); - - if (pointDistance(center, nonRotated) < bindingGap) { - return -1; - } - - if ( - nonRotated[0] <= x + width / 2 && - nonRotated[1] > center[1] - verticalThreshold && - nonRotated[1] < center[1] + verticalThreshold - ) { - return 2; - } else if ( - nonRotated[1] <= y + height / 2 && - nonRotated[0] > center[0] - horizontalThreshold && - nonRotated[0] < center[0] + horizontalThreshold - ) { - return 3; - } else if ( - nonRotated[0] >= x + width / 2 && - nonRotated[1] > center[1] - verticalThreshold && - nonRotated[1] < center[1] + verticalThreshold - ) { - return 0; - } else if ( - nonRotated[1] >= y + height / 2 && - nonRotated[0] > center[0] - horizontalThreshold && - nonRotated[0] < center[0] + horizontalThreshold - ) { - return 1; - } else if (element.type === "diamond") { - const distance = bindingGap; - const topLeft = pointFrom( - x + width / 4 - distance, - y + height / 4 - distance, - ); - const topRight = pointFrom( - x + (3 * width) / 4 + distance, - y + height / 4 - distance, - ); - const bottomLeft = pointFrom( - x + width / 4 - distance, - y + (3 * height) / 4 + distance, - ); - const bottomRight = pointFrom( - x + (3 * width) / 4 + distance, - y + (3 * height) / 4 + distance, - ); - - if ( - pointDistance(bottomLeft, nonRotated) < - Math.max(horizontalThreshold, verticalThreshold) - ) { - return 1; - } - if ( - pointDistance(bottomRight, nonRotated) < - Math.max(horizontalThreshold, verticalThreshold) - ) { - return 0; - } - if ( - pointDistance(topLeft, nonRotated) < - Math.max(horizontalThreshold, verticalThreshold) - ) { - return 2; - } - if ( - pointDistance(topRight, nonRotated) < - Math.max(horizontalThreshold, verticalThreshold) - ) { - return 3; - } - } + const bindingGap = getBindingGap(element); + if (pointDistance(center, nonRotated) < bindingGap) { return -1; } + if ( + nonRotated[0] <= x + width / 2 && + nonRotated[1] > center[1] - verticalThreshold && + nonRotated[1] < center[1] + verticalThreshold + ) { + return 2; + } else if ( + nonRotated[1] <= y + height / 2 && + nonRotated[0] > center[0] - horizontalThreshold && + nonRotated[0] < center[0] + horizontalThreshold + ) { + return 3; + } else if ( + nonRotated[0] >= x + width / 2 && + nonRotated[1] > center[1] - verticalThreshold && + nonRotated[1] < center[1] + verticalThreshold + ) { + return 0; + } else if ( + nonRotated[1] >= y + height / 2 && + nonRotated[0] > center[0] - horizontalThreshold && + nonRotated[0] < center[0] + horizontalThreshold + ) { + return 1; + } else if (element.type === "diamond") { + const distance = bindingGap; + const topLeft = pointFrom( + x + width / 4 - distance, + y + height / 4 - distance, + ); + const topRight = pointFrom( + x + (3 * width) / 4 + distance, + y + height / 4 - distance, + ); + const bottomLeft = pointFrom( + x + width / 4 - distance, + y + (3 * height) / 4 + distance, + ); + const bottomRight = pointFrom( + x + (3 * width) / 4 + distance, + y + (3 * height) / 4 + distance, + ); + + if ( + pointDistance(bottomLeft, nonRotated) < + Math.max(horizontalThreshold, verticalThreshold) + ) { + return 1; + } + if ( + pointDistance(bottomRight, nonRotated) < + Math.max(horizontalThreshold, verticalThreshold) + ) { + return 0; + } + if ( + pointDistance(topLeft, nonRotated) < + Math.max(horizontalThreshold, verticalThreshold) + ) { + return 2; + } + if ( + pointDistance(topRight, nonRotated) < + Math.max(horizontalThreshold, verticalThreshold) + ) { + return 3; + } + } + + return -1; +}; + +const getSnappedMidpointIndexForSimpleArrow = ( + element: ExcalidrawBindableElement, + point: GlobalPoint, + elementsMap: ElementsMap, + horizontalThreshold: number, + verticalThreshold: number, +) => { const baseMidpoints = getAllMidpoints(element, elementsMap); for (let i = 0; i < baseMidpoints.length; i++) { @@ -708,41 +705,6 @@ export const getHighlightedMidpointIndex = ( return -1; }; -export const getSnapOutlineMidPoint = ( - point: GlobalPoint, - element: ExcalidrawBindableElement, - elementsMap: ElementsMap, - zoom: AppState["zoom"], - arrow: { elbowed: boolean }, -): GlobalPoint | undefined => { - const center = elementCenterPoint(element, elementsMap); - const baseMidpoints = getAllMidpoints(element, elementsMap); - - const sideMidpoints = - element.type === "diamond" - ? baseMidpoints.map((midpoint) => { - return pointFrom( - midpoint[0] + (midpoint[0] - center[0]) * 0.1, - midpoint[1] + (midpoint[1] - center[1]) * 0.1, - ); - }) - : baseMidpoints; - - const idx = getHighlightedMidpointIndex( - point, - element, - elementsMap, - zoom, - arrow, - ); - - if (idx === -1) { - return undefined; - } - - return sideMidpoints[idx]; -}; - export const getAllMidpoints = ( element: ExcalidrawBindableElement, elementsMap: ElementsMap, @@ -750,10 +712,9 @@ export const getAllMidpoints = ( const center = elementCenterPoint(element, elementsMap); if (element.type === "diamond") { - return getDiamondBaseCorners(element).map((curve) => { - const point = bezierEquation(curve, 0.5); - return pointRotateRads(point, center, element.angle); - }); + return getDiamondBaseCorners(element).map((curve) => + pointRotateRads(bezierEquation(curve, 0.5), center, element.angle), + ); } return [ @@ -770,6 +731,52 @@ export const getAllMidpoints = ( ); }; +export const getSnapOutlineMidPoint = ( + point: GlobalPoint, + element: ExcalidrawBindableElement, + elementsMap: ElementsMap, + zoom: AppState["zoom"], + arrow: { elbowed: boolean }, +): GlobalPoint | undefined => { + const center = elementCenterPoint(element, elementsMap); + const baseMidpoints = getAllMidpoints(element, elementsMap); + const sideMidpoints = + element.type === "diamond" + ? baseMidpoints.map((midpoint) => { + return pointFrom( + midpoint[0] + (midpoint[0] - center[0]) * 0.1, + midpoint[1] + (midpoint[1] - center[1]) * 0.1, + ); + }) + : baseMidpoints; + + const TOLERANCE = 0.05; + const maxDistance = maxBindingDistance_simple(zoom) + element.strokeWidth / 2; + const verticalThreshold = clamp(TOLERANCE * element.height, 5, maxDistance); + const horizontalThreshold = clamp(TOLERANCE * element.width, 5, maxDistance); + const idx = arrow.elbowed + ? getSnappedMidpointIndexForElbowArrow( + element, + point, + center, + horizontalThreshold, + verticalThreshold, + ) + : getSnappedMidpointIndexForSimpleArrow( + element, + point, + elementsMap, + horizontalThreshold, + verticalThreshold, + ); + + if (idx === -1) { + return undefined; + } + + return sideMidpoints[idx]; +}; + export const projectFixedPointOntoDiagonal = ( arrow: ExcalidrawArrowElement, point: GlobalPoint, @@ -780,9 +787,6 @@ export const projectFixedPointOntoDiagonal = ( isMidpointSnappingEnabled: boolean = true, ): GlobalPoint | null => { invariant(arrow.points.length >= 2, "Arrow must have at least two points"); - if (arrow.width < 3 && arrow.height < 3) { - return null; - } if (isMidpointSnappingEnabled) { const sideMidPoint = getSnapOutlineMidPoint( diff --git a/packages/excalidraw/renderer/interactiveScene.ts b/packages/excalidraw/renderer/interactiveScene.ts index 19b3840acb..2fb417a1ba 100644 --- a/packages/excalidraw/renderer/interactiveScene.ts +++ b/packages/excalidraw/renderer/interactiveScene.ts @@ -24,13 +24,11 @@ import { deconstructRectanguloidElement, elementCenterPoint, getAllMidpoints, - getHighlightedMidpointIndex, FOCUS_POINT_SIZE, getOmitSidesForEditorInterface, getTransformHandles, getTransformHandlesFromCoords, hasBoundingBox, - hitElementItself, isArrowElement, isBindableElement, isElbowArrow, @@ -412,74 +410,42 @@ const renderBindingHighlightForBindableElement_simple = ( break; } + // Draw midpoint indicators if ( appState.isMidpointSnappingEnabled && (isFrameLikeElement(suggestedBinding.element) || isBindableElement(suggestedBinding.element)) ) { - // Draw midpoint indicators - const linearElement = appState.selectedLinearElement; - const arrow = - linearElement?.elementId && - LinearElementEditor.getElement(linearElement?.elementId, elementsMap); - const cursorIsInsideBindable = - pointerCoords && - hitElementItself({ - point: pointerCoords, - element: suggestedBinding.element, - elementsMap, - threshold: 0, - overrideShouldTestInside: true, - }); + context.save(); - const isElbow = - (arrow && isElbowArrow(arrow)) || - (appState.activeTool.type === "arrow" && - appState.currentItemArrowType === "elbow"); + const midpointRadius = 4 / appState.zoom.value; - if (!cursorIsInsideBindable || isElbow) { - context.save(); - - const midpoints = getAllMidpoints(suggestedBinding.element, elementsMap); - - const highlightedIdx = pointerCoords - ? getHighlightedMidpointIndex( - pointerCoords, - suggestedBinding.element, - elementsMap, - appState.zoom, - { elbowed: isElbow }, - ) - : -1; - - const midpointRadius = 4 / appState.zoom.value; - - midpoints.forEach((midpoint, idx) => { - const isHighlighted = - highlightedIdx === idx && (!cursorIsInsideBindable || isElbow); - - if (isHighlighted) { - context.fillStyle = - appState.theme === THEME.DARK - ? `rgba(3, 93, 161, 1)` - : `rgba(106, 189, 252, 1)`; - - context.beginPath(); - context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI); - context.fill(); - } else { - context.fillStyle = - appState.theme === THEME.DARK - ? `rgba(0, 0, 0, 0.8)` - : `rgba(65, 65, 65, 0.5)`; - context.beginPath(); - context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI); - context.fill(); - } - }); - - context.restore(); + // Render base midpoints + const midpoints = getAllMidpoints(suggestedBinding.element, elementsMap); + for (const midpoint of midpoints) { + context.fillStyle = + appState.theme === THEME.DARK + ? `rgba(0, 0, 0, 0.8)` + : `rgba(65, 65, 65, 0.5)`; + context.beginPath(); + context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI); + context.fill(); } + + // Render the highlighted midpoint if any + const midpoint = appState.suggestedBinding?.midPoint; + if (midpoint) { + context.fillStyle = + appState.theme === THEME.DARK + ? `rgba(3, 93, 161, 1)` + : `rgba(106, 189, 252, 1)`; + + context.beginPath(); + context.arc(midpoint[0], midpoint[1], midpointRadius, 0, 2 * Math.PI); + context.fill(); + } + + context.restore(); } }; diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 37765a4bd0..421075f389 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -16703,7 +16703,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "id": "id13", "index": "a3", "isDeleted": false, @@ -16718,7 +16718,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -16729,8 +16729,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -16742,7 +16742,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 10, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", } `; @@ -16787,8 +16787,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -16807,8 +16807,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -17121,7 +17121,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "index": "a3", "isDeleted": false, "link": null, @@ -17134,7 +17134,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -17145,8 +17145,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -17157,7 +17157,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 7, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", }, "inserted": { "isDeleted": true, @@ -17451,7 +17451,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "id": "id13", "index": "a3", "isDeleted": false, @@ -17466,7 +17466,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -17477,8 +17477,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -17490,7 +17490,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 10, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", } `; @@ -17759,7 +17759,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "index": "a3", "isDeleted": false, "link": null, @@ -17772,7 +17772,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -17783,8 +17783,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -17795,7 +17795,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 10, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", }, "inserted": { "isDeleted": true, @@ -18097,7 +18097,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "id": "id13", "index": "a3", "isDeleted": false, @@ -18112,7 +18112,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -18123,8 +18123,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -18136,7 +18136,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 10, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", } `; @@ -18405,7 +18405,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "index": "a3", "isDeleted": false, "link": null, @@ -18418,7 +18418,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -18429,8 +18429,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -18441,7 +18441,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 10, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", }, "inserted": { "isDeleted": true, @@ -18741,7 +18741,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "id": "id13", "index": "a3", "isDeleted": false, @@ -18756,7 +18756,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -18767,8 +18767,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -18780,7 +18780,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 10, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", } `; @@ -18841,8 +18841,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -19135,7 +19135,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "index": "a3", "isDeleted": false, "link": null, @@ -19148,7 +19148,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -19159,8 +19159,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -19171,7 +19171,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 7, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", }, "inserted": { "isDeleted": true, @@ -19493,7 +19493,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "id": "id13", "index": "a3", "isDeleted": false, @@ -19508,7 +19508,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -19519,8 +19519,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -19532,7 +19532,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 11, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", } `; @@ -19604,8 +19604,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -19883,7 +19883,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "0.00661", + "height": 0, "index": "a3", "isDeleted": false, "link": null, @@ -19896,7 +19896,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding ], [ "88.00000", - "-0.00661", + 0, ], ], "roughness": 1, @@ -19907,8 +19907,8 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "startBinding": { "elementId": "id0", "fixedPoint": [ - "0.50021", - "0.50021", + 1, + "0.50010", ], "mode": "orbit", }, @@ -19919,7 +19919,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding "version": 7, "width": "88.00000", "x": 6, - "y": "0.01706", + "y": "0.01000", }, "inserted": { "isDeleted": true, diff --git a/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap index d9c7da5fdb..5857132962 100644 --- a/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap @@ -182,14 +182,14 @@ exports[`move element > rectangles with binding arrow 7`] = ` "elementId": "id3", "fixedPoint": [ "-0.02000", - "0.47928", + "0.48010", ], "mode": "orbit", }, "fillStyle": "solid", "frameId": null, "groupIds": [], - "height": "93.60377", + "height": "90.01760", "id": "id6", "index": "a2", "isDeleted": false, @@ -204,7 +204,7 @@ exports[`move element > rectangles with binding arrow 7`] = ` ], [ 89, - "93.60377", + "90.01760", ], ], "roughness": 1, @@ -217,7 +217,7 @@ exports[`move element > rectangles with binding arrow 7`] = ` "elementId": "id0", "fixedPoint": [ "1.06000", - "0.52181", + "0.56011", ], "mode": "orbit", }, @@ -230,6 +230,6 @@ exports[`move element > rectangles with binding arrow 7`] = ` "versionNonce": 271613161, "width": 89, "x": 106, - "y": "52.18052", + "y": "56.01120", } `; diff --git a/packages/excalidraw/tests/history.test.tsx b/packages/excalidraw/tests/history.test.tsx index 8f8468289d..ddbe93a8ef 100644 --- a/packages/excalidraw/tests/history.test.tsx +++ b/packages/excalidraw/tests/history.test.tsx @@ -1590,9 +1590,7 @@ describe("history", () => { expect(API.getUndoStack().length).toBe(5); expect(arrow.startBinding).toEqual({ elementId: rect1.id, - fixedPoint: expect.arrayContaining([ - 0.5002127206977238, 0.5002127206977238, - ]), + fixedPoint: expect.arrayContaining([1, 0.5001]), mode: "orbit", }); expect(arrow.endBinding).toEqual({ @@ -1615,9 +1613,7 @@ describe("history", () => { expect(API.getRedoStack().length).toBe(1); expect(arrow.startBinding).toEqual({ elementId: rect1.id, - fixedPoint: expect.arrayContaining([ - 0.5002127206977238, 0.5002127206977238, - ]), + fixedPoint: expect.arrayContaining([1, 0.5001]), mode: "orbit", }); expect(arrow.endBinding).toEqual({ @@ -1640,9 +1636,7 @@ describe("history", () => { expect(API.getRedoStack().length).toBe(0); expect(arrow.startBinding).toEqual({ elementId: rect1.id, - fixedPoint: expect.arrayContaining([ - 0.5002127206977238, 0.5002127206977238, - ]), + fixedPoint: expect.arrayContaining([1, 0.5001]), mode: "orbit", }); expect(arrow.endBinding).toEqual({ @@ -1673,9 +1667,7 @@ describe("history", () => { expect(API.getRedoStack().length).toBe(0); expect(arrow.startBinding).toEqual({ elementId: rect1.id, - fixedPoint: expect.arrayContaining([ - 0.5002127206977238, 0.5002127206977238, - ]), + fixedPoint: expect.arrayContaining([1, 0.5001]), mode: "orbit", }); expect(arrow.endBinding).toEqual({ @@ -1698,9 +1690,7 @@ describe("history", () => { expect(API.getRedoStack().length).toBe(1); expect(arrow.startBinding).toEqual({ elementId: rect1.id, - fixedPoint: expect.arrayContaining([ - 0.5002127206977238, 0.5002127206977238, - ]), + fixedPoint: expect.arrayContaining([1, 0.5001]), mode: "orbit", }); expect(arrow.endBinding).toEqual({ diff --git a/packages/excalidraw/tests/move.test.tsx b/packages/excalidraw/tests/move.test.tsx index cad39e198b..d6ce82bf99 100644 --- a/packages/excalidraw/tests/move.test.tsx +++ b/packages/excalidraw/tests/move.test.tsx @@ -115,11 +115,11 @@ describe("move element", () => { expect([rectA.x, rectA.y]).toEqual([0, 0]); expect([rectB.x, rectB.y]).toEqual([200, 0]); expect([[arrow.x, arrow.y]]).toCloselyEqualPoints( - [[106, 52.18052313249668]], + [[106, 56.011199999998695]], 0, ); expect([[arrow.width, arrow.height]]).toCloselyEqualPoints( - [[88, 91.60376557808824]], + [[88, 88.01760000000121]], 0, ); @@ -140,11 +140,11 @@ describe("move element", () => { expect([rectA.x, rectA.y]).toEqual([0, 0]); expect([rectB.x, rectB.y]).toEqual([201, 2]); expect([[arrow.x, arrow.y]]).toCloselyEqualPoints( - [[106, 52.18052313249668]], + [[106, 56.011199999998695]], 0, ); expect([[arrow.width, arrow.height]]).toCloselyEqualPoints( - [[89, 93.60376557808823]], + [[89, 90.01760000000121]], 0, );