#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;
+ }
</style>
</head>
}
}
-
/**
* Center the security code within its container.
*
* 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. */
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);
codetext.setAttribute("class", ticket_class);
codebg.setAttribute("class", ticket_class);
+ qr.style.transform = qr_transform;
qr.setAttribute("class", qr_class);
}