From f8b25375a4f6554e4152d7a6f1c16711018d8103 Mon Sep 17 00:00:00 2001 From: Aakansha Doshi Date: Fri, 31 Mar 2023 15:53:03 +0530 Subject: [PATCH] introduce baseline in element making it backward compat --- src/actions/actionBoundText.tsx | 3 ++- src/components/App.tsx | 11 ++++----- src/data/restore.ts | 42 ++++++++++++++++++++------------- src/element/newElement.ts | 15 ++++++++---- src/element/textElement.ts | 17 ++++++++----- src/element/textWysiwyg.tsx | 11 +++++---- src/element/types.ts | 1 + src/renderer/renderElement.ts | 41 +------------------------------- 8 files changed, 62 insertions(+), 79 deletions(-) diff --git a/src/actions/actionBoundText.tsx b/src/actions/actionBoundText.tsx index 639a003fc..e790bf2a1 100644 --- a/src/actions/actionBoundText.tsx +++ b/src/actions/actionBoundText.tsx @@ -42,7 +42,7 @@ export const actionUnbindText = register({ selectedElements.forEach((element) => { const boundTextElement = getBoundTextElement(element); if (boundTextElement) { - const { width, height } = measureText( + const { width, height, baseline } = measureText( boundTextElement.originalText, getFontString(boundTextElement), boundTextElement.lineHeight, @@ -56,6 +56,7 @@ export const actionUnbindText = register({ containerId: null, width, height, + baseline, text: boundTextElement.originalText, }); mutateElement(element, { diff --git a/src/components/App.tsx b/src/components/App.tsx index 3369dd306..9b4fc864d 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1348,14 +1348,13 @@ class App extends React.Component { return false; } } - return true; // don't render text element that's being currently edited (it's // rendered on remote only) - // return ( - // !this.state.editingElement || - // this.state.editingElement.type !== "text" || - // element.id !== this.state.editingElement.id - // ); + return ( + !this.state.editingElement || + this.state.editingElement.type !== "text" || + element.id !== this.state.editingElement.id + ); }); const selectionColor = getComputedStyle( diff --git a/src/data/restore.ts b/src/data/restore.ts index 57ea329c3..fdf11b4d3 100644 --- a/src/data/restore.ts +++ b/src/data/restore.ts @@ -31,11 +31,15 @@ import { import { getDefaultAppState } from "../appState"; import { LinearElementEditor } from "../element/linearElementEditor"; import { bumpVersion } from "../element/mutateElement"; -import { getUpdatedTimestamp, updateActiveTool } from "../utils"; +import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils"; import { arrayToMap } from "../utils"; import oc from "open-color"; import { MarkOptional, Mutable } from "../utility-types"; -import { detectLineHeight, getDefaultLineHeight } from "../element/textElement"; +import { + detectLineHeight, + getDefaultLineHeight, + measureBaseline, +} from "../element/textElement"; type RestoredAppState = Omit< AppState, @@ -170,7 +174,19 @@ const restoreElement = ( fontFamily = getFontFamilyByName(_fontFamily); } const text = element.text ?? ""; - + // line-height might not be specified either when creating elements + // programmatically, or when importing old diagrams. + // For the latter we want to detect the original line height which + // will likely differ from our per-font fixed line height we now use, + // to maintain backward compatibility. + const lineHeight = + element.lineHeight || + (element.height + ? // detect line-height from current element height and font-size + detectLineHeight(element) + : // no element height likely means programmatic use, so default + // to a fixed line height + getDefaultLineHeight(element.fontFamily)); element = restoreElementWithProperties(element, { fontSize, fontFamily, @@ -179,19 +195,13 @@ const restoreElement = ( verticalAlign: element.verticalAlign || DEFAULT_VERTICAL_ALIGN, containerId: element.containerId ?? null, originalText: element.originalText || text, - // line-height might not be specified either when creating elements - // programmatically, or when importing old diagrams. - // For the latter we want to detect the original line height which - // will likely differ from our per-font fixed line height we now use, - // to maintain backward compatibility. - lineHeight: - element.lineHeight || - (element.height - ? // detect line-height from current element height and font-size - detectLineHeight(element) - : // no element height likely means programmatic use, so default - // to a fixed line height - getDefaultLineHeight(element.fontFamily)), + + lineHeight, + baseline: measureBaseline( + element.text, + getFontString(element), + lineHeight, + ), }); if (refreshDimensions) { diff --git a/src/element/newElement.ts b/src/element/newElement.ts index 6581097cd..fd8937293 100644 --- a/src/element/newElement.ts +++ b/src/element/newElement.ts @@ -30,6 +30,7 @@ import { wrapText, getMaxContainerWidth, getDefaultLineHeight, + measureBaseline, } from "./textElement"; import { VERTICAL_ALIGN } from "../constants"; import { isArrowElement } from "./typeChecks"; @@ -145,6 +146,7 @@ export const newTextElement = ( const text = normalizeText(opts.text); const metrics = measureText(text, getFontString(opts), lineHeight); const offsets = getTextElementPositionOffsets(opts, metrics); + const textElement = newElementWith( { ..._newElementBase("text", opts), @@ -157,6 +159,7 @@ export const newTextElement = ( y: opts.y - offsets.y, width: metrics.width, height: metrics.height, + baseline: metrics.baseline, containerId: opts.containerId || null, originalText: text, lineHeight, @@ -174,14 +177,15 @@ const getAdjustedDimensions = ( y: number; width: number; height: number; + baseline: number; } => { const container = getContainerElement(element); - const { width: nextWidth, height: nextHeight } = measureText( - nextText, - getFontString(element), - element.lineHeight, - ); + const { + width: nextWidth, + height: nextHeight, + baseline: nextBaseline, + } = measureText(nextText, getFontString(element), element.lineHeight); const { textAlign, verticalAlign } = element; let x: number; let y: number; @@ -256,6 +260,7 @@ const getAdjustedDimensions = ( return { width: nextWidth, height: nextHeight, + baseline: nextBaseline, x: Number.isFinite(x) ? x : element.x, y: Number.isFinite(y) ? y : element.y, }; diff --git a/src/element/textElement.ts b/src/element/textElement.ts index 94d045541..27e936129 100644 --- a/src/element/textElement.ts +++ b/src/element/textElement.ts @@ -58,6 +58,7 @@ export const redrawTextBoundingBox = ( text: textElement.text, width: textElement.width, height: textElement.height, + baseline: textElement.baseline, }; boundTextUpdates.text = textElement.text; @@ -78,6 +79,7 @@ export const redrawTextBoundingBox = ( boundTextUpdates.width = metrics.width; boundTextUpdates.height = metrics.height; + boundTextUpdates.baseline = metrics.baseline; if (container) { if (isArrowElement(container)) { @@ -183,6 +185,7 @@ export const handleBindTextResize = ( const maxWidth = getMaxContainerWidth(container); const maxHeight = getMaxContainerHeight(container); let containerHeight = containerDims.height; + let nextBaseLine = textElement.baseline; if (transformHandleType !== "n" && transformHandleType !== "s") { if (text) { text = wrapText( @@ -191,13 +194,14 @@ export const handleBindTextResize = ( maxWidth, ); } - const dimensions = measureText( + const metrics = measureText( text, getFontString(textElement), textElement.lineHeight, ); - nextHeight = dimensions.height; - nextWidth = dimensions.width; + nextHeight = metrics.height; + nextWidth = metrics.width; + nextBaseLine = metrics.baseline; } // increase height in case text element height exceeds if (nextHeight > maxHeight) { @@ -225,6 +229,7 @@ export const handleBindTextResize = ( text, width: nextWidth, height: nextHeight, + baseline: nextBaseLine, }); if (!isArrowElement(container)) { @@ -285,8 +290,8 @@ export const measureText = ( const fontSize = parseFloat(font); const height = getTextHeight(text, fontSize, lineHeight); const width = getTextWidth(text, font); - - return { width, height }; + const baseline = measureBaseline(text, font, lineHeight); + return { width, height, baseline }; }; export const measureBaseline = ( @@ -300,7 +305,7 @@ export const measureBaseline = ( container.style.whiteSpace = "pre"; container.style.font = font; container.style.minHeight = "1em"; - + console.log("HEYYY you are here!!"); if (wrapInContainer) { container.style.overflow = "hidden"; container.style.wordBreak = "break-word"; diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx index 468c15155..7b2d60668 100644 --- a/src/element/textWysiwyg.tsx +++ b/src/element/textWysiwyg.tsx @@ -34,7 +34,6 @@ import { wrapText, getMaxContainerHeight, getMaxContainerWidth, - measureBaseline, computeContainerDimensionForBoundText, } from "./textElement"; import { @@ -273,7 +272,10 @@ export const textWysiwyg = ({ textElementWidth += 0.5; } - const top = viewportY; + let verticalOffset = 0; + if (element.verticalAlign === VERTICAL_ALIGN.BOTTOM) { + //verticalOffset = getBoundTextElementOffset(element); + } // Make sure text editor height doesn't go beyond viewport const editorMaxHeight = (appState.height - viewportY) / appState.zoom.value; @@ -284,7 +286,7 @@ export const textWysiwyg = ({ width: `${textElementWidth}px`, height: `${textElementHeight}px`, left: `${viewportX}px`, - top: `${top}px`, + top: `${viewportY + verticalOffset}px`, transform: getTransform( textElementWidth, textElementHeight, @@ -295,8 +297,7 @@ export const textWysiwyg = ({ ), textAlign, verticalAlign, - // color: updatedTextElement.strokeColor, - color: "red", + color: updatedTextElement.strokeColor, opacity: updatedTextElement.opacity / 100, filter: "var(--theme-filter)", maxHeight: `${editorMaxHeight}px`, diff --git a/src/element/types.ts b/src/element/types.ts index 4b4bad74e..0760d054d 100644 --- a/src/element/types.ts +++ b/src/element/types.ts @@ -131,6 +131,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase & fontSize: number; fontFamily: FontFamilyValues; text: string; + baseline: number; textAlign: TextAlign; verticalAlign: VerticalAlign; containerId: ExcalidrawGenericElement["id"] | null; diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts index 50e8a5053..e366e7bae 100644 --- a/src/renderer/renderElement.ts +++ b/src/renderer/renderElement.ts @@ -46,7 +46,6 @@ import { getLineHeightInPx, getMaxContainerHeight, getMaxContainerWidth, - measureBaseline, } from "../element/textElement"; import { LinearElementEditor } from "../element/linearElementEditor"; @@ -201,17 +200,6 @@ const drawImagePlaceholder = ( size, ); }; -//@ts-ignore -const drawLine = (x, y, width, height, stroke, context) => { - context.lineWidth = "2"; - context.strokeStyle = stroke; - context.beginPath(); - context.moveTo(x, y); - context.lineTo(x + width, y); - context.closePath(); - context.stroke(); -}; - const drawElementOnCanvas = ( element: NonDeletedExcalidrawElement, rc: RoughCanvas, @@ -288,33 +276,6 @@ const drawElementOnCanvas = ( context.save(); context.font = getFontString(element); - // drawLine(0, 0, metrics.width, element.height, "green", context); - - // drawLine( - // 0, - // -metrics.actualBoundingBoxAscent, - // metrics.width, - // element.height, - // "magenta", - // context, - // ); - - // drawLine( - // 0, - // metrics.actualBoundingBoxDescent, - // metrics.width, - // element.height, - // "magenta", - // context, - // ); - const container = getContainerElement(element); - const baseline = measureBaseline( - element.text, - getFontString(element), - element.lineHeight, - !!container, - ); - context.fillStyle = element.strokeColor; context.textAlign = element.textAlign as CanvasTextAlign; @@ -331,7 +292,7 @@ const drawElementOnCanvas = ( element.fontSize, element.lineHeight, ); - const verticalOffset = element.height - baseline; + const verticalOffset = element.height - element.baseline; for (let index = 0; index < lines.length; index++) { context.fillText(