Closed itsravenous closed 7 years ago
Is the element visible by scrolling on the page? What element are you passing to html2canvas as the element to render?
No, it's absolutely positioned and off-screened with left: -9999px. The element in question is a bar chart I created with some divs. It renders to canvas fine when on-screen.
So, the reason I'm off-screening it: The image generated is going to (at some point) be printed off, and so needs to be reasonably high-res. Thus I clone the chart, put it offscreen and enlarge it by a factor of 2 (using font-size and settings widhts/heights - I found using a CSS3 scale transform resulted in a blank image too, even if it was on-screen), and then call html2canvas on it.
Think a quick solution would be to position it on the page right before you call html2canvas on it, and then move it away right after. I'll have to look through the code to see where exactly it stops the off-screen elements to be rendered, but if you were calling html2canvas on the body element, the expected result would be to not have the item visible.
As for the scale CSS property, none of the CSS3 transorms work currently, but will hopefully be implemented, at least in part, at some point.
Aah, thanks - I'll try that out! Thanks for the info :)
Will you be fixing the problem? http://jsfiddle.net/makubex/DZDGw/2/
Or perhaps at least add a way to handle the error?
What exactly is the issue in your example? Seems to be doing what it should (tested with Chrome)
When the element is off-screen on the left, html2canvas just crashes, and provides no means of error handling. Chrome lets the exception go and onrendered is still fired, but in firefox it fails, it just throws the exception and stop executing the code.
The example is to demonstrate that :
I'm having a similar issue...I have a scrollable modal that I want to convert to canvas. When running html2canvas, it only captures the visible portion of the screen, truncating everything hidden from the scroll. Setting the height attribute has no impact.
@yojoe26, try using the scrollIntoView function to move the screen around as html2canvas is parsing it. I had a similar problem, and found a solution. Very hacky solution, and would not recommend if "scrolling wildly around the page" is going to be a user experience issue!
I added "options.elements[0].scrollIntoView(false);" as the first line in the "renderElement" function right before the variable declarations.
@parnelle89 - thanks for the tip!
@parnelle89 thanks very much! "options.elements[0].scrollIntoView(false);"
@parnelle89 "options.elements[0].scrollIntoView(false);" ? Can you give me an example with a whole js snippet? I am new to html2canvas. Thanks!
@niklasvh regarding the question above, can you tell me where in the code you specify the stopping point for off-screen elements to be rendered ?
by default, html2canvas uses the current viewport as the size of the canvas to be rendered (for obvious reasons). If, for instance, you want to render a particular element on the page that extends pass the fold -- or is entirely below the fold -- you can utilize the width/height options in the html2canvas call to render the element in it's entirety (not just the part that's within the viewport).
As long as the item is ulimately scrollable (and not, for example, positioned absolutely at something like left: -9999px) this should work :
var useWidth = document.getElementById("myElementThatExtendsBeyondTheViewport").style.width;
var useHeight = document.getElementById("myElementThatExtendsBeyondTheViewport").style.height;
html2canvas(element, {
width: useWidth,
height: useHeight,
onrendered: function(canvas) {
// you should get a canvas that includes the entire element -- not just the visible portion
}
});
If the element IS absolutely positioned offscreen -- as in @itsravenous 's case -- I would temporarily add the following CSS to make it renderable by html2canvas (but still invisible -- just past the viewport):
var myOffscreenEl = document.getElementById("myOffscreenEl"),
useWidth = myOffscreenEl.style.width,
useHeight = myOffscreenEl.style.height;
// position it relatively, just below the fold..
myOffscreenEl.style.position = 'relative';
myOffscreenEl.style.top = window.innerHeight + 'px';
myOffscreenEl.style.left = 0;
html2canvas(myOffscreenEl, {
width: useWidth,
height: useHeight,
onrendered: function(canvas) {
// restore the old offscreen position
myOffscreenEl.style.position = 'absolute';
myOffscreenEl.style.top = 0;
myOffscreenEl.style.left = "-9999px"
}
});
^^ seems potentially simpler/safer than @parnelle89's solution, but I might be missing something here...
EDIT: I'm encountering some scenarios with my solution where some extremely tall elements get cropped unless if I first clone the element with element.cloneNode and then append it to body. Not sure why..
hi im facing the same problem, but the above solution didnt work for me.. i have a scrollable div content and i want to capture the whole content. not the one in the viewport only.. can someone help me ?
why is mine is like this ? T_T
We solved this by changing line 604 from
return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
to
return renderDocument(node.ownerDocument, options, options.width != undefined ? options.width : node.ownerDocument.defaultView.innerWidth, options.height != undefined ? options.height : node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
Basically force it to respect the width/height arguments set during setup rather than getting the viewable area according to the document.. No weird positioning hacks necessary..
Hello, I'm trying to render an element that is offscreen (need to scroll to see it). I don't capture the whole page, only one element. Should it work or I need to tweak some things ?
+1 this is the issue i'm having
@eworksmedia solution above worked for me. Great stuff thanks
I had to put my canvas in an iframe, run html2canvas inside the iframe, run toDataURL(), and pass the image back to the parent.
@eworksmedia Thank you , good code. works like a charm.
@eworksmedia your fix worked for me as well.
@eworksmedia MAGIC! it works perfectly!!
Is the fix that @eworksmedia mentioned (to line 604) in any of the available releases? Or is this a manual change everyone's making to get this to work?
Thanks @eworksmedia for solution, I am able to see the canvas getting rendered, but it's very small in size, I have tried giving width and height params but still image is very small, is there any way we could scale the image?
@codebyuma this change we need to update manually.
My fix is strange, but it work
CSS:
.html2canvas-container { width: 3000px !important; height: 3000px !important; }
+1
@eworksmedia not working for me :( Still not rendering off-screen width gantt chart who im wanting to render.
Any help?
@Romerski make sure your container is set visibility: visible;
@gururajmca thanks but still not working :( Here is an image: http://i.imgur.com/EE8GyHD.png
Green: Popup when I click print button on Gantt chart. Blue: HTML gantt chart who I want to render. Red: What is rendering html2canvas from html (only screen visible part of html)
I tried to set visibility and overflow attributes to html gantt's div and to canvas div but nothing happens :(
Thanks again!!
@Romerski Can you try this one, which worked me.
//Default css
display: none;
visibility: hidden;
position: absolute;
top: 0;
left: 0;
}
function HtmltoImage() { $('#hidden_div').css("display" , "block"); $('#hidden_div').css("visibility" , "visible");
var defer = $q.defer();
html2canvas($('#hidden_div'),
{
useCORS: true,
allowTaint: true,
letterRendering: true,
logging:true,
onrendered: function (canvas) {
$('#hidden_div').css("overflow" , "hidden");
var quality =[0.0,1.0];
img = canvas.toDataURL('image/png',quality);
var data = {
"pngdata" : img,
};
defer.resolve(data);
}
});
return defer.promise;
}
@gururajmca thanks for your help but unfortunately still not working... I have no problem with the height, is rendering well but the problem is with the width, which is not rendering off-screen width of gantt chart.
Im pretty sure that is something related to the gantt chart overflow, This gantt chartt which im rendring is via JQuery.gantt(). I'll keep investigating.
Appreciate it any help.
@eworksmedia solution didn't work for me.
I fixed mine with this code.
function generateToPdf(element, fileName, method) {
var c = document.getElementById(element);
// overwrite owner doc inner height with your div clientHeight
c.ownerDocument.defaultView.innerHeight = c.clientHeight;
c.ownerDocument.defaultView.innerWidth = c.clientWidth;
if (method === 'canvas') {
html2canvas(c, {
onrendered: function (canvas) {
document.body.appendChild(canvas);
// scale paper height based on ratio new canvas height and width
var paperHeight = 210 * (canvas.height / canvas.width);
var paperFormatInMm = [210, paperHeight];
var doc = new jsPDF('p', 'mm', paperFormatInMm);
doc.addImage(canvas, 'PNG', 2, 2);
doc.save(fileName + '.pdf');
}
});
}
}
Its a closed issue, but some people like me could searching for the same issue, so i'll just add an comment in here. Solution as suggested by @eworksmedia, I created an npm module for personal use, but feel free use.
npm install --save html2canvas-render-offscreen
and use it just like html2canvas
I'm not a developper or anything but I had the same issue and none of your fixes worked for me. But then I tried something very simple: instead of putting the container off screen, I just "z-indexed" it below everything else. This way, it was technically on screen for the script to work, even though it was not visible to the final user. I'm pretty sure there are some side effects to this, according to your own layout but in my case, it worked just fine.
@eworksmedia You are legend !!!!!!
The solution below worked for me, but it works only in the web browser, if I try to download the pdf through the mobile application (using WebView) does not work, someone else has gone through something similar and know a way to correct?
Note: sorry my English I am using Google Translate
@battlesteel Your solution worked for me, others didn't Thks !
@eworksmedia solution didn't work for me.
I fixed mine with this code.
function generateToPdf(element, fileName, method) { var c = document.getElementById(element); // overwrite owner doc inner height with your div clientHeight c.ownerDocument.defaultView.innerHeight = c.clientHeight; c.ownerDocument.defaultView.innerWidth = c.clientWidth; if (method === 'canvas') { html2canvas(c, { onrendered: function (canvas) { document.body.appendChild(canvas); // scale paper height based on ratio new canvas height and width var paperHeight = 210 * (canvas.height / canvas.width); var paperFormatInMm = [210, paperHeight]; var doc = new jsPDF('p', 'mm', paperFormatInMm); doc.addImage(canvas, 'PNG', 2, 2); doc.save(fileName + '.pdf'); } }); } }
We solved this by changing line 604 from
return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
to
return renderDocument(node.ownerDocument, options, options.width != undefined ? options.width : node.ownerDocument.defaultView.innerWidth, options.height != undefined ? options.height : node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
Basically force it to respect the width/height arguments set during setup rather than getting the viewable area according to the document.. No weird positioning hacks necessary..
What is line 604? can you give some context? I can't find line 604 anywhere
@andylighthouse see 5 comments above: https://github.com/niklasvh/html2canvas/issues/117#issuecomment-323076300
Still having this issue
Was having this issue still on version 1.0.0-rc.7. My element to convert is at the top of the page. If html2canvas is run when the user has scrolled down, it would crop the top of the image off. I tried @wotomas / @eworksmedia solution and while it fixed the cropping, the captured text was improperly positioned (as if it was forced down similar to the crop). In conjunction with html2canvas-render-offscreen window.scrollTo(0, 0)
did the trick to fix the text, but I don't want to jump the user back up to the top. Hope this gets a solution soon. Honestly, I'd like to get the entire thing working without any visibility as I'm using it in an Electron app, generating thumbnail images on the fly based on changes made.
Ultimately, I ended up using html2canvas-render-offscreen
and floating it top, left of 0, 0 with a z-index that placed it under everything. Thanks for the great tool.
This has been an issue for 6-8 years and still isn't fixed. Gosh. There are multiple solutions posted above. Why aren't they being implemented?
-> Add CSS overflow-y: scroll; to HTML element pdfHTML -> Add attribute width & windowWidth to html2canvas method, which should be equal to width of pdfHTML Div
html2canvas(document.querySelector(".pdfHTML"), {
width: 1350, windowWidth: 1350
}).then(canvas => {
base64stringpdf = canvas.toDataURL("image/jpeg");
});
-> Add CSS overflow-y: scroll; to HTML element pdfHTML -> Add attribute width & windowWidth to html2canvas method, which should be equal to width of pdfHTML Div
html2canvas(document.querySelector(".pdfHTML"), {
width: 1350, windowWidth: 1350
}).then(canvas => {
base64stringpdf = canvas.toDataURL("image/jpeg");
});
First - thanks for your hard work - this is an extremely useful library :)
I'm looking to render an offscreen element onto canvas, but this just results in a blank image. I assume this is because html2canvas renders the whole (visible) page and then crops down to the specified element, meaning anything that's outside the page boundaries is missed.
I suspect this requires a rewrite of how html2canvas handles rendering a specific element as opposed to the whole page, so I appreciate it's a big ask.
Cheers Tom