Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lines-wordwrap): support wordbreak and hyphens option on lines method #3

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,11 @@ Defaults to `el.innerText` if an element is available
#### options
Type: `object`

| key | default | description
| --------- | ------- | -----------
| multiline | `false` | The width of widest line instead of the width of the complete text
| key | default | options | description |
|-----------|-------------|--------------|--------------------------------------------------------------------------------------|
| multiline | `false` | [true|false] | The width of widest line instead of the width of the complete text |
| wordBreak | `undefined` | [break-all] | Should insert line breaks wherever the text would otherwise overflow its content box |
| hypens | `undefined` | [auto] | AllowsAllows unbreakable words to be broken with `-` as separator |

#### overwrites
Type: `object`
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@
return computeLinesBreakAll({ ctx: ctx, text: text, max: max, wordSpacing: wordSpacing, letterSpacing: letterSpacing });
}

return computeLinesDefault({ ctx: ctx, text: text, max: max, wordSpacing: wordSpacing, letterSpacing: letterSpacing });
return computeLinesDefault({ ctx: ctx, text: text, max: max, wordSpacing: wordSpacing, letterSpacing: letterSpacing, options: options });
}
}, {
key: 'maxFontSize',
Expand Down
33 changes: 27 additions & 6 deletions dist/text-metrics.bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@
return computeLinesBreakAll({ ctx: ctx, text: text, max: max, wordSpacing: wordSpacing, letterSpacing: letterSpacing });
}

return computeLinesDefault({ ctx: ctx, text: text, max: max, wordSpacing: wordSpacing, letterSpacing: letterSpacing });
return computeLinesDefault({ ctx: ctx, text: text, max: max, wordSpacing: wordSpacing, letterSpacing: letterSpacing, options: options });
}
}, {
key: 'maxFontSize',
Expand Down Expand Up @@ -556,7 +556,7 @@
text = text.replace(/<wbr>/ig, '\u200B').replace(/<br\s*\/?>/ig, '\n').replace(/&shy;/ig, '\xAD').replace(/&mdash;/ig, '\u2014');

if (/&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+);/g.test(text) && console) {
console.error('text-metrics: Found encoded htmlenties. \nYou may want to use https://mths.be/he to decode your text first.');
console.error('text-metrics: Found encoded htmlenties.\nYou may want to use https://mths.be/he to decode your text first.');
}

return text.trim();
Expand Down Expand Up @@ -645,7 +645,8 @@
text = _ref.text,
max = _ref.max,
wordSpacing = _ref.wordSpacing,
letterSpacing = _ref.letterSpacing;
letterSpacing = _ref.letterSpacing,
options = _ref.options;

var addSpacing = addWordAndLetterSpacing(wordSpacing, letterSpacing);
var lines = [];
Expand Down Expand Up @@ -689,7 +690,27 @@
}

if (part) {
parts.push(part);
var width = parseInt(ctx.measureText(part).width, 10);

if (width > max && options.wordwrap) {
part.split('').reduce(function (prev, next) {
var lastPartPosition = prev.length && prev.length - 1 || 0;

prev[lastPartPosition] = prev[lastPartPosition] ? prev[lastPartPosition] : '';

if (parseInt(ctx.measureText(prev[lastPartPosition]).width, 10) > max) {
prev.push(next);
}

prev[lastPartPosition] += next;

return prev;
}, []).map(function (item) {
return parts.push(item) && breakpoints.push({ type: 'SHY' });
});
} else {
parts.push(part);
}
}

// Loop over text parts and compute the lines
Expand All @@ -711,9 +732,9 @@
}

// Measure width
var width = parseInt(ctx.measureText(line + _chr + _part).width + addSpacing(line + _chr + _part), 10);
var _width = parseInt(ctx.measureText(line + _chr + _part).width + addSpacing(line + _chr + _part), 10);
// Still fits in line
if (width <= max) {
if (_width <= max) {
line += _chr + _part;
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion dist/text-metrics.bundle.min.js

Large diffs are not rendered by default.

31 changes: 26 additions & 5 deletions dist/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@
text = text.replace(/<wbr>/ig, '\u200B').replace(/<br\s*\/?>/ig, '\n').replace(/&shy;/ig, '\xAD').replace(/&mdash;/ig, '\u2014');

if (/&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+);/g.test(text) && console) {
console.error('text-metrics: Found encoded htmlenties. \nYou may want to use https://mths.be/he to decode your text first.');
console.error('text-metrics: Found encoded htmlenties.\nYou may want to use https://mths.be/he to decode your text first.');
}

return text.trim();
Expand Down Expand Up @@ -371,7 +371,8 @@
text = _ref.text,
max = _ref.max,
wordSpacing = _ref.wordSpacing,
letterSpacing = _ref.letterSpacing;
letterSpacing = _ref.letterSpacing,
options = _ref.options;

var addSpacing = addWordAndLetterSpacing(wordSpacing, letterSpacing);
var lines = [];
Expand Down Expand Up @@ -415,7 +416,27 @@
}

if (part) {
parts.push(part);
var width = parseInt(ctx.measureText(part).width, 10);

if (width > max && options.wordwrap) {
part.split('').reduce(function (prev, next) {
var lastPartPosition = prev.length && prev.length - 1 || 0;

prev[lastPartPosition] = prev[lastPartPosition] ? prev[lastPartPosition] : '';

if (parseInt(ctx.measureText(prev[lastPartPosition]).width, 10) > max) {
prev.push(next);
}

prev[lastPartPosition] += next;

return prev;
}, []).map(function (item) {
return parts.push(item) && breakpoints.push({ type: 'SHY' });
});
} else {
parts.push(part);
}
}

// Loop over text parts and compute the lines
Expand All @@ -437,9 +458,9 @@
}

// Measure width
var width = parseInt(ctx.measureText(line + _chr + _part).width + addSpacing(line + _chr + _part), 10);
var _width = parseInt(ctx.measureText(line + _chr + _part).width + addSpacing(line + _chr + _part), 10);
// Still fits in line
if (width <= max) {
if (_width <= max) {
line += _chr + _part;
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ class TextMetrics {
return computeLinesBreakAll({ctx, text, max, wordSpacing, letterSpacing});
}

return computeLinesDefault({ctx, text, max, wordSpacing, letterSpacing});
return computeLinesDefault({ctx, text, max, wordSpacing, letterSpacing, options});
}

/**
Expand Down
36 changes: 33 additions & 3 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export function prepareText(text) {
.replace(/&mdash;/ig, '\u2014');

if (/&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+);/g.test(text) && console) {
console.error(`text-metrics: Found encoded htmlenties.
console.error(`text-metrics: Found encoded htmlenties.
You may want to use https://mths.be/he to decode your text first.`);
}

Expand Down Expand Up @@ -329,7 +329,7 @@ export function checkBreak(chr) {
(BK.includes(chr) && 'BK');
}

export function computeLinesDefault({ctx, text, max, wordSpacing, letterSpacing}) {
export function computeLinesDefault({ctx, text, max, wordSpacing, letterSpacing, options}) {
const addSpacing = addWordAndLetterSpacing(wordSpacing, letterSpacing);
const lines = [];
const parts = [];
Expand All @@ -351,7 +351,37 @@ export function computeLinesDefault({ctx, text, max, wordSpacing, letterSpacing}
}

if (part) {
parts.push(part);
const width = parseInt(ctx.measureText(part).width, 10);
let breakPointType = null;

if (options.wordBreak === 'break-all') {
breakPointType = 'BAI';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} else if (options.hyphens === 'auto') {
breakPointType = 'SHY';
}

if ((width > max) && breakPointType) {
part
.split('')
.reduce((prev, next) => {
const lastPartPosition = (prev.length && (prev.length - 1)) || 0;

prev[lastPartPosition] = prev[lastPartPosition] ? prev[lastPartPosition] : '';

if (parseInt(ctx.measureText(prev[lastPartPosition]).width, 10) > max) {
prev.push(next);
}

prev[lastPartPosition] += next;

return prev;
}, [])
.map(item => (
parts.push(item) && breakpoints.push({type: breakPointType})
));
} else {
parts.push(part);
}
}

// Loop over text parts and compute the lines
Expand Down
54 changes: 54 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,60 @@ test('Computes maxFontSize', t => {
t.is(val, '183px');
});

test('Computes lines with one very long word with break all option', t => {
const el = document.querySelector('#height');

const text = 'Craspharetrapharetragravida.Vivamusconsequatlacusvelposuerecongue.Duisaloremvitaeexauctorscelerisquenoneuturpis.Utimperdietmagnasitametjustobibendumvehicula.';
const expected = [
'Craspharetraphar',
'retragravida.Vivam',
'musconsequatlac',
'cusvelposuerecon',
'ngue.Duisaloremv',
'vitaeexauctorscel',
'lerisquenoneutur',
'rpis.Utimperdietma',
'agnasitametjustob',
'bibendumvehicul',
'la.'
];

const value = textMetrics(el).lines(text, {multiline: true, wordBreak: 'break-all'});

t.is(value.length, expected.length);

for (let i = 0; i < value.length; i++) {
t.is(value[i], expected[i]);
}
});

test('Computes lines with one very long word with hyphen option', t => {
const el = document.querySelector('#height');

const text = 'Craspharetrapharetragravida.Vivamusconsequatlacusvelposuerecongue.Duisaloremvitaeexauctorscelerisquenoneuturpis.Utimperdietmagnasitametjustobibendumvehicula.';
const expected = [
'Craspharetraphar-',
'retragravida.Vivam-',
'musconsequatlac-',
'cusvelposuerecon-',
'ngue.Duisaloremv-',
'vitaeexauctorscel-',
'lerisquenoneutur-',
'rpis.Utimperdietma-',
'agnasitametjustob-',
'bibendumvehicul-',
'la.'
];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hyphens 'auto' behaves different. If you want to add a hyphen at the end of each line you can do

const value = textMetrics(el).lines(text.replace(/(.{1})/g,"$1&shy;"))


const value = textMetrics(el).lines(text, {multiline: true, hyphens: 'auto'});

t.is(value.length, expected.length);

for (let i = 0; i < value.length; i++) {
t.is(value[i], expected[i]);
}
});

test('Computes lines', t => {
const el = document.querySelector('#height');

Expand Down