Skip to content

Instantly share code, notes, and snippets.

@emilioeduardob
Forked from niflostancu/wkhtmltopdf.tablesplit.js
Last active December 10, 2015 23:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save emilioeduardob/4510790 to your computer and use it in GitHub Desktop.
Save emilioeduardob/4510790 to your computer and use it in GitHub Desktop.
/**
* 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 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 pageWidthInchs = parseFloat($('meta[name=pageWidth]').attr('content'));
var pageHeightInchs = parseFloat($('meta[name=pageHeight]').attr('content'));
var pdfPage = {
width: pageWidthInchs, // inches
height: pageHeightInchs, // 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.
*
* @type {Number}
*/
var splitThreshold = -1; //calculated at runtime
/**
* 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');
//recalculate splitThreshold after page resize
$('.block-content tr').each(function() {
var h = $(this).height();
splitThreshold = h > splitThreshold ? h : splitThreshold;
})
/*
* Cycle through all tables and split them in two if necessary.
* We need this in a loop for it to work for tables spanning multiple pages:
* first, the table is split in two; then, if the second table also spans multiple
* pages, it is also split and so on until there are no more.
* Because when modifying the upper tables, the elements' positions will change,
* we need to maintain an offset correction value.
*
* This method can be used for all document's elements (not just tables), but the
* overhead would be too big. Use CSS's `page-break-inside: avoid` which works for
* divs and many other block elements.
*/
var tablesModified = true;
var offsetCorrection = 0;
while (tablesModified) {
tablesModified = false;
$('table.'+splitClassName).each(function(){
var $t = $(this);
//check to see if the thead TR is on the threshold
var ttop = offsetCorrection + $t.offset().top;
var pageEnd = (Math.floor(ttop/pageHeight)+1)*pageHeight;
if ($t.offset().top >= (pageEnd - splitThreshold)) {
var $br = $('<div style="height: 10px;"></div>')
.css('page-break-before', 'always');
$br.insertBefore($t);
return false;
}
// clone the original table
var copy = $t.clone();
copy.find('tbody > tr').remove();
var $cbody = copy.find('tbody');
var found = false;
$t.removeClass(splitClassName); // for optimisation
var newOffsetCorrection = offsetCorrection;
$('tbody tr', $t).each(function(){
var $tr = $(this);
// compute element's top position and page's end
var top = $tr.offset().top;
var ctop = offsetCorrection + top;
var pageEnd = (Math.floor(ctop/pageHeight)+1)*pageHeight;
// use for debugging (prints TR's top inside its first column)
// $tr.find('td:last').html(ctop + " - " + pageEnd + " T:" + splitThreshold);
// check whether the current element is close to the page's end.
if (ctop >= (pageEnd - splitThreshold)) {
// move the element to the cloned table
$tr.detach().appendTo($cbody);
if (!found) {
// compute the new offset correction
newOffsetCorrection += (pageEnd - ctop);
}
found = true;
}
});
// if the cloned table has no contents...
if (!found)
return;
offsetCorrection = newOffsetCorrection;
tablesModified = true;
// add a page-breaking div
// (with some whitespace to correctly show table top border)
var $br = $('<div style="height: 10px;"></div>')
.css('page-break-before', 'always');
$br.insertAfter($t);
copy.insertAfter($br);
});
}
// restore body's padding
$body.css('padding-left', 0);
$body.css('padding-right', 0);
});
@emilioeduardob
Copy link
Author

Modified to read the page size from the meta elements on the HTML

@emilioeduardob
Copy link
Author

  • Calculate TR max height after page load.
  • Check if THEAD is on the page threshold

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