|  | @@ -4,6 +4,7 @@ import { rescalePoints } from "../points";
 | 
	
		
			
				|  |  |  import { rotate, adjustXYWithRotation, getFlipAdjustment } from "../math";
 | 
	
		
			
				|  |  |  import {
 | 
	
		
			
				|  |  |    ExcalidrawLinearElement,
 | 
	
		
			
				|  |  | +  ExcalidrawTextElement,
 | 
	
		
			
				|  |  |    NonDeletedExcalidrawElement,
 | 
	
		
			
				|  |  |    NonDeleted,
 | 
	
		
			
				|  |  |  } from "./types";
 | 
	
	
		
			
				|  | @@ -24,6 +25,7 @@ import {
 | 
	
		
			
				|  |  |    getResizeCenterPointKey,
 | 
	
		
			
				|  |  |    getResizeWithSidesSameLengthKey,
 | 
	
		
			
				|  |  |  } from "../keys";
 | 
	
		
			
				|  |  | +import { measureText, getFontString } from "../utils";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  type ResizeTestType = ReturnType<typeof resizeTest>;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -55,6 +57,20 @@ export const resizeElements = (
 | 
	
		
			
				|  |  |          pointerX,
 | 
	
		
			
				|  |  |          pointerY,
 | 
	
		
			
				|  |  |        );
 | 
	
		
			
				|  |  | +    } else if (
 | 
	
		
			
				|  |  | +      element.type === "text" &&
 | 
	
		
			
				|  |  | +      (resizeHandle === "nw" ||
 | 
	
		
			
				|  |  | +        resizeHandle === "ne" ||
 | 
	
		
			
				|  |  | +        resizeHandle === "sw" ||
 | 
	
		
			
				|  |  | +        resizeHandle === "se")
 | 
	
		
			
				|  |  | +    ) {
 | 
	
		
			
				|  |  | +      resizeSingleTextElement(
 | 
	
		
			
				|  |  | +        element,
 | 
	
		
			
				|  |  | +        resizeHandle,
 | 
	
		
			
				|  |  | +        getResizeCenterPointKey(event),
 | 
	
		
			
				|  |  | +        pointerX,
 | 
	
		
			
				|  |  | +        pointerY,
 | 
	
		
			
				|  |  | +      );
 | 
	
		
			
				|  |  |      } else if (resizeHandle) {
 | 
	
		
			
				|  |  |        resizeSingleElement(
 | 
	
		
			
				|  |  |          element,
 | 
	
	
		
			
				|  | @@ -188,6 +204,95 @@ const rescalePointsInElement = (
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      : {};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const resizeSingleTextElement = (
 | 
	
		
			
				|  |  | +  element: NonDeleted<ExcalidrawTextElement>,
 | 
	
		
			
				|  |  | +  resizeHandle: "nw" | "ne" | "sw" | "se",
 | 
	
		
			
				|  |  | +  isResizeFromCenter: boolean,
 | 
	
		
			
				|  |  | +  pointerX: number,
 | 
	
		
			
				|  |  | +  pointerY: number,
 | 
	
		
			
				|  |  | +) => {
 | 
	
		
			
				|  |  | +  const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
 | 
	
		
			
				|  |  | +  const cx = (x1 + x2) / 2;
 | 
	
		
			
				|  |  | +  const cy = (y1 + y2) / 2;
 | 
	
		
			
				|  |  | +  // rotation pointer with reverse angle
 | 
	
		
			
				|  |  | +  const [rotatedX, rotatedY] = rotate(
 | 
	
		
			
				|  |  | +    pointerX,
 | 
	
		
			
				|  |  | +    pointerY,
 | 
	
		
			
				|  |  | +    cx,
 | 
	
		
			
				|  |  | +    cy,
 | 
	
		
			
				|  |  | +    -element.angle,
 | 
	
		
			
				|  |  | +  );
 | 
	
		
			
				|  |  | +  let scale;
 | 
	
		
			
				|  |  | +  switch (resizeHandle) {
 | 
	
		
			
				|  |  | +    case "se":
 | 
	
		
			
				|  |  | +      scale = Math.max(
 | 
	
		
			
				|  |  | +        (rotatedX - x1) / (x2 - x1),
 | 
	
		
			
				|  |  | +        (rotatedY - y1) / (y2 - y1),
 | 
	
		
			
				|  |  | +      );
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  | +    case "nw":
 | 
	
		
			
				|  |  | +      scale = Math.max(
 | 
	
		
			
				|  |  | +        (x2 - rotatedX) / (x2 - x1),
 | 
	
		
			
				|  |  | +        (y2 - rotatedY) / (y2 - y1),
 | 
	
		
			
				|  |  | +      );
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  | +    case "ne":
 | 
	
		
			
				|  |  | +      scale = Math.max(
 | 
	
		
			
				|  |  | +        (rotatedX - x1) / (x2 - x1),
 | 
	
		
			
				|  |  | +        (y2 - rotatedY) / (y2 - y1),
 | 
	
		
			
				|  |  | +      );
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  | +    case "sw":
 | 
	
		
			
				|  |  | +      scale = Math.max(
 | 
	
		
			
				|  |  | +        (x2 - rotatedX) / (x2 - x1),
 | 
	
		
			
				|  |  | +        (rotatedY - y1) / (y2 - y1),
 | 
	
		
			
				|  |  | +      );
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (scale > 0) {
 | 
	
		
			
				|  |  | +    const newFontSize = Math.max(element.fontSize * scale, 10);
 | 
	
		
			
				|  |  | +    const metrics = measureText(
 | 
	
		
			
				|  |  | +      element.text,
 | 
	
		
			
				|  |  | +      getFontString({ fontSize: newFontSize, fontFamily: element.fontFamily }),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +    if (
 | 
	
		
			
				|  |  | +      Math.abs(metrics.width - element.width) <= 1 ||
 | 
	
		
			
				|  |  | +      Math.abs(metrics.height - element.height) <= 1
 | 
	
		
			
				|  |  | +    ) {
 | 
	
		
			
				|  |  | +      // we ignore 1px change to avoid janky behavior
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    const [nextX1, nextY1, nextX2, nextY2] = getResizedElementAbsoluteCoords(
 | 
	
		
			
				|  |  | +      element,
 | 
	
		
			
				|  |  | +      metrics.width,
 | 
	
		
			
				|  |  | +      metrics.height,
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +    const deltaX1 = (x1 - nextX1) / 2;
 | 
	
		
			
				|  |  | +    const deltaY1 = (y1 - nextY1) / 2;
 | 
	
		
			
				|  |  | +    const deltaX2 = (x2 - nextX2) / 2;
 | 
	
		
			
				|  |  | +    const deltaY2 = (y2 - nextY2) / 2;
 | 
	
		
			
				|  |  | +    const [nextElementX, nextElementY] = adjustXYWithRotation(
 | 
	
		
			
				|  |  | +      resizeHandle,
 | 
	
		
			
				|  |  | +      element.x,
 | 
	
		
			
				|  |  | +      element.y,
 | 
	
		
			
				|  |  | +      element.angle,
 | 
	
		
			
				|  |  | +      deltaX1,
 | 
	
		
			
				|  |  | +      deltaY1,
 | 
	
		
			
				|  |  | +      deltaX2,
 | 
	
		
			
				|  |  | +      deltaY2,
 | 
	
		
			
				|  |  | +      isResizeFromCenter,
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +    mutateElement(element, {
 | 
	
		
			
				|  |  | +      fontSize: newFontSize,
 | 
	
		
			
				|  |  | +      width: metrics.width,
 | 
	
		
			
				|  |  | +      height: metrics.height,
 | 
	
		
			
				|  |  | +      baseline: metrics.baseline,
 | 
	
		
			
				|  |  | +      x: nextElementX,
 | 
	
		
			
				|  |  | +      y: nextElementY,
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  const resizeSingleElement = (
 | 
	
		
			
				|  |  |    element: NonDeletedExcalidrawElement,
 | 
	
		
			
				|  |  |    resizeHandle: "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se",
 |