Last active
November 7, 2022 12:12
-
-
Save GeekyDeaks/635b0f0fb767f84a48c157aa9f684c49 to your computer and use it in GitHub Desktop.
Simple Stopwatch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>Stopwatch</title> | |
<link rel="preconnect" href="https://fonts.googleapis.com"> | |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
<link href="https://fonts.googleapis.com/css2?family=Overpass+Mono&display=swap" rel="stylesheet"> | |
<style> | |
html { height: 100%; } | |
body { | |
font-family: 'Arial', sans-serif; margin: 0em; | |
width: 100%; | |
} | |
#app { | |
width: 100%; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
} | |
button { | |
display: inline-block; | |
background-color: #555; | |
margin: 0.2em; | |
padding: 0.25em 0.75em 0.25em 0.75em; | |
border-radius: .25em; | |
color: white; | |
font-size: 1.25em; | |
} | |
button:disabled { | |
color: lightgray; | |
background-color: #777; | |
} | |
.buttonbox { | |
width: auto; | |
display: flex; | |
align-items: center; | |
flex-direction: row; | |
} | |
.timerbox { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
width: 100%; | |
} | |
#elapsedtime { | |
font-family: 'Overpass Mono', monospace; | |
font-size: 1.5em; | |
color: #555; | |
} | |
#splittime { | |
font-family: 'Overpass Mono', monospace; | |
font-size: 1.75em; | |
font-weight: bold; | |
padding-top: 0.25em; | |
} | |
table { border-collapse: collapse; width: 100%; } | |
tr:nth-child(even) { background: #FFF } | |
tr:nth-child(odd) { background: #EEE } | |
tr:first-child {font-weight: bold; background: #BBB } | |
table, th, td { border: 1px solid gray; padding: 5px } | |
td { font-family: 'Overpass Mono', monospace; } | |
</style> | |
</head> | |
<body> | |
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> | |
<div id="app"> | |
<div class="timerbox"> | |
<div id="splittime">{{ splitTime }}</div> | |
<div id="elapsedtime">{{ elapsedTime }}</div> | |
</div> | |
<div class="buttonbox"> | |
<button id="startbutton" class="button" @click="start" v-if="!timer">start</button> | |
<button id="stopbutton" class="button" @click="stop" v-if="timer">stop</button> | |
<button id="splitbutton" class="button" @click="split" :disabled="!timer">split</button> | |
<button id="resetbutton" class="button" @click="reset">reset</button> | |
</div> | |
<table> | |
<tr><th>lap</th><th>split</th><th>elapsed</th></tr> | |
<tr v-for="lap in laps"> | |
<td>{{ lap.lap }}</td> | |
<td>{{ lap.splitTime }}</td> | |
<td>{{ lap.elapsedTime }}</td> | |
</tr> | |
</table> | |
</div> | |
<script> | |
const { createApp } = Vue | |
function createTimer() { | |
let last = 0 | |
let total = 0 | |
return { | |
start(now = Date.now()) { | |
last = now | |
}, | |
update(now = Date.now()) { | |
total += now - last | |
last = now | |
}, | |
toString() { | |
let ms = total % 1000 | |
let sec = Math.floor(total % 60000 / 1000) | |
let min = Math.floor(total % 3600000 / 1000 / 60) | |
let hour = Math.floor(total / 1000 / 3600) | |
return hour.toString().padStart(2, '0') + ':' | |
+ min.toString().padStart(2, '0') + ':' | |
+ sec.toString().padStart(2, '0') + '.' | |
+ ms.toString().padStart(3, '0') | |
} | |
} | |
} | |
let app = createApp({ | |
data() { | |
return { | |
laps: [], | |
timer: undefined, | |
elapsedTimer: createTimer(), | |
elapsedTime: '', | |
splitTimer: createTimer(), | |
splitTime: '' | |
} | |
}, | |
methods: { | |
update(now = Date.now()) { | |
this.elapsedTimer.update(now) | |
this.elapsedTime = this.elapsedTimer.toString() | |
this.splitTimer.update(now) | |
this.splitTime = this.splitTimer.toString() | |
}, | |
start() { | |
if(this.timer) return | |
let now = Date.now() | |
this.elapsedTimer.start(now) | |
this.splitTimer.start(now) | |
this.timer = setInterval(this.update.bind(this), 10) | |
}, | |
split() { | |
if(!this.timer) return | |
// add the latest times to the laps | |
let now = Date.now() | |
this.update(now) | |
let lap = this.laps.length + 1 | |
this.laps.unshift({ lap, elapsedTime: this.elapsedTime, splitTime: this.splitTime }) | |
this.splitTimer = createTimer() | |
this.splitTimer.start(now) | |
}, | |
stop() { | |
if(!this.timer) return | |
clearInterval(this.timer) | |
this.timer = undefined | |
this.update() | |
}, | |
reset() { | |
this.stop() | |
this.elapsedTimer = createTimer() | |
this.splitTimer = createTimer() | |
this.laps = [] | |
this.update(0) | |
} | |
}, | |
mounted() { | |
this.update(0) | |
} | |
}).mount('#app') | |
</script> | |
</body> | |
</html> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment