diff --git a/content/index.html b/content/index.html index 88ffb1942326e0355ec9a65c460ed28dff81d339..54231a8773c4d2b2d69a3296f6c3adb7b5d86b21 100644 --- a/content/index.html +++ b/content/index.html @@ -61,7 +61,7 @@ </header> <main> - <div id="content"> + <div id="step1"> <p id="intro-text"> Již za dva měsíce nás čekají prezidentské volby a Piráti znovu nabízí možnost, jak si vyřídit voličský průkaz - tedy potvrzení, že můžeš volit i na jiném místě, než v trvalém bydlišti.<br> Vyplň náš jednoduchý formulář, stáhni si ho v PDF a pošli ho datovkou nebo dones osobně na úřad. Neboj se - vážíme si tvého soukromí, nesbíráme žádná osobní data a vše zpracovává tvůj prohlížeč. @@ -73,22 +73,25 @@ type="text" id="name" placeholder="Jméno *" + value="Tomáš" > <input type="text" id="surname" placeholder="Příjmení *" + value="Černohorský" > </div> <div class="input-single-with-label"> <label - for="birthday" + for="birth-date" >Datum narození *</label> <input type="date" - id="birthday" - name="birthday" + id="birth-date" + name="birth-date" + value="2004-04-25" > </div> @@ -97,13 +100,13 @@ <div id="address-autocomplete" aria-role="textbox" - class="autocomplete-container" ></div> <input type="text" id="street" placeholder="Ulice, popisné a orientační č. *" + value="Svojsíkova 145" > <div class="input-group input-group-2"> @@ -111,12 +114,14 @@ type="text" id="city" placeholder="Obec *" + value="Krupka" > <input type="text" id="zip" placeholder="PSČ *" + value="41501" > </div> @@ -126,9 +131,17 @@ <option>Vyzvednout osobně</option> <option>Předat osobě, která se prokáže plnou mocí</option> <option>Zaslat na adresu trvalého pobytu</option> - <option>Zaslat jinam</option> + <option selected>Zaslat jinam</option> </select> + <input + type="text" + id="other-address-conditional" + placeholder="Doručovací adresa *" + style="display:none" + value="Svojsíkova 13, 415 01 Teplice" + > + <select id="card-type" > @@ -146,7 +159,7 @@ </div> </div> - <div id="canvas-wrapper"> + <div id="step2"> <canvas id="page-1-canvas" width="2480" height="3507"></canvas> <canvas id="page-2-canvas" width="2480" height="3507"></canvas> </div> diff --git a/content/static/css/base.css b/content/static/css/base.css index 81ca82d58ee94b8928007d79e3022951e64adb94..ee1e20831351714105fd67bbb95571c0ab8c70e1 100644 --- a/content/static/css/base.css +++ b/content/static/css/base.css @@ -72,15 +72,20 @@ textarea { align-items:center } -#content { +#step1 { max-width:1000px; margin-left:auto; margin-right:auto; padding-top:40px } -#canvas-wrapper { - display:none +#step2 { + display:none; + object-fit:contain +} + +#step2 canvas { + width:100% } #intro-text { @@ -96,11 +101,13 @@ textarea { gap:14px; max-width:750px; margin-left:auto; - margin-right:auto + margin-right:auto; + padding-bottom:20px } #address-autocomplete { - position:relative + position:relative; + text-align:center } #form-preview { @@ -133,11 +140,3 @@ textarea { .input-single-with-label input { flex:1 1 0px } - -.geoapify-autocomplete-input { - border:0; - font-size:medium; - height:42px; - line-height:42px; - width:100% -} diff --git a/content/static/css/geo-autocomplete.css b/content/static/css/geo-autocomplete.css index c8032523ef252c2f32d901000a47ac66a7fbf963..8b88514aa040993354dca9272e3a2796fa823e08 100644 --- a/content/static/css/geo-autocomplete.css +++ b/content/static/css/geo-autocomplete.css @@ -1,14 +1,14 @@ .geoapify-autocomplete-input { - padding: 0 31px 0 7px; - width: calc(100% - 40px); + padding: 0 31px 0 10px; + width: calc(100% - 41px); outline: none; - line-height: 36px; - height: 36px; - border: 1px solid rgba(0, 0, 0, 0.3); + line-height: 42px; + height: 42px; + border: 0; - font-size: 14px; + font-size: medium; } .geoapify-autocomplete-items { diff --git a/content/static/images/check.webp b/content/static/images/check.webp new file mode 100644 index 0000000000000000000000000000000000000000..500f994425ac08aa512430d2f01690d65af422b1 Binary files /dev/null and b/content/static/images/check.webp differ diff --git a/content/static/images/page2.webp b/content/static/images/page2.webp index 6b910c07f94a57ad09fea519e312771f2791b636..0f6ccfcdb9a7bc0751d9b45661337f4701199feb 100644 Binary files a/content/static/images/page2.webp and b/content/static/images/page2.webp differ diff --git a/content/static/js/main.js b/content/static/js/main.js index df8ad4be773c16b395f348f3c7245767646a4213..8c906bc89b31022e287facad64952174c4263e87 100644 --- a/content/static/js/main.js +++ b/content/static/js/main.js @@ -1,5 +1,308 @@ 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 -= 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; + } + + const currentDate = new Date(); + const formattedCurrentDate = ( + currentDate.getDate() + + ". " + + currentDate.getMonth() + + ". " + + currentDate.getFullYear() + ); + + setHighestPossibleFontSize( + secondPageContext, + formattedCurrentDate, + "Open Sans", + secondPageCanvas.height * 0.013, + secondPageCanvas.width * 0.32 + ); + + secondPageContext.fillText( + formattedCurrentDate, + secondPageCanvas.width * 0.56, secondPageCanvas.height * 0.232 + ); +} + window.onload = () => { const autocompleteWidget = new autocomplete.GeocoderAutocomplete( document.getElementById("address-autocomplete"), @@ -41,13 +344,37 @@ window.onload = () => { } ); + $("#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", - (event) => { + 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"); + + $("#step2").css("opacity", "0"); + $("#step2").css("display", "flex"); + await new Promise( + resolve => { $("#step2").fadeIn(200, resolve); } + ); } ); }