fix: support breaking words containing hyphen - (#6014)
* fix: support breaking words containing hyphen - * fix * add spec * fix * fix * fix * fix and add spec * improve code and add more tests
This commit is contained in:
parent
404a79e241
commit
5ddb28d378
@ -9,6 +9,7 @@ import {
|
|||||||
detectLineHeight,
|
detectLineHeight,
|
||||||
getLineHeightInPx,
|
getLineHeightInPx,
|
||||||
getDefaultLineHeight,
|
getDefaultLineHeight,
|
||||||
|
parseTokens,
|
||||||
} from "./textElement";
|
} from "./textElement";
|
||||||
import { FontString } from "./types";
|
import { FontString } from "./types";
|
||||||
|
|
||||||
@ -183,6 +184,56 @@ now`,
|
|||||||
expect(wrapText(text, font, -1)).toEqual(text);
|
expect(wrapText(text, font, -1)).toEqual(text);
|
||||||
expect(wrapText(text, font, Infinity)).toEqual(text);
|
expect(wrapText(text, font, Infinity)).toEqual(text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should wrap the text correctly when text contains hyphen", () => {
|
||||||
|
let text =
|
||||||
|
"Wikipedia is hosted by Wikimedia- Foundation, a non-profit organization that also hosts a range-of other projects";
|
||||||
|
const res = wrapText(text, font, 110);
|
||||||
|
expect(res).toBe(
|
||||||
|
`Wikipedia \nis hosted \nby \nWikimedia-\nFoundation,\na non-\nprofit \norganizati\non that \nalso hosts\na range-of\nother \nprojects`,
|
||||||
|
);
|
||||||
|
|
||||||
|
text = "Hello thereusing-now";
|
||||||
|
expect(wrapText(text, font, 100)).toEqual("Hello \nthereusin\ng-now");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Test parseTokens", () => {
|
||||||
|
it("should split into tokens correctly", () => {
|
||||||
|
let text = "Excalidraw is a virtual collaborative whiteboard";
|
||||||
|
expect(parseTokens(text)).toEqual([
|
||||||
|
"Excalidraw",
|
||||||
|
"is",
|
||||||
|
"a",
|
||||||
|
"virtual",
|
||||||
|
"collaborative",
|
||||||
|
"whiteboard",
|
||||||
|
]);
|
||||||
|
|
||||||
|
text =
|
||||||
|
"Wikipedia is hosted by Wikimedia- Foundation, a non-profit organization that also hosts a range-of other projects";
|
||||||
|
expect(parseTokens(text)).toEqual([
|
||||||
|
"Wikipedia",
|
||||||
|
"is",
|
||||||
|
"hosted",
|
||||||
|
"by",
|
||||||
|
"Wikimedia-",
|
||||||
|
"",
|
||||||
|
"Foundation,",
|
||||||
|
"a",
|
||||||
|
"non-",
|
||||||
|
"profit",
|
||||||
|
"organization",
|
||||||
|
"that",
|
||||||
|
"also",
|
||||||
|
"hosts",
|
||||||
|
"a",
|
||||||
|
"range-",
|
||||||
|
"of",
|
||||||
|
"other",
|
||||||
|
"projects",
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Test measureText", () => {
|
describe("Test measureText", () => {
|
||||||
|
@ -419,6 +419,24 @@ export const getTextHeight = (
|
|||||||
return getLineHeightInPx(fontSize, lineHeight) * lineCount;
|
return getLineHeightInPx(fontSize, lineHeight) * lineCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const parseTokens = (text: string) => {
|
||||||
|
// Splitting words containing "-" as those are treated as separate words
|
||||||
|
// by css wrapping algorithm eg non-profit => non-, profit
|
||||||
|
const words = text.split("-");
|
||||||
|
if (words.length > 1) {
|
||||||
|
// non-proft org => ['non-', 'profit org']
|
||||||
|
words.forEach((word, index) => {
|
||||||
|
if (index !== words.length - 1) {
|
||||||
|
words[index] = word += "-";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Joining the words with space and splitting them again with space to get the
|
||||||
|
// final list of tokens
|
||||||
|
// ['non-', 'profit org'] =>,'non- proft org' => ['non-','profit','org']
|
||||||
|
return words.join(" ").split(" ");
|
||||||
|
};
|
||||||
|
|
||||||
export const wrapText = (text: string, font: FontString, maxWidth: number) => {
|
export const wrapText = (text: string, font: FontString, maxWidth: number) => {
|
||||||
// if maxWidth is not finite or NaN which can happen in case of bugs in
|
// if maxWidth is not finite or NaN which can happen in case of bugs in
|
||||||
// computation, we need to make sure we don't continue as we'll end up
|
// computation, we need to make sure we don't continue as we'll end up
|
||||||
@ -444,17 +462,16 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
|
|||||||
currentLine = "";
|
currentLine = "";
|
||||||
currentLineWidthTillNow = 0;
|
currentLineWidthTillNow = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
originalLines.forEach((originalLine) => {
|
originalLines.forEach((originalLine) => {
|
||||||
const currentLineWidth = getTextWidth(originalLine, font);
|
const currentLineWidth = getTextWidth(originalLine, font);
|
||||||
|
|
||||||
//Push the line if its <= maxWidth
|
// Push the line if its <= maxWidth
|
||||||
if (currentLineWidth <= maxWidth) {
|
if (currentLineWidth <= maxWidth) {
|
||||||
lines.push(originalLine);
|
lines.push(originalLine);
|
||||||
return; // continue
|
return; // continue
|
||||||
}
|
}
|
||||||
const words = originalLine.split(" ");
|
|
||||||
|
|
||||||
|
const words = parseTokens(originalLine);
|
||||||
resetParams();
|
resetParams();
|
||||||
|
|
||||||
let index = 0;
|
let index = 0;
|
||||||
@ -472,6 +489,7 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
|
|||||||
else if (currentWordWidth > maxWidth) {
|
else if (currentWordWidth > maxWidth) {
|
||||||
// push current line since the current word exceeds the max width
|
// push current line since the current word exceeds the max width
|
||||||
// so will be appended in next line
|
// so will be appended in next line
|
||||||
|
|
||||||
push(currentLine);
|
push(currentLine);
|
||||||
|
|
||||||
resetParams();
|
resetParams();
|
||||||
@ -492,15 +510,15 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
|
|||||||
currentLine += currentChar;
|
currentLine += currentChar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// push current line if appending space exceeds max width
|
// push current line if appending space exceeds max width
|
||||||
if (currentLineWidthTillNow + spaceWidth >= maxWidth) {
|
if (currentLineWidthTillNow + spaceWidth >= maxWidth) {
|
||||||
push(currentLine);
|
push(currentLine);
|
||||||
resetParams();
|
resetParams();
|
||||||
} else {
|
|
||||||
// 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
|
// to previous line unless the line ends with hyphen to sync
|
||||||
|
// with css word-wrap
|
||||||
|
} else if (!currentLine.endsWith("-")) {
|
||||||
currentLine += " ";
|
currentLine += " ";
|
||||||
currentLineWidthTillNow += spaceWidth;
|
currentLineWidthTillNow += spaceWidth;
|
||||||
}
|
}
|
||||||
@ -518,12 +536,23 @@ export const wrapText = (text: string, font: FontString, maxWidth: number) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
currentLine += `${word} `;
|
|
||||||
|
// if word ends with "-" then we don't need to add space
|
||||||
|
// to sync with css word-wrap
|
||||||
|
const shouldAppendSpace = !word.endsWith("-");
|
||||||
|
currentLine += word;
|
||||||
|
|
||||||
|
if (shouldAppendSpace) {
|
||||||
|
currentLine += " ";
|
||||||
|
}
|
||||||
|
|
||||||
// Push the word if appending space exceeds max width
|
// Push the word if appending space exceeds max width
|
||||||
if (currentLineWidthTillNow + spaceWidth >= maxWidth) {
|
if (currentLineWidthTillNow + spaceWidth >= maxWidth) {
|
||||||
const word = currentLine.slice(0, -1);
|
if (shouldAppendSpace) {
|
||||||
push(word);
|
lines.push(currentLine.slice(0, -1));
|
||||||
|
} else {
|
||||||
|
lines.push(currentLine);
|
||||||
|
}
|
||||||
resetParams();
|
resetParams();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user