I am trying to convert a chunk of html to image data using html2canvas so that I can easily add it to a pdf. I've noticed that the few pieces of html which are SVG foreignObjects render in the pdf more closely to their actual appearance when the html2canvas foreignObjectRendering option is set to true, but everything else looks very wrong. Naturally, I expected that making two separate calls to html2canvas, one with the foreignObjectRendering option unset for the main chunk of html, and one with the option set as true for the few pesky foreignObjects, would be a viable solution. I decided to remove the foreignObjects from the DOM, complete a first-pass render and add the main chunk to the pdf, then add the foreignObjects back to the DOM and pass those to html2canvas next. When I try calling html2canvas on the re-added foreignObjects, I receive the following error:
Unable to find element in cloned iframe
Here is the outline of the relevant code:
let chunkToRender = document.querySelector('div.wrapper') as HTMLElement;
let pdf = new jsPDF("p", "mm", "a4");
const foreignObjects: Array<any> = [];
chunkToRender.querySelectorAll('foreignObject').forEach(fo => {
foreignObjects.push({parent: fo.parentNode, child: fo.parentNode?.removeChild(fo)});
})
async function addPDFPiece(targetElem: HTMLElement) {
await html2canvas(targetElem, {foreignObjectRendering: targetElem.nodeName === 'foreignObject'})
.then(canvas => {
let imgData = canvas.toDataURL("image/jpeg",1);
const imageWidth = canvas.width;
const imageHeight = canvas.height;
const ratio = imageWidth / imageHeight >= pageWidth / pageHeight ? pageWidth / imageWidth : pageHeight / imageHeight;
const x = targetElem.getBoundingClientRect().x * ratio;
const y = targetElem.getBoundingClientRect().y * ratio + 15;
const w = !isNaN(imageWidth * ratio) ? imageWidth * ratio : 1;
const h = !isNaN(imageHeight * ratio) ? imageHeight * ratio : 1;
pdf.addImage(imgData, 'JPEG', x, y, w, h);
})
}
await addPDFPiece(chunkToRender);
for (let fo of foreignObjects) {
fo.parent?.appendChild(fo.child);
console.log(fo.child); // This prints the correct foreignObject...
await addPDFPiece(fo.child);
// Error occurs here ^^^^, when html2canvas is initialized
}
pdf.save(filename);
Is there any way to achieve what I'm looking to do?
question from:
https://stackoverflow.com/questions/65850674/how-can-i-render-html-containing-an-svg-foreignobject-using-html2canvas 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…