]> gitweb.michael.orlitzky.com - charm-bypass.git/commitdiff
index.html.in: finish the QR focus toggle
authorMichael Orlitzky <michael@orlitzky.com>
Wed, 10 Sep 2025 14:30:19 +0000 (10:30 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Wed, 10 Sep 2025 14:30:19 +0000 (10:30 -0400)
Get the QR focus toggle working "completely."

  * Don't show ticket resize transitions when the page loads
    (Commuter bus / MARC).
  * Fade out the origin/destination and zone when the QR is
    focused (Commuter bus / MARC).
  * Resize the bottom portion of the ticket when the QR code
    is focused, so that the QR sits in the "middle" like it
    does on CharmPass.
  * Don't recompute dimensions if we're going to toggle the
    QR code _off_.

BaltimoreLink tickets are essentially correct. I have yet to compare
against real Commuter bus and MARC train tickets, but the current
behavior is reasonable.

index.html.in

index 3cea85430510903f7b5a8fc510d70f38113a6c27..3fe12944b7bb16af297e7e742c093bac826a9d93 100644 (file)
       /*****************/
 
       #ticketbottombg {
-        transform-box: fill-box;
+        transform-box: fill-box; /* don't reposition on scale */
         transform-origin: top; /* scale down only */
       }
 
+      #ticketbottombg.loaded {
+        /* The transitions are for the QR focus animation. These are
+         * specified in a class that is assigned only after commuter
+         * bus / MARC train tickets are initially (re)sized, so that
+         * the transition animation doesn't play prematurely. */
+        transition-property: transform;
+        transition-duration: 0.25s;
+      }
+
       /*****************/
       /* QR code focus */
       /*****************/
 
-      #serviceid, #servicename, #codebg, #codetext {
+      #codebg, #codetext, #origindest, #serviceid, #servicename, #zone {
         transition-property: opacity;
         transition-duration: 0.25s;
       }
           t.setAttribute("transform", "translate(0 -67.17)");
           sn.setAttribute("transform", "translate(0 131.0)");
         }
+
+        /* Enable CSS transitions for future scalings, namely
+         * for the QR focus animation. */
+        tbbg.setAttribute("class", "loaded");
       }
 
 
        * 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.
+       *
+       * A posteriori, using CSS was the right way to do this, because
+       * the commuter bus and MARC train tickets are initially sized
+       * with the transform _attribute_. The CSS property takes
+       * precedence, but when we unset the CSS property, whatever
+       * scaling factor was set in the attribute kicks back in. So
+       * ultimately we don't have to worry about the initial ticket
+       * size: the scaled-up size for the QR focus is always bigger
+       * than the ticket; everything just works.
        */
       function toggle_qr_focus(event) {
         /* Don't swap night/day if the tap was on the QR code. */
         event.stopPropagation();
 
+        const codetext = document.getElementById("codetext");
+        const codebg = document.getElementById("codebg");
+        const origindest = document.getElementById("origindest");
         const qr = document.getElementById("qr");
         const serviceid = document.getElementById("serviceid");
         const servicename = document.getElementById("servicename");
-        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;
+        const t = document.getElementById("ticket");
+        const tbbg = document.getElementById("ticketbottombg");
+        const zone = document.getElementById("zone");
 
-        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 */
+        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 */
+        let tbbg_transform; /* transform (resize) of ticket bottom */
+        let t_transform;    /* upwards ticket translation */
 
         if (qr.getAttribute("class") == "big") {
           ticket_class = "";
           qr_class = "";
           qr_transform = "";
+          tbbg_transform = "";
+          t_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
+          /* Compute the QR x-translation amount in pixels using the
+           * (known) width of the security code box. 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)";
+           * then centering it on the ticket. This gives you the
+           * offset in SVG units, which we then have to DIVIDE by the
+           * scaling factor, because when we scale the QR code in a
+           * second, the scaling is going to affect the translation.
+           *
+           * The y-translations for the QR code and ticket by contrast
+           * were pretty much chosen on vibes.
+           *
+           * Note: the fucked up spacing around the QR code is there in
+           * CharmPass, too -- that's not my fault.
+           */
+          const client_width = codebg.getBoundingClientRect().width;
+          const svg_width = parseFloat(codebg.getAttribute("width"));
+          const svg_to_client = client_width / svg_width;
+          const qr_xoffset = -6.56 * svg_to_client;
+          const qr_yoffset = 43 * svg_to_client;
+          const t_yoffset = -40 * svg_to_client;
+
+          /* The _CSS_ translate transform takes comma-separated strings,
+           * and is specified in px. */
+          const qr_translate = `${qr_xoffset}px, ${qr_yoffset}px`;
+          const t_translate = `0, ${t_yoffset}px`;
+
+          /* The scale factors can easily be measured in CharmPass by
+           * taking two screenshots, pre- and post-tap. */
+          qr_transform = `scale(4.13333333) translate(${qr_translate})`;
+          tbbg_transform = "scale(1, 1.47)";
+          t_transform = `translate(${t_translate})`;
         }
 
-        serviceid.setAttribute("class", ticket_class);
-        servicename.setAttribute("class", ticket_class);
+        /* The origindest and zone are only visible on commuter bus and
+         * MARC train tickets, but they're hidden with "display: none",
+         * so we don't have to worry about making them opaque. */
         codetext.setAttribute("class", ticket_class);
         codebg.setAttribute("class", ticket_class);
+        origindest.setAttribute("class", ticket_class);
+        serviceid.setAttribute("class", ticket_class);
+        servicename.setAttribute("class", ticket_class);
+        zone.setAttribute("class", ticket_class);
 
+        tbbg.style.transform = tbbg_transform;
+        t.style.transform = t_transform;
         qr.style.transform = qr_transform;
         qr.setAttribute("class", qr_class);
       }