More accurate timing; styling fixes
[jschessclock.git] / script.js
CommitLineData
72b294bb 1"use strict";
2
3function Timer(id) {
4 var precision = 100; // milliseconds
5 var defaultTime = (15 * 60 + 0) * 1000; // milliseconds
6 var time = defaultTime;
7 var intervalID;
8 this.isTicking = false;
9 var outputTime = function() {
10 document.getElementById(id).innerHTML = timeToTimeStr(time);
11 var flagid = "flag-" + id.split('-')[1];
12 var flagelem = document.getElementById(flagid);
13 flagelem.style.visibility = time <= 0 ? "visible" : "hidden";
14 };
6f474901
AIL
15
16 var startTickingUnixTime = null;
17 var remainingTimeAtTickingStart = null;
18
72b294bb 19 var thisTimer = this; // workaround to use this in setInterval
20 this.tick = function() {
6f474901
AIL
21 var currentPassedTime = new Date() - startTickingUnixTime;
22 time = remainingTimeAtTickingStart - currentPassedTime;
72b294bb 23 if(time <= 0) {
6f474901 24 time = 0;
72b294bb 25 // time's up
26 clearInterval(intervalID);
27 thisTimer.isTicking = false;
28 }
29 outputTime();
30 };
31 this.start = function() {
6f474901
AIL
32 startTickingUnixTime = new Date();
33 remainingTimeAtTickingStart = time;
72b294bb 34 intervalID = setInterval(this.tick, precision);
35 this.isTicking = true;
36 };
37 this.stop = function() {
38 clearInterval(intervalID);
39 this.isTicking = false;
40 };
41 this.setTime = function(t) {
42 time = t;
43 defaultTime = t;
44 outputTime();
45 };
46 this.getTime = function() {
47 return time;
48 };
49 this.reset = function() {
50 if(this.isTicking) {
51 this.stop();
52 }
53 this.setTime(defaultTime);
54 };
55 this.getDefaultTime = function() {
56 return defaultTime;
57 };
58}
59
60var currentTimers = new (function() {
61 this.leftTimer = new Timer("timer-left");
62 this.rightTimer = new Timer("timer-right");
63 this.active = this.leftTimer;
64 this.passive = this.rightTimer;
65 this.isPaused = true;
66 this.swap = function() {
67 var tmp = this.passive;
68 this.passive = this.active;
69 this.active = tmp;
70 var icon = document.getElementById("play");
71 icon.innerHTML = (icon.innerHTML == "◀" ? "▶" : "◀");
72 };
73 this.pause = function() {
74 this.active.stop();
75 this.isPaused = true;
76 document.getElementById("pause").style.visibility = "visible";
77 };
78 this.resume = function() {
79 this.active.start();
80 this.isPaused = false;
81 document.getElementById("pause").style.visibility = "hidden";
82 };
83})();
84
85function timeStrToTime(timeStr) {
86 var minute = parseInt(timeStr.substr(0, 2));
87 var second = parseInt(timeStr.substr(3, 2));
88 return (minute * 60 + second) * 1000;
89}
90
91function timeToTimeStr(time) {
92 var minute = Math.floor(time / 1000 / 60);
93 var second = Math.floor(time / 1000) % 60;
94 if(minute < 10) {
95 minute = '0' + minute.toString();
96 }
97 if(second < 10) {
98 second = '0' + second.toString();
99 }
100 return minute + ':' + second;
101}
102
103document.onkeydown = function(e) {
104 if(e.key) {
105 switch(e.key) {
106 case ' ': return toggle();
107 case 'S':
108 case 's': return setTime();
109 case 'R':
110 case 'r': return reset();
111 case 'p':
112 case 'P': return pauseResume();
113 default: return;
114 }
115 } else if(e.keyCode) {
116 switch(e.keyCode) {
117 case 32: return toggle(); // space
118 case 83: return setTime(); // S
119 case 82: return reset(); // R
120 case 80: return pauseResume(); // P
121 default: return;
122 }
123 } else {
124 alert("Browser not supported");
125 }
126};
127
128function toggle() {
129 if(!currentTimers.isPaused) {
130 currentTimers.active.stop();
131 currentTimers.passive.start();
132 }
133 currentTimers.swap();
134 var lbt = document.getElementById('left-button-top');
135 var leftIsLong = lbt.getAttribute('class') == 'button-long';
136 var lbt_d = lbt.getAttribute('d').split(' ');
137 var lbb = document.getElementById('left-button-body');
138 var rbt = document.getElementById('right-button-top');
139 var rbt_d = rbt.getAttribute('d').split(' ');
140 var rbb = document.getElementById('right-button-body');
6f474901 141
72b294bb 142 var y_diff = 50 * (leftIsLong ? 1 : -1);
143 var classes = ['button-short', 'button-long'];
144
145 lbt_d[2] = (parseInt(lbt_d[2]) + y_diff).toString();
146 lbt_d[10] = (parseInt(lbt_d[10]) + y_diff).toString();
147 lbb.setAttribute('height',
148 (parseInt(lbb.getAttribute('height')) - y_diff).toString());
149 lbb.setAttribute('y', (parseInt(lbb.getAttribute('y')) + y_diff).toString());
150 rbt_d[2] = (parseInt(rbt_d[2]) - y_diff).toString();
151 rbt_d[10] = (parseInt(rbt_d[10]) - y_diff).toString();
152 rbb.setAttribute('height',
153 (parseInt(rbb.getAttribute('height')) + y_diff).toString());
154 rbb.setAttribute('y', (parseInt(rbb.getAttribute('y')) - y_diff).toString());
155 lbt.setAttribute('class', classes[(leftIsLong + 1) % 2]);
156 lbb.setAttribute('class', classes[(leftIsLong + 1) % 2]);
157 rbt.setAttribute('class', classes[(leftIsLong + 1) % 2]);
158 rbb.setAttribute('class', classes[(leftIsLong + 1) % 2]);
159 lbt.setAttribute('d', lbt_d.join(' '));
160 rbt.setAttribute('d', rbt_d.join(' '));
6f474901 161
72b294bb 162 lbt.setAttribute('onclick', leftIsLong ? '' : 'toggle()');
163 lbb.setAttribute('onclick', leftIsLong ? '' : 'toggle()');
164 lbt.setAttribute('cursor', leftIsLong ? 'default' : 'pointer');
165 lbb.setAttribute('cursor', leftIsLong ? 'default' : 'pointer');
166 rbt.setAttribute('onclick', leftIsLong ? 'toggle()' : '');
167 rbb.setAttribute('onclick', leftIsLong ? 'toggle()' : '');
168 rbt.setAttribute('cursor', leftIsLong ? 'pointer' : 'default');
169 rbb.setAttribute('cursor', leftIsLong ? 'pointer' : 'default');
170}
171
172function pauseResume() {
173 if(currentTimers.isPaused) {
174 currentTimers.resume();
175 } else {
176 currentTimers.pause();
177 }
178}
179
180function setTime() {
181 var leftstart, rightstart;
182 var def = timeToTimeStr(currentTimers.leftTimer.getDefaultTime());
183 var regex = /[0-9][0-9]:[0-5][0-9]/;
6f474901 184
72b294bb 185 leftstart = prompt("Time for LEFT player in MM:SS", def);
186 if(leftstart === null) return; // Cancel
187 while(!leftstart.match(regex)) {
188 leftstart = prompt("Invalid value\nTime for LEFT player in MM:SS", def);
189 if(leftstart === null) return; // Cancel
190 }
191 def = leftstart;
192 rightstart = prompt("Time for RIGHT player in MM:SS", def);
193 if(rightstart === null) return; // Cancel
194 while(!rightstart.match(regex)) {
195 rightstart = prompt("Invalid value\nTime for RIGHT player in MM:SS", def);
196 if(rightstart === null) return; // Cancel
197 }
198 currentTimers.leftTimer.setTime(timeStrToTime(leftstart));
199 currentTimers.rightTimer.setTime(timeStrToTime(rightstart));
200}
201
202function reset() {
203 currentTimers.pause();
204 currentTimers.active.reset();
205 currentTimers.passive.reset();
206}
207
208function init() {
209 insertcss();
6f474901 210 setTimeout(fitscreen, 2000); // hack to allow DOM to be redrawn with new css
72b294bb 211}
212
213function fitscreen() {
214 /*
215 * Scale body so as to fit the screen
216 */
217 var heightRatio = window.innerHeight / document.body.scrollHeight;
218 var widthRatio = window.innerWidth / document.body.scrollWidth;
6f474901 219 var scaleRatio = Math.min(heightRatio, widthRatio, 1);
72b294bb 220 document.body.style.transform = 'scale(' + scaleRatio + ')';
221}
222
223function insertcss() {
224 /* fix positions for browsers that don't support flex */
6f474901
AIL
225 var cssfile = document.getElementById("style");
226 if(!('align-items' in document.body.style)) {
72b294bb 227 cssfile.setAttribute("href", "noflex.css");
228 }
72b294bb 229}