From 230fedbb2d7736eba81ee3a278e2cad3621fd686 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Mon, 8 Sep 2025 22:15:36 -0400 Subject: [PATCH] index.html.in: more work on the QR focus Tapping the QR code now brings it into focus and centers it in the ticket, accompanied by a nice CSS transition that mimics the real thing. The timing was adjusted to make the transition faster, and a portability issue was hacked around. What does work, works in both Firefox and WebKit (on the desktop) at least. Still to-do is the ticket resizing that takes place when the QR code gets bigger, and the vertical translation of the (growing) QR code. --- index.html.in | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/index.html.in b/index.html.in index 9316fb9..6813c4b 100644 --- a/index.html.in +++ b/index.html.in @@ -204,11 +204,18 @@ #serviceid, #servicename, #codebg, #codetext { transition-property: opacity; - transition-duration: 0.5s; + transition-duration: 0.25s; } .transparent { opacity: 0; } + + #qr { + transition-property: transform; + transition-duration: 0.25s; + transform-box: fill-box; + transform-origin: bottom right; + } @@ -639,7 +646,6 @@ } } - /** * Center the security code within its container. * @@ -752,6 +758,18 @@ * ticket itself also grows somewhat, at least on BaltimoreLink * tickets. When the QR code is tapped again, this process * reverses. + * + * We use a CSS class to indicate whether or not the QR code is + * focused because that's cleaner than a global variable, but + * we perform the translation using Javascript because we need + * to compute the offset on-the-fly. It's easy to figure out + * the offset in SVG coordinates, but it turns out that WebKit + * won't do transition effects for the SVG "transform" attribute. + * So to get transitions, we have to use the "transform" style + * instead. But, the "transform" style uses pixels! Ergo, we + * must first convert between the two using an object whose + * size is known. We use the same trick when centering the + * security code within its box. */ function toggle_qr_focus(event) { /* Don't swap night/day if the tap was on the QR code. */ @@ -763,16 +781,32 @@ const codetext = document.getElementById("codetext"); const codebg = document.getElementById("codebg"); + /* Compute the QR translation amount in pixels using + * the (known) width of the security code box. */ + const r1 = codebg.getBoundingClientRect(); + const svg_to_css = r1.width / parseFloat(codebg.getAttribute("width")); + const offset = -6.56 * svg_to_css; + let ticket_class; /* transparent, or none (opaque) */ let qr_class; /* big, or none (normal sized) */ + let qr_transform; /* text of the transform style to be set */ if (qr.getAttribute("class") == "big") { ticket_class = ""; qr_class = ""; + qr_transform = ""; } else { ticket_class = "transparent"; qr_class = "big"; + + /* The scale factor can easily be measured in CharmPass by + * taking two screenshots, pre- and post-tap. The magic offset + * was measured by scaling up the QR code in the SVG, and + * then centering it on the ticket. This gives you the offset + * in SVG units, which we then have to DIVIDE by 4.1333333, + * because the scale factor affects the translation. */ + qr_transform = "scale(4.1333333) translate(" + offset + "px, 0px)"; } serviceid.setAttribute("class", ticket_class); @@ -780,6 +814,7 @@ codetext.setAttribute("class", ticket_class); codebg.setAttribute("class", ticket_class); + qr.style.transform = qr_transform; qr.setAttribute("class", qr_class); } -- 2.49.0