introduce baseline in element making it backward compat

This commit is contained in:
Aakansha Doshi 2023-03-31 15:53:03 +05:30
parent 974745b9e5
commit f8b25375a4
8 changed files with 62 additions and 79 deletions

View file

@ -42,7 +42,7 @@ export const actionUnbindText = register({
selectedElements.forEach((element) => { selectedElements.forEach((element) => {
const boundTextElement = getBoundTextElement(element); const boundTextElement = getBoundTextElement(element);
if (boundTextElement) { if (boundTextElement) {
const { width, height } = measureText( const { width, height, baseline } = measureText(
boundTextElement.originalText, boundTextElement.originalText,
getFontString(boundTextElement), getFontString(boundTextElement),
boundTextElement.lineHeight, boundTextElement.lineHeight,
@ -56,6 +56,7 @@ export const actionUnbindText = register({
containerId: null, containerId: null,
width, width,
height, height,
baseline,
text: boundTextElement.originalText, text: boundTextElement.originalText,
}); });
mutateElement(element, { mutateElement(element, {

View file

@ -1348,14 +1348,13 @@ class App extends React.Component<AppProps, AppState> {
return false; return false;
} }
} }
return true;
// don't render text element that's being currently edited (it's // don't render text element that's being currently edited (it's
// rendered on remote only) // rendered on remote only)
// return ( return (
// !this.state.editingElement || !this.state.editingElement ||
// this.state.editingElement.type !== "text" || this.state.editingElement.type !== "text" ||
// element.id !== this.state.editingElement.id element.id !== this.state.editingElement.id
// ); );
}); });
const selectionColor = getComputedStyle( const selectionColor = getComputedStyle(

View file

@ -31,11 +31,15 @@ import {
import { getDefaultAppState } from "../appState"; import { getDefaultAppState } from "../appState";
import { LinearElementEditor } from "../element/linearElementEditor"; import { LinearElementEditor } from "../element/linearElementEditor";
import { bumpVersion } from "../element/mutateElement"; import { bumpVersion } from "../element/mutateElement";
import { getUpdatedTimestamp, updateActiveTool } from "../utils"; import { getFontString, getUpdatedTimestamp, updateActiveTool } from "../utils";
import { arrayToMap } from "../utils"; import { arrayToMap } from "../utils";
import oc from "open-color"; import oc from "open-color";
import { MarkOptional, Mutable } from "../utility-types"; import { MarkOptional, Mutable } from "../utility-types";
import { detectLineHeight, getDefaultLineHeight } from "../element/textElement"; import {
detectLineHeight,
getDefaultLineHeight,
measureBaseline,
} from "../element/textElement";
type RestoredAppState = Omit< type RestoredAppState = Omit<
AppState, AppState,
@ -170,7 +174,19 @@ const restoreElement = (
fontFamily = getFontFamilyByName(_fontFamily); fontFamily = getFontFamilyByName(_fontFamily);
} }
const text = element.text ?? ""; 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, { element = restoreElementWithProperties(element, {
fontSize, fontSize,
fontFamily, fontFamily,
@ -179,19 +195,13 @@ const restoreElement = (
verticalAlign: element.verticalAlign || DEFAULT_VERTICAL_ALIGN, verticalAlign: element.verticalAlign || DEFAULT_VERTICAL_ALIGN,
containerId: element.containerId ?? null, containerId: element.containerId ?? null,
originalText: element.originalText || text, originalText: element.originalText || text,
// line-height might not be specified either when creating elements
// programmatically, or when importing old diagrams. lineHeight,
// For the latter we want to detect the original line height which baseline: measureBaseline(
// will likely differ from our per-font fixed line height we now use, element.text,
// to maintain backward compatibility. getFontString(element),
lineHeight: 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)),
}); });
if (refreshDimensions) { if (refreshDimensions) {

View file

@ -30,6 +30,7 @@ import {
wrapText, wrapText,
getMaxContainerWidth, getMaxContainerWidth,
getDefaultLineHeight, getDefaultLineHeight,
measureBaseline,
} from "./textElement"; } from "./textElement";
import { VERTICAL_ALIGN } from "../constants"; import { VERTICAL_ALIGN } from "../constants";
import { isArrowElement } from "./typeChecks"; import { isArrowElement } from "./typeChecks";
@ -145,6 +146,7 @@ export const newTextElement = (
const text = normalizeText(opts.text); const text = normalizeText(opts.text);
const metrics = measureText(text, getFontString(opts), lineHeight); const metrics = measureText(text, getFontString(opts), lineHeight);
const offsets = getTextElementPositionOffsets(opts, metrics); const offsets = getTextElementPositionOffsets(opts, metrics);
const textElement = newElementWith( const textElement = newElementWith(
{ {
..._newElementBase<ExcalidrawTextElement>("text", opts), ..._newElementBase<ExcalidrawTextElement>("text", opts),
@ -157,6 +159,7 @@ export const newTextElement = (
y: opts.y - offsets.y, y: opts.y - offsets.y,
width: metrics.width, width: metrics.width,
height: metrics.height, height: metrics.height,
baseline: metrics.baseline,
containerId: opts.containerId || null, containerId: opts.containerId || null,
originalText: text, originalText: text,
lineHeight, lineHeight,
@ -174,14 +177,15 @@ const getAdjustedDimensions = (
y: number; y: number;
width: number; width: number;
height: number; height: number;
baseline: number;
} => { } => {
const container = getContainerElement(element); const container = getContainerElement(element);
const { width: nextWidth, height: nextHeight } = measureText( const {
nextText, width: nextWidth,
getFontString(element), height: nextHeight,
element.lineHeight, baseline: nextBaseline,
); } = measureText(nextText, getFontString(element), element.lineHeight);
const { textAlign, verticalAlign } = element; const { textAlign, verticalAlign } = element;
let x: number; let x: number;
let y: number; let y: number;
@ -256,6 +260,7 @@ const getAdjustedDimensions = (
return { return {
width: nextWidth, width: nextWidth,
height: nextHeight, height: nextHeight,
baseline: nextBaseline,
x: Number.isFinite(x) ? x : element.x, x: Number.isFinite(x) ? x : element.x,
y: Number.isFinite(y) ? y : element.y, y: Number.isFinite(y) ? y : element.y,
}; };

View file

@ -58,6 +58,7 @@ export const redrawTextBoundingBox = (
text: textElement.text, text: textElement.text,
width: textElement.width, width: textElement.width,
height: textElement.height, height: textElement.height,
baseline: textElement.baseline,
}; };
boundTextUpdates.text = textElement.text; boundTextUpdates.text = textElement.text;
@ -78,6 +79,7 @@ export const redrawTextBoundingBox = (
boundTextUpdates.width = metrics.width; boundTextUpdates.width = metrics.width;
boundTextUpdates.height = metrics.height; boundTextUpdates.height = metrics.height;
boundTextUpdates.baseline = metrics.baseline;
if (container) { if (container) {
if (isArrowElement(container)) { if (isArrowElement(container)) {
@ -183,6 +185,7 @@ export const handleBindTextResize = (
const maxWidth = getMaxContainerWidth(container); const maxWidth = getMaxContainerWidth(container);
const maxHeight = getMaxContainerHeight(container); const maxHeight = getMaxContainerHeight(container);
let containerHeight = containerDims.height; let containerHeight = containerDims.height;
let nextBaseLine = textElement.baseline;
if (transformHandleType !== "n" && transformHandleType !== "s") { if (transformHandleType !== "n" && transformHandleType !== "s") {
if (text) { if (text) {
text = wrapText( text = wrapText(
@ -191,13 +194,14 @@ export const handleBindTextResize = (
maxWidth, maxWidth,
); );
} }
const dimensions = measureText( const metrics = measureText(
text, text,
getFontString(textElement), getFontString(textElement),
textElement.lineHeight, textElement.lineHeight,
); );
nextHeight = dimensions.height; nextHeight = metrics.height;
nextWidth = dimensions.width; nextWidth = metrics.width;
nextBaseLine = metrics.baseline;
} }
// increase height in case text element height exceeds // increase height in case text element height exceeds
if (nextHeight > maxHeight) { if (nextHeight > maxHeight) {
@ -225,6 +229,7 @@ export const handleBindTextResize = (
text, text,
width: nextWidth, width: nextWidth,
height: nextHeight, height: nextHeight,
baseline: nextBaseLine,
}); });
if (!isArrowElement(container)) { if (!isArrowElement(container)) {
@ -285,8 +290,8 @@ export const measureText = (
const fontSize = parseFloat(font); const fontSize = parseFloat(font);
const height = getTextHeight(text, fontSize, lineHeight); const height = getTextHeight(text, fontSize, lineHeight);
const width = getTextWidth(text, font); const width = getTextWidth(text, font);
const baseline = measureBaseline(text, font, lineHeight);
return { width, height }; return { width, height, baseline };
}; };
export const measureBaseline = ( export const measureBaseline = (
@ -300,7 +305,7 @@ export const measureBaseline = (
container.style.whiteSpace = "pre"; container.style.whiteSpace = "pre";
container.style.font = font; container.style.font = font;
container.style.minHeight = "1em"; container.style.minHeight = "1em";
console.log("HEYYY you are here!!");
if (wrapInContainer) { if (wrapInContainer) {
container.style.overflow = "hidden"; container.style.overflow = "hidden";
container.style.wordBreak = "break-word"; container.style.wordBreak = "break-word";

View file

@ -34,7 +34,6 @@ import {
wrapText, wrapText,
getMaxContainerHeight, getMaxContainerHeight,
getMaxContainerWidth, getMaxContainerWidth,
measureBaseline,
computeContainerDimensionForBoundText, computeContainerDimensionForBoundText,
} from "./textElement"; } from "./textElement";
import { import {
@ -273,7 +272,10 @@ export const textWysiwyg = ({
textElementWidth += 0.5; 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 // Make sure text editor height doesn't go beyond viewport
const editorMaxHeight = const editorMaxHeight =
(appState.height - viewportY) / appState.zoom.value; (appState.height - viewportY) / appState.zoom.value;
@ -284,7 +286,7 @@ export const textWysiwyg = ({
width: `${textElementWidth}px`, width: `${textElementWidth}px`,
height: `${textElementHeight}px`, height: `${textElementHeight}px`,
left: `${viewportX}px`, left: `${viewportX}px`,
top: `${top}px`, top: `${viewportY + verticalOffset}px`,
transform: getTransform( transform: getTransform(
textElementWidth, textElementWidth,
textElementHeight, textElementHeight,
@ -295,8 +297,7 @@ export const textWysiwyg = ({
), ),
textAlign, textAlign,
verticalAlign, verticalAlign,
// color: updatedTextElement.strokeColor, color: updatedTextElement.strokeColor,
color: "red",
opacity: updatedTextElement.opacity / 100, opacity: updatedTextElement.opacity / 100,
filter: "var(--theme-filter)", filter: "var(--theme-filter)",
maxHeight: `${editorMaxHeight}px`, maxHeight: `${editorMaxHeight}px`,

View file

@ -131,6 +131,7 @@ export type ExcalidrawTextElement = _ExcalidrawElementBase &
fontSize: number; fontSize: number;
fontFamily: FontFamilyValues; fontFamily: FontFamilyValues;
text: string; text: string;
baseline: number;
textAlign: TextAlign; textAlign: TextAlign;
verticalAlign: VerticalAlign; verticalAlign: VerticalAlign;
containerId: ExcalidrawGenericElement["id"] | null; containerId: ExcalidrawGenericElement["id"] | null;

View file

@ -46,7 +46,6 @@ import {
getLineHeightInPx, getLineHeightInPx,
getMaxContainerHeight, getMaxContainerHeight,
getMaxContainerWidth, getMaxContainerWidth,
measureBaseline,
} from "../element/textElement"; } from "../element/textElement";
import { LinearElementEditor } from "../element/linearElementEditor"; import { LinearElementEditor } from "../element/linearElementEditor";
@ -201,17 +200,6 @@ const drawImagePlaceholder = (
size, 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 = ( const drawElementOnCanvas = (
element: NonDeletedExcalidrawElement, element: NonDeletedExcalidrawElement,
rc: RoughCanvas, rc: RoughCanvas,
@ -288,33 +276,6 @@ const drawElementOnCanvas = (
context.save(); context.save();
context.font = getFontString(element); 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.fillStyle = element.strokeColor;
context.textAlign = element.textAlign as CanvasTextAlign; context.textAlign = element.textAlign as CanvasTextAlign;
@ -331,7 +292,7 @@ const drawElementOnCanvas = (
element.fontSize, element.fontSize,
element.lineHeight, element.lineHeight,
); );
const verticalOffset = element.height - baseline; const verticalOffset = element.height - element.baseline;
for (let index = 0; index < lines.length; index++) { for (let index = 0; index < lines.length; index++) {
context.fillText( context.fillText(