html2canvas
works great for taking screenshot but currently doesn’t capture longer text in textAreas or more than one variable in a multiple-select. See https://github.com/niklasvh/html2canvas/issues/2008 for discussion.
@chawes13 provided excellent suggestions to work around these issues that resulted in the function below. I set height: document.body.scrollHeight
to vertically crop the screenshot of the app I’m working on. However, the height can be changed during the onclone
process. I have tried lots of different options but the only things that seem to work are either (1) don’t use any vertical cropping or (2) use cropping based on the initial body height which, unfortunately, cuts off the lower part of the image if changes have been made during onclone
. The app has lots of tabs and dynamically changes size as different data is loaded or variables are selected, so setting to one fixed height isn’t an option.
Question: Is it possible to determine the (scroll) height of the clonedDocument and use that to adjust the screenshot height when needed?
function generate_screenshot() {
html2canvas($("body")[0], {
y: 55,
height: document.body.scrollHeight,
onclone: (clonedDocument) => {
Array.from(clonedDocument.querySelectorAll("textarea")).forEach((textArea) => {
if (textArea && textArea.value.length > 30) {
const labelFor = textArea.getAttribute("id")
const label = clonedDocument.querySelector(`label[for="${labelFor}"]`)
const div = clonedDocument.createElement("div")
div.innerText = textArea.value
div.style.border = "1px solid #d3d3d3"
div.style.padding = "10px 10px 10px 10px"
div.style.width = "100%"
div.style.borderRadius = "5px"
div.style.boxSizing = "border-box";
div.style.margin = "0";
div.style.backgroundColor = "white"
textArea.style.display = "none"
textArea.parentElement.append(label, div);
}
})
Array.from(clonedDocument.querySelectorAll('select[multiple]')).forEach((msel) => {
const multiSelect = document.querySelector("#" + msel.getAttribute("id"));
if (multiSelect && multiSelect.selectedOptions.length > 1) {
const clonedMultiSelect = clonedDocument.querySelector("#" + msel.getAttribute("id"));
const list = clonedDocument.createElement('ul')
Array.from(multiSelect.selectedOptions).forEach((option) => {
const item = clonedDocument.createElement('li')
item.innerHTML = option.value
item.style = "list-style: none; padding-left: 0.5em"
item.style.width = "100%"
list.appendChild(item)
})
list.style.border = "1px solid #d3d3d3"
list.style.padding = "5px 5px 5px 5px"
list.style.width = "100%"
list.style.backgroundColor = "white"
list.style.borderRadius = "5px"
clonedMultiSelect.style.display = "none"
clonedMultiSelect.parentElement.appendChild(list)
}
});
},
ignoreElements: function(el) {
return el.classList.contains("navbar-inverse") || el.classList.contains("dropdown-menu");
}
}).then(canvas => {
var img = document.createElement("img");
img.src = canvas.toDataURL("png");
img.width = parseInt(canvas.style.width);
img.height = parseInt(canvas.style.height);
$("#screenshot_preview").empty();
$("#screenshot_preview").append(img);
});
}
2
Answers
Ok, no tested, but you can try something like this:
Essentially i moved the "onclone" to the beginning, before the height and y options. Inside the onclone function, i added the code to adjust the height dynamically based on the cloned document’s scroll height.
I had this problem once when I tried to create a PDF from a report page. Here’s my code. It not only prints everything as it splits the pages.