From 795511ee6b769ece5f96ef348dd46a5c2f21d52e Mon Sep 17 00:00:00 2001 From: Ryan Di Date: Thu, 21 Dec 2023 16:56:05 +0800 Subject: [PATCH] include arrowheads in bounds --- packages/excalidraw/element/bounds.ts | 47 +++++++++++++++---- .../excalidraw/element/linearElementEditor.ts | 23 ++++----- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/packages/excalidraw/element/bounds.ts b/packages/excalidraw/element/bounds.ts index 292fc995d..54a7996b5 100644 --- a/packages/excalidraw/element/bounds.ts +++ b/packages/excalidraw/element/bounds.ts @@ -701,14 +701,45 @@ const getLinearElementRotatedBounds = ( return coords; } - // first element is always the curve - const cachedShape = ShapeCache.get(element)?.[0]; - const shape = cachedShape ?? generateLinearElementShape(element); - const ops = getCurvePathOps(shape); - const transformXY = (x: number, y: number) => - rotate(element.x + x, element.y + y, cx, cy, element.angle); - const res = getMinMaxXYFromCurvePathOps(ops, transformXY); - let coords: Bounds = [res[0], res[1], res[2], res[3]]; + const cachedShape = + ShapeCache.get(element) ?? ShapeCache.generateElementShape(element, null); + + const [arrowCurve, ...arrowhead] = cachedShape; + + let coords = getMinMaxXYFromCurvePathOps( + getCurvePathOps(arrowCurve), + (x: number, y: number) => + rotate(element.x + x, element.y + y, cx, cy, element.angle), + ); + + for (const shape of arrowhead) { + let [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps( + getCurvePathOps(shape), + ); + + [minX, minY] = rotate( + minX + element.x, + minY + element.y, + cx, + cy, + element.angle, + ); + [maxX, maxY] = rotate( + maxX + element.x, + maxY + element.y, + cx, + cy, + element.angle, + ); + + coords = [ + Math.min(minX, coords[0]), + Math.min(minY, coords[1]), + Math.max(maxX, coords[2]), + Math.max(maxY, coords[3]), + ]; + } + const boundTextElement = getBoundTextElement(element); if (boundTextElement) { const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText( diff --git a/packages/excalidraw/element/linearElementEditor.ts b/packages/excalidraw/element/linearElementEditor.ts index bf64ee732..d7e1cb9bd 100644 --- a/packages/excalidraw/element/linearElementEditor.ts +++ b/packages/excalidraw/element/linearElementEditor.ts @@ -1421,10 +1421,10 @@ export class LinearElementEditor { includeBoundText: boolean = false, ): [number, number, number, number, number, number] => { let coords: [number, number, number, number, number, number]; - let x1; - let y1; - let x2; - let y2; + let x1 = Infinity; + let y1 = Infinity; + let x2 = -Infinity; + let y2 = -Infinity; if (element.points.length < 2 || !ShapeCache.get(element)) { // XXX this is just a poor estimate and not very useful const { minX, minY, maxX, maxY } = element.points.reduce( @@ -1446,14 +1446,15 @@ export class LinearElementEditor { } else { const shape = ShapeCache.generateElementShape(element, null); - // first element is always the curve - const ops = getCurvePathOps(shape[0]); + for (const s of shape) { + const ops = getCurvePathOps(s); - const [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps(ops); - x1 = minX + element.x; - y1 = minY + element.y; - x2 = maxX + element.x; - y2 = maxY + element.y; + const [minX, minY, maxX, maxY] = getMinMaxXYFromCurvePathOps(ops); + x1 = Math.min(minX + element.x, x1); + y1 = Math.min(minY + element.y, y1); + x2 = Math.max(maxX + element.x, x2); + y2 = Math.max(maxY + element.y, y2); + } } const cx = (x1 + x2) / 2; const cy = (y1 + y2) / 2;