100% table width, with auto column sizing
While looking to make my tables 100% width, I found #44:
set at least one column to star-sizing
So I tried setting all of the columns * but that results in all columns having the same width.
So I tried * in the first item and auto for the others:
widths: $.map( data.header, function (d, i) {
return i===0 ? '*' : 'auto';
} ),
But that just added the extra width to the first column.
So I'm wondering if there is a way to have the auto column width, but with 100% table width.
Another option might be if there is a method to get the page width, I could compute the sizes to use based on my HTML table.
Having just tried to use PDFMake myself, I find the inability to set the total width to 100% for the chosen page size and then setting setting the widths to say auto, *, * so that your first column is sized to the content and the rest of the page is evenly distributed between columns 2 and 3, to be a very limiting capability and makes the functional use of creating PDF based on a table nearly useless.
I know this question has been posted a long time ago, is there is any feedback from the developer on this? @bpampuch
I'm trying to use 100% width with datatables, anyone know how?
From what I can tell a page is 600 wide less any margins. So:
100% = 600 - (marginLeft + marginRight)
bump!
I found a good implementation for DataTables, I added a star auto sizing option for the table widths. It basically works by figuring out the full auto sized width of all the columns and than stretches that to 100% of the available width that is left. Star sizing kind of seemed weird to me because it gives all of the columns the same width when I think naturally they just want it to fit the page. Anyway its a starting point and it works great for me, let me know if it helps anybody and we can try to get it added to the repository
Changes to pdfmake.js (version v0.1.33):
line 23083 replace the buildColumnWidths function with this modified version:
function buildColumnWidths(columns, availableWidth) {
var autoColumns = [],
autoMin = 0, autoMax = 0,
starColumns = [],
starAutoColumns = [],
starMaxMin = 0,
starMaxMax = 0,
starAutoColWidth = 0,
fixedColumns = [],
initial_availableWidth = availableWidth;
columns.forEach(function (column) {
if (isAutoColumn(column)) {
autoColumns.push(column);
autoMin += column._minWidth;
autoMax += column._maxWidth;
} else if (isStarColumn(column)) {
starColumns.push(column);
starMaxMin = Math.max(starMaxMin, column._minWidth);
starMaxMax = Math.max(starMaxMax, column._maxWidth);
} else if (isStarAutoColumn(column)){
starAutoColumns.push(column);
} else {
fixedColumns.push(column);
}
starAutoColWidth += column._minWidth;
});
starAutoColumns.forEach(function (column) {
column._calcWidth = initial_availableWidth*(column._minWidth/starAutoColWidth);
});
fixedColumns.forEach(function (col) {
// width specified as %
if (typeof col.width === 'string' && /\d+%/.test(col.width)) {
col.width = parseFloat(col.width) * initial_availableWidth / 100;
}
if (col.width < (col._minWidth) && col.elasticWidth) {
col._calcWidth = col._minWidth;
} else {
col._calcWidth = col.width;
}
availableWidth -= col._calcWidth;
});
// http://www.freesoft.org/CIE/RFC/1942/18.htm
// http://www.w3.org/TR/CSS2/tables.html#width-layout
// http://dev.w3.org/csswg/css3-tables-algorithms/Overview.src.htm
var minW = autoMin + starMaxMin * starColumns.length;
var maxW = autoMax + starMaxMax * starColumns.length;
if (minW >= availableWidth) {
// case 1 - there's no way to fit all columns within available width
// that's actually pretty bad situation with PDF as we have no horizontal scroll
// no easy workaround (unless we decide, in the future, to split single words)
// currently we simply use minWidths for all columns
autoColumns.forEach(function (col) {
col._calcWidth = col._minWidth;
});
starColumns.forEach(function (col) {
col._calcWidth = starMaxMin; // starMaxMin already contains padding
});
} else {
if (maxW < availableWidth) {
// case 2 - we can fit rest of the table within available space
autoColumns.forEach(function (col) {
col._calcWidth = col._maxWidth;
availableWidth -= col._calcWidth;
});
} else {
// maxW is too large, but minW fits within available width
var W = availableWidth - minW;
var D = maxW - minW;
autoColumns.forEach(function (col) {
var d = col._maxWidth - col._minWidth;
col._calcWidth = col._minWidth + d * W / D;
availableWidth -= col._calcWidth;
});
}
if (starColumns.length > 0) {
var starSize = availableWidth / starColumns.length;
starColumns.forEach(function (col) {
col._calcWidth = starSize;
});
}
}
}
The only difference is that it utilizes the isStarAutoColumn function if it is being used but I figured this would be easier than copying and pasting on different lines inside the funciton.
line 23183 add:
function isStarAutoColumn(column){
return column.width === null || column.width === undefined || column.width === '%';
}
And inside of your datatables options use this inside of your customize function for your pdf button:
doc.content[0].table.widths =
Array(doc.content[0].table.body[0].length + 1).join('%').split('');
doc.content[1].table.widths = Array(doc.content[1].table.body[0].length + 1).join('%').split('');
But actually it wrongly distributing the width, column with less data taking more width than column with more data. Is there any solution?
It works perfectly in mine, if you could provide an example maybe I could help out?
My god I have been trying to find this solution for the longest time.
You are a gentlemen and a scholar.
Thanks for sharing that function.
@Jbegley1995 , excellent solution. It seems to have a bug though if you use mixed fixed widths and star-auto columns, like this: doc.content[1].table.widths=["50","%","%"];
Isn't there any generic way to get a 100% width table. I find the above code is an incredible overhead for this small feature?
any updates? how to set up the entire table to the 100% available width?
up
I was/am in strict need of this feature as well, but I decided to try to add the support to pdfmake, inspired by this thread. If it's of interest to others I can potentially add a test etc as well and submit a pull request.
The change itself is fairly basic and as nonintrusive as I could come up with. I added support for a new width type called "auto*" which kind of behaves as a combination of "auto" and "*", so whenever there is more space available than strictly needed any "auto*" columns will scale up proportionally until all space is filled. So essentially you get a full width table, but you can combine it with "auto" so certain columns won't grow.
It fills my need so far, so I though I might ask what others think. Can be seen here: 8a7e430f27d1608f2d7f7c18735d4f12fe6b89af
If there is header in your table then
table : { headerRows: 1, width:['auto','*','*'], body:[ [{text:'Count', style:'tableHeader'}, {text:'Alias', style:'tableHeader', margin:[80,0,80,0]}, {text:'Asset(s)', style:'tableHeader', margin:[80,0,80,0]}], ['1', 'Aasdjlalskjdflsjfldsjfjfslfljfjsdlajsdlad', 'Asstt'] ] }
adding margin at header also helps sometimes.
doc.content[0].table.widths = Array(doc.content[0].table.body[0].length + 1).join('*').split(''); make table width full fit to page
doc.content[1].table.widths = Array(doc.content[1].table.body[0].length + 1).join('*').split('');
customize: function (doc) { doc.content[1].table.widths = Array(doc.content[1].table.body[0].length + 1).join('*').split(''); #for full fit to page doc.content[1].table.widths = [ 50, 'auto', '*' ]; #customize if you know sum of columns ex. 3 cols }
It works for me
table: {
...
widths: cols.map((_, i) => {
const colsTotal = cols.length
if (i + 1 === colsTotal) {
return "*"
}
return `${100 / colsTotal}%`
}),
...
},