Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
based on https://gist.github.com/niflostancu/3683510 by Florin Stancu This is a reworked table split hack. I had problems with the original with the tables not being populated evenly (I would sometimes have empty tables with headers only, or a table with only a few rows) This version has support for tfoot tags. Your table should be laid out with…
/**
* WkHtmlToPdf table splitting hack.
*
* Script to automatically split multiple-pages-spanning HTML tables for PDF
* generation using webkit.
*
* To use, you must adjust pdfPage object's contents to reflect your PDF's
* page format.
* The tables you want to be automatically splitted when the page ends must
* have a class name of "splitForPrint" (can be changed).
* Also, it might be a good idea to update the splitThreshold value if you have
* large table rows.
*
* Dependencies: jQuery.
*
* WARNING: WorksForMe(tm)!
* If it doesn't work, first check for javascript errors using a webkit browser.
*
* @author Jason Playne <jason@jasonplayne.com>
* @version 1.1
*
* @author Florin Stancu <niflostancu@gmail.com>
* @version 1.0
*
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* PDF page settings.
* Must have the correct values for the script to work.
* All numbers must be in inches (as floats)!
* Use google to convert margins from mm to in ;)
*
* @type {Object}
*/
var pdfPage = {
width: 8.26, // inches
height: 11.69, // inches
margins: {
top: 0.393701, left: 0.393701,
right: 0.393701, bottom: 0.393701
}
};
/**
* The distance to bottom of which if the element is closer, it should moved on
* the next page. Should be at least the element (TR)'s height.
*
* @type {Number}
*/
var splitThreshold = 60;
/**
* Class name of the tables to automatically split.
* Should not contain any CSS definitions because it is automatically removed
* after the split.
*
* @type {String}
*/
var splitClassName = 'splitForPrint';
/**
* Window load event handler.
* We use this instead of DOM ready because webkit doesn't load the images yet.
*/
$(window).load(function () {
// get document resolution
var dpi = $('<div id="dpi"></div>')
.css({
height: '1in', width: '1in',
top: '-100%', left: '-100%',
position: 'absolute'
})
.appendTo('body')
.height();
// page height in pixels
var pageHeight = Math.ceil(
(pdfPage.height - pdfPage.margins.top - pdfPage.margins.bottom) * dpi);
// temporary set body's width and padding to match pdf's size
var $body = $('body');
$body.css('width', (pdfPage.width - pdfPage.margins.left - pdfPage.margins.right) + 'in');
$body.css('padding-left', pdfPage.margins.left + 'in');
$body.css('padding-right', pdfPage.margins.right + 'in');
//////
$('table.' + splitClassName).each(function () {
var $origin_table = $(this);
var $template = $origin_table.clone()
$template.find('> tbody > tr').remove();
$template.find('> tfoot > tr').remove();
var current_table = 0
var split_tables = Array()
split_tables.push($template.clone())
insertIntoDom($origin_table, split_tables[current_table])
$origin_table.find('> tbody tr').each(function () {
var $tr = $(this);
$tr.detach().appendTo(split_tables[current_table].find('> tbody'));
if ($(split_tables[current_table]).height() > (pageHeight - splitThreshold)) {
current_table++
split_tables.push($template.clone())
insertIntoDom($origin_table, split_tables[current_table])
}
});
//table footer
var $tfoot = $origin_table.find('> tfoot')
var last_table_height = $(split_tables[current_table]).height()
if (last_table_height + $tfoot.height() > (pageHeight - splitThreshold)) {
current_table++
split_tables.push($template.clone())
insertIntoDom($origin_table, split_tables[current_table])
alert('made new table for footer')
}
$tfoot.detach().appendTo($(split_tables[current_table]))
$origin_table.remove()
$('div.page-breaker').last().remove()
});
function insertIntoDom(after, what) {
var $br = $('<div class="page-breaker" style="height: 10px;"></div>').css('page-break-before', 'always');
$(what).appendTo($(after).parent());
$br.insertAfter(what);
}
// restore body's padding
$body.css('padding-left', 0);
$body.css('padding-right', 0);
});
@carloshike

This comment has been minimized.

Copy link

carloshike commented May 14, 2013

The use of splitThreshold not seem very accurate, especially if the columns of the last row of the table are very large, so I made the following change:

if ($(split_tables[current_table]).height() > (pageHeight)) {
current_table++
split_tables.push($template.clone())
insertIntoDom($origin_table, split_tables[current_table])
split_tables[current_table - 1].find('> tbody > tr:last').detach().prependTo(split_tables[current_table].find('> tbody'))
}

It is also interesting to add a class for each table generated and set size like this:

$('.table_report').css('height', String(pageHeight) + 'px')
$('.table_report:last').css('height', 'auto')

@AAverin

This comment has been minimized.

Copy link

AAverin commented May 29, 2013

Here is another implementation from me, check it out!
https://github.com/AAverin/JSUtils/tree/master/wkhtmltopdfTableSplitHack

@vstefanoxx

This comment has been minimized.

Copy link

vstefanoxx commented Jul 9, 2014

I did a similar script that does vertical splitting on wide tables instead of horizontal splitting.
I wrote it starting from the idea of Florin Stancu & forks.

I didn't find any satisfying solution for it on the web, so maybe you can find it helpful:
https://github.com/vstefanoxx/JSUtils/tree/master/TableVerticalSplitHack

Here is a working example:
http://jsfiddle.net/mU2Ne/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.