
【JavaScript入門】ドラック&ドロップとファイルの読み込む(imageArea.js)
ここでは 画像アップロード UI の核となる imageArea.js
を実装し、ドラッグ&ドロップ/ファイルダイアログ/File Reader を組み合わせて「画像 ⇒ Canvas ⇒ localStorage」までを完結させる流れを解説します。あわせて、前回提示した storage.js
の主な API も再掲し、どこで連携しているかを整理します。

フォルダ構成
node-js/
├─ app/
│ ├─ index.html
│ ├─ style.css
│ └─ js/
│ ├─ common.js
│ ├─ storage.js ← 画像&コメントの永続化
│ ├─ imageArea.js ← ★今回実装
│ ├─ imageEffects.js
│ ├─ controlArea.js
│ ├─ commentArea.js
│ ├─ sendArea.js
│ ├─ dateFormat.js
│ └─ postListArea.js
├─ index.js ← API/サーバ側(今回触れず)
├─ upload_images/
└─ post-dat.txt
imageArea.js ― フルコード & 詳細コメント
/* ---------------------------------------------------
imageArea.js
- #imageArea で画像ファイルを受け取り Canvas に描画
- 受け取り方法は ①ドラッグ&ドロップ ②クリック→ファイルダイアログ
- 描画完了後は storage.js の saveCanvasToStorage() を呼び
次回アクセス時に自動復元できるようにする
--------------------------------------------------- */
window.addEventListener('DOMContentLoaded', () => {
const dropZone = document.querySelector('#imageArea');
const hiddenFile = document.querySelector('#file');
const canvas = document.querySelector('#view');
const ctx = canvas.getContext('2d');
const noView = document.querySelector('#noView');
/* === 1. ドラッグオーバー時のハイライト === */
['dragenter', 'dragover'].forEach(ev =>
dropZone.addEventListener(ev, e => {
e.preventDefault(); // デフォルト挙動(ブラウザ遷移)を阻止
dropZone.classList.add('isDrag'); // CSS で枠色変更など
}));
/* === 2. ドラッグアウト時にハイライト解除 === */
['dragleave', 'drop'].forEach(ev =>
dropZone.addEventListener(ev, () => dropZone.classList.remove('isDrag')));
/* === 3. ファイルをドロップした瞬間 === */
dropZone.addEventListener('drop', async e => {
e.preventDefault();
if (!e.dataTransfer.files.length) return;
const file = e.dataTransfer.files[0];
await drawImageFile(file);
});
/* === 4. クリックで隠し <input type=file> を起動 === */
dropZone.addEventListener('click', () => hiddenFile.click());
/* === 5. input でファイル選択された場合 === */
hiddenFile.addEventListener('change', async () => {
if (!hiddenFile.files.length) return;
const file = hiddenFile.files[0];
await drawImageFile(file);
hiddenFile.value = ''; // 同じファイルでも change が発火するようリセット
});
/* -------------------------------------------------
drawImageFile()
指定 File → Base64 取得 → <img> → Canvas 描画
------------------------------------------------- */
async function drawImageFile(file){
if (!file.type.startsWith('image/')){
alert('画像ファイルを指定してください');
return;
}
try{
// FileReader を Promise ラップで DataURL 取得
const dataURL = await readAsDataURL(file);
// <img> に読み込んでから Canvas へ描画
await new Promise((res, rej) => {
const img = new Image();
img.onload = () => res(img);
img.onerror= () => rej(new Error('画像の読み込みに失敗しました'));
img.src = dataURL;
}).then(img => {
// Canvas のサイズをアップロード画像の比率で調整したい場合はここで
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
canvas.style.display = 'block';
noView.style.display = 'none';
canvas.setAttribute('time', Date.now());
});
// 永続化 (storage.js)
saveCanvasToStorage();
}catch(err){
console.error(err);
alert('ファイルの読み込みに失敗しました');
}
}
/* -------------------------------------------------
readAsDataURL() : File → Base64 を Promise 化
------------------------------------------------- */
function readAsDataURL(file){
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
reader.readAsDataURL(file); // ★ここが本題
});
}
});
imageArea.js の主要 API/イベント
要素/API | 働き | 具体的な使い方 |
---|---|---|
dragenter / dragover | ドロップ可能領域への侵入/滞留 | e.preventDefault() でブラウザ既定動作を抑止 |
drop | ドロップ完了 | e.dataTransfer.files[0] で File を取得 |
FileReader.readAsDataURL(file) | File → Base64 | 画像プレビューに最適 |
<input type="file"> | 手動選択ダイアログ | .click() でプログラム的に発火 |
CanvasRenderingContext2D.drawImage() | 画像描画 | ctx.drawImage(img, x, y, w, h) |
saveCanvasToStorage() | Canvas を localStorage に永続化 | storage.js で定義済み |
storage.js との連携ポイント
imageArea.js 内の処理 | 呼び出す storage.js API | 目的 |
---|---|---|
画像描画完了後 | saveCanvasToStorage() | 次回アクセス時に同じ画像を自動復元 |
“削除” ボタン(controlArea.js 側) | removeCanvasStorage() | localStorage から画像データを消去 |
storage.js についての詳細な関数一覧や内部動作は 前回記事 を参照してください。
関数別フロー解説
- DOMContentLoaded
・すべてのイベントリスナを設定。これ以降は宣言的に待つだけ。 - ドラッグオーバー/リーブ
・視覚フィードバックとしてisDrag
クラスを付与・除去。Shadow/Border 変更は CSS で。 - drop / change
・いずれもdrawImageFile(file)
へ File オブジェクトを渡す一点に集約。 - drawImageFile(file)
・型チェック → readAsDataURL → Image オブジェクト化 → Canvas 描画 → saveCanvasToStorage。
・途中で失敗したらcatch
してユーザ通知。 - readAsDataURL(file)
・FileReader を Promise 化するとawait
で書けて読みやすい。
・成功でreader.result
(Base64)が得られる。
まとめ
imageArea.js
は「ユーザが画像を選ぶ → 即時プレビュー → 永続化」までをカバーしました。
次回は、描画済み画像に対して エフェクトを適用する imageEffects.js
を深掘りし、Canvas 操作の楽しさを最大化する実装テクニックを紹介します。