VulpesOS/gaia/apps/clock/js/stopwatch.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

179 lines
4.4 KiB
JavaScript
Executable file

define(function() {
'use strict';
var priv = new WeakMap();
function Defaults() {
this.startTime = 0;
this.totalElapsed = 0;
this.state = Stopwatch.RESET;
this.laps = [];
}
/**
* Stopwatch
*
* Create new or revive existing stopwatch objects.
*
* @param {Object} opts Optional stopwatch object to create or revive
* a new or existing stopwatch object.
* - startTime, number time in ms.
* - totalElapsed, number time in ms.
* - isStarted, started state boolean.
* - laps, array of lap objects (lap = {time:, duration:}).
*/
function Stopwatch(opts = {}) {
var defaults = new Defaults();
var obj = {};
obj.startTime = opts.startTime || defaults.startTime;
obj.totalElapsed = opts.totalElapsed || defaults.totalElapsed;
obj.state = opts.state || defaults.state;
obj.laps = opts.laps ? opts.laps.slice() : defaults.laps;
priv.set(this, obj);
}
Stopwatch.RUNNING = 'RUNNING';
Stopwatch.PAUSED = 'PAUSED';
Stopwatch.RESET = 'RESET';
Stopwatch.prototype = {
constructor: Stopwatch,
getState: function() {
var sw = priv.get(this);
return sw.state;
},
setState: function(state) {
var sw = priv.get(this);
sw.state = state;
},
/**
* start Starts the stopwatch, either from a reset or paused state
*/
start: function sw_start() {
var sw = priv.get(this);
if (sw.state === Stopwatch.RUNNING) {
return;
}
var now = Date.now() - sw.totalElapsed;
sw.startTime = now;
this.setState(Stopwatch.RUNNING);
},
/**
* getElapsedTime Calculates the total elapsed duration since the
* stopwatch was started
* @return {Number} return total elapsed duration.
*/
getElapsedTime: function sw_getElapsedTime() {
var sw = priv.get(this);
var elapsed = 0;
if (sw.state === Stopwatch.RUNNING) {
elapsed = Date.now() - sw.startTime;
} else {
elapsed = sw.totalElapsed;
}
return elapsed;
},
/**
* pause Pauses the stopwatch
*/
pause: function sw_pause() {
var sw = priv.get(this);
if (sw.state === Stopwatch.PAUSED) {
return;
}
sw.totalElapsed = Date.now() - sw.startTime;
this.setState(Stopwatch.PAUSED);
},
/**
* nextLap Calculates the duration of the next lap.
* @return {object} return an object containing:
* duration - the duration of this lap in ms.
* time - the start time of this lap in ms from epoch.
*/
nextLap: function sw_nextLap() {
var sw = priv.get(this);
var now;
if (sw.state === Stopwatch.RUNNING) {
now = Date.now();
} else {
now = sw.startTime + sw.totalElapsed;
}
var lastLapTime;
var newLap = {};
if (sw.laps.length > 0) {
lastLapTime = sw.laps[sw.laps.length - 1].time;
} else {
lastLapTime = 0;
}
newLap.duration = now - (sw.startTime + lastLapTime);
newLap.time = now - sw.startTime;
return newLap;
},
/**
* lap Calculates a new lap duration since the last lap time,
* and mutates `priv[this].laps` to contain the new value.
* If the stopwatch isn't currently running, returns 0.
* @return {number} return the lap duration in ms.
*/
lap: function sw_lap() {
var sw = priv.get(this);
if (sw.state !== Stopwatch.RUNNING) {
return 0;
}
var nl = this.nextLap();
sw.laps.push(nl);
return nl;
},
/**
* getLaps Returns an array of laps, sorted by oldest first
* @return {Array} return an array of laps.
*/
getLaps: function sw_getLaps() {
var sw = priv.get(this);
return sw.laps.map(function(lap) {
return lap;
});
},
/**
* reset Resets the stopwatch back to 0, clears laps
*/
reset: function sw_reset() {
priv.set(this, new Defaults());
},
/**
* toSerializable Returns a serializable object for persisting Stopwatch data
* @return {Object} A serializable object.
*/
toSerializable: function sw_toSerializable() {
var sw = priv.get(this);
var obj = {};
for (var i in sw) {
if (sw.hasOwnProperty(i)) {
obj[i] = Array.isArray(sw[i]) ? sw[i].slice() : sw[i];
}
}
return obj;
}
};
return Stopwatch;
});