This post is the extension to the previous tutorial. This tutorial add the width and height controls. User can change the width of embedded page and can visually see it’s impact on final PDF in realtime.
Implementation
We will continue with updating the HTML markup
<main>
<input id="fileInput" type="file" accept=".pdf" />
<label>Width <input class="widthInput" step="25" type="number" min="200" max="600" /></label>
<label>Height <input readonly class="heightInput" type="number" min="0" max="500" /></label>
</main>
We have added the two inputs. One for width and one for height. The height one is readonly as we want to maintain the aspect ratio when width is changed, more on that later.
.widthInput, .heightInput {
width: 5rem;
}We just increased the default width of those input elements.
// output goes here
const widthEl = document.querySelector('input[type="number"].widthInput') as HTMLInputElement
const heightEl = document.querySelector('input[type="number"].heightInput') as HTMLInputElement
widthEl?.addEventListener('change', event => {
const value = (event.target as HTMLInputElement).valueAsNumber
createDocument(firstPage, secondPage, value)
}We have some references of dom elements with some type assertions to HTMLInputElements to silence some typescript errors.
Next we listen to change in the width input and react to the document creation accordingly. Our createDocument function accepts third argument, guess what the width
What’s new in create document?
async function createDocument(pageAToEmbed: PDFPage, pageBToEmbed: PDFPage, width = PageSizes.A4[0] ) {
// .....
let [, height] = PageSizes.A4;
const calcHeight = aspectCorrectDimension(width);
The third argument is width= PageSize.A4[0], we are setting the default value to A4 page width for the first run of the function. As this function also runs when the width is changed.
In Line 3 we skip the width and only de-structure the height
Let’s explain the what’s happening on Line 4
aspectCorrectDimension
We need to calculate the aspect ratio of the A4 page. The dimension of A4 page is 545 x 841 in pixels. We embedded takes half of the page so our dimensions becomes 545 x 420.5. The aspect ratio becomes
/**
* Decimal Ratio
* 545 ÷ 420.5 ≈ 1.296
*/
function aspectCorrectDimension(width: number) {
const aR = 1.296;
return width / aR
}Our function calculates the appropriate height to maintain the aspect ratio.
page.drawPage(embeddedPageA, { x: 10, y: height/2, width: width, height: calcHeight })
widthEl.value = String(width);
heightEl.value = String(calcHeight);
page.drawPage(embeddedPageB, { x: 10, y: 0, width, height: calcHeight})
.../
}
We have update the height config for the drawPage method with newly calculatedHeight. We also need to update the input controls as well and that’s it.
Output
Horizontally centering
const remainder = (PageSizes.A4[0] - width) / 2
const centeredX = remainder
page.drawPage(embeddedPageA, { x: centeredX, y: height/2, width: width, height: calcHeight })
//...
page.drawPage(embeddedPageB, { x: centeredX, y: 0, width, height: calcHeight})We have updated the x: centeredX which is calculated by some subtraction and division. This way, our faces remains always in the center.
Conclusion
We have introduced some input elements. Change in width recalculates the dimension of card face while maintaining the aspect ration and embeds it.
