Last active
September 6, 2023 10:04
-
-
Save motsu0/2b0b7098e259234a177385fe388c96ac to your computer and use it in GitHub Desktop.
多段階タイマー
This file contains 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
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; | |
} |
This file contains 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
<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> |
This file contains 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
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