/*****************/
#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);
}