mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-04-14 16:40:58 -04:00
introduce baseline in element making it backward compat
This commit is contained in:
parent
974745b9e5
commit
f8b25375a4
8 changed files with 62 additions and 79 deletions
|
@ -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, {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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`,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Add table
Reference in a new issue