JavaScript編 ドラッグアンドドロップされたファイルを表示するの続編です。今回はフォルダも対象にします。前回はファイルはひとつに限定していましたが、今回は複数のファイルも対象とします。
HTML部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>フォルダをドラッグ&ドロップ</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="./style.css" type="text/css" media="all"> </head> <body> <div id="drop-area"></div> <canvas id="canvas"></canvas> <script src="./app.js"></script> </body> </html> |
style.css
1 2 3 4 5 6 7 8 9 10 |
#drop-area { width: 360px; height: 200px; border: 1px solid #000; margin-bottom: 30px; } #canvas { border: 1px solid #000; } |
JavaScript部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
let $dropArea = document.getElementById("drop-area"); let $canvas = document.getElementById("canvas"); $dropArea.ondragover = (ev) => { ev.preventDefault(); } $dropArea.ondrop = async (ev) => { ev.preventDefault(); const items = ev.dataTransfer.items; const results = []; const promise = []; for (const item of items) { const entry = item.webkitGetAsEntry(); promise.push(ScanFiles(entry, results)); // ScanFiles関数は後述 } await Promise.all(promise); let files = await GetFiles(results); // GetFiles関数は後述 let size = { width:0, height:0, } let data = await GetImageDataFromFiles(files, size); // GetImageDataFromFiles関数は後述 ShowImagesToDiv($dropArea, data, size); // ShowImagesToDiv関数は後述 ShowImagesToCanvas($canvas, data, size); // ShowImagesToCanvas関数は後述 } |
描画に必要な情報を取得する
ScanFiles関数はフォルダのなかにあるファイルを調べます。もしフォルダのなかにフォルダがある場合はもう一度自分自身を呼び出します。
1 2 3 4 5 6 7 8 9 10 11 12 |
async function ScanFiles(entry, tmpObject) { if(entry.isDirectory){ const entryReader = entry.createReader(); const entries = await new Promise(resolve => { entryReader.readEntries(entries => resolve(entries)); }); await Promise.all(entries.map(entry => ScanFiles(entry, tmpObject))); } if(entry.isFile){ tmpObject.push(entry); } } |
GetFiles関数はScanFiles関数の結果を引数にしてFileオブジェクトの配列を返します。
1 2 3 4 5 6 7 8 9 10 11 12 |
async function GetFiles(results){ let files = []; for(let i = 0; i < results.length; i++){ await new Promise(resolve => { results[i].file((file) => { files.push(file); resolve('成功'); }); }) } return files; } |
Fileオブジェクトから取得できたデータを格納するオブジェクトを定義します。
1 2 3 4 5 6 7 8 9 10 11 |
const image = new Image(); const imageHTML = ''; const path = ''; const fileName = ''; const datum = { image : image, // Imageオブジェクト imageHTML: imageHTML, // imgタグ path: '', // ファイル名 name: fileName, // ファイルの相対パス }; |
GetImageDataFromFiles関数はFileオブジェクトの配列からHTMLを生成したりcanvas要素に描画処理をするために必要な情報(datum)の配列を返します。またdiv要素やcanvas要素のサイズを計算します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
async function GetImageDataFromFiles(files, size){ let data = []; for(let i=0; i<files.length; i++){ await new Promise(resolve => { const reader = new FileReader(); reader.readAsDataURL(files[i]); reader.onload = (ev) => { let $image = new Image(); $image.src = ev.target.result; $image.onload = () => { size.height += $image.height + 4; if(size.width < $image.width) size.width = $image.width; let path = files[i].webkitRelativePath != '' ? files[i].webkitRelativePath : files[i].name; data.push({ image: $image, imageHTML : `${$image.outerHTML}`, path: path, name: files[i].name, }); resolve('成功'); } $image.onerror = (ev) => { let path = files[i].webkitRelativePath != '' ? files[i].webkitRelativePath : files[i].name; data.push({ image: null, imageHTML : ``, path: path, name: files[i].name, }); resolve('画像ファイルではない'); } } }) } return data; } |
取得した情報をつかって描画する
ShowImagesToDiv関数は、第一引数で指定したdiv要素のサイズを指定したsize(変更するのは幅だけ、高さは’auto’とする)に変更してdataを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function ShowImagesToDiv(elm, data, size){ elm.innerHTML = ''; let width = size.width > 0 ? size.width : 300; elm.style.width = width + 'px'; elm.style.height = 'auto'; // パスまたはファイル名と画像ファイルの場合はimg要素を追加する for(let i=0; i<data.length; i++){ if(data[i].image) elm.innerHTML += `<div>${data[i].path}</div>` + data[i].imageHTML; else elm.innerHTML += `<div>${data[i].path}は画像ファイルではありません。</div>`; } } |
ShowImagesToCanvas関数は、第一引数で指定したcanvas要素のサイズを指定したsizeに変更してdataを描画します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
function ShowImagesToCanvas(canvas, data, size){ // 画像ファイルがひとつもない場合は size.width == 0 となる。 // この場合のcanvas要素の幅は300pxとする。 let width = size.width > 0 ? size.width : 300; let nextY = 0; let ctx = canvas.getContext('2d'); // 描画処理をするまえにcanvas要素のサイズを変更する。 // 描画処理をしたあとcanvas要素のサイズを変更するとなにも表示されない。 canvas.width = width; canvas.height = size.height + data.length * 30; for(let i=0; i<data.length; i++){ ctx.font="18px MS ゴシック"; if(data[i].image){ let str =`${data[i].name}`; ctx.fillText(str, 0, nextY+18); nextY += 30; ctx.drawImage(data[i].image, 0, nextY); nextY += data[i].image.height; } else{ let str =`NotImae ${data[i].name}`; ctx.fillText(str, 0, nextY+20); nextY += 30; } } } |