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

100% table width, with auto column sizing #344

Open
DataTables opened this issue Jun 26, 2015 · 17 comments
Open

100% table width, with auto column sizing #344

DataTables opened this issue Jun 26, 2015 · 17 comments

Comments

@DataTables
Copy link
Contributor

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.

@GuardianMajor
Copy link

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

@BitPopCoin
Copy link

I'm trying to use 100% width with datatables, anyone know how?

@DougHayward
Copy link

From what I can tell a page is 600 wide less any margins. So:

100% = 600 - (marginLeft + marginRight)

@liborm85 liborm85 added the table label Feb 6, 2017
@fr0z3nfyr
Copy link

bump!

@Jbegley1995
Copy link

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('');

@azizrahaman
Copy link

azizrahaman commented Dec 30, 2017

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?

@Jbegley1995
Copy link

It works perfectly in mine, if you could provide an example maybe I could help out?

@pstoneg
Copy link

pstoneg commented Mar 27, 2018

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.

@pkExec
Copy link

pkExec commented Apr 3, 2018

@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","%","%"];

@hitautodestruct
Copy link

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?

@nickensoul
Copy link

any updates? how to set up the entire table to the 100% available width?

@dayrontbs12001

This comment has been minimized.

@kennylovrin
Copy link

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: 8a7e430

@krishankantray
Copy link

krishankantray commented Jan 16, 2021

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.

@mjy12
Copy link

mjy12 commented Dec 1, 2021

doc.content[0].table.widths = Array(doc.content[0].table.body[0].length + 1).join('*').split('');
make table width full fit to page

@RodSebDaS
Copy link

doc.content[1].table.widths = Array(doc.content[1].table.body[0].length + 1).join('*').split('');

@rachmd1987
Copy link

rachmd1987 commented Apr 19, 2023

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
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests