fix: preserve trailing spaces in word wrap

This commit is contained in:
Aakansha Doshi 2023-04-20 20:13:01 +05:30
parent 5ddb28d378
commit caf0a904db
2 changed files with 62 additions and 20 deletions

View File

@ -384,7 +384,7 @@ export const getApproxMinLineHeight = (
let canvas: HTMLCanvasElement | undefined; let canvas: HTMLCanvasElement | undefined;
const getLineWidth = (text: string, font: FontString) => { export const getLineWidth = (text: string, font: FontString) => {
if (!canvas) { if (!canvas) {
canvas = document.createElement("canvas"); canvas = document.createElement("canvas");
} }
@ -444,10 +444,9 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
if (!Number.isFinite(maxWidth) || maxWidth < 0) { if (!Number.isFinite(maxWidth) || maxWidth < 0) {
return text; return text;
} }
console.log("TEXT =", text, maxWidth);
const lines: Array<string> = []; const lines: Array<string> = [];
const originalLines = text.split("\n"); const originalLines = text.split("\n");
const spaceWidth = getLineWidth(" ", font);
let currentLine = ""; let currentLine = "";
let currentLineWidthTillNow = 0; let currentLineWidthTillNow = 0;
@ -463,7 +462,7 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
currentLineWidthTillNow = 0; currentLineWidthTillNow = 0;
}; };
originalLines.forEach((originalLine) => { originalLines.forEach((originalLine) => {
const currentLineWidth = getTextWidth(originalLine, font); const currentLineWidth = getLineWidth(originalLine, font);
// Push the line if its <= maxWidth // Push the line if its <= maxWidth
if (currentLineWidth <= maxWidth) { if (currentLineWidth <= maxWidth) {
@ -472,6 +471,7 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
} }
const words = parseTokens(originalLine); const words = parseTokens(originalLine);
console.log(words, "words");
resetParams(); resetParams();
let index = 0; let index = 0;
@ -511,23 +511,25 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
} }
} }
// push current line if appending space exceeds max width // push current line if appending space exceeds max width
if (currentLineWidthTillNow + spaceWidth >= maxWidth) { if (currentLineWidthTillNow >= maxWidth) {
push(currentLine); push(currentLine);
resetParams(); resetParams();
// space needs to be appended before next word // space needs to be appended before next word
// as currentLine contains chars which couldn't be appended // as currentLine contains chars which couldn't be appended
// to previous line unless the line ends with hyphen to sync // to previous line unless the line ends with hyphen to sync
// with css word-wrap // with css word-wrap
} else if (!currentLine.endsWith("-")) { } else if (!currentLine.endsWith("-") && index < words.length) {
currentLine += " "; currentLine += " ";
currentLineWidthTillNow += spaceWidth;
} }
index++; index++;
} else { } else {
// Start appending words in a line till max width reached // Start appending words in a line till max width reached
while (currentLineWidthTillNow < maxWidth && index < words.length) { while (currentLineWidthTillNow < maxWidth && index < words.length) {
const word = words[index]; const word = words[index];
currentLineWidthTillNow = getLineWidth(currentLine + word, font); currentLineWidthTillNow = getLineWidth(
`${currentLine + word}`.trimEnd(),
font,
);
if (currentLineWidthTillNow > maxWidth) { if (currentLineWidthTillNow > maxWidth) {
push(currentLine); push(currentLine);
@ -535,36 +537,44 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
break; break;
} }
index++;
// if word ends with "-" then we don't need to add space // if word ends with "-" then we don't need to add space
// to sync with css word-wrap // to sync with css word-wrap
const shouldAppendSpace = !word.endsWith("-"); const shouldAppendSpace = !word.endsWith("-");
currentLine += word; currentLine += word;
if (shouldAppendSpace) { if (shouldAppendSpace && index < words.length) {
currentLine += " "; currentLine += " ";
} }
console.log("currentLine", currentLine, currentLine.length, index);
index++;
// Push the word if appending space exceeds max width // Push the word if appending space exceeds max width
if (currentLineWidthTillNow + spaceWidth >= maxWidth) { if (currentLineWidthTillNow >= maxWidth) {
if (shouldAppendSpace) { // if (
lines.push(currentLine.slice(0, -1)); // currentLineWidthTillNow + spaceWidth === maxWidth &&
} else { // index < words.length &&
// words[index] === ""
// ) {
// currentLine += " ";
// index++;
// }
lines.push(currentLine); lines.push(currentLine);
}
resetParams(); resetParams();
break; break;
} }
} }
} }
} }
console.log("currentLine", currentLine);
if (currentLine.slice(-1) === " ") { if (currentLine.slice(-1) === " ") {
// only remove last trailing space which we have added when joining words // only remove last trailing space which we have added when joining words
currentLine = currentLine.slice(0, -1); currentLine = currentLine.slice(0, -1);
push(currentLine); push(currentLine);
} }
}); });
console.log("TEXT Words", lines);
return lines.join("\n"); return lines.join("\n");
}; };

View File

@ -37,17 +37,21 @@ import {
MAX_DECIMALS_FOR_SVG_EXPORT, MAX_DECIMALS_FOR_SVG_EXPORT,
MIME_TYPES, MIME_TYPES,
SVG_NS, SVG_NS,
TEXT_ALIGN,
} from "../constants"; } from "../constants";
import { getStroke, StrokeOptions } from "perfect-freehand"; import { getStroke, StrokeOptions } from "perfect-freehand";
import { import {
getBoundTextElement, getBoundTextElement,
getBoundTextElementOffset,
getContainerCoords, getContainerCoords,
getContainerElement, getContainerElement,
getLineHeightInPx, getLineHeightInPx,
getLineWidth,
getMaxContainerHeight, getMaxContainerHeight,
getMaxContainerWidth, getMaxContainerWidth,
} from "../element/textElement"; } from "../element/textElement";
import { LinearElementEditor } from "../element/linearElementEditor"; import { LinearElementEditor } from "../element/linearElementEditor";
import heILJsonE0bd304682986695208c from "../packages/excalidraw/dist/excalidraw-assets-dev/locales/he-IL-json-e0bd304682986695208c";
// using a stronger invert (100% vs our regular 93%) and saturate // using a stronger invert (100% vs our regular 93%) and saturate
// as a temp hack to make images in dark theme look closer to original // as a temp hack to make images in dark theme look closer to original
@ -319,13 +323,17 @@ const drawElementOnCanvas = (
} }
context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr"); context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr");
context.save(); context.save();
context.font = getFontString(element); const font = getFontString(element);
context.font = font;
context.fillStyle = element.strokeColor; context.fillStyle = element.strokeColor;
context.textAlign = element.textAlign as CanvasTextAlign; context.textAlign = element.textAlign as CanvasTextAlign;
context.fillStyle = "yellow";
context.fillRect(0, 0, element.width, element.height);
context.fillStyle = element.strokeColor;
// Canvas does not support multiline text by default // Canvas does not support multiline text by default
const lines = element.text.replace(/\r\n?/g, "\n").split("\n"); const lines = element.text.replace(/\r\n?/g, "\n").split("\n");
const horizontalOffset = const horizontalOffset =
element.textAlign === "center" element.textAlign === "center"
? element.width / 2 ? element.width / 2
@ -336,11 +344,35 @@ const drawElementOnCanvas = (
element.fontSize, element.fontSize,
element.lineHeight, element.lineHeight,
); );
const container = getContainerElement(element);
if (container) {
console.log(
"Element width = ",
element.width,
getMaxContainerWidth(container),
);
}
const verticalOffset = element.height - element.baseline; const verticalOffset = element.height - element.baseline;
for (let index = 0; index < lines.length; index++) { for (let index = 0; index < lines.length; index++) {
const trailingSpacesWidth =
getLineWidth(lines[index], font) -
getLineWidth(lines[index].trimEnd(), font);
console.log(trailingSpacesWidth, "width");
const maxWidth = container
? getMaxContainerWidth(container)
: element.width;
const availableWidth =
maxWidth - getLineWidth(lines[index].trimEnd(), font);
let spacesOffset = 0;
if (element.textAlign === TEXT_ALIGN.CENTER) {
spacesOffset = -trailingSpacesWidth / 2;
} else if (element.textAlign === TEXT_ALIGN.RIGHT) {
spacesOffset = -Math.min(availableWidth, trailingSpacesWidth);
}
console.log(spacesOffset, "spacesOffset", trailingSpacesWidth);
context.fillText( context.fillText(
lines[index], lines[index].trimEnd(),
horizontalOffset, horizontalOffset + spacesOffset,
(index + 1) * lineHeightPx - verticalOffset, (index + 1) * lineHeightPx - verticalOffset,
); );
} }