import html2canvas from 'html2canvas'
import JsPDF from 'jspdf'
export default class DomToPdf {
constructor(options) {
const {
targetEl,
fileName,
splitClassName,
emptyDivBgColor = 'white',
pageWidth = 595,
pageHeight = 842
} = options
this.ele = targetEl
this.pdfFileName = fileName
this.splitClassName = splitClassName
this.emptyDivBgColor = emptyDivBgColor
this.pageWidth = pageWidth
this.pageHeight = pageHeight
}
handlePagination(scale) {
this.ele.style.height = 'initial'
this.scale = scale || 2
const target = this.ele
const pageHeight = (target.scrollWidth / this.pageWidth) * this.pageHeight
const domList = document.getElementsByClassName(this.splitClassName)
let pageNum = 1
const eleBounding = this.ele.getBoundingClientRect()
for (let i = 0; i < domList.length; i++) {
const node = domList[i]
const bound = node.getBoundingClientRect()
const offset2Ele = bound.top - eleBounding.top
const currentPage = Math.ceil(
(bound.bottom - eleBounding.top) / pageHeight
)
if (pageNum < currentPage) {
pageNum++
const divParent = node.parentNode
const newNode = document.createElement('div')
newNode.className = 'emptyDiv'
newNode.style.background = this.emptyDivBgColor
newNode.style.height = `${
pageHeight * (pageNum - 1) - offset2Ele + 30
}px`
newNode.style.width = '100%'
divParent.insertBefore(newNode, node)
}
}
}
async exportToBlob(options = {}) {
return new Promise((resolve, reject) => {
try {
this.handlePagination(options.scale || 2)
const ele = this.ele
const eleW = ele.offsetWidth
const eleH = ele.scrollHeight
const eleOffsetTop = ele.offsetTop
const eleOffsetLeft = ele.offsetLeft
const canvas = document.createElement('canvas')
let abs = 0
const win_in =
document.documentElement.clientWidth || document.body.clientWidth
const win_out = window.innerWidth
if (win_out > win_in) {
abs = (win_out - win_in) / 2
}
canvas.width = eleW * this.scale
canvas.height = eleH * this.scale
const context = canvas.getContext('2d')
context.scale(this.scale, this.scale)
context.translate(-eleOffsetLeft - abs, -eleOffsetTop)
html2canvas(ele, {
scale: this.scale,
useCORS: true,
logging: false
}).then((canvasResult) => {
const contentWidth = canvasResult.width
const contentHeight = canvasResult.height
const pageHeight = (contentWidth / this.pageWidth) * this.pageHeight
let leftHeight = contentHeight
let position = 0
const imgWidth = this.pageWidth - 10
const imgHeight = (this.pageWidth / contentWidth) * contentHeight
const pageData = canvasResult.toDataURL('image/jpeg', 1.0)
const pdf = new JsPDF('', 'pt', 'a4')
if (leftHeight < pageHeight) {
pdf.addImage(pageData, 'JPEG', 5, 0, imgWidth, imgHeight)
} else {
while (leftHeight > 0) {
pdf.addImage(pageData, 'JPEG', 5, position, imgWidth, imgHeight)
leftHeight -= pageHeight
position -= this.pageHeight
if (leftHeight > 0) {
pdf.addPage()
}
}
}
const pdfBlob = pdf.output('blob')
const doms = document.querySelectorAll('.emptyDiv')
for (let i = 0; i < doms.length; i++) {
doms[i].remove()
}
this.ele.style.height = ''
resolve(pdfBlob)
}).catch((error) => {
reject(error)
})
} catch (error) {
reject(error)
}
})
}
async exportToPdf(options = {}) {
return new Promise((resolve, reject) => {
try {
this.handlePagination(options.scale || 2)
this.exportToBlob(options).then((pdfBlob) => {
const url = URL.createObjectURL(pdfBlob)
const link = document.createElement('a')
link.href = url
link.download = `${this.pdfFileName}.pdf`
link.click()
URL.revokeObjectURL(url)
resolve()
}).catch((error) => {
reject(error)
})
} catch (error) {
reject(error)
}
})
}
}
