Skip to content

Instantly share code, notes, and snippets.

@benshimmin
Last active December 23, 2021 01:19
Show Gist options
  • Save benshimmin/50ab957d3c7b12cf88f9c9113400db3c to your computer and use it in GitHub Desktop.
Save benshimmin/50ab957d3c7b12cf88f9c9113400db3c to your computer and use it in GitHub Desktop.
How to render a web page into a multi-page PDF with html2canvas and jsPDF
# Assumptions:
# 1. $("#pdf-download") is something you can click on (not really required).
# 2. $(".result-page") is something in your existing page that you want to turn into a PDF.
# 3. You want to add a class of `pdf-rendered` to it and then specify some CSS which applies when that class is added.
# 4. Your CSS for `.pdf-rendered` specifies a useful width for a PDF (795px is pretty good) and anything else you like
# (this is for portrait ("p") PDFs; obviously you'll need to make a few modifications for landscape PDFs!).
# How it works:
# 1. Take the requested element in your existing page, clone it, add a "pdf-rendered" class to it, and append to
# the body.
# 2. Get the cloned element's height and use this to calculate how many `pages`.
# 3. For each page, turn the cloned element into a canvas using html2canvas, store the result in the `images`
# array, and then shift the content of the cloned element up by `pageCount` * `pageHeight`.
# 4. Repeat until you've run out of pages.
# 5. When done, call jsPDF and add a new page for each image in `images`, and add the image to the new page.
# 6. Save the PDF.
# Problems:
# 1. Yeah, it doesn't split the pages up very nicely. You'll have to live with that.
# 2. html2canvas doesn't understand all CSS, though it was fine for my examples.
# 3. I'm not convinced your pages won't end up out of order like this, though it didn't happen for me.
# 4. Why not just use the built-in functionality in your browser and OS to print a PDF? I don't know, maybe
# this is more flexible.
# 5. The PDFs generated are obviously pretty huge!
$("#pdf-download").on "click", ->
$toRender = $(".result-page").parent().clone().addClass "pdf-rendered"
# you can hide bits of the clone that you don't want to include in your PDF here using either
# CSS (.pdf-rendered .whatever { display : none }) or JavaScript ($toRender.remove(whatever))
$("body").append $toRender
images = []
pageHeight = 1110
h = $toRender.height()
pages = Math.ceil(h / pageHeight)
pageCount = 0
$toRender.css
overflow : "hidden"
height : pageHeight + 10
render = ->
$toRender.find(".result-page").css
position : "relative"
top : -(pageHeight + 10) * pageCount
html2canvas $toRender, {
onrendered : (canvas) ->
imgData = canvas.toDataURL("image/png")
images.push imgData
if ++pageCount < pages
render()
else
done()
}
render()
done = ->
doc = new jsPDF("p", "mm")
_.each images, (image, i) ->
if i > 0
doc.addPage()
doc.addImage(image, "PNG", 0, 0)
doc.save("output.pdf")
$toRender.remove()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment