Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

html2canvas Option onclone Not Working as Expected with jsPDF #2987

Open
chucknelson opened this issue Oct 29, 2020 · 11 comments
Open

html2canvas Option onclone Not Working as Expected with jsPDF #2987

chucknelson opened this issue Oct 29, 2020 · 11 comments

Comments

@chucknelson
Copy link

chucknelson commented Oct 29, 2020

When passing a function to the html2canvas option onclone via jsPDF, via the html module's html2canvas property, the generated PDF does not reflect the changes in the cloned document.

Some self-contained html is below to copy+paste, which demonstrates what seems to be happening. From what I can tell, jsPDF is using an overlay and container for its document source, while html2canvas creates its own container for its cloned document, which jsPDF never seems to reference.

I didn't see any existing issues around this, so not sure if I'm missing something, using incompatible versions of something, etc. Thanks for any help!

<html>
<head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.1.1/jspdf.umd.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/html2canvas@1.0.0-rc.7/dist/html2canvas.js"></script>
    <style type="text/css">
        .html2pdf__overlay {
            margin: 12px 0;
            visibility: visible !important;
            position: unset !important;
            border: solid 1px red !important;
            height: 250px !important;
            width: 500px !important;
        }

        .html2canvas-container {
            visibility: visible !important;
            position: unset !important;
            border: solid 1px blue !important;
            height: 250px !important;
            width: 500px !important;
        }
    </style>
</head>

<body>
    <div id="mainContainer">
        <span id="mainText">Original Document</span>
    </div>
    <button id="jsPdfButton">Generate PDF</button>
    <div>
        <span style="color: red;">jsPDF / html2pdf overlay is red</span><br />
        <span style="color: blue;">html2canvas container for cloned document in blue</span>
    </div>

    <script type="text/javascript">
        function delay(t, v) {
            return new Promise(function (resolve) {
                setTimeout(resolve.bind(null, v), t)
            });
        }

        const { jsPDF } = window.jspdf;
        const doc = new jsPDF("portrait", "pt", "a4");
        
        document.getElementById("jsPdfButton").addEventListener("click", (event) => {    
            doc.html(document.getElementById("mainContainer"), {
                html2canvas: {
                    removeContainer: false,
                    onclone: async function (doc) {
                        // Change text in cloned document, which should reflect in generated PDF
                        // Slowing it down to see what's going on...
                        await delay(2000);
                        doc.getElementById("mainText").innerHTML = "Cloned Document";
                        await delay(2000);
                    }
                },
                callback: function (doc) {
                    window.open(doc.output("bloburl"));
                }
            });
        });
    </script>
</body>
</html>
@HackbrettXXX
Copy link
Collaborator

HackbrettXXX commented Dec 3, 2020

The html2canvas option is currently not for passing options to html2canvas, but for injecting the html2canvas module. We should probably improve this situation, though.

@chucknelson
Copy link
Author

The html2canvas option is currently not for passing options to html2canvas, but for injecting the html2canvas option.

Thanks - not sure I understand what the difference is? The Html2CanvasOptions type supports the onclone option, and other options are respected by html2canvas.

In lieu of improving the situation, is there some way we can improve the documentation maybe? Not entirely sure what we'd say, but hoping to figure it out :)

@HackbrettXXX
Copy link
Collaborator

Ah sorry, I wrote "html2canvas option" instead of "html2canvas module". The typings suggest that you can pass html2canvas options to html2canvas, but that's unfortunately not true/not implemented. I'm willing to accept a PR that will improve this situation. Passing options to html2canvas should really be possible. For backwards compatibility, we should probably check if the argument is the html2canvas function or the options object and treat it respectively.

@nivb52
Copy link

nivb52 commented Feb 16, 2021

Try use it like this,
i didn't found problem with that.

const PDFisLoadingEl = document.getElementById('PDFisLoading');
const removeLoadingModal = () => PDFisLoadingEl.remove();
pdfDoc.html(document.body, {
                    callback: function (JsPDFinstance) {
                        JsPDFinstance.save();
                    },
                    filename,
                    html2canvas: {scale: 0.1, onclone: removeLoadingModal},
                    x: 0,
                    y: 0
                });

@github-actions
Copy link

This issue is stale because it has been open 90 days with no activity. It will be closed soon. Please comment/reopen if this issue is still relevant.

@LorenzoDelpi
Copy link

LorenzoDelpi commented Jun 3, 2021

there is any update about that? i have a similar problem, my changes in the onclone function are reflected in the cloned document but only few are showed when the premises is solved

@noeGnh
Copy link

noeGnh commented Dec 8, 2021

It seems that the issue is due to the fact that the styles of the clone element used by jsPDF keep the same properties as the source html element. It would be necessary to be able to apply to them the same modifications made in the onclone option for that to work.

@ericjames
Copy link

html2canvas onclone is necessary in order to intercept and modify elements in the finished document before final output. The current workaround is to chain it by directly installing and using html2canvas and using the final canvas object to create the jsPDF.

@jclark-dot-org
Copy link

Has this changed? @HackbrettXXX stated previously:

The typings suggest that you can pass html2canvas options to html2canvas, but that's unfortunately not true/not implemented. I'm willing to accept a PR that will improve this situation. Passing options to html2canvas should really be possible.

However, the current docs show the html2canvas param to .html() as type Html2CanvasOptions, and other params appear to be passed to html2canvas correctly now. However, I'm still not seeing changes made in the onclone callback reflected in the pdf. With html2canvas logging enabled (by passing an options object to html2canvas in fact), I see the clone start, the onclone callback called, and the clone end, but my pdf if still not getting the changes.

@JxstWieslaw
Copy link

@HackbrettXXX Apparently on my rendered canvas, l have noticed that some css properties such as left are not maintained and as such the rendered image is out of the actually required viewport.

I have tried the onclone option to add the style back to my document, but its not being fulfilled unfortunately. I have also noticed that as a matter of fact, the required section had already been turned a canvas regardless of the callback function implement. Simple console.logging has ascertained this.

Is there a fix or get-around to the onclone method. Please assist, its a bit important...thanks

@RenatoLemons
Copy link

Hi there,
I was looking for a solution for my similar issue and found this thread, for me these steps bellow make the original post works:

  1. Upgrade the html2canvas to version 1.4.1
  2. Replace onclone: async function(doc) by onclone: async function(doc, element) and doc.getElementById("mainText") by element.querySelector("#mainText")

I also created a fiddle to test https://jsfiddle.net/renatobl/emzjufr2/
Thanks

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

No branches or pull requests

9 participants