I am currently working on a tool which generates random pdf's using the python library pdfkit which uses wkhtmltopdf. I want to position elements randomly in a predefined bounding box, this is currently implemented by a <script> which is added to the html before generation.
One problem that comes with content placing in a bounding box is overflow. Picking a random position in a given bounding box will lead to overlapping due to the width and height of the elment. Thus I want to reallocate a given element, if it overlaps the bounding box.
Problem is that element.offsetWidth() does return 0 for images and tables (?). I know - images have to load first, before an actual width can be accessed, however my solution does not work as intended.
<script>
window.addEventListener('load', function () {
var all = document.getElementsByTagName('*')
for (var i = 0; i < all.length; i++) {
var elem = all[i];
if (elem.hasAttribute("data-position")) {
var boundingBox = elem.getAttribute('data-position').split(" ");
var bottom = randomIntFromInterval(parseInt(boundingBox[1]), parseInt(boundingBox[3]));
var left = randomIntFromInterval(parseInt(boundingBox[0]), parseInt(boundingBox[2]));
bottom = Math.min(bottom, parseInt(boundingBox[3]) - elem.offsetHeight);
left = Math.min(left, parseInt(boundingBox[2]) - elem.offsetWidth);
elem.style.position = 'absolute';
elem.style.left = left + "px";
elem.style.bottom = bottom + "px";
}
}
})
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
</script>
I tried adding this eventListener to prevent execution of the code, if the image/document is not fully loaded yet, but it seems to have no effect on the elem.offsetWidth call (checked with console.log(). The offsetHeight is correct, but note that it gets defined in the html and does not have to be calculated)
Is this an issue with wkhtmltopdf? I could not find a documentation/question which stated that event loading like this would not work.
In addition to that, if i console.log the offsetWidth in the onload attribute of the img element itself, the correct value gets printed.
Here is the entire html for more information:
<html>
<head>
<meta content="3508px" name="pdfkit-page-height" />
<meta content="2480px" name="pdfkit-page-width" />
<meta content="60" name="pdfkit-image-dpi" />
<meta content="20px" name="pdfkit-margin-top" />
<meta content="20px" name="pdfkit-margin-right" />
<meta content="20px" name="pdfkit-margin-left" />
<meta content="20px" name="pdfkit-margin-bottom" />
<meta content="" name="pdfkit-disable-smart-shrinking" />
<meta content="600" name="pdfkit-javascript-delay" />
</head>
<div class="border-container" data-position="0 0 2435 3463"></div>
<div class="logo-container" data-position="1800 3200 2395 3423"><img
src="https://app.useanvil.com/img/email-logo-black.png" style="height:100px"
onload="console.log('\nmy width is:' + this.offsetWidth + '\n' + 'my height is: ' + this.offsetHeight)" />
</div>
<table class="line-items-container" data-position="40 1400 2395 2200" data-type="" style="font-size: 80px">
<thead>
<tr>
<th class="heading-quantity"></th>
<th class="heading-description">Description</th>
<th class="heading-price"></th>
<th class="heading-subtotal">Subtotal</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>test</td>
<td class="right"></td>
<td class="bold">{{subtotal1}}</td>
</tr>
<tr>
<td></td>
<td>test</td>
<td class="right"></td>
<td class="bold">{{subtotal2}}</td>
</tr>
<tr>
<td></td>
<td>test</td>
<td class="right"></td>
<td class="bold">{{subtotal3}}</td>
</tr>
</tbody>
</table>
<div style="
position: absolute;
height: 3463px;
width: 2435px;
left: 0px;
bottom: 0px;
border: 1px solid #f32177;
"></div>
<div style="
position: absolute;
height: 223px;
width: 595px;
left: 1800px;
bottom: 3200px;
border: 1px solid #f32177;
"></div>
<div style="
position: absolute;
height: 800px;
width: 2355px;
left: 40px;
bottom: 1400px;
border: 1px solid #f32177;
"></div>
<script>
window.addEventListener('load', function () {
var all = document.getElementsByTagName('*')
for (var i = 0; i < all.length; i++) {
var elem = all[i];
if (elem.hasAttribute("data-position")) {
var boundingBox = elem.getAttribute('data-position').split(" ");
var bottom = randomIntFromInterval(parseInt(boundingBox[1]), parseInt(boundingBox[3]));
var left = randomIntFromInterval(parseInt(boundingBox[0]), parseInt(boundingBox[2]));
bottom = Math.min(bottom, parseInt(boundingBox[3]) - elem.offsetHeight);
left = Math.min(left, parseInt(boundingBox[2]) - elem.offsetWidth);
elem.style.position = 'absolute';
elem.style.left = left + "px";
elem.style.bottom = bottom + "px";
}
}
})
function randomIntFromInterval(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
</script>
</html>