X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=index.html.in;h=44b31c5bea1c4ea32051b55007962c151c5069f0;hb=db204009c315bda2f7b59fc2b3dabc637ddcf078;hp=f600950306a38c7ca893d6bb186c23a282cfbbbc;hpb=7d7bc2b602001340f22b4d0e400b82b232f9b4fb;p=charm-bypass.git diff --git a/index.html.in b/index.html.in index f600950..44b31c5 100644 --- a/index.html.in +++ b/index.html.in @@ -12,77 +12,78 @@ * Reset styles for the html and body elements, the only two HTML * elements we use. */ html, body { - margin: 0; - padding: 0; - border: 0; - font-weight: normal; - font-style: inherit; - font-size: 100%; - line-height: 1.5; - font-family: inherit; - text-align: inherit; - text-decoration: none; - vertical-align: baseline; - background: transparent; + margin: 0; + padding: 0; + border: 0; + font-weight: normal; + font-style: inherit; + font-size: 100%; + line-height: 1.5; + font-family: inherit; + text-align: inherit; + text-decoration: none; + vertical-align: baseline; + background: transparent; } html, body { - /* To create our "window" onto the scene, we're going to slide the + /* To create our "window" onto the scene, we're going to slide the * SVG off the left-hand side of the screen, and we don't want - * scroll bars to appear. */ - overflow: hidden; + * scroll bars to appear. */ + overflow: hidden; } svg { - /* Set the height to 100% of the screen, which we'll keep; and the - * initial position to (0,0), which we're going to change - * every time the window is resized, because the exact amount - * that we have to slide the SVG to the left to get the ticket - * into the center will change. */ - position: fixed; - top: 0; - left: 0; - height: 100%; + /* Set the height to 100% of the screen, which we'll keep; and the + * initial position to (0,0), which we're going to change + * every time the window is resized, because the exact amount + * that we have to slide the SVG to the left to get the ticket + * into the center will change. */ + position: fixed; + top: 0; + left: 0; + height: 100%; } /* The blinking fade in/out animation for the ticket date and time */ @keyframes blink { - 25% { - opacity: 0.5; - } - 50% { - opacity: 0; - } - 75% { - opacity: 0.5; - } + 25% { + opacity: 0.5; + } + 50% { + opacity: 0; + } + 75% { + opacity: 0.5; + } } #tickettime, #ticketdate { - /* 300 two-second blinks is ten minutes */ - animation: blink 2s linear 300; + /* 300 two-second blinks is ten minutes */ + animation: blink 2s linear 300; } /* Define, load, and specify the custom font we use for the ticket * date, time, and service name. */ @font-face { - font-family: "CharmBypass Regular"; - src: - url("data:font/woff2;base64,@CBPREGULAR@") format("woff2") + font-family: "CharmBypass Regular"; + src: + url("data:font/woff2;base64,@CBPREGULAR@") format("woff2") } - #servicename, #tickettime, #ticketdate { - font-family: "CharmBypass Regular"; + #servicename, #tickettime, #ticketdate, #codetext { + font-family: "CharmBypass Regular", sans-serif; } @font-face { - font-family: "CharmBypass Bold"; - src: - url("data:font/woff2;base64,@CBPBOLD@") format("woff2") + font-family: "CharmBypass Bold"; + src: + url("data:font/woff2;base64,@CBPBOLD@") format("woff2") } #serviceletter { - font-family: "CharmBypass Bold"; + font-family: "CharmBypass Bold", sans-serif; + font-weight: bold; } /************************/ @@ -91,130 +92,130 @@ /* Bus */ @keyframes busroll { - from { - transform: translateX(0%); - } - to { - transform: translateX(100%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(-100%); + } } #bus { - animation: busroll 23s linear infinite; + animation: busroll 23s linear infinite; } /* Tram */ @keyframes tramroll { - from { - transform: translateX(0%); - } - to { - transform: translateX(100%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(100%); + } } #tram { - animation: tramroll 17s linear infinite; + animation: tramroll 17s linear infinite; } /* Tram */ @keyframes trainroll { - from { - transform: translateX(0%); - } - to { - transform: translateX(100%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(100%); + } } #train { - animation: trainroll 11s linear infinite; + animation: trainroll 11s linear infinite; } /* Clouds */ @keyframes cloudsfloat { - from { - transform: translateX(0%); - } - to { - transform: translateX(-50%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(-50%); + } } #clouds { - animation: cloudsfloat 40s linear infinite; + animation: cloudsfloat 40s linear infinite; } @keyframes cloudscopyfloat { - from { - transform: translateX(0%); - } - to { - transform: translateX(-50%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(-50%); + } } #cloudscopy { - animation: cloudscopyfloat 40s linear infinite; + animation: cloudscopyfloat 40s linear infinite; } /* Trees */ @keyframes treespass { - from { - transform: translateX(0%); - } - to { - transform: translateX(-50%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(-50%); + } } #trees { /* The trees move a little faster than the clouds */ - animation: treespass 30s linear infinite; + animation: treespass 30s linear infinite; } @keyframes treescopypass { - from { - transform: translateX(0%); - } - to { - transform: translateX(-50%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(-50%); + } } #treescopy { /* The trees move a little faster than the clouds */ - animation: treescopypass 30s linear infinite; + animation: treescopypass 30s linear infinite; } /* City skyline */ @keyframes cityscroll { - from { - transform: translateX(0%); - } - to { - transform: translateX(-50%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(-50%); + } } #city { /* The city moves faster than the clouds but slower * than the trees */ - animation: cityscroll 35s linear infinite; + animation: cityscroll 35s linear infinite; } @keyframes citycopyscroll { - from { - transform: translateX(0%); - } - to { - transform: translateX(-50%); - } + from { + transform: translateX(0%); + } + to { + transform: translateX(-50%); + } } #citycopy { @@ -235,115 +236,120 @@ /***********************************************/ function center_ticket() { - /* We're relying on the SVG being the full height of the - * viewport already, and on the aspect ratio being - * preserved. First, find the center of the ticket. */ - const r = document.getElementById("ticket").getBoundingClientRect(); - const c = r.left + (r.width / 2); + /* We're relying on the SVG being the full height of the + * viewport already, and on the aspect ratio being + * preserved. First, find the center of the ticket. */ + const r = document.getElementById("ticket").getBoundingClientRect(); + const c = r.left + (r.width / 2); - /* That's the center-line of the ticket. We want to move it to - * the center-line of the viewport. */ - const vc = document.documentElement.clientWidth / 2; + /* That's the center-line of the ticket. We want to move it to + * the center-line of the viewport. */ + const vc = document.documentElement.clientWidth / 2; - /* This is how much we need to translate the SVG */ - const delta = vc - c; + /* This is how much we need to translate the SVG */ + const hdelta = vc - c; - /* But before we can set the absolute left-coordinate of the - * SVG, we need to know where it is now. Note: without the - * "px" this doesn't default to pixels like CSS does. */ - const svg = document.querySelector("svg"); - svg.style.left = (svg.getBoundingClientRect().left + delta) + "px"; + /* But before we can set the absolute left-coordinate of the + * SVG, we need to know where it is now. Note: without the + * "px" this doesn't default to pixels like CSS does. */ + const svg = document.querySelector("svg"); + svg.style.left = (svg.getBoundingClientRect().left + hdelta) + "px"; } - /* Re-center it when the window is resized */ - window.addEventListener("resize", center_ticket); - /* Center it once when the page has loaded, too */ - window.addEventListener("load", center_ticket); + /****************************************/ + /* Set and reposition the security code */ + /****************************************/ + function set_code() { + const ct = document.getElementById("codetext"); - /*************************/ - /* Set the security code */ - /*************************/ + /* Get the "code" from the querystring if it's there */ + let params = new URLSearchParams(document.location.search); + if (params.get("code")) { + ct.textContent = params.get("code"); + } + else { + /* Otherwise, use a random code */ + const bucket = ["0","1","2","3","4","5","6","7","8","9", + "A","B","C","D","E","F","G","H","I","J", + "K","L","M","N","O","P","Q","R","S","T", + "U","V","W","X","Y","Z"]; - /* All elements produced by inkscape contain a single - * that itself contains the actual text. This does something real - * sneaky, and actually OVERWRITES that tspan with our own text - * content. This turns out to be what we need anyway because trying - * to center a (display: inline) tspan is a pain in the butt. */ - const ct = document.getElementById("codetext"); - - /* Get the "code" from the querystring if it's there */ - let params = new URLSearchParams(document.location.search); - if (params.get("code")) { - ct.textContent = params.get("code"); + /* Two random ints between 0 and 35 */ + const i1 = Math.floor(Math.random() * 36); + const i2 = Math.floor(Math.random() * 36); + const d1 = bucket[i1]; + const d2 = bucket[i2]; + ct.textContent = d1 + d2; + } } - else { - /* Otherwise, use a random code */ - const bucket = ["0","1","2","3","4","5","6","7","8","9", - "A","B","C","D","E","F","G","H","I","J", - "K","L","M","N","O","P","Q","R","S","T", - "U","V","W","X","Y","Z"]; - /* Two random ints between 0 and 35 */ - const i1 = Math.floor(Math.random() * 36); - const i2 = Math.floor(Math.random() * 36); - const d1 = bucket[i1]; - const d2 = bucket[i2]; - ct.textContent = d1 + d2; - } - /* Now center the security code inside its red box */ - /* First, find the center of the red box */ - const r1 = document.getElementById("codebg").getBoundingClientRect(); - const c1 = r1.left + (r1.width / 2); + function center_code() { + /* Center the security code inside its red box */ + const ct = document.getElementById("codetext"); - /* Now the center of the code text */ - const r2 = ct.getBoundingClientRect(); - const c2 = r2.left + (r2.width / 2); + /* First, find the center of the red box */ + const r1 = document.getElementById("codebg").getBoundingClientRect(); + const c1 = r1.left + (r1.width / 2); - /* What do we add to c2 to make it equal to c1? */ - const code_delta = c1 - c2; + /* Now the center of the code text */ + const r2 = ct.getBoundingClientRect(); + const c2 = r2.left + (r2.width / 2); - /* Since this element has an "x" attribute it's easier for us - * to shift that than it is to mess with the "left" style. */ - ct.setAttribute("x", parseFloat(ct.getAttribute("x")) + code_delta); + /* What do we add to c2 to make it equal to c1? */ + const hdelta = c1 - c2; + /* Since this element has an "x" attribute it's easier for + * us to shift that than it is to mess with the "left" style. */ + ct.setAttribute("x", parseFloat(ct.getAttribute("x")) + hdelta); + } + + function center_code_repeatedly() { + /* Lets us call center_code five times on page load. Why we + * need to do this is an interesting (i.e. stupid) topic for + * conversation. */ + center_code(); + center_code(); + center_code(); + center_code(); + center_code(); + } /*****************************************/ /* Next, set up the ticket date and time */ /*****************************************/ - /* There are two parameters, time and date, that we store in one - * underlying "date" variable. Default both to an hour and a - * half from now. This is what the CharmPass app does for - * one-way tickets. - */ - const date = new Date(); - - /* Add an hour and a half. We use the low-level get/setTime to - * change the number of milliseconds since the epoch that this - * date represents. Obviously correct, and avoids all suspicious - * corner cases (well, for a few more decades). */ - date.setTime(date.getTime() + (90*60*1000)); - - /* All elements produced by inkscape contain a single - * that itself contains the actual text. */ - tt = document.getElementById("tickettime"); - tt.firstChild.textContent = date.toLocaleTimeString(); - - const td = document.getElementById("ticketdate"); - const dateopts = { - day: "2-digit", - month: "2-digit", - year: "2-digit" - }; - td.firstChild.textContent = date.toLocaleDateString("en-US", dateopts); - - - /*************************************************************/ - /* Finally, add the onclick handler for the night/day switch */ - /*************************************************************/ + function set_ticket_expiry() { + /* There are two parameters, time and date, that we store in one + * underlying "date" variable. Default both to an hour and a + * half from now. This is what the CharmPass app does for + * one-way tickets. */ + const date = new Date(); + + /* Add an hour and a half. We use the low-level get/setTime to + * change the number of milliseconds since the epoch that this + * date represents. Obviously correct, and avoids all suspicious + * corner cases (well, for a few more decades). */ + date.setTime(date.getTime() + (90*60*1000)); + + tt = document.getElementById("tickettime"); + tt.textContent = date.toLocaleTimeString(); + + const td = document.getElementById("ticketdate"); + const dateopts = { + day: "2-digit", + month: "2-digit", + year: "2-digit" + }; + td.textContent = date.toLocaleDateString("en-US", dateopts); + } + + + /*********************************************************/ + /* Finally, the onclick handler for the night/day switch */ + /*********************************************************/ /* We always start in "day" mode */ is_day = true; @@ -353,20 +359,51 @@ } function set_night() { - sky.style.fill = "#143b66"; + sky.style.fill = "#143b66"; } function swap_colors() { - if (is_day) { - set_night(); - is_day = false; - } - else { - set_day(); - is_day = true; - } + if (is_day) { + set_night(); + is_day = false; + } + else { + set_day(); + is_day = true; + } } + + /*****************************************************/ + /* Add event handlers for all of the functions above */ + /*****************************************************/ + + /* Center the ticket once when the page has loaded */ + window.addEventListener("load", center_ticket); + + /* Re-center the ticket when the window is resized */ + window.addEventListener("resize", center_ticket); + + /* Set the security code text when the page has loaded */ + window.addEventListener("load", set_code); + + /* Center the security code text when the page has loaded; in + * particular, after we set it. And then center it again. And + * again and again and again. Why? I'm glad you asked. Because + * it doesn't actually get centered the first time; it's off by + * a few pixels. But then if we center it _again_, it moves a + * little closer to the true center. Do that enough times and + * any errors become unnoticeable. */ + window.addEventListener("load", center_code_repeatedly); + + /* Re-center the security code when the window is resized, + * and in particular after the ticket is re-centered */ + window.addEventListener("resize", center_code); + + /* Set the ticket expiration date/time upon page load */ + window.addEventListener("load", set_ticket_expiry); + + /* Swap colors when the screen is tapped */ document.body.addEventListener("click", swap_colors);