Browse Source

fix: cleanup getMaxContainerHeight and getMaxContainerWidth (#6519)

* fix: cleanup getMaxContainerHeight and getMaxContainerWidth

* rename getMaxContainerWidth -> getBoundTextMaxMaxWidth and getMaxContainerHeight -> getBoundTextMaxHeight

* add specs
Aakansha Doshi 2 years ago
parent
commit
da8dd389a9

+ 2 - 2
src/element/newElement.ts

@@ -33,7 +33,7 @@ import {
   measureText,
   normalizeText,
   wrapText,
-  getMaxContainerWidth,
+  getBoundTextMaxWidth,
   getDefaultLineHeight,
 } from "./textElement";
 import {
@@ -310,7 +310,7 @@ export const refreshTextDimensions = (
     text = wrapText(
       text,
       getFontString(textElement),
-      getMaxContainerWidth(container),
+      getBoundTextMaxWidth(container),
     );
   }
   const dimensions = getAdjustedDimensions(textElement, text);

+ 7 - 7
src/element/resizeElements.ts

@@ -44,10 +44,10 @@ import {
   getBoundTextElementId,
   getContainerElement,
   handleBindTextResize,
-  getMaxContainerWidth,
+  getBoundTextMaxWidth,
   getApproxMinLineHeight,
   measureText,
-  getMaxContainerHeight,
+  getBoundTextMaxHeight,
 } from "./textElement";
 
 export const normalizeAngle = (angle: number): number => {
@@ -204,7 +204,7 @@ const measureFontSizeFromWidth = (
   if (hasContainer) {
     const container = getContainerElement(element);
     if (container) {
-      width = getMaxContainerWidth(container);
+      width = getBoundTextMaxWidth(container);
     }
   }
   const nextFontSize = element.fontSize * (nextWidth / width);
@@ -435,8 +435,8 @@ export const resizeSingleElement = (
 
       const nextFont = measureFontSizeFromWidth(
         boundTextElement,
-        getMaxContainerWidth(updatedElement),
-        getMaxContainerHeight(updatedElement),
+        getBoundTextMaxWidth(updatedElement),
+        getBoundTextMaxHeight(updatedElement, boundTextElement),
       );
       if (nextFont === null) {
         return;
@@ -718,10 +718,10 @@ const resizeMultipleElements = (
       const metrics = measureFontSizeFromWidth(
         boundTextElement ?? (element.orig as ExcalidrawTextElement),
         boundTextElement
-          ? getMaxContainerWidth(updatedElement)
+          ? getBoundTextMaxWidth(updatedElement)
           : updatedElement.width,
         boundTextElement
-          ? getMaxContainerHeight(updatedElement)
+          ? getBoundTextMaxHeight(updatedElement, boundTextElement)
           : updatedElement.height,
       );
 

+ 48 - 11
src/element/textElement.test.ts

@@ -3,15 +3,15 @@ import { API } from "../tests/helpers/api";
 import {
   computeContainerDimensionForBoundText,
   getContainerCoords,
-  getMaxContainerWidth,
-  getMaxContainerHeight,
+  getBoundTextMaxWidth,
+  getBoundTextMaxHeight,
   wrapText,
   detectLineHeight,
   getLineHeightInPx,
   getDefaultLineHeight,
   parseTokens,
 } from "./textElement";
-import { FontString } from "./types";
+import { ExcalidrawTextElementWithContainer, FontString } from "./types";
 
 describe("Test wrapText", () => {
   const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
@@ -311,7 +311,7 @@ describe("Test measureText", () => {
     });
   });
 
-  describe("Test getMaxContainerWidth", () => {
+  describe("Test getBoundTextMaxWidth", () => {
     const params = {
       width: 178,
       height: 194,
@@ -319,39 +319,76 @@ describe("Test measureText", () => {
 
     it("should return max width when container is rectangle", () => {
       const container = API.createElement({ type: "rectangle", ...params });
-      expect(getMaxContainerWidth(container)).toBe(168);
+      expect(getBoundTextMaxWidth(container)).toBe(168);
     });
 
     it("should return max width when container is ellipse", () => {
       const container = API.createElement({ type: "ellipse", ...params });
-      expect(getMaxContainerWidth(container)).toBe(116);
+      expect(getBoundTextMaxWidth(container)).toBe(116);
     });
 
     it("should return max width when container is diamond", () => {
       const container = API.createElement({ type: "diamond", ...params });
-      expect(getMaxContainerWidth(container)).toBe(79);
+      expect(getBoundTextMaxWidth(container)).toBe(79);
     });
   });
 
-  describe("Test getMaxContainerHeight", () => {
+  describe("Test getBoundTextMaxHeight", () => {
     const params = {
       width: 178,
       height: 194,
+      id: '"container-id',
     };
 
+    const boundTextElement = API.createElement({
+      type: "text",
+      id: "text-id",
+      x: 560.51171875,
+      y: 202.033203125,
+      width: 154,
+      height: 175,
+      fontSize: 20,
+      fontFamily: 1,
+      text: "Excalidraw is a\nvirtual \nopensource \nwhiteboard for \nsketching \nhand-drawn like\ndiagrams",
+      textAlign: "center",
+      verticalAlign: "middle",
+      containerId: params.id,
+    }) as ExcalidrawTextElementWithContainer;
+
     it("should return max height when container is rectangle", () => {
       const container = API.createElement({ type: "rectangle", ...params });
-      expect(getMaxContainerHeight(container)).toBe(184);
+      expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(184);
     });
 
     it("should return max height when container is ellipse", () => {
       const container = API.createElement({ type: "ellipse", ...params });
-      expect(getMaxContainerHeight(container)).toBe(127);
+      expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(127);
     });
 
     it("should return max height when container is diamond", () => {
       const container = API.createElement({ type: "diamond", ...params });
-      expect(getMaxContainerHeight(container)).toBe(87);
+      expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(87);
+    });
+
+    it("should return max height when container is arrow", () => {
+      const container = API.createElement({
+        type: "arrow",
+        ...params,
+      });
+      expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(194);
+    });
+
+    it("should return max height when container is arrow and height is less than threshold", () => {
+      const container = API.createElement({
+        type: "arrow",
+        ...params,
+        height: 70,
+        boundElements: [{ type: "text", id: "text-id" }],
+      });
+
+      expect(getBoundTextMaxHeight(container, boundTextElement)).toBe(
+        boundTextElement.height,
+      );
     });
   });
 });

+ 19 - 22
src/element/textElement.ts

@@ -65,7 +65,7 @@ export const redrawTextBoundingBox = (
   boundTextUpdates.text = textElement.text;
 
   if (container) {
-    maxWidth = getMaxContainerWidth(container);
+    maxWidth = getBoundTextMaxWidth(container);
     boundTextUpdates.text = wrapText(
       textElement.originalText,
       getFontString(textElement),
@@ -84,7 +84,10 @@ export const redrawTextBoundingBox = (
 
   if (container) {
     const containerDims = getContainerDims(container);
-    const maxContainerHeight = getMaxContainerHeight(container);
+    const maxContainerHeight = getBoundTextMaxHeight(
+      container,
+      textElement as ExcalidrawTextElementWithContainer,
+    );
 
     let nextHeight = containerDims.height;
     if (metrics.height > maxContainerHeight) {
@@ -173,8 +176,11 @@ export const handleBindTextResize = (
     let nextHeight = textElement.height;
     let nextWidth = textElement.width;
     const containerDims = getContainerDims(container);
-    const maxWidth = getMaxContainerWidth(container);
-    const maxHeight = getMaxContainerHeight(container);
+    const maxWidth = getBoundTextMaxWidth(container);
+    const maxHeight = getBoundTextMaxHeight(
+      container,
+      textElement as ExcalidrawTextElementWithContainer,
+    );
     let containerHeight = containerDims.height;
     let nextBaseLine = textElement.baseline;
     if (transformHandleType !== "n" && transformHandleType !== "s") {
@@ -246,8 +252,8 @@ export const computeBoundTextPosition = (
     );
   }
   const containerCoords = getContainerCoords(container);
-  const maxContainerHeight = getMaxContainerHeight(container);
-  const maxContainerWidth = getMaxContainerWidth(container);
+  const maxContainerHeight = getBoundTextMaxHeight(container, boundTextElement);
+  const maxContainerWidth = getBoundTextMaxWidth(container);
 
   let x;
   let y;
@@ -880,18 +886,10 @@ export const computeContainerDimensionForBoundText = (
   return dimension + padding;
 };
 
-export const getMaxContainerWidth = (container: ExcalidrawElement) => {
+export const getBoundTextMaxWidth = (container: ExcalidrawElement) => {
   const width = getContainerDims(container).width;
   if (isArrowElement(container)) {
-    const containerWidth = width - BOUND_TEXT_PADDING * 8 * 2;
-    if (containerWidth <= 0) {
-      const boundText = getBoundTextElement(container);
-      if (boundText) {
-        return boundText.width;
-      }
-      return BOUND_TEXT_PADDING * 8 * 2;
-    }
-    return containerWidth;
+    return width - BOUND_TEXT_PADDING * 8 * 2;
   }
 
   if (container.type === "ellipse") {
@@ -908,16 +906,15 @@ export const getMaxContainerWidth = (container: ExcalidrawElement) => {
   return width - BOUND_TEXT_PADDING * 2;
 };
 
-export const getMaxContainerHeight = (container: ExcalidrawElement) => {
+export const getBoundTextMaxHeight = (
+  container: ExcalidrawElement,
+  boundTextElement: ExcalidrawTextElementWithContainer,
+) => {
   const height = getContainerDims(container).height;
   if (isArrowElement(container)) {
     const containerHeight = height - BOUND_TEXT_PADDING * 8 * 2;
     if (containerHeight <= 0) {
-      const boundText = getBoundTextElement(container);
-      if (boundText) {
-        return boundText.height;
-      }
-      return BOUND_TEXT_PADDING * 8 * 2;
+      return boundTextElement.height;
     }
     return height;
   }

+ 9 - 6
src/element/textWysiwyg.tsx

@@ -32,8 +32,8 @@ import {
   normalizeText,
   redrawTextBoundingBox,
   wrapText,
-  getMaxContainerHeight,
-  getMaxContainerWidth,
+  getBoundTextMaxHeight,
+  getBoundTextMaxWidth,
   computeContainerDimensionForBoundText,
   detectLineHeight,
 } from "./textElement";
@@ -205,8 +205,11 @@ export const textWysiwyg = ({
           }
         }
 
-        maxWidth = getMaxContainerWidth(container);
-        maxHeight = getMaxContainerHeight(container);
+        maxWidth = getBoundTextMaxWidth(container);
+        maxHeight = getBoundTextMaxHeight(
+          container,
+          updatedTextElement as ExcalidrawTextElementWithContainer,
+        );
 
         // autogrow container height if text exceeds
         if (!isArrowElement(container) && textElementHeight > maxHeight) {
@@ -377,7 +380,7 @@ export const textWysiwyg = ({
         const wrappedText = wrapText(
           `${editable.value}${data}`,
           font,
-          getMaxContainerWidth(container),
+          getBoundTextMaxWidth(container),
         );
         const width = getTextWidth(wrappedText, font);
         editable.style.width = `${width}px`;
@@ -394,7 +397,7 @@ export const textWysiwyg = ({
         const wrappedText = wrapText(
           normalizeText(editable.value),
           font,
-          getMaxContainerWidth(container!),
+          getBoundTextMaxWidth(container!),
         );
         const { width, height } = measureText(
           wrappedText,

+ 7 - 4
src/renderer/renderElement.ts

@@ -44,8 +44,8 @@ import {
   getContainerCoords,
   getContainerElement,
   getLineHeightInPx,
-  getMaxContainerHeight,
-  getMaxContainerWidth,
+  getBoundTextMaxHeight,
+  getBoundTextMaxWidth,
 } from "../element/textElement";
 import { LinearElementEditor } from "../element/linearElementEditor";
 
@@ -868,14 +868,17 @@ const drawElementFromCanvas = (
         "true" &&
       hasBoundTextElement(element)
     ) {
+      const textElement = getBoundTextElement(
+        element,
+      ) as ExcalidrawTextElementWithContainer;
       const coords = getContainerCoords(element);
       context.strokeStyle = "#c92a2a";
       context.lineWidth = 3;
       context.strokeRect(
         (coords.x + renderConfig.scrollX) * window.devicePixelRatio,
         (coords.y + renderConfig.scrollY) * window.devicePixelRatio,
-        getMaxContainerWidth(element) * window.devicePixelRatio,
-        getMaxContainerHeight(element) * window.devicePixelRatio,
+        getBoundTextMaxWidth(element) * window.devicePixelRatio,
+        getBoundTextMaxHeight(element, textElement) * window.devicePixelRatio,
       );
     }
   }

+ 4 - 4
src/tests/linearElementEditor.test.tsx

@@ -20,7 +20,7 @@ import { resize, rotate } from "./utils";
 import {
   getBoundTextElementPosition,
   wrapText,
-  getMaxContainerWidth,
+  getBoundTextMaxWidth,
 } from "../element/textElement";
 import * as textElementUtils from "../element/textElement";
 import { ROUNDNESS, VERTICAL_ALIGN } from "../constants";
@@ -729,7 +729,7 @@ describe("Test Linear Elements", () => {
         type: "text",
         x: 0,
         y: 0,
-        text: wrapText(text, font, getMaxContainerWidth(container)),
+        text: wrapText(text, font, getBoundTextMaxWidth(container)),
         containerId: container.id,
         width: 30,
         height: 20,
@@ -1149,7 +1149,7 @@ describe("Test Linear Elements", () => {
       expect(rect.x).toBe(400);
       expect(rect.y).toBe(0);
       expect(
-        wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)),
+        wrapText(textElement.originalText, font, getBoundTextMaxWidth(arrow)),
       ).toMatchInlineSnapshot(`
         "Online whiteboard collaboration
         made easy"
@@ -1172,7 +1172,7 @@ describe("Test Linear Elements", () => {
         false,
       );
       expect(
-        wrapText(textElement.originalText, font, getMaxContainerWidth(arrow)),
+        wrapText(textElement.originalText, font, getBoundTextMaxWidth(arrow)),
       ).toMatchInlineSnapshot(`
         "Online whiteboard 
         collaboration made