fix: set the width correctly using measureText in editor (#6162)
This commit is contained in:
parent
b52c8943e4
commit
e41ea9562b
@ -171,7 +171,7 @@ describe("Test measureText", () => {
|
|||||||
|
|
||||||
expect(res.container).toMatchInlineSnapshot(`
|
expect(res.container).toMatchInlineSnapshot(`
|
||||||
<div
|
<div
|
||||||
style="position: absolute; white-space: pre-wrap; font: Emoji 20px 20px; min-height: 1em; width: 111px; overflow: hidden; word-break: break-word; line-height: 0px;"
|
style="position: absolute; white-space: pre-wrap; font: Emoji 20px 20px; min-height: 1em; max-width: 191px; overflow: hidden; word-break: break-word; line-height: 0px;"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
style="display: inline-block; overflow: hidden; width: 1px; height: 1px;"
|
style="display: inline-block; overflow: hidden; width: 1px; height: 1px;"
|
||||||
|
@ -271,12 +271,11 @@ export const measureText = (
|
|||||||
container.style.whiteSpace = "pre";
|
container.style.whiteSpace = "pre";
|
||||||
container.style.font = font;
|
container.style.font = font;
|
||||||
container.style.minHeight = "1em";
|
container.style.minHeight = "1em";
|
||||||
const textWidth = getTextWidth(text, font);
|
|
||||||
|
|
||||||
if (maxWidth) {
|
if (maxWidth) {
|
||||||
const lineHeight = getApproxLineHeight(font);
|
const lineHeight = getApproxLineHeight(font);
|
||||||
container.style.width = `${String(Math.min(textWidth, maxWidth) + 1)}px`;
|
// since we are adding a span of width 1px later
|
||||||
|
container.style.maxWidth = `${maxWidth + 1}px`;
|
||||||
container.style.overflow = "hidden";
|
container.style.overflow = "hidden";
|
||||||
container.style.wordBreak = "break-word";
|
container.style.wordBreak = "break-word";
|
||||||
container.style.lineHeight = `${String(lineHeight)}px`;
|
container.style.lineHeight = `${String(lineHeight)}px`;
|
||||||
@ -293,11 +292,7 @@ export const measureText = (
|
|||||||
container.appendChild(span);
|
container.appendChild(span);
|
||||||
// Baseline is important for positioning text on canvas
|
// Baseline is important for positioning text on canvas
|
||||||
const baseline = span.offsetTop + span.offsetHeight;
|
const baseline = span.offsetTop + span.offsetHeight;
|
||||||
// Since span adds 1px extra width to the container
|
const width = container.offsetWidth;
|
||||||
let width = container.offsetWidth;
|
|
||||||
if (maxWidth && textWidth > maxWidth) {
|
|
||||||
width = width - 1;
|
|
||||||
}
|
|
||||||
const height = container.offsetHeight;
|
const height = container.offsetHeight;
|
||||||
document.body.removeChild(container);
|
document.body.removeChild(container);
|
||||||
if (isTestEnv()) {
|
if (isTestEnv()) {
|
||||||
@ -332,8 +327,11 @@ const getLineWidth = (text: string, font: FontString) => {
|
|||||||
if (isTestEnv()) {
|
if (isTestEnv()) {
|
||||||
return metrics.width * 10;
|
return metrics.width * 10;
|
||||||
}
|
}
|
||||||
|
// Since measureText behaves differently in different browsers
|
||||||
|
// OS so considering a adjustment factor of 0.2
|
||||||
|
const adjustmentFactor = 0.2;
|
||||||
|
|
||||||
return metrics.width;
|
return metrics.width + adjustmentFactor;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTextWidth = (text: string, font: FontString) => {
|
export const getTextWidth = (text: string, font: FontString) => {
|
||||||
|
@ -142,11 +142,11 @@ export const textWysiwyg = ({
|
|||||||
const appState = app.state;
|
const appState = app.state;
|
||||||
const updatedTextElement =
|
const updatedTextElement =
|
||||||
Scene.getScene(element)?.getElement<ExcalidrawTextElement>(id);
|
Scene.getScene(element)?.getElement<ExcalidrawTextElement>(id);
|
||||||
|
|
||||||
if (!updatedTextElement) {
|
if (!updatedTextElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { textAlign, verticalAlign } = updatedTextElement;
|
const { textAlign, verticalAlign } = updatedTextElement;
|
||||||
|
|
||||||
const approxLineHeight = getApproxLineHeight(
|
const approxLineHeight = getApproxLineHeight(
|
||||||
getFontString(updatedTextElement),
|
getFontString(updatedTextElement),
|
||||||
);
|
);
|
||||||
@ -161,6 +161,7 @@ export const textWysiwyg = ({
|
|||||||
// Set to element height by default since that's
|
// Set to element height by default since that's
|
||||||
// what is going to be used for unbounded text
|
// what is going to be used for unbounded text
|
||||||
let textElementHeight = updatedTextElement.height;
|
let textElementHeight = updatedTextElement.height;
|
||||||
|
|
||||||
if (container && updatedTextElement.containerId) {
|
if (container && updatedTextElement.containerId) {
|
||||||
if (isArrowElement(container)) {
|
if (isArrowElement(container)) {
|
||||||
const boundTextCoords =
|
const boundTextCoords =
|
||||||
@ -206,7 +207,6 @@ export const textWysiwyg = ({
|
|||||||
maxHeight = getMaxContainerHeight(container);
|
maxHeight = getMaxContainerHeight(container);
|
||||||
|
|
||||||
// autogrow container height if text exceeds
|
// autogrow container height if text exceeds
|
||||||
|
|
||||||
if (!isArrowElement(container) && textElementHeight > maxHeight) {
|
if (!isArrowElement(container) && textElementHeight > maxHeight) {
|
||||||
const diff = Math.min(
|
const diff = Math.min(
|
||||||
textElementHeight - maxHeight,
|
textElementHeight - maxHeight,
|
||||||
@ -276,7 +276,6 @@ export const textWysiwyg = ({
|
|||||||
// 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;
|
||||||
|
|
||||||
Object.assign(editable.style, {
|
Object.assign(editable.style, {
|
||||||
font: getFontString(updatedTextElement),
|
font: getFontString(updatedTextElement),
|
||||||
// must be defined *after* font ¯\_(ツ)_/¯
|
// must be defined *after* font ¯\_(ツ)_/¯
|
||||||
@ -395,11 +394,12 @@ export const textWysiwyg = ({
|
|||||||
// first line as well as setting height to "auto"
|
// first line as well as setting height to "auto"
|
||||||
// doubles the height as soon as user starts typing
|
// doubles the height as soon as user starts typing
|
||||||
if (isBoundToContainer(element) && lines > 1) {
|
if (isBoundToContainer(element) && lines > 1) {
|
||||||
|
const container = getContainerElement(element);
|
||||||
|
|
||||||
let height = "auto";
|
let height = "auto";
|
||||||
editable.style.height = "0px";
|
editable.style.height = "0px";
|
||||||
let heightSet = false;
|
let heightSet = false;
|
||||||
if (lines === 2) {
|
if (lines === 2) {
|
||||||
const container = getContainerElement(element);
|
|
||||||
const actualLineCount = wrapText(
|
const actualLineCount = wrapText(
|
||||||
editable.value,
|
editable.value,
|
||||||
font,
|
font,
|
||||||
@ -416,6 +416,14 @@ export const textWysiwyg = ({
|
|||||||
heightSet = true;
|
heightSet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const wrappedText = wrapText(
|
||||||
|
normalizeText(editable.value),
|
||||||
|
font,
|
||||||
|
getMaxContainerWidth(container!),
|
||||||
|
);
|
||||||
|
const width = getTextWidth(wrappedText, font);
|
||||||
|
editable.style.width = `${width}px`;
|
||||||
|
|
||||||
if (!heightSet) {
|
if (!heightSet) {
|
||||||
editable.style.height = `${editable.scrollHeight}px`;
|
editable.style.height = `${editable.scrollHeight}px`;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user