mirror of
https://github.com/pdfme/pdfme.git
synced 2026-05-19 04:11:18 -04:00
Support for line breaking on hyphens (#451)
* support for line breaking on hyphens * update test pdfs
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -74,23 +74,29 @@ describe('getSplitPosition test with mocked font width calculations', () => {
|
||||
expect(getSplittedLines('aaaa', mockCalcValues)).toEqual(['aaaa']);
|
||||
});
|
||||
|
||||
it('splits a line to the nearest previous space', () => {
|
||||
it('splits a line to the nearest previous breakable char', () => {
|
||||
expect(getSplittedLines('aaa bbb', mockCalcValues)).toEqual(['aaa', 'bbb']);
|
||||
expect(getSplittedLines('top-hat', mockCalcValues)).toEqual(['top-', 'hat']);
|
||||
expect(getSplittedLines('top—hat', mockCalcValues)).toEqual(['top—', 'hat']); // em dash
|
||||
expect(getSplittedLines('top–hat', mockCalcValues)).toEqual(['top–', 'hat']); // en dash
|
||||
});
|
||||
|
||||
it('splits a line where the split point is on a space', () => {
|
||||
it('splits a line where the split point is on a breakable char', () => {
|
||||
expect(getSplittedLines('aaaaa bbbbb', mockCalcValues)).toEqual(['aaaaa', 'bbbbb']);
|
||||
expect(getSplittedLines('left-hand', mockCalcValues)).toEqual(['left-', 'hand']);
|
||||
});
|
||||
|
||||
it('splits a long line in the middle of a word if too long', () => {
|
||||
expect(getSplittedLines('aaaaaa bbb', mockCalcValues)).toEqual(['aaaaa', 'a bbb']);
|
||||
expect(getSplittedLines('aaaaaa-a b', mockCalcValues)).toEqual(['aaaaa', 'a-a b']);
|
||||
expect(getSplittedLines('aaaaa-aa b', mockCalcValues)).toEqual(['aaaaa', '-aa b']);
|
||||
});
|
||||
|
||||
it('splits a long line without spaces at exactly 5 chars', () => {
|
||||
it('splits a long line without breakable chars at exactly 5 chars', () => {
|
||||
expect(getSplittedLines('abcdef', mockCalcValues)).toEqual(['abcde', 'f']);
|
||||
});
|
||||
|
||||
it('splits a very long line without spaces at exactly 5 chars', () => {
|
||||
it('splits a very long line without breakable chars at exactly 5 chars', () => {
|
||||
expect(getSplittedLines('abcdefghijklmn', mockCalcValues)).toEqual(['abcde', 'fghij', 'klmn']);
|
||||
});
|
||||
|
||||
|
||||
@@ -152,21 +152,41 @@ const getOverPosition = (textLine: string, calcValues: FontWidthCalcValues) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Line breakable chars depend on the language and writing system.
|
||||
* Western writing systems typically use spaces and hyphens as line breakable chars.
|
||||
* Other writing systems often break on word boundaries so the following
|
||||
* does not negatively impact them.
|
||||
* However, this might need to be revisited for broader language support.
|
||||
*/
|
||||
const isLineBreakableChar = (char: string) => {
|
||||
const lineBreakableChars = [' ', '-', "\u2014", "\u2013"];
|
||||
return lineBreakableChars.includes(char);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position of the split. Splits the exceeding line at
|
||||
* the last whitespace prior to it exceeding the bounding box width.
|
||||
* the last breakable char prior to it exceeding the bounding box width.
|
||||
*/
|
||||
const getSplitPosition = (textLine: string, calcValues: FontWidthCalcValues) => {
|
||||
const overPos = getOverPosition(textLine, calcValues);
|
||||
if (overPos === null) return textLine.length; // input line is shorter than the available space
|
||||
|
||||
let overPosTmp = overPos;
|
||||
while (textLine[overPosTmp] !== ' ' && overPosTmp >= 0) {
|
||||
if (textLine[overPos] === ' ') {
|
||||
// if the character immediately beyond the boundary is a space, split
|
||||
return overPos;
|
||||
}
|
||||
|
||||
let overPosTmp = overPos - 1;
|
||||
while (overPosTmp >= 0) {
|
||||
if (isLineBreakableChar(textLine[overPosTmp])) {
|
||||
return overPosTmp+1;
|
||||
}
|
||||
overPosTmp--;
|
||||
}
|
||||
|
||||
// For very long lines with no whitespace use the original overPos
|
||||
return overPosTmp > 0 ? overPosTmp : overPos;
|
||||
// For very long lines with no breakable chars use the original overPos
|
||||
return overPos;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -175,7 +195,7 @@ const getSplitPosition = (textLine: string, calcValues: FontWidthCalcValues) =>
|
||||
*/
|
||||
export const getSplittedLines = (textLine: string, calcValues: FontWidthCalcValues): string[] => {
|
||||
const splitPos = getSplitPosition(textLine, calcValues);
|
||||
const splittedLine = textLine.substring(0, splitPos);
|
||||
const splittedLine = textLine.substring(0, splitPos).trimEnd();
|
||||
const rest = textLine.substring(splitPos).trimStart();
|
||||
|
||||
if (rest === textLine) {
|
||||
|
||||
Reference in New Issue
Block a user