Переглянути джерело

fix: vertically center align the bounded text correctly when zoomed (#4444)

* fix: vertically center align the bounded text correctly when zoomed

* dnt add offsets since its calculated correctly

* set editor max width better when offsets present

* Update src/element/textWysiwyg.tsx

* const

* revert
Aakansha Doshi 3 роки тому
батько
коміт
081e097cef
1 змінених файлів з 38 додано та 24 видалено
  1. 38 24
      src/element/textWysiwyg.tsx

+ 38 - 24
src/element/textWysiwyg.tsx

@@ -2,7 +2,6 @@ import { CODES, KEYS } from "../keys";
 import {
   isWritableElement,
   getFontString,
-  viewportCoordsToSceneCoords,
   getFontFamilyString,
 } from "../utils";
 import Scene from "../scene/Scene";
@@ -37,16 +36,20 @@ const getTransform = (
   angle: number,
   appState: AppState,
   maxWidth: number,
+  maxHeight: number,
 ) => {
   const { zoom, offsetTop, offsetLeft } = appState;
   const degree = (180 * angle) / Math.PI;
   // offsets must be multiplied by 2 to account for the division by 2 of
   // the whole expression afterwards
   let translateX = ((width - offsetLeft * 2) * (zoom.value - 1)) / 2;
-  const translateY = ((height - offsetTop * 2) * (zoom.value - 1)) / 2;
+  let translateY = ((height - offsetTop * 2) * (zoom.value - 1)) / 2;
   if (width > maxWidth && zoom.value !== 1) {
     translateX = (maxWidth / 2) * (zoom.value - 1);
   }
+  if (height > maxHeight && zoom.value !== 1) {
+    translateY = ((maxHeight - offsetTop * 2) * (zoom.value - 1)) / 2;
+  }
   return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
 };
 
@@ -106,12 +109,13 @@ export const textWysiwyg = ({
 
       let maxHeight = updatedElement.height;
       let width = updatedElement.width;
-      let height = updatedElement.height;
+      const height = Math.max(editable.scrollHeight, updatedElement.height);
       if (container && updatedElement.containerId) {
         const propertiesUpdated = textPropertiesUpdated(
           updatedElement,
           editable,
         );
+
         if (propertiesUpdated) {
           const currentContainer = Scene.getScene(updatedElement)?.getElement(
             updatedElement.containerId,
@@ -133,15 +137,14 @@ export const textWysiwyg = ({
         maxWidth = container.width - PADDING * 2;
         maxHeight = container.height - PADDING * 2;
         width = maxWidth;
-        height = Math.min(height, maxHeight);
         // The coordinates of text box set a distance of
         // 30px to preserve padding
         coordX = container.x + PADDING;
 
         // autogrow container height if text exceeds
-        if (editable.clientHeight > maxHeight) {
+        if (editable.scrollHeight > maxHeight) {
           const diff = Math.min(
-            editable.clientHeight - maxHeight,
+            editable.scrollHeight - maxHeight,
             approxLineHeight,
           );
           mutateElement(container, { height: container.height + diff });
@@ -150,10 +153,10 @@ export const textWysiwyg = ({
           // autoshrink container height until original container height
           // is reached when text is removed
           container.height > originalContainerHeight &&
-          editable.clientHeight < maxHeight
+          editable.scrollHeight < maxHeight
         ) {
           const diff = Math.min(
-            maxHeight - editable.clientHeight,
+            maxHeight - editable.scrollHeight,
             approxLineHeight,
           );
           mutateElement(container, { height: container.height - diff });
@@ -161,18 +164,17 @@ export const textWysiwyg = ({
         // Start pushing text upward until a diff of 30px (padding)
         // is reached
         else {
-          const lines = editable.clientHeight / approxLineHeight;
+          const lines = editable.scrollHeight / approxLineHeight;
           // For some reason the scrollHeight gets set to twice the lineHeight
           // when you start typing for first time  and thus line count is 2
           // hence this check
           if (lines > 2 || propertiesUpdated) {
             // vertically center align the text
             coordY =
-              container.y + container.height / 2 - editable.clientHeight / 2;
+              container.y + container.height / 2 - editable.scrollHeight / 2;
           }
         }
       }
-
       const [viewportX, viewportY] = getViewportCoords(coordX, coordY);
       const { textAlign, angle } = updatedElement;
 
@@ -192,19 +194,35 @@ export const textWysiwyg = ({
             ).marginRight.slice(0, -2),
           );
       }
+
       // Make sure text editor height doesn't go beyond viewport
       const editorMaxHeight =
-        (appState.offsetTop + appState.height - viewportY) /
+        (appState.height -
+          viewportY -
+          // There is a ~14px difference which keeps on increasing
+          // with every zoom step when offset present hence I am subtracting it here
+          // However this is not the best fix and breaks in
+          // few scenarios
+          (appState.offsetTop
+            ? ((appState.zoom.value * 100 - 100) / 10) * 14
+            : 0)) /
         appState.zoom.value;
       Object.assign(editable.style, {
         font: getFontString(updatedElement),
         // must be defined *after* font ¯\_(ツ)_/¯
         lineHeight: `${lineHeight}px`,
         width: `${width}px`,
-        height: `${Math.max(editable.clientHeight, updatedElement.height)}px`,
+        height: `${height}px`,
         left: `${viewportX}px`,
         top: `${viewportY}px`,
-        transform: getTransform(width, height, angle, appState, maxWidth),
+        transform: getTransform(
+          width,
+          height,
+          angle,
+          appState,
+          maxWidth,
+          editorMaxHeight,
+        ),
         textAlign,
         color: updatedElement.strokeColor,
         opacity: updatedElement.opacity / 100,
@@ -416,20 +434,16 @@ export const textWysiwyg = ({
           getFontString(updateElement),
           container.width,
         );
-        const { x, y } = viewportCoordsToSceneCoords(
-          {
-            clientX: Number(editable.style.left.slice(0, -2)),
-            clientY: Number(editable.style.top.slice(0, -2)),
-          },
-          appState,
-        );
         if (isTextElement(updateElement) && updateElement.containerId) {
+          const editorHeight = Number(editable.style.height.slice(0, -2));
           if (editable.value) {
             mutateElement(updateElement, {
-              y: y + appState.offsetTop,
-              height: Number(editable.style.height.slice(0, -2)),
+              // vertically center align
+              y: container.y + container.height / 2 - editorHeight / 2,
+              height: editorHeight,
               width: Number(editable.style.width.slice(0, -2)),
-              x: x + appState.offsetLeft,
+              // preserve padding
+              x: container.x + PADDING,
             });
             const boundTextElementId = getBoundTextElementId(container);
             if (!boundTextElementId || boundTextElementId !== element.id) {