Cuckoo: single click gives one call, double-click strikes the hour
Nine cuckoos on an idle click is a lot. There's no singleclick event and click always fires before dblclick, so the single call is deferred by one double-click interval (260ms) and cancelled if a second click lands.
This commit is contained in:
parent
63902f095a
commit
6b6d80ded3
@ -25,8 +25,8 @@
|
||||
class="cuckoo__btn"
|
||||
id="cuckoo-clock"
|
||||
type="button"
|
||||
aria-label="Cuckoo clock — click to strike the hour"
|
||||
title="Strike the hour"
|
||||
aria-label="Cuckoo clock. Click for one call; double-click to strike the hour."
|
||||
title="Click for one call · double-click strikes the hour"
|
||||
>
|
||||
<svg viewBox="0 0 200 272" class="cuckoo__svg" aria-hidden="true">
|
||||
<defs>
|
||||
@ -120,7 +120,9 @@
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<span class="cuckoo__hint">Strike the hour</span>
|
||||
<span class="cuckoo__hint">
|
||||
Click <span class="cuckoo__hint-sep">·</span> double-click strikes the hour
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<p class="cuckoo__live" role="status" aria-live="polite" id="cuckoo-live"></p>
|
||||
@ -196,7 +198,7 @@
|
||||
return 0.78; // seconds until the next call may begin
|
||||
};
|
||||
|
||||
clock.addEventListener("click", async () => {
|
||||
const strike = async (calls) => {
|
||||
if (striking) return;
|
||||
striking = true;
|
||||
|
||||
@ -204,18 +206,42 @@
|
||||
ctx = ctx ?? new (window.AudioContext || window.webkitAudioContext)();
|
||||
if (ctx.state === "suspended") await ctx.resume();
|
||||
|
||||
const hour = new Date().getHours() % 12 || 12;
|
||||
let t = ctx.currentTime + 0.05;
|
||||
for (let i = 0; i < hour; i++) t += call(t);
|
||||
for (let i = 0; i < calls; i++) t += call(t);
|
||||
|
||||
clock.classList.add("is-striking");
|
||||
if (live) live.textContent = `Cuckoo ×${hour}`;
|
||||
if (live) live.textContent = `Cuckoo ×${calls}`;
|
||||
|
||||
const total = (t - ctx.currentTime) * 1000;
|
||||
setTimeout(() => {
|
||||
clock.classList.remove("is-striking");
|
||||
striking = false;
|
||||
}, total);
|
||||
};
|
||||
|
||||
// A single click is a greeting: one call. Double-click and it strikes the
|
||||
// hour properly — which at eleven o'clock is a commitment.
|
||||
//
|
||||
// There is no `singleclick` event, and `click` always fires BEFORE `dblclick`.
|
||||
// So hold the single call for one double-click interval and cancel it if a
|
||||
// second click lands. 260 ms is comfortably under the platform's threshold
|
||||
// but longer than a deliberate double-tap.
|
||||
let pending = null;
|
||||
|
||||
clock.addEventListener("click", () => {
|
||||
if (pending) return; // this is the 2nd of a pair — let dblclick take it
|
||||
pending = setTimeout(() => {
|
||||
pending = null;
|
||||
strike(1);
|
||||
}, 260);
|
||||
});
|
||||
|
||||
clock.addEventListener("dblclick", () => {
|
||||
if (pending) {
|
||||
clearTimeout(pending);
|
||||
pending = null;
|
||||
}
|
||||
strike(new Date().getHours() % 12 || 12);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -260,6 +286,7 @@
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.cuckoo__btn:hover .cuckoo__hint { color: var(--sl-color-accent); }
|
||||
.cuckoo__hint-sep { opacity: 0.5; margin: 0 0.15em; }
|
||||
|
||||
.cuckoo__live {
|
||||
min-height: 1.2em;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user