<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
</head>
<body>
<div id="app">
<div class="container">
<p class="time" v-show="ongoing || stop">{{ display_time }}</p>
<div class="input-section" v-show="!(ongoing || stop)">
<input type="number" v-model="set_hour" min="0">hr
<input type="number" v-model="set_min" min="0" max="59">min
<input type="number" v-model="set_sec" min="0" max="59">sec
</div>
<div class="button-section">
<button class="btn btn-primary" v-on:click="startTimer()" v-show="!(stop || ongoing)" :disabled="set_hour == 0 && set_min== 0 && set_sec == 0">Start</button>
<button class="btn btn-danger" v-on:click="stopTimer()" v-show="(ongoing && !stop)">Stop</button>
<button class="btn btn-info" v-on:click="resumeTimer()" v-show="(!ongoing && stop)">Resume</button>
<button class="btn btn-secondary" v-on:click="resetTimer()" v-show="(!ongoing && stop) || (ongoing && !stop)">Reset</button>
</div>
</div>
<div class="water" :style="[running]" :class="{timeup : !(ongoing || stop)}">
<svg class="waterwave back" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 749.866 619.483">
<path id="path_11" class="cls-1" d="M.127-35.3S50.2,6.431,99.143,6.489,164.71-12.845,193.368-35.1s53.288-29.32,96.2-29.058,85.049,29.274,85.049,29.274l.626,590.2L-.626,555.21Z" transform="translate(374.626 64.167)" />
<path id="path_21" class="cls-1" d="M.127-35.3S50.2,6.431,99.143,6.489,164.71-12.845,193.368-35.1s53.288-29.32,96.2-29.058,85.049,29.274,85.049,29.274l.626,590.2L-.626,555.21Z" transform="translate(0.626 64.167)" />
</svg>
<svg class="waterwave front" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 749.866 619.483">
<g transform="translate(0.126 -192.333)">
<path id="path_1" class="cls-1" d="M374.487-35.3S324.41,6.431,275.472,6.489,209.905-12.845,181.247-35.1s-53.288-29.32-96.2-29.058S0-34.885,0-34.885l-.626,590.2,375.866-.107Z" transform="translate(0.5 256.5)" />
<path id="path_2" class="cls-1" d="M374.487-35.3S324.41,6.431,275.472,6.489,209.905-12.845,181.247-35.1s-53.288-29.32-96.2-29.058S0-34.885,0-34.885l-.626,590.2,375.866-.107Z" transform="translate(374.5 256.5)" />
</g>
</svg>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</body>
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type="number"] {
-moz-appearance: textfield;
}
body {
margin: 0;
padding: 0;
}
#app {
position: relative;
font-family: "Hiragino Kaku Gothic ProN", "メイリオ", sans-serif;
background: #1E276A;
height: 100vh;
width: 100vw;
margin: 0 auto;
color: #fff;
z-index: 0;
}
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
z-index: 2;
}
.time {
font-size: 96px;
text-align: center;
}
.button-section {
padding-top: 20px;
margin-bottom: 50px;
display: block;
text-align: center;
}
.button-section button {
margin: 0 10px;
}
.input-section {
text-align: center;
font-size: 24px;
}
.input-section input {
width: 110px;
text-align: right;
border: none;
font-size: 80px;
color: #fff;
background: none;
}
.input-section input:focus {
outline: none;
}
.timeup {
top: 5% !important;
}
.water {
transition: all 1s ease-out;
position: fixed;
top: 100%;
left: 0;
height: 100%;
width: 100%;
z-index: 1;
}
.waterwave {
position: absolute;
top: 0;
width: 200%;
}
@keyframes wavegrad {
from {
left: -100%;
}
to {
left: 0%;
}
}
@keyframes wavegrad-back {
from {
left: 0%;
}
to {
left: -100%;
}
}
.back {
animation-duration: 20s;
animation-fill-mode: none;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-name: wavegrad-back;
fill: #2e55be;
}
.front {
animation-duration: 20s;
animation-fill-mode: none;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-name: wavegrad;
fill: #8ba5ea;
}
window.CP.PenTimer.MAX_TIME_IN_LOOP_WO_EXIT = 359999000; // to avoid an infinite loop protection
const sleep = msec => new Promise(r => setTimeout(r, msec));
var v = new Vue({
el: "#app",
data: {
set_hour: 0,
set_min: 0,
set_sec: 0,
set_ms: 0,
remain: 0,
ongoing: false,
stop: false
},
computed: {
display_time: function() {
var r = this.remain / 1000;
var r_sec = Math.floor(r % 60);
var r_min = Math.floor(r / 60);
var r_hour = Math.floor(r_min / 60);
if (r_hour > 0) {
return this.zfill(r_hour) + ":" + this.zfill(r_min % 60) + ":" + this.zfill(r_sec);
} else {
return this.zfill(r_min % 60) + ":" + this.zfill(r_sec);
}
},
wave_height: function() {
return ((95 / this.set_ms) * (this.set_ms - this.remain) + 5)
},
running: function() {
return {
active: this.ongoing || this.stop,
top: this.wave_height + "%"
}
}
},
methods: {
zfill: function(n) {
var zeros = Array(2).join("0");
return (zeros + n).slice(-2);
},
setTime: function() {
return ((this.set_hour * 3600) + (this.set_min * 60) + parseInt(this.set_sec)) * 1000
},
startTimer: function() {
this.set_ms = this.setTime();
this.remain = this.set_ms;
this.stop = false;
this.ongoing = true;
this.runTimer();
},
runTimer: async function() {
while (this.ongoing) {
await sleep(100);
this.remain -= 100;
if (this.remain <= 0) {
this.finishTimer();
break;
}
}
},
finishTimer: function() {
// beep!
window.alert("Time's up!");
this.stop = true;
this.resetTimer();
},
stopTimer: function() {
this.ongoing = false;
this.stop = true;
},
resumeTimer: function() {
this.ongoing = true;
this.stop = false;
this.runTimer();
},
resetTimer: function() {
this.ongoing = false;
this.stop = false;
this.set_ms = this.setTime();
this.remain = this.set_ms;
}
}
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.