var SLIDE_PUZZLE = window.SLIDE_PUZZLE || {}; SLIDE_PUZZLE.Stopwatch = function(tickMillis) { var self = this; this._tickMillis = tickMillis; this._startTime = null; this._intervalID = null; this._priorElapsed = 0; this._currentElapsed = 0; this._listeners = []; this.__defineGetter__("isRunning", function() { return self._intervalID !== null; }); this.__defineGetter__("elapsedMillis", function() { return self._priorElapsed + self._currentElapsed; }); function divideInt(a, b) { return Math.floor(a/b); } this.__defineGetter__("elapsedString", function() { var totalMillis = self._priorElapsed + self._currentElapsed; var seconds = divideInt(totalMillis, 1000) % 60; var minutes = divideInt(totalMillis, 60000) % 60; var hours = divideInt(totalMillis, 3600000); var showHours = hours > 0; var showMinutes = minutes > 0 || showHours; var fixMinutes = showHours; var fixSeconds = showMinutes; var hoursString; if (showHours) { hoursString = hours + ':'; } else { hoursString = ''; } var minutesString; if (showMinutes) { if (fixMinutes && minutes < 10) { minutesString = '0' + minutes + ':'; } else { minutesString = minutes + ':'; } } else { minutesString = ''; } var secondsString; if (fixSeconds && seconds < 10) { secondsString = '0' + seconds; } else { secondsString = seconds.toString(); } return hoursString + minutesString + secondsString; }); }; SLIDE_PUZZLE.Stopwatch.prototype.start = function() { if (!this.isRunning) { var self = this; function tick() { self._currentElapsed = window.performance.now() - self._startTime; self._dispatchTickEvent(); } this._startTime = window.performance.now(); this._intervalID = window.setInterval(tick, this._tickMillis); } else { throw new Error("can't start a started stopwatch"); } }; SLIDE_PUZZLE.Stopwatch.prototype.stop = function() { if (this.isRunning) { window.clearInterval(this._intervalID); this._intervalID = null; this._startTime = null; this._priorElapsed += this._currentElapsed; this._currentElapsed = 0; } else { throw new Error("can't stop a stopped stopwatch"); } }; SLIDE_PUZZLE.Stopwatch.prototype.reset = function() { if (!this.isRunning) { this._priorElapsed = 0; this._currentElapsed = 0; this._dispatchTickEvent(); } else { throw new Error("can't reset a started stopwatch"); } }; SLIDE_PUZZLE.Stopwatch.prototype.addEventListener = function(type, listener) { if (type === 'tick') { this._listeners.push(listener); } }; SLIDE_PUZZLE.Stopwatch.prototype._dispatchTickEvent = function() { var event = document.createEvent('CustomEvent'); event.initCustomEvent('tick', false, false, null); for (var i = 0; i < this._listeners.length; i++) { this._listeners[i](event); } }