diff --git a/packages/element/src/resizeElements.ts b/packages/element/src/resizeElements.ts
index 8a1702afa..7ded4dc0a 100644
--- a/packages/element/src/resizeElements.ts
+++ b/packages/element/src/resizeElements.ts
@@ -1369,8 +1369,21 @@ export const resizeMultipleElements = (
);
if (keepAspectRatio) {
- scaleX = scale;
- scaleY = scale;
+ // If the elements are in a group and shouldMaintainAspectRatio is true(meaning user is holding shift),
+ // we need to adjust the scaleX or scaleY based on the handleDirection
+ if(targetElements.some(item => isInGroup(item.latest)) && shouldMaintainAspectRatio) {
+ if(handleDirection.length === 1) {
+ if(handleDirection.includes("e") || handleDirection.includes("w")) {
+ scaleX = scale;
+ } else if (handleDirection.includes("n") || handleDirection.includes("s")) {
+ scaleY = scale;
+ }
+ }
+ }
+ else {
+ scaleX = scale;
+ scaleY = scale;
+ }
}
/**
@@ -1481,11 +1494,15 @@ export const resizeMultipleElements = (
}
if (isTextElement(orig)) {
- const metrics = measureFontSizeFromWidth(orig, elementsMap, width);
- if (!metrics) {
- return;
+ if (!shouldMaintainAspectRatio) {
+ const metrics = measureFontSizeFromWidth(orig, elementsMap, width);
+ if (!metrics) {
+ return;
+ }
+ update.fontSize = metrics.size;
+ } else {
+ update.fontSize = orig.fontSize;
}
- update.fontSize = metrics.size;
}
const boundTextElement = originalElementsMap.get(
@@ -1493,7 +1510,7 @@ export const resizeMultipleElements = (
) as ExcalidrawTextElementWithContainer | undefined;
if (boundTextElement) {
- if (keepAspectRatio) {
+ if (keepAspectRatio && !shouldMaintainAspectRatio) {
const newFontSize = boundTextElement.fontSize * scale;
if (newFontSize < MIN_FONT_SIZE) {
return;
diff --git a/packages/element/tests/groupResize.test.tsx b/packages/element/tests/groupResize.test.tsx
new file mode 100644
index 000000000..c3be95be1
--- /dev/null
+++ b/packages/element/tests/groupResize.test.tsx
@@ -0,0 +1,116 @@
+import { API } from "@excalidraw/excalidraw/tests/helpers/api";
+import { UI, Keyboard, Pointer } from "@excalidraw/excalidraw/tests/helpers/ui";
+import { KEYS } from "@excalidraw/common";
+import { unmountComponent } from "@excalidraw/excalidraw/tests/test-utils";
+import { render } from "@excalidraw/excalidraw/tests/test-utils";
+import { Excalidraw } from "@excalidraw/excalidraw";
+const { h } = window;
+const mouse = new Pointer("mouse");
+
+unmountComponent();
+
+describe("group resize", () => {
+ beforeEach(() => {
+ h.elements = [];
+ });
+
+ it("resizes group with locked aspect ratio using side handles", async () => {
+ await render();
+
+ UI.clickTool("rectangle");
+ mouse.down(10, 10);
+ mouse.up(10, 10);
+
+ UI.clickTool("rectangle");
+ mouse.down(10, -10);
+ mouse.up(10, 10);
+
+ UI.clickTool("rectangle");
+ mouse.down(10, -10);
+ mouse.up(10, 10);
+ const end = mouse.getPosition();
+
+ mouse.reset();
+ mouse.down();
+ mouse.restorePosition(...end);
+ mouse.up();
+
+ expect(h.elements.length).toBe(3);
+ for (const element of h.elements) {
+ expect(element.groupIds.length).toBe(0);
+ expect(h.state.selectedElementIds[element.id]).toBe(true);
+ }
+
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress(KEYS.G);
+ });
+
+ for (const element of h.elements) {
+ expect(element.groupIds.length).toBe(1);
+ }
+
+ mouse.select(h.elements[0]);
+ let originalWidth = h.elements[0].width;
+ let originalHeight = h.elements[0].height;
+
+ UI.resize(h.elements[0], 'se', [50, 50], { shift: true });
+
+ expect(h.elements[0].width).toBe(originalWidth + 50);
+ expect(h.elements[0].height).toBe(originalHeight + 50);
+
+ originalWidth = h.elements[0].width;
+ originalHeight = h.elements[0].height;
+
+ UI.resize(h.elements[0], "e", [50, 0], { shift: true });
+
+ expect(h.elements[0].width).toBe(originalWidth - 50);
+ expect(h.elements[0].height).toBe(originalHeight - 50);
+ });
+
+ it("resizes group with locked aspect ratio using corner handles", async () => {
+ await render();
+
+ UI.clickTool("rectangle");
+ mouse.down(10, 10);
+ mouse.up(10, 10);
+
+ UI.clickTool("rectangle");
+ mouse.down(10, -10);
+ mouse.up(10, 10);
+
+ UI.clickTool("rectangle");
+ mouse.down(10, -10);
+ mouse.up(10, 10);
+ const end = mouse.getPosition();
+
+ mouse.reset();
+ mouse.down();
+ mouse.restorePosition(...end);
+ mouse.up();
+
+ expect(h.elements.length).toBe(3);
+ for (const element of h.elements) {
+ expect(element.groupIds.length).toBe(0);
+ expect(h.state.selectedElementIds[element.id]).toBe(true);
+ }
+
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress(KEYS.G);
+ });
+
+ for (const element of h.elements) {
+ expect(element.groupIds.length).toBe(1);
+ }
+
+ mouse.select(h.elements[0]);
+
+ let originalWidth = h.elements[0].width;
+ let originalHeight = h.elements[0].height;
+
+ UI.resize(h.elements[0], "se", [50, 50], { shift: true });
+
+
+ expect(h.elements[0].width).toBe(originalWidth + 50);
+ expect(h.elements[0].height).toBe(originalHeight + 50);
+ });
+});
\ No newline at end of file