[Enhancement Suggestion] Proper word-break (don't break in the middle of words)
See original GitHub issueFirst, Thank you for such a great plugin which made our life much easier.
I’m facing a big problem when using the plugin with real-life data, when there’s even only one cell in a column with long text, the other columns cells will break in the middle of words which makes it unreadable and taking double the vertical space when it should take space from the big column.
This makes it unusable without defining minCellWidth
for columns or preventing it from wrapping altogether, that could work for some cases but that’s not the answer, I have user-defined data in these rows which could be one word, or more, I want it to break into lines (correctly) only when needed.
So, as an attempt to solve the problem, I tried to figure out how HTML tables handle this, What I found is that each column will have a minimum width that will not get smaller than the longest word in that column.
So I used the following hook
code to set minWidth
for each column to the longest word :
doc.autoTable({
// ...
/**
* Prevent AutoTable from breaking lines in the middle of words
* by setting the minWidth to the longest word in the column
*
* WARNING: this may cause the table to exceede the allowed width (just like in HTML)
* and give a "can't fit page" console error, could be improved.
*/
didParseCell({doc, cell, column}) {
if (cell === undefined) {
return;
}
const hasCustomWidth = (typeof cell.styles.cellWidth === 'number');
if (hasCustomWidth || cell.raw == null || cell.colSpan > 1) {
return
}
let text;
if (cell.raw instanceof Node) {
text = cell.raw.innerText;
} else {
if (typeof cell.raw == 'object') {
// not implemented yet
// when a cell contains other cells (colSpan)
return;
} else {
text = '' + cell.raw;
}
}
// split cell string by spaces
const words = text.split(/\s+/);
// calculate longest word width
const maxWordUnitWidth = words.map(s => Math.floor(doc.getStringUnitWidth(s) * 100) / 100).reduce((a, b) => Math.max(a, b), 0);
const maxWordWidth = maxWordUnitWidth * (cell.styles.fontSize / doc.internal.scaleFactor)
const minWidth = cell.padding('horizontal') + maxWordWidth;
// update minWidth for cell & column
if (minWidth > cell.minWidth) {
cell.minWidth = minWidth;
}
if (cell.minWidth > cell.wrappedWidth) {
cell.wrappedWidth = cell.minWidth;
}
if (cell.minWidth > column.minWidth) {
column.minWidth = cell.minWidth;
}
if (column.minWidth > column.wrappedWidth) {
column.wrappedWidth = column.minWidth;
}
}
});
codepen: https://codepen.io/mmghv/pen/eYYvQqO?editors=1010
And this was the result :
As you can see, It fixed the problem, now the spacing makes more sense and the table actually look more like the HTML version.
I believe that this should be the default behavior.
I didn’t do a pull request because it still needs improvements and a way to handle colSpan
but I’m in the middle of a project right now, so I’m leaving this here as a starting point, and as a quick fix for anyone who could be facing the same problem.
Note
side effect of this, it may cause the table width to get outside of the defined boundaries if the total width of the longest words in each column is greater than the defined tableWidth
.
This is actually how HTML tables behave, But I fell like it shouldn’t be that way with AutoTable, I’m not sure.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:7
- Comments:12 (5 by maintainers)
Top GitHub Comments
Prioritizing not breaking words sounds like a great way to solve many of these issues!
Implemented on master but this feature needs some more testing before release.