How to create a multipage PDF in Rails representing one table of data (including column headers on each new page)?
Asked Answered
W

3

3

How to create a multipage PDF in Rails representing one table of data (including column headers on each new page)? I've looked at many examples with wicked-pdf, pdfkit, and prawn but haven't seen anything that specifically addresses the overflow into subsequent pages and the need to repeat the headers with each new page. Thanks for the help.

Woodsman answered 23/5, 2012 at 1:24 Comment(3)
what about creating a header function (like a partial or something).. then after n records writed place a page break... https://mcmap.net/q/404347/-rails-wickedpdf-page-breaks , i did something like this once but in classic asp.... btw this is a dumb approach and use it as last resource..Chinese
This may not be a bad approach if the content of each row is predictably one line per record.Woodsman
yeah it worked right when i did it because i knew the exact size of each row (don't know if this is your case).. so.. after 40 records do a page break, if no more records, put the "footer" of the document.. .. it was simple but im sure there's a more efficient way to do itChinese
S
4

I use Prawn to generate my pdfs, and can get the effect you desire like this:

def render_photo_table(pdf)
  ps = self.photos.map do |photo|
    [photo.filename, photo.image_height, photo.image_width]
  end
  ps.insert(0, ['Filename', 'Height', 'Width'])
  pdf.table(ps) do |table|
    table.header = true
  end
end

This yields a header (set in array position 0) at the top of each page.

Supposing answered 15/6, 2012 at 4:0 Comment(0)
F
3

Had trouble with this too, but found a fairly easy way(after much headaches) to do this.

Place a floated placemark div above the items so you can get starting coordinates (I call it ID item_top).

Then render the page with top level divs of data, with class 'unbreakable'.

Also include a class to force a page break:

.page-breaker {
  display: block;
  clear: both;
  page-break-after: always;
}

Then after rendering

<script>
// Very top of items
var current_top = $('#item_top').offset().top;
// Check distance from top of page to bottom of item
// If greater than page size put page break and headers before
// Reset top of page to top of item.
$('.unbreakable_section').each(function(index) {
  var item_bottom = $(this).offset().top + $(this).outerHeight(true);
  if ((item_bottom - current_top) > 1250) {
    $(this).before("<div class='page-breaker'></div>");
    $(this).before("Headings Div here");
    current_top = $(this).offset().top - 48; // item - header height
  }
});

</script>

This will measure the vertical space since the last page break and start a new page and place a header above it, if the space exceeds the page height. (1250 is approximate which was close enough for me - I have a footer on the page as well so height may vary depending on your setup).

Tested on a 100 page document works as expected.

Fletcherfletcherism answered 15/11, 2012 at 9:19 Comment(0)
H
1

We wrote our in-house jquery code for this.

If you have pages like:

<div class="mypage">
  <div class="mypage_footer"></div>
</div>

And outside you have:

<div class="mybox">
  <table><tbody><tr><td>omg</td></tr></tbody></table>
</div>
<div class="mybox">
  <table><tbody><tr><td>lol</td></tr></tbody></table>
</div>

Assuming you have a fixed page height (preferably A4 size), you can use jquery to:

  • Compute remaining space inside mypage by subtracting the $(element).height() of the page's children from the height of mypage
  • While there is remaining space, pick a mybox from outside the page and place it inside the page
  • If there is no more space, create a copy of the first page and repeat.
Historiographer answered 25/5, 2012 at 15:22 Comment(3)
Interesting approach. Did you see any limit to the number of pages you could handle this way? Can you share the actual function?Woodsman
Yes, in fact after 50 or so pages, the wkhtmltopdf zoom parameter loses its accurracy and millimetric sliding starts to happen. I will ask if I can share the code.Historiographer
Also, we can't get more than 96dpi with this method.Historiographer

© 2022 - 2024 — McMap. All rights reserved.