const AUTOCOMPLETE_API_KEY = "a17b542575f34d8795f90a23d650349f"; const getImage = async (url) => { const image = new Image(); const imageLoadPromise = new Promise( resolve => { image.onload = () => { resolve(); } image.src = url; } ); await imageLoadPromise; return image; } const setHighestPossibleFontSize = ( context, text, font, desiredSize, maxWidth ) => { let currentSize = desiredSize; context.font = `${currentSize}px ${font}`; while (context.measureText(text).width > maxWidth && currentSize > 0) { currentSize -= 1; context.font = `${currentSize}px ${font}`; } return desiredSize; } const createCheck = async ( context, canvas, x, y ) => { const checkImage = await getImage("static/images/check.webp"); const size = canvas.width * 0.0215; context.drawImage( checkImage, x, y, size, size ); } const fillCanvas = async () => { const firstPageCanvas = document.getElementById("page-1-canvas"); const firstPageContext = firstPageCanvas.getContext("2d"); const secondPageCanvas = document.getElementById("page-2-canvas"); const secondPageContext = secondPageCanvas.getContext("2d"); const firstPageImage = await getImage("static/images/page1.webp"); const secondPageImage = await getImage("static/images/page2.webp"); firstPageContext.drawImage( firstPageImage, 0, 0, firstPageCanvas.width, firstPageCanvas.height ); secondPageContext.drawImage( secondPageImage, 0, 0, secondPageImage.width, secondPageImage.height ); // BEGIN First page // Local office name const officeName = $("#city").val(); setHighestPossibleFontSize( firstPageContext, officeName, "Open Sans", firstPageCanvas.height * 0.015, firstPageCanvas.width * 0.76 ); firstPageContext.fillStyle = "#000"; firstPageContext.fillText( officeName, firstPageCanvas.width * 0.12, firstPageCanvas.height * 0.205 ); // We're always doing the presidential one, so always make this check const checkboxSharedY = firstPageCanvas.width * 0.12; await createCheck( firstPageContext, firstPageCanvas, checkboxSharedY, firstPageCanvas.height * 0.3665 ); const roundCheckSharedY = firstPageCanvas.width * 0.185; let electionDate = ""; switch ($("#card-type").val()) { case "1. kolo": createCheck( firstPageContext, firstPageCanvas, roundCheckSharedY, firstPageCanvas.height * 0.3853 ); electionDate = "13. ledna 2023 - 14. ledna 2023"; break; case "2. kolo": createCheck( firstPageContext, firstPageCanvas, roundCheckSharedY, firstPageCanvas.height * 0.404 ); electionDate = "27. ledna 2023 - 28. ledna 2023"; break; } const personalInfoSharedX = firstPageCanvas.width * 0.37; // Election dates setHighestPossibleFontSize( firstPageContext, electionDate, "Open Sans", firstPageCanvas.height * 0.013, firstPageCanvas.width * 0.51 ); firstPageContext.fillText( electionDate, personalInfoSharedX, firstPageCanvas.height * 0.505 ); // Name const fullName = ( $("#name").val() + " " + $("#surname").val() ); setHighestPossibleFontSize( firstPageContext, fullName, "Open Sans", firstPageCanvas.height * 0.013, firstPageCanvas.width * 0.51 ); firstPageContext.fillText( fullName, personalInfoSharedX, firstPageCanvas.height * 0.535 ); // Birth date const birthDate = new Date($("#birth-date").val()); const formattedBirthDate = ( birthDate.getDate() + ". " + birthDate.getMonth() + ". " + birthDate.getFullYear() ); setHighestPossibleFontSize( firstPageContext, formattedBirthDate, "Open Sans", firstPageCanvas.height * 0.013, firstPageCanvas.width * 0.51 ); firstPageContext.fillText( formattedBirthDate, personalInfoSharedX, firstPageCanvas.height * 0.565 ); // Street + number const address = ( $("#street").val() + ", " + $("#zip").val() + " " + $("#city").val() ); setHighestPossibleFontSize( firstPageContext, address, "Open Sans", firstPageCanvas.height * 0.013, firstPageCanvas.width * 0.51 ); firstPageContext.fillText( address, personalInfoSharedX, firstPageCanvas.height * 0.597 ); // Pick up options secondPageContext.fillStyle = "#000"; switch ($("#receiving-type").val()) { case "Vyzvednout osobně": createCheck( firstPageContext, firstPageCanvas, checkboxSharedY, firstPageCanvas.height * 0.7195 ); break; case "Předat osobě, která se prokáže plnou mocí": createCheck( firstPageContext, firstPageCanvas, checkboxSharedY, firstPageCanvas.height * 0.751 ); break; // END First page // BEGIN Second page case "Zaslat na adresu trvalého pobytu": createCheck( secondPageContext, secondPageCanvas, checkboxSharedY, secondPageCanvas.height * 0.08475 ); break; case "Zaslat jinam": createCheck( secondPageContext, secondPageCanvas, checkboxSharedY, secondPageCanvas.height * 0.1152 ); const deliveryAddress = $("#other-address-conditional").val(); setHighestPossibleFontSize( secondPageContext, deliveryAddress, "Open Sans", secondPageCanvas.height * 0.013, secondPageCanvas.width * 0.51 ); secondPageContext.fillText( deliveryAddress, secondPageCanvas.width * 0.145, secondPageCanvas.height * 0.155 ); break; } } $(window).ready( () => { const { jsPDF } = window.jspdf; const currentDate = new Date(); $("#current-date").val( currentDate.getDate() + ". " + currentDate.getMonth() + ". " + currentDate.getFullYear() ); const autocompleteWidget = new autocomplete.GeocoderAutocomplete( document.getElementById("address-autocomplete"), AUTOCOMPLETE_API_KEY, { "lang": "cs", "filter": { "countrycode": ["cz"] }, "placeholder": "🔎 Vyhledat adresu..." } ); autocompleteWidget.on( "select", (location) => { const properties = location.properties; const street = ( (properties.street !== undefined) ? properties.street : "" ); const houseNumber = ( (properties.housenumber !== undefined) ? properties.housenumber : "" ); document.getElementById("street").value = ( street + ( (street !== "") ? " " : "" ) + houseNumber ); if (properties.city !== undefined) document.getElementById("city").value = properties.city; if (properties.postcode !== undefined) document.getElementById("zip").value = properties.postcode; } ); $("#receiving-type").on( "change", (event) => { if (event.target.value === "Zaslat jinam") { $("#other-address-conditional").css("display", "block"); } else { $("#other-address-conditional").css("display", "none"); } } ); $("#create-filled-form").on( "click", async (event) => { $("#form-wrapper input,#form-wrapper select").attr("disabled", true); // We already know this, don't waste time looking it up. // Repeating ourselves once is fine here. $(event.target).attr("disabled", true); await fillCanvas(); await new Promise( resolve => { $("#step1").fadeOut(200, resolve); } ); $("#step1").css("display", "none"); await new Promise( resolve => { $("#step2").fadeIn(200, resolve); } ); $("#signature").jSignature(); } ); $("#signature-undo").on( "click", (event) => { $("#signature").jSignature("reset"); } ); $("#show-document").on( "click", async (event) => { await new Promise( resolve => { $("#step2").fadeOut(200, resolve); } ); $("#step2").css("display", "none"); await new Promise( resolve => { $("#canvas-wrapper").fadeIn(200, resolve); } ); } ); $("#back-to-step2").on( "click", async (event) => { await new Promise( resolve => { $("#canvas-wrapper").fadeOut(200, resolve); } ); $("#canvas-wrapper").css("display", "none"); await new Promise( resolve => { $("#step2").fadeIn(200, resolve); } ); } ); $("#finish").on( "click", async (event) => { // Canvas const secondPageCanvas = document.getElementById("page-2-canvas"); const secondPageContext = secondPageCanvas.getContext("2d"); // Date const desiredCurrentDate = $("#current-date").val() setHighestPossibleFontSize( secondPageContext, desiredCurrentDate, "Open Sans", secondPageCanvas.height * 0.013, secondPageCanvas.width * 0.32 ); secondPageContext.fillText( desiredCurrentDate, secondPageCanvas.width * 0.56, secondPageCanvas.height * 0.232 ); // Location const location = $("#signature-location").val(); setHighestPossibleFontSize( secondPageContext, location, "Open Sans", secondPageCanvas.height * 0.013, secondPageCanvas.width * 0.31 ); secondPageContext.fillText( location, secondPageCanvas.width * 0.155, secondPageCanvas.height * 0.232 ); // Signature const signature = await getImage($("#signature").jSignature("getData")); const signatureWidth = secondPageCanvas.width * 0.315; const signatureHeight = ( signature.height * (signatureWidth / signature.width) ); console.log(signatureHeight, signatureWidth, signature); secondPageContext.drawImage( signature, secondPageCanvas.width * 0.57, secondPageCanvas.height * 0.31 - signatureHeight, signatureWidth, signatureHeight ); // UI await new Promise( resolve => { $("#step2").fadeOut(200, resolve); } ); $("#step2").css("display", "none"); const city = $("#city").val(); if (city in OFFICES) { const office = OFFICES[city]; $("#office-address-direction").html( office["address"]["street"] + ", " + office["address"]["zip"] + " " + office["address"]["city"] ); $("#office-ds-id-direction").html(office["ds_id"]); $("#found-office").css("display", "block"); } else { $("#not-found-office").css("display", "block"); } await new Promise( resolve => { $("#step3").fadeIn(200, resolve); } ); } ); $("#download-pdf").on( "click", () => { const pdfDocument = new jsPDF({ orientation: "portrait", unit: "pt", format: "a4" }); pdfDocument.addImage( document.getElementById("page-1-canvas"), "JPEG", 0, 0, 595.28, 841.89 ); pdfDocument.addPage(); pdfDocument.addImage( document.getElementById("page-2-canvas"), "JPEG", 0, 0, 595.28, 841.89 ); pdfDocument.save("Přihláška k volebnímu průkazu.pdf"); } ); } );