Skip to content

Instantly share code, notes, and snippets.

@motsu0
Last active September 6, 2023 10:04
Show Gist options
  • Save motsu0/2b0b7098e259234a177385fe388c96ac to your computer and use it in GitHub Desktop.
Save motsu0/2b0b7098e259234a177385fe388c96ac to your computer and use it in GitHub Desktop.
多段階タイマー
button{
cursor: pointer;
}
#bt-area{
margin: 10px 0;
text-align: right;
}
#display-box,.timer{
padding: 10px;
}
.timer{
margin: 10px 0;
position: relative;
background-color: #E0E0E0;
border: 1px solid #E0E0E0;
}
#display-box{
padding: 20px;
background-color: #FBE9E7;
border: 2px solid #FFAB91;
font-size: 30px;
}
#display-time{
margin-top: 20px;
}
.timer.active{
background-color: #FFF3E0;
border: 1px solid #FFB74D;
}
#display-name,.timer__name{
display: block;
box-sizing: border-box;
width: 80%;
}
.timer__area-time{
margin-top: 10px;
}
.timer__time{
width: 3em;
margin: 0 10px;
}
.bt-del{
position: absolute;
top: 5px;
right: 5px;
}
#bt-play,#bt-add{
display: block;
margin: 10px auto;
}
#bt-play{
padding: 10px 20px;
}
.cb-option{
transform: scale(1.5);
margin: 0 10px;
cursor: pointer;
}
<div id="bt-area">
<button id="bt-cancel">中止</button>
</div>
<div id="option-area">
<input type="checkbox" id="cb-auto" class="cb-option" checked>自動的に次のタイマーへ進む<br>
<input type="checkbox" id="cb-loop" class="cb-option">ループさせる
</div>
<div id="display">
<div id="display-box">
<div id="display-name"> </div>
<div class="timer__area-time">
<div id="display-time">0:00:00</div>
</div>
</div>
</div>
<div id="control-area">
<button id="bt-play">
<i id="icon-play" class="fas fa-play"></i>
</button>
</div>
<div id="area-timer">
<div class="timer">
<input type="text" class="timer__name" value="タイマー1" placeholder="タイマー名">
<div class="timer__area-time">
time<input type="number" class="timer__time time-h" value="0" min="0">:<!--
--><input type="number" class="timer__time time-m" value="0" min="0" max="59">:<!--
--><input type="number" class="timer__time time-s" value="0" min="0" max="59">
</div>
<button class="bt-del">×</button>
</div>
</div>
<button id="bt-add">+</button>
const el_display_name = document.getElementById('display-name');
const el_display_time = document.getElementById('display-time');
const bt_cancel = document.getElementById('bt-cancel');
const bt_play = document.getElementById('bt-play');
const bt_add = document.getElementById('bt-add');
const bts_del = document.getElementsByClassName('bt-del');
const el_icon_play = document.getElementById('icon-play');
const el_area_timer = document.getElementById('area-timer');
const els_timer = document.getElementsByClassName('timer');
const els_timer__name = document.getElementsByClassName('timer__name');
const els_timer__time = document.getElementsByClassName('timer__time');
const els_cb_option = document.getElementsByClassName('cb-option');
const cb_auto = document.getElementById('cb-auto');
const cb_loop = document.getElementById('cb-loop');
const alarm = new Audio();
const bgm = new Audio();
const name_cookie = 'multi-step-timer-save';
let count = 0;
let timer;
let remain_sec;
let is_running = false;
let playing = false;
let change = false;
let is_save_valid = false;
checkCookie();
timerInit();
loadData();
function timerInit(){
//audio用無音ループ挿入
bgm.src = '/se/muon.mp3';
bgm.volume = 0;
bgm.loop = true;
alarm.src = '/se/alarm1.mp3';
alarm.addEventListener('ended',()=>{
alarm.pause();
alarm.currentTime = 0;
});
//ボタンリスナ
bt_play.addEventListener('click',pushPlay);
bt_add.addEventListener('click',()=>{
if(is_running) return;
addTimer();
});
[...bts_del].forEach((bt,i)=>{
bt.addEventListener('click',(e)=>{
if(is_running) return;
delTimer(e);
});
});
bt_cancel.addEventListener('click',()=>{
if(window.confirm('中止しますか?')){
cancel();
}
});
window.addEventListener('beforeunload',saveData);
}
function pushPlay(){
console.log('pushPlay');
if(is_running){
if(playing){
console.log('pause')
pausePlay();
clearInterval(timer);
}else{
console.log('restart')
if(change){
alarm.loop = false;
alarm.pause();
alarm.currentTime = 0;
startPlay();
nextTimer();
}else{
startPlay();
runTimer();
}
}
}else{
///初再生時はbgm starg
if(bgm.paused){
console.log('bgm start');
bgm.play();
}
setTimer();
}
}
function setTimer(){
if(els_timer.length==0) return;
console.log('setTimer');
runStart();
startPlay();
els_timer[count].classList.add('active');
//get hms
const timer_num = count*3;
let hms = new Array(3);
for(i=0;i<=2;i++){
const val = els_timer__time[timer_num+i].value;
if(val==''||!Number.isInteger(Number(val))){
els_timer__time[timer_num+i].value = 0;
hms[i] = 0;
}else{
hms[i] = Number(val);
}
}
//set name
el_display_name.textContent = els_timer__name[count].value;
//
remain_sec = hms[0]*3600 + hms[1]*60 + hms[2];
runTimer();
}
function runTimer(){
if(remain_sec==0){
nextTimer();
return;
}
writeTime(remain_sec);
timer = setInterval(()=>{
remain_sec--;
writeTime(remain_sec);
if(remain_sec<=0){
clearInterval(timer);
alarm.currentTime = 0;
if(cb_auto.checked){
alarm.loop = false;
}else{
alarm.loop = true;
}
alarm.play();
if(cb_auto.checked){
nextTimer();
}else{
change = true;
pausePlay();
}
}
},1000);
}
function nextTimer(){
els_timer[count].classList.remove('active');
count++;
if(count>=els_timer.length){
//終了
console.log('end');
count = 0;
if(cb_loop.checked){
setTimer();
}else{
el_display_name.textContent = ' ';
pausePlay();
runStop();
}
}else{
setTimer();
}
}
function startPlay(){
playing = true;
change = false;
el_icon_play.classList.add('fa-pause');
el_icon_play.classList.remove('fa-play');
}
function pausePlay(){
playing = false;
el_icon_play.classList.add('fa-play');
el_icon_play.classList.remove('fa-pause');
}
function writeTime(sec){
let h = Math.floor(sec/3600);
sec = sec % 3600;
let m = Math.floor(sec/60);
sec = sec % 60;
let s = sec;
el_display_time.textContent = `${h}:${nn(m)}:${nn(s)}`;
function nn(x){
if(x<10){
return '0'+x;
}else{
return x;
}
}
}
function addTimer(){
const el = els_timer[0].cloneNode(true);
const n = els_timer.length;
el_area_timer.appendChild(el);
els_timer__name[n].value = 'タイマー'+(n+1);
bts_del[n].addEventListener('click',(e)=>{
if(is_running) return;
delTimer(e);
});
}
function delTimer(e){
console.log('delTimer');
if(els_timer.length<=1) return;
els_timer[[...bts_del].indexOf(e.target)].remove();
}
function runStart(){
is_running = true;
bt_add.classList.add('invisible');
[...bts_del].forEach(bt=>{
bt.classList.add('invisible');
});
}
function runStop(){
is_running = false;
bt_add.classList.remove('invisible');
[...bts_del].forEach(bt=>{
bt.classList.remove('invisible');
});
}
function cancel(){
console.log('cancel');
count = 0;
change = false;
clearInterval(timer);
alarm.loop = false;
alarm.pause();
alarm.currentTime = 0;
el_display_name.textContent = ' ';
el_display_time.textContent = '0:00:00';
[...els_timer].forEach(el=>{
el.classList.remove('active');
});
pausePlay();
runStop();
}
function checkCookie(){
const is_cookie_valid = navigator.cookieEnabled;
if(!is_cookie_valid){
is_save_valid = false;
return;
}
if(typeof window.localStorage===undefined){
is_save_valid = false;
return;
}
is_save_valid = true;
}
function saveData(){
if(!is_save_valid) return;
const num = els_timer.length;
let data_name = new Array(num);
let data_time = new Array(num*3);
let data_option = [];
for(let i=0;i<num;i++){
data_name[i] = els_timer__name[i].value;
}
for(let i=0;i<num*3;i++){
data_time[i] = els_timer__time[i].value;
}
[...els_cb_option].forEach(cb=>{
if(cb.checked){
data_option.push(true);
}else{
data_option.push(false);
}
});
const data = JSON.stringify([num, data_name, data_time, data_option]);
localStorage.setItem(name_cookie, data);
}
function loadData(){
if(!is_save_valid) return;
const cookie = localStorage.getItem(name_cookie);
if(cookie===null) return;
const data = JSON.parse(cookie);
for(let i=1;i<data[0];i++){
addTimer();
}
for(let i=0;i<data[0];i++){
els_timer__name[i].value = data[1][i];
}
for(let i=0;i<data[0]*3;i++){
els_timer__time[i].value = data[2][i];
}
data[3].forEach((d,i)=>{
if(d){
els_cb_option[i].checked = true;
}else{
els_cb_option[i].checked = false;
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment