From f5379d156385f480ec711d055288b7907795c8d5 Mon Sep 17 00:00:00 2001 From: Alex Kim <45559664+alex-kim-dev@users.noreply.github.com> Date: Sat, 29 Oct 2022 16:01:38 +0500 Subject: [PATCH] fix: multiple elements resizing regressions (#5586) --- src/element/bounds.test.ts | 6 ++--- src/element/bounds.ts | 50 +++++++++++++++++++++++------------ src/element/resizeElements.ts | 31 +++++++++++++--------- 3 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/element/bounds.test.ts b/src/element/bounds.test.ts index d58fabcc67..c352a81e94 100644 --- a/src/element/bounds.test.ts +++ b/src/element/bounds.test.ts @@ -22,7 +22,7 @@ const _ce = ({ backgroundColor: "#000", fillStyle: "solid", strokeWidth: 1, - roughness: 1, + roughness: 0, opacity: 1, x, y, @@ -106,7 +106,7 @@ describe("getElementBounds", () => { } as ExcalidrawLinearElement); expect(x1).toEqual(360.3176068760539); expect(y1).toEqual(185.90654264413516); - expect(x2).toEqual(473.8171188951176); - expect(y2).toEqual(320.391865303557); + expect(x2).toEqual(480.87005902729743); + expect(y2).toEqual(320.4751269334226); }); }); diff --git a/src/element/bounds.ts b/src/element/bounds.ts index b6f655ec4a..793f4c50f0 100644 --- a/src/element/bounds.ts +++ b/src/element/bounds.ts @@ -387,34 +387,49 @@ export const getArrowheadPoints = ( return [x2, y2, x3, y3, x4, y4]; }; +const generateLinearElementShape = ( + element: ExcalidrawLinearElement, +): Drawable => { + const generator = rough.generator(); + const options = generateRoughOptions(element); + + const method = (() => { + if (element.strokeSharpness !== "sharp") { + return "curve"; + } + if (options.fill) { + return "polygon"; + } + return "linearPath"; + })(); + + return generator[method](element.points as Mutable[], options); +}; + const getLinearElementRotatedBounds = ( element: ExcalidrawLinearElement, cx: number, cy: number, ): [number, number, number, number] => { - if (element.points.length < 2 || !getShapeForElement(element)) { - // XXX this is just a poor estimate and not very useful - const { minX, minY, maxX, maxY } = element.points.reduce( - (limits, [x, y]) => { - [x, y] = rotate(element.x + x, element.y + y, cx, cy, element.angle); - limits.minY = Math.min(limits.minY, y); - limits.minX = Math.min(limits.minX, x); - limits.maxX = Math.max(limits.maxX, x); - limits.maxY = Math.max(limits.maxY, y); - return limits; - }, - { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity }, + if (element.points.length < 2) { + const [pointX, pointY] = element.points[0]; + const [x, y] = rotate( + element.x + pointX, + element.y + pointY, + cx, + cy, + element.angle, ); - return [minX, minY, maxX, maxY]; + return [x, y, x, y]; } - const shape = getShapeForElement(element)!; - // first element is always the curve - const ops = getCurvePathOps(shape[0]); - + const cachedShape = getShapeForElement(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); + return getMinMaxXYFromCurvePathOps(ops, transformXY); }; @@ -538,6 +553,7 @@ export const getResizedElementAbsoluteCoords = ( points as [number, number][], generateRoughOptions(element), ); + const ops = getCurvePathOps(curve); bounds = getMinMaxXYFromCurvePathOps(ops); } diff --git a/src/element/resizeElements.ts b/src/element/resizeElements.ts index 7de00afe87..5f2d93a01c 100644 --- a/src/element/resizeElements.ts +++ b/src/element/resizeElements.ts @@ -721,7 +721,7 @@ const resizeMultipleElements = ( (pointerSideY * Math.abs(pointerY - anchorY)) / (maxY - minY), ) * (shouldResizeFromCenter ? 2 : 1); - if (scale === 1) { + if (scale === 0) { return; } @@ -766,21 +766,26 @@ const resizeMultipleElements = ( width - optionalPadding, height - optionalPadding, ); - if (textMeasurements) { - if (isTextElement(element.orig)) { - update.fontSize = textMeasurements.size; - update.baseline = textMeasurements.baseline; - } - - if (boundTextElement) { - boundTextUpdates = { - fontSize: textMeasurements.size, - baseline: textMeasurements.baseline, - }; - } + + if (!textMeasurements) { + return; + } + + if (isTextElement(element.orig)) { + update.fontSize = textMeasurements.size; + update.baseline = textMeasurements.baseline; + } + + if (boundTextElement) { + boundTextUpdates = { + fontSize: textMeasurements.size, + baseline: textMeasurements.baseline, + }; } } + updateBoundElements(element.latest, { newSize: { width, height } }); + mutateElement(element.latest, update); if (boundTextElement && boundTextUpdates) {