const states = { START: 'start', TIMEOUT: 'timeout', READY: 'ready' } const colors = { TIMEOUT: 'crimson', START: 'dodgerblue', READY: 'limegreen' } var state = states.START; var times = []; var ready_time; var ready_id; // timeout id const min_time = 1000; const max_time = 3000; function handle_click() { switch (state) { // click received on start, activate timer and set state to timeout case states.START: { // this is a hack to access thisptr from setTimeout let self = this; ready_id = setTimeout(function () { ready_time = Date.now(); self.style["background-color"] = colors.READY; self.innerText = "Click now!"; state = states.READY; }, min_time + (Math.random() * (max_time - min_time))); this.style["background-color"] = colors.TIMEOUT; this.innerText = "Get ready!"; state = states.TIMEOUT; } break; // click received during timeout, clear timeout and reset case states.TIMEOUT: { clearTimeout(ready_id); this.style["background-color"] = colors.START; this.innerText = "Too early!"; state = states.START; } break; // click received after timeout, calculate score and reset case states.READY: { let time = (Date.now() - ready_time); times.push(time); let average = times.reduce((a, b) => a + b) / times.length; // update average text document.getElementById("average").innerText = "Average: " + average + "ms"; // create and add time listing var li = document.createElement("li"); li.appendChild(document.createTextNode(time + "ms")); document.getElementById("times").appendChild(li); this.style["background-color"] = colors.START; this.innerText = time + "ms"; state = states.START; } break; default: break } } window.onload = function () { create_prologue(); let area = document.getElementById("area"); area.innerText = "Click here to begin!"; area.onclick = handle_click; }