はじめに
4枚の画像を、ブラウザ上で2行2列の定型レイアウトに並べるHTMLを作成しました。
画像を各枠へドラッグ&ドロップすると、その場でプレビューできます。サーバーへのアップロードは行わず、HTML・CSS・JavaScriptだけで動作します。
完成したもの
- 4枚の画像を個別にドラッグ&ドロップできる
- 画像以外のファイルをドロップした場合はエラーを表示する
- 各画像を幅460px、高さ260px以内で表示する
- 各
OKボタンでドロップ領域を隠し、配置結果を確認できる - 「プレビュー表示」ボタンでドロップ領域を再表示できる
画面の構成
画像の表示枠は、HTMLのテーブルを使って2行2列にしています。
<table border="1">
<tr>
<td width="460px" height="260px"><div id="preview1"></div></td>
<td width="460px" height="260px"><div id="preview2"></div></td>
</tr>
<tr>
<td width="460px" height="260px"><div id="preview3"></div></td>
<td width="460px" height="260px"><div id="preview4"></div></td>
</tr>
</table>
それぞれの表示枠に対応するドロップ領域を配置します。
<span id="drop_zone1">
<button onclick="vew_look1();">OK 1</button>
ここに画像をドロップ 1
</span>
実際のHTMLでは、同じ形式の領域を4つ用意しています。
ドラッグ&ドロップの処理
ブラウザは、ファイルをドロップしたときに既定の動作でファイルを開こうとします。そのため、dragoverとdropの両方でpreventDefault()を呼び出します。
dropZone1.addEventListener('dragover', function (event) {
event.preventDefault();
dropZone1.classList.add('dragover');
});
dropZone1.addEventListener('dragleave', function () {
dropZone1.classList.remove('dragover');
});
ドロップされたファイルは、DataTransfer.filesから取得します。今回は各枠につき先頭の1ファイルだけを使います。
dropZone1.addEventListener('drop', function (event) {
event.preventDefault();
dropZone1.classList.remove('dragover');
const files = event.dataTransfer.files;
if (!files || files.length === 0) {
alert('ファイルが選択されていません');
return;
}
const file = files[0];
if (!file.type.startsWith('image/')) {
alert('画像ファイルをドロップしてください');
return;
}
const reader = new FileReader();
reader.onload = function (loadEvent) {
preview1.innerHTML = '';
const image = document.createElement('img');
image.src = loadEvent.target.result;
preview1.appendChild(image);
};
reader.onerror = function () {
alert('画像の読み込みに失敗しました');
};
reader.readAsDataURL(file);
});
FileReaderで画像を表示する
FileReader.readAsDataURL()を使うと、ローカルの画像ファイルをData URLとして読み込めます。読み込みが完了したら、その値をimg要素のsrcへ設定します。
この方法では画像をサーバーへ送信しないため、HTMLファイルをブラウザで直接開いても利用できます。
画像サイズを枠に合わせる
各画像には、表示枠に合わせたサイズをCSSで指定しました。
#preview1 img,
#preview2 img,
#preview3 img,
#preview4 img {
width: 460px;
max-height: 260px;
display: block;
}
元画像の縦横比が異なる場合は表示が変形することがあります。縦横比を維持したい場合は、次のようにobject-fitを使用できます。
#preview1 img,
#preview2 img,
#preview3 img,
#preview4 img {
width: 460px;
height: 260px;
object-fit: contain;
display: block;
}
ドロップ領域の表示と非表示
画像を配置した後は、対応するOKボタンでドロップ領域を透明にしています。
function vew_look1() {
document.getElementById('drop_zone1').style.opacity = '0';
document.getElementById('drop_zone1').style.backgroundColor = '#aaaaaa';
}
4つのドロップ領域を再表示するときは、「プレビュー表示」ボタンからvew_on()を実行します。
使い方
- HTMLファイルをブラウザで開く
- 4つの領域へ画像を1枚ずつドラッグ&ドロップする
- 各領域の
OKボタンを押す - 2行2列に並んだ画像を確認する
今後追加したい機能
現在はブラウザ上に4枚を配置して表示するところまでです。次の段階では、canvasへ4枚を描画し、1枚のPNG画像としてダウンロードできる機能を追加できます。
また、同じイベント処理を4回記述しているため、ドロップ領域とプレビュー領域を配列で管理するとコードを短くできます。
まとめ
HTML5のドラッグ&ドロップAPIとFileReaderを使い、4枚のローカル画像を定型レイアウトへ配置できました。
小さなツールですが、画像をサーバーへ送信せず、ブラウザだけでプレビューできる点が便利です。今後は画像の結合とダウンロードまで実装したいと思います。