Last active
July 18, 2022 12:20
-
-
Save motsu0/a74aede87352ccc200035dd2d90ed8fe 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
#quiz{ | |
display: flex; | |
flex-direction: column; | |
box-sizing: border-box; | |
height: 90vh; | |
border: 2px solid #777; | |
background-color: #fff; | |
-webkit-tap-highlight-color: transparent; | |
} | |
.quiz__img-outer{ | |
flex-grow: 1; | |
height: 0; | |
} | |
#quiz__img{ | |
width: 100%; | |
height: 100%; | |
object-fit: contain; | |
filter: brightness(1); | |
cursor: pointer; | |
} | |
#quiz__img.s-black{ | |
filter: brightness(0); | |
} | |
.quiz__control{ | |
display: flex; | |
justify-content: space-between; | |
box-sizing: border-box; | |
padding: 12px; | |
} | |
.quiz__bt{ | |
padding: 8px 12px; | |
cursor: pointer; | |
} | |
#bt-fullscreen{ | |
display: block; | |
padding: 4px 8px; | |
margin: 20px auto 100px auto; | |
cursor: pointer; | |
} | |
/* */ | |
.settings{ | |
padding: 8px 12px; | |
margin: 12px 0; | |
border: 2px solid #aaa; | |
} | |
.settings-row{ | |
margin: 16px 0; | |
} | |
#input-file,#bt-rand{ | |
cursor: pointer; | |
} | |
/* */ | |
.preview-area{ | |
padding: 8px 0; | |
border-top: 1px dashed #aaa; | |
} | |
.preview-area>summary{ | |
display: inline-block; | |
cursor: pointer; | |
} | |
.preview-area>summary::before{ | |
display: inline-block; | |
content: "+"; | |
margin-right: 4px; | |
border: 1px solid #333; | |
line-height: 1em; | |
} | |
.preview-area[open]>summary::before{ | |
content: "-"; | |
} | |
#preview-box{ | |
display: grid; | |
grid-template-columns: repeat(auto-fill,minmax(200px,1fr)); | |
grid-template-rows: 200px; | |
grid-auto-rows: 200px; | |
row-gap: 12px; | |
column-gap: 12px; | |
margin-top: 8px; | |
} | |
.preview{ | |
box-sizing: border-box; | |
position: relative; | |
border: 1px solid #FF6F00; | |
} | |
.preview__img{ | |
box-sizing: border-box; | |
width: 100%; | |
height: 100%; | |
object-fit: contain; | |
padding: 8px; | |
cursor: pointer; | |
} | |
.bt-del{ | |
padding: 2px 6px; | |
position: absolute; | |
top: 4px; | |
right: 4px; | |
border: none; | |
background-color: #e00000; | |
color: #fff; | |
cursor: pointer; | |
} | |
.preview__cursor-outer{ | |
padding: 2px; | |
position: absolute; | |
right: 4px; | |
bottom: 4px; | |
border: 1px solid #777; | |
background-color: #fff; | |
cursor: move; | |
} | |
.preview__cursor-cover{ | |
width: 100%; | |
height: 100%; | |
position: absolute; | |
top: 0; | |
left: 0; | |
z-index: 1; | |
} | |
.preview__cursor{ | |
display: block; | |
width: 20px; | |
height: 20px; | |
position: relative; | |
z-index: 0; | |
} | |
/* */ | |
.radio-area{ | |
display: flex; | |
} | |
.radio-letter{ | |
display: none; | |
} | |
.label-letter{ | |
display: inline-block; | |
padding: 4px 8px; | |
margin: none; | |
border: 1px solid #777; | |
cursor: pointer; | |
} | |
.label-letter:first-of-type{ | |
border-right: none; | |
} | |
.radio-letter:checked+.label-letter{ | |
background-color: #FFECB3; | |
} | |
/* */ | |
.s-hide{ | |
display: none; | |
} | |
.s-invisible{ | |
visibility: hidden; | |
} | |
.s-selected{ | |
background-color: #FFE082; | |
} | |
.s-dragging,.s-target{ | |
box-shadow: 0 0 0 3px #0000e0; | |
} |
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
<!-- head --> | |
<link rel="stylesheet" href="pathto/now-loading.css"> | |
<!-- /head --> | |
<h2>本体</h2> | |
<div id="quiz"> | |
<div class="quiz__img-outer"> | |
<img src="" alt="" id="quiz__img" class="s-invisible" draggable="false"> | |
</div> | |
<div class="quiz__control"> | |
<button id="bt-prev" class="quiz__bt" data-kana="まえのもんだい" data-kanji="前の問題">まえのもんだい</button> | |
<button id="bt-next" class="quiz__bt" data-kana="つぎのもんだい" data-kanji="次の問題">つぎのもんだい</button> | |
</div> | |
</div> | |
<button id="bt-fullscreen">全画面で遊ぶ</button> | |
<h2>設定</h2> | |
<div class="settings"> | |
<div class="settings-row"> | |
<input type="file" id="input-file" multiple> | |
<div id="message"></div> | |
</div> | |
<div class="settings-row"> | |
<button id="bt-rand">ランダムに並び替える</button> | |
</div> | |
<details class="preview-area" open> | |
<summary>問題一覧</summary> | |
<div id="preview-box"> | |
<div class="preview"> | |
<img src="pathto/sample04.png" alt="" class="preview__img" draggable="false"> | |
<button class="bt-del">×</button> | |
<div class="preview__cursor-outer"> | |
<div class="preview__cursor-cover" draggable="true"></div> | |
<img src="pathto/cross.svg" alt="クロスカーソル" class="preview__cursor"> | |
</div> | |
</div> | |
</div> | |
</details> | |
</div> | |
<div class="settings"> | |
<div class="settings-row"> | |
<div class="radio-area"> | |
<input type="radio" name="radio-letter" id="radio-kana" class="radio-letter" checked> | |
<label for="radio-kana" class="label-letter">ひらがな</label> | |
<input type="radio" name="radio-letter" id="radio-kanji" class="radio-letter"> | |
<label for="radio-kanji" class="label-letter">漢字</label> | |
</div> | |
</div> | |
</div> | |
<div id="preview-template" class="preview s-hide"> | |
<img src="" alt="" class="preview__img" draggable="false"> | |
<button class="bt-del">×</button> | |
<div class="preview__cursor-outer"> | |
<div class="preview__cursor-cover" draggable="true"></div> | |
<img src="pathto/cross.svg" alt="クロスカーソル" class="preview__cursor"> | |
</div> | |
</div> | |
<script src="pathto/now-loading.js"></script> |
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_quiz = document.getElementById('quiz'); | |
const el_quiz__img = document.getElementById('quiz__img'); | |
const bt_prev = document.getElementById('bt-prev'); | |
const bt_next = document.getElementById('bt-next'); | |
const bt_fullscreen = document.getElementById('bt-fullscreen'); | |
const input_file = document.getElementById('input-file'); | |
const el_message = document.getElementById('message') | |
const bt_rand = document.getElementById('bt-rand'); | |
const el_preview_box = document.getElementById('preview-box'); | |
const els_preview = el_preview_box.getElementsByClassName('preview'); | |
const els_preview__img = el_preview_box.getElementsByClassName('preview__img'); | |
const el_preview_template = document.getElementById('preview-template'); | |
const els_radio_letter = document.getElementsByClassName('radio-letter'); | |
const el_radio_kana = document.getElementById('radio-kana'); | |
let el_dragging; | |
const nowloading = new nowLoading(); | |
//アニメ準備 | |
const anime = el_quiz__img.animate([ | |
{filter: 'brightness(0)'}, | |
{filter: 'brightness(1)'} | |
],{ | |
duration: 1000, | |
fill: 'forwards' | |
}); | |
anime.pause(); | |
anime.onfinish = ()=>{ | |
el_quiz__img.classList.remove('s-black'); | |
}; | |
el_quiz__img.onload = ()=>{ | |
el_quiz__img.classList.remove('s-invisible'); | |
}; | |
el_quiz__img.addEventListener('click',toggleBlack); | |
//リスナ | |
bt_prev.addEventListener('click',()=>{changeImg('prev')}); | |
bt_next.addEventListener('click',()=>{changeImg('next')}); | |
input_file.addEventListener('change',checkFile); | |
[...els_radio_letter].forEach(el=>{ | |
el.addEventListener('change',changeLetter); | |
}); | |
bt_rand.addEventListener('click',shufflePreview); | |
bt_fullscreen.addEventListener('click',toFullScreen); | |
//デモ処理 | |
initPreview(els_preview[0]); | |
displayImg(els_preview__img[0]); | |
//ここから関数 | |
function checkFile(e){ | |
nowloading.start(); | |
const files = e.target.files; | |
const first = (els_preview.length==0); | |
el_message.textContent = ''; | |
if(files.length==0){ | |
nowloading.stop(); | |
el_message.textContent = 'ファイルを読み込めませんでした。'; | |
return | |
} | |
const promise_set = []; | |
[...files].forEach(file=>{ | |
if(file.type.indexOf('image')==-1){ | |
return; | |
} | |
loadFile(file); | |
}); | |
Promise.all(promise_set).then(()=>{ | |
if(first){ | |
displayImg(els_preview__img[0]); | |
} | |
nowloading.stop(); | |
e.target.value = ''; | |
}); | |
function loadFile(file){ | |
const promise = new Promise(solve=>{ | |
const reader = new FileReader(); | |
reader.onload = ev=>{ | |
const el_clone = el_preview_template.cloneNode(true); | |
el_clone.id = ''; | |
el_clone.classList.remove('s-hide'); | |
initPreview(el_clone); | |
// | |
const el_img = el_clone.getElementsByClassName('preview__img')[0]; | |
el_img.src = ev.target.result; | |
// | |
el_preview_box.appendChild(el_clone); | |
solve(); | |
} | |
reader.readAsDataURL(file); | |
}); | |
promise_set.push(promise); | |
} | |
} | |
function initPreview(el_clone){ | |
//リスナ登録 | |
const el_img = el_clone.getElementsByClassName('preview__img')[0]; | |
el_img.addEventListener('click',selectImg); | |
const bt_del = el_clone.getElementsByClassName('bt-del')[0]; | |
bt_del.addEventListener('click',()=>{ | |
deletePreview(el_clone,el_img); | |
}); | |
//ドラッグアンドロップ用処理 | |
const el_cursor = el_clone.getElementsByClassName('preview__cursor-cover')[0]; | |
el_cursor.addEventListener('dragstart',e=>{ | |
dragStart(e,el_clone); | |
}); | |
el_cursor.addEventListener('dragend',e=>{ | |
dragEnd(e,el_clone); | |
}); | |
//受け側 | |
el_clone.addEventListener('dragover',dragOver); | |
el_clone.addEventListener('dragleave',dragLeave); | |
el_clone.addEventListener('drop',drop); | |
} | |
function selectImg(e){ | |
anime.cancel(); | |
[...els_preview__img].forEach(el=>{ | |
el.classList.remove('s-selected'); | |
}); | |
// | |
displayImg(e.currentTarget); | |
} | |
function changeImg(type){ | |
if(els_preview__img.length==0) return; | |
const index_old = (()=>{ | |
for(let i=0;i<els_preview__img.length;i++){ | |
if(els_preview__img[i].classList.contains('s-selected')){ | |
els_preview__img[i].classList.remove('s-selected'); | |
return i; | |
} | |
} | |
return false; | |
})(); | |
if(index_old===false) return; | |
// | |
const diff = (()=>{ | |
if(type=='prev'){ | |
return -1; | |
}else{ | |
return 1; | |
} | |
})(); | |
const index_new = (()=>{ | |
let temp = index_old + diff; | |
if(temp<0){ | |
temp = els_preview__img.length-1; | |
}else if(temp>=els_preview__img.length){ | |
temp = 0 | |
} | |
return temp; | |
})(); | |
// | |
anime.cancel(); | |
const el = els_preview__img[index_new]; | |
displayImg(el); | |
} | |
function displayImg(el_img){ | |
el_img.classList.add('s-selected'); | |
el_quiz__img.classList.add('s-invisible'); | |
el_quiz__img.classList.add('s-black'); | |
el_quiz__img.src = el_img.src; | |
} | |
function toggleBlack(e){ | |
const el = e.currentTarget; | |
if(el.classList.contains('s-black')){ | |
if(anime.playState!='running') anime.play(); | |
}else{ | |
anime.cancel(); | |
el.classList.add('s-black'); | |
} | |
} | |
function shufflePreview(){ | |
if(els_preview__img.length<2) return; | |
shuffleCollection(els_preview,el_preview_box); | |
anime.cancel(); | |
[...els_preview__img].forEach(el=>{ | |
el.classList.remove('s-selected'); | |
}); | |
displayImg(els_preview__img[0]); | |
} | |
function deletePreview(el_clone,el_img){ | |
if(el_img.classList.contains('s-selected')){ | |
const index = [...els_preview__img].indexOf(el_img); | |
el_clone.remove(); | |
anime.cancel(); | |
el_quiz__img.src = ''; | |
if(els_preview__img.length>0){ | |
if(els_preview__img[index]==undefined){ | |
displayImg(els_preview__img[0]); | |
}else{ | |
displayImg(els_preview__img[index]); | |
} | |
}else{ | |
el_quiz__img.classList.add('s-invisible'); | |
} | |
}else{ | |
el_clone.remove(); | |
} | |
} | |
function dragStart(e,el){ | |
const x_offset = (el.clientWidth - 4) - (e.target.clientWidth - e.offsetX); | |
const y_offset = el.clientHeight - 4 - (e.target.clientHeight - e.offsetY); | |
e.dataTransfer.setDragImage(el,x_offset,y_offset); | |
e.dataTransfer.setData('text','d'); //スマホ用に必要 | |
el_dragging = el; | |
setTimeout(()=>{ | |
el.classList.add('s-dragging'); | |
},1); | |
} | |
function dragOver(e){ | |
if(el_dragging!=undefined){ | |
e.preventDefault(); | |
e.currentTarget.classList.add('s-target'); | |
} | |
} | |
function dragLeave(e){ | |
e.currentTarget.classList.remove('s-target'); | |
} | |
function drop(e){ | |
if(el_dragging==undefined) return; | |
const el = e.currentTarget; | |
const dummy = document.createElement('span'); | |
dummy.style.display = 'none'; | |
el_preview_box.insertBefore(dummy,el_dragging); | |
el_preview_box.insertBefore(el_dragging,el); | |
el_preview_box.insertBefore(el,dummy); | |
dummy.remove(); | |
el.classList.remove('s-target'); | |
el_dragging.classList.remove('s-dragging'); | |
el_dragging = undefined; | |
} | |
function dragEnd(e,el){ | |
el_dragging = undefined; | |
el.classList.remove('s-dragging'); | |
} | |
function toFullScreen(){ | |
el_quiz.requestFullscreen(); | |
} | |
function changeLetter(){ | |
if(el_radio_kana.checked){ | |
bt_prev.textContent = bt_prev.dataset.kana; | |
bt_next.textContent = bt_next.dataset.kana; | |
}else{ | |
bt_prev.textContent = bt_prev.dataset.kanji; | |
bt_next.textContent = bt_next.dataset.kanji; | |
} | |
} | |
function randomMN(m,n){ | |
const d = Math.max(m,n)-Math.min(m,n); | |
return Math.floor(Math.random()*(d+1)+Math.min(m,n)); | |
} | |
function shuffleCollection(collection,parent){ | |
const array = (new Array(collection.length)).fill(0).map((v,i)=>i); | |
for(let i=array.length-1;i>=1;i--){ | |
const j = randomMN(0,i); | |
[array[j],array[i]] = [array[i],array[j]]; | |
} | |
const els = new Array(collection.length); | |
array.forEach((v,i)=>{ | |
els[i] = collection[v]; | |
}); | |
els.forEach(el=>{ | |
parent.appendChild(el); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment