diff --git a/src/components/App.tsx b/src/components/App.tsx index 91a6cbe7f..bbb90f0c5 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2399,7 +2399,6 @@ class App extends React.Component { ); } } - const element = existingTextElement ? existingTextElement : newTextElement({ diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 2d6a12afe..848ab0dc8 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -21,7 +21,12 @@ import { AppState } from "../types"; import { getElementAbsoluteCoords } from "."; import { adjustXYWithRotation } from "../math"; import { getResizedElementAbsoluteCoords } from "./bounds"; -import { getContainerElement, measureText, wrapText } from "./textElement"; +import { + getContainerElement, + getContainerDims, + measureText, + wrapText, +} from "./textElement"; import { BOUND_TEXT_PADDING, VERTICAL_ALIGN } from "../constants"; type ElementConstructorOpts = MarkOptional< @@ -164,7 +169,9 @@ const getAdjustedDimensions = ( let maxWidth = null; const container = getContainerElement(element); if (container) { - maxWidth = container.width - BOUND_TEXT_PADDING * 2; + const containerDims = getContainerDims(container); + + maxWidth = containerDims.width - BOUND_TEXT_PADDING * 2; } const { width: nextWidth, @@ -224,16 +231,21 @@ const getAdjustedDimensions = ( // make sure container dimensions are set properly when // text editor overflows beyond viewport dimensions if (container) { - let height = container.height; - let width = container.width; + const containerDims = getContainerDims(container); + let { width, height } = containerDims; if (nextHeight > height - BOUND_TEXT_PADDING * 2) { height = nextHeight + BOUND_TEXT_PADDING * 2; } if (nextWidth > width - BOUND_TEXT_PADDING * 2) { width = nextWidth + BOUND_TEXT_PADDING * 2; } - if (height !== container.height || width !== container.width) { - mutateElement(container, { height, width }); + if (height !== containerDims.height || width !== containerDims.height) { + const diffHeight = height - containerDims.height; + const diffWidth = width - containerDims.width; + mutateElement(container, { + height: container.height + diffHeight, + width: container.width + diffWidth, + }); } } return { @@ -259,7 +271,11 @@ export const updateTextElement = ( ): ExcalidrawTextElement => { const container = getContainerElement(element); if (container) { - text = wrapText(text, getFontString(element), container.width); + text = wrapText( + text, + getFontString(element), + getContainerDims(container).width, + ); } const dimensions = getAdjustedDimensions(element, text); return newElementWith(element, { diff --git a/src/element/textElement.ts b/src/element/textElement.ts index f1969a89e..604ff8f82 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -16,16 +16,20 @@ export const redrawTextBoundingBox = ( element: ExcalidrawTextElement, container: ExcalidrawElement | null, ) => { - const maxWidth = container - ? container.width - BOUND_TEXT_PADDING * 2 + let containerDims; + if (container) { + containerDims = getContainerDims(container); + } + const maxWidth = containerDims + ? containerDims.width - BOUND_TEXT_PADDING * 2 : undefined; let text = element.text; - if (container) { + if (containerDims) { text = wrapText( element.originalText, getFontString(element), - container.width, + containerDims.width, ); } const metrics = measureText( @@ -37,18 +41,24 @@ export const redrawTextBoundingBox = ( let coordX = element.x; // Resize container and vertically center align the text if (container) { - let nextHeight = container.height; - coordX = container.x + BOUND_TEXT_PADDING; + const containerDims = getContainerDims(container); + const containerCoords = getBoundTextContainerCoords(container); + let nextHeight = containerDims.height; + coordX = containerCoords.x + BOUND_TEXT_PADDING; if (element.verticalAlign === VERTICAL_ALIGN.TOP) { - coordY = container.y + BOUND_TEXT_PADDING; + coordY = containerCoords.y + BOUND_TEXT_PADDING; } else if (element.verticalAlign === VERTICAL_ALIGN.BOTTOM) { coordY = - container.y + container.height - metrics.height - BOUND_TEXT_PADDING; + containerCoords.y + + containerDims.height - + metrics.height - + BOUND_TEXT_PADDING; } else { - coordY = container.y + container.height / 2 - metrics.height / 2; - if (metrics.height > container.height - BOUND_TEXT_PADDING * 2) { + coordY = + containerCoords.y + containerDims.height / 2 - metrics.height / 2; + if (metrics.height > containerDims.height - BOUND_TEXT_PADDING * 2) { nextHeight = metrics.height + BOUND_TEXT_PADDING * 2; - coordY = container.y + nextHeight / 2 - metrics.height / 2; + coordY = containerCoords.y + nextHeight / 2 - metrics.height / 2; } } mutateElement(container, { height: nextHeight }); @@ -121,7 +131,7 @@ export const handleBindTextResize = ( text = wrapText( textElement.originalText, getFontString(textElement), - element.width, + getContainerDims(element).width, ); } @@ -474,3 +484,28 @@ export const getContainerElement = ( } return null; }; + +export const getContainerDims = (element: ExcalidrawElement) => { + if (element.type === "ellipse") { + return { + width: Math.round((element.width / 2) * Math.sqrt(2)), + height: Math.round((element.height / 2) * Math.sqrt(2)), + }; + } + return { width: element.width, height: element.height }; +}; + +export const getBoundTextContainerCoords = (container: ExcalidrawElement) => { + if (container.type === "ellipse") { + const offsetX = (container.width / 2) * (1 - Math.sqrt(2) / 2); + const offsetY = (container.height / 2) * (1 - Math.sqrt(2) / 2); + return { + x: container.x + offsetX, + y: container.y + offsetY, + }; + } + return { + x: container.x, + y: container.y, + }; +}; diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index 1bd940deb..6d5618ecb 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -19,7 +19,9 @@ import { getApproxLineHeight, getBoundTextElementId, getContainerElement, + getContainerDims, wrapText, + getBoundTextContainerCoords, } from "./textElement"; import { actionDecreaseFontSize, @@ -126,26 +128,28 @@ export const textWysiwyg = ({ updatedElement, editable, ); + const containerDims = getContainerDims(container); // using editor.style.height to get the accurate height of text editor const editorHeight = Number(editable.style.height.slice(0, -2)); if (editorHeight > 0) { height = editorHeight; } if (propertiesUpdated) { - originalContainerHeight = container.height; + originalContainerHeight = containerDims.height; // update height of the editor after properties updated height = updatedElement.height; } if (!originalContainerHeight) { - originalContainerHeight = container.height; + originalContainerHeight = containerDims.height; } - maxWidth = container.width - BOUND_TEXT_PADDING * 2; - maxHeight = container.height - BOUND_TEXT_PADDING * 2; + maxWidth = containerDims.width - BOUND_TEXT_PADDING * 2; + maxHeight = containerDims.height - BOUND_TEXT_PADDING * 2; width = maxWidth; + const boundTextCoords = getBoundTextContainerCoords(container); // The coordinates of text box set a distance of // 5px to preserve padding - coordX = container.x + BOUND_TEXT_PADDING; + coordX = boundTextCoords.x + BOUND_TEXT_PADDING; // autogrow container height if text exceeds if (height > maxHeight) { const diff = Math.min(height - maxHeight, approxLineHeight); @@ -154,7 +158,7 @@ export const textWysiwyg = ({ } else if ( // autoshrink container height until original container height // is reached when text is removed - container.height > originalContainerHeight && + containerDims.height > originalContainerHeight && height < maxHeight ) { const diff = Math.min(maxHeight - height, approxLineHeight); @@ -165,11 +169,14 @@ export const textWysiwyg = ({ else { // vertically center align the text if (verticalAlign === VERTICAL_ALIGN.MIDDLE) { - coordY = container.y + container.height / 2 - height / 2; + coordY = boundTextCoords.y + containerDims.height / 2 - height / 2; } if (verticalAlign === VERTICAL_ALIGN.BOTTOM) { coordY = - container.y + container.height - height - BOUND_TEXT_PADDING; + boundTextCoords.y + + containerDims.height - + height - + BOUND_TEXT_PADDING; } } } @@ -303,7 +310,7 @@ export const textWysiwyg = ({ const actualLineCount = wrapText( editable.value, font, - container!.width, + getContainerDims(container!).width, ).split("\n").length; // This is browser behaviour when setting height to "auto" // It sets the height needed for 2 lines even if actual