デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI
ドラッグ&ドロップAPIは、名前のとおり、ページ上のさまざまな要素をマウスでドラッグ&ドロップできるようにするための仕組みです。
一例を挙げると、ドラッグ&ドロップ機能とFile APIとを組み合わせることで、ブラウザに対してドロップしたファイルをそのままサーバーにアップロードできるようになるなど、よりデスクトップアプリ的な仕掛けを実装できるようになります。
- TIPS 059:特定の要素をドラッグ可能にする
- TIPS 060:要素をドロップ可能にする
- TIPS 061:ドラッグ&ドロップ時のスタイルを設定する
- TIPS 062:他のアプリからテキストデータを受け取る
- TIPS 063:ファイルをドラッグ&ドロップする
- TIPS 064:ドラッグ&ドロップで許可される動作を指定する
- TIPS 065:ドラッグアイコンをカスタマイズする
仕掛けそのものは単純ですが、アプリの操作性を大きく変える可能性を持ったAPIと言えるでしょう。ドラッグ&ドロップAPIのブラウザごとの対応バージョンは、以下のとおりです。
表1:ドラッグ&ドロップAPIの対応状況
ブラウザ | 対応バージョン |
---|---|
Internet Explorer | 5.5以降(*) |
Firefox | 3.5以降 |
Chrome | 4以降 |
Safari | 5以降 |
Opera | 12以降 |
*:draggable属性は10以降
サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。
TIPS 059:特定の要素をドラッグ可能にする
ドラッグ&ドロップ機能を利用するには、まず「その要素がドラッグ可能である」ことを宣言しておく必要があります。ページ内の特定の要素をドラッグできるようにするには、対象の要素にグローバル属性であるdraggable属性を付与します。
[リスト01]、要素をドラッグ可能に(dnd.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HTML5 TIPS</title>
...中略...
</head>
<body>
<div id="d1" draggable="true">こんにちは、赤ちゃん!</div>
<img id="d2" src="wings.jpg" />
</body>
</html>
draggable属性には、true(ドラッグ可能)、false(ドラッグ不可)を指定してください。ただし、以下の要素については、デフォルトでドラッグ可能ですので、draggable属性を明示する必要はありません。
- src属性が指定されている要素
- href属性が指定されている要素
- 選択されたテキスト
確かに、サンプルでも要素にはdraggable属性を付与していないことが確認できます。逆に、これらの要素をドラッグ不可にする場合には、明示的にdraggable属性をfalseにセットしなければなりません。
TIPS 060:要素をドロップ可能にする
要素をドラッグできるようにしただけでは、ほとんど意味がありません。一般的には、ドラッグした要素をどこかにドロップできるような仕組みを設ける必要があります。
例えば以下のサンプルは、画像をドラッグしてあらかじめ決められた領域にドロップし、移動させるための仕組みです。
[リスト02]画像をドラッグ&ドロップで移動するコード(drop.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HTML5 TIPS</title>
<script>
window.addEventListener('DOMContentLoaded', function() {
// ドラッグ対象要素、ドロップ先要素を取得
var drag = document.querySelector('#drag');
var drop = document.querySelector('#drop');
// ドラッグ開始時に、ドラッグする要素のid値をセット(1)
drag.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('text', e.target.id);
}, true);
// dragoverイベントをキャンセル(3)
drop.addEventListener('dragover', function(e) {
e.preventDefault();
}, true);
// ドロップ時に、ドラッグ要素をドロップ領域に追加(移動(2))
drop.addEventListener('drop', function(e) {
var id = e.dataTransfer.getData('text');
e.currentTarget.appendChild(document.getElementById(id));
e.preventDefault();
}, true);
});
</script>
</head>
<body>
<!--ドラッグ可能な画像-->
<div style="width:250px; height:70px;">
<img id="drag" src="wings.jpg" draggable="true" />
</div>
<!--ドロップ先の領域-->
<div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div>
</body>
</html>
ドラッグ&ドロップに関するイベントとしては、以下のようなものが用意されています。
表2:ドラッグ&ドロップ関連のイベント
分類
イベント
発生タイミング
ドラッグ
dragstart
ドラッグの開始
drag
ドラッグ中
dragend
ドラッグを終了
ドロップ
dragenter
ドラッグ要素がドロップ領域に入った
dragover
ドラッグ要素がドロップ領域にある
dragleave
ドラッグ要素がドロップ領域から出た
drop
ドロップした
最低限、ドラッグ&ドロップ機能を実装するには、この中からdragstart、dragover、dropイベントリスナーを準備する必要があります。dragstartイベントでドラッグ元要素を記録し、dragoverイベントでドラッグ中の処理を、dropイベントでドロップ時の操作を、それぞれ受け持つわけです。
そして、これらのイベントリスナーで中心となるのは、DataTransferオブジェクトです。イベントオブジェクトのdataTransferプロパティ経由でアクセスできます。DataTransferオブジェクトは、ドラッグ&ドロップ時にやりとりするデータを管理するオブジェクトで、以下のようなメンバーを公開しています。
表3:DataTransferオブジェクトの主なメンバー
メンバー
概要
setData(key, value)
ドラッグ&ドロップで受け渡しする情報をキー/値の組み合わせで設定
getData(key)
メソッドで設定されたデータを、指定のキーで取得
clearData()
メソッドで設定されたデータをクリア
setDragImage(img, x, y)
ドラッグアイコンを指定(x、yでポインタからの相対位置を指定)
files
他のアプリからドラッグされたファイルを取得
effectAllowed
ドラッグ要素で許可される操作
dropEffect
ドロップ領域で許可される操作
まず、(1)のdragstartイベントリスナーでは、ドラッグした要素のid値を保存しておきます。この値を(2)のdropイベントリスナーで取り出し、これをキーにドラッグ元要素を操作しています(ここではドラッグ元要素をドラッグ領域の子要素として追加します)。引数keyには、テキスト情報の場合は「text」を、URL/ファイルリストの場合には「url」のいずれかを指定します。
(3)のdragoverイベントリスナーでpreventDefaultメソッドを呼び出しているのは、デフォルトの動作ではブラウザ標準の挙動が優先されてしまい、ドロップ操作が拒否されてしまうからです。そのため、ここで明示的にブラウザの挙動をキャンセルしておきます。
TIPS 061:ドラッグ&ドロップ時のスタイルを設定する
ドラッグ操作時に、操作中であることを視覚的に明確に示すため、ドラッグ元要素やドロップ領域のスタイルを変更することは、よく行われます。
以下では、dragstart/dragenter/dragleave/dropendなどのイベントを利用して、「ドラッグ時にドラッグ要素に枠線を付与し」、「ドロップ領域進入時に領域の背景色を変化」してみましょう。
[リスト03]ドラッグ元要素、ドロップ領域にスタイルを設定するコード(drop2.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HTML5 TIPS</title>
<script>
window.addEventListener('DOMContentLoaded', function() {
// ドラッグ対象要素、ドロップ先要素を取得
var drag = document.querySelector('#drag');
var drop = document.querySelector('#drop');
// ドラッグ開始
drag.addEventListener('dragstart', function(e) {
e.dataTransfer.setData('text', e.target.id);
// ドラッグ元要素に対して枠線を付与
this.style.border = 'solid 1px #f0f';
}, true);
// ドロップ領域に進入時
drop.addEventListener('dragenter', function(e) {
// ドロップ領域の背景を変更
this.style.backgroundColor = '#ff0';
e.preventDefault();
}, true);
// dragoverイベントをキャンセル
drop.addEventListener('dragover', function(e) {
e.preventDefault();
}, true);
// ドロップ領域から外れた時
drop.addEventListener('dragleave', function(e) {
// ドロップ領域の背景を元に戻す
this.style.backgroundColor = '#ffc';
e.preventDefault();
}, true);
// ドラッグ操作を終えた時
drag.addEventListener('dragend', function(e) {
// ドラッグ元要素から枠線を外す
this.style.borderStyle = 'none';
e.preventDefault();
}, true);
// ドロップ時
drop.addEventListener('drop', function(e) {
var id = e.dataTransfer.getData('text');
e.currentTarget.appendChild(document.getElementById(id));
e.preventDefault();
}, true);
});
</script>
</head>
<body>
<img id="drag" src="wings.jpg" draggable="true" />
<div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div>
</body>
</html>
操作自体は、ごく単純です。dragstart/dragendイベントでドラッグ元要素の枠線を、dragenter/dragleaveイベントでドロップ領域の背景色を、それぞれ操作しています。
TIPS 062:他のアプリからテキストデータを受け取る
ドラッグ&ドロップできるのは、ブラウザ(ページ)内部の要素ばかりではありません。他のアプリからドラッグしたテキストやファイルを取得し、ブラウザ内部で処理することもできます。
例えば以下は、外部のアプリで選択したテキストをブラウザ上の決められた領域にドロップする例です。ドロップされたテキストは、そのまま領域内部に表示します。
[リスト04]外部のアプリから選択テキストをドラッグ&ドロップするコード(otherDrop.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HTML5 TIPS</title>
<script>
window.addEventListener('DOMContentLoaded', function() {
// ドロップ先要素を取得
var drop = document.querySelector('#drop');
// ドロップ時の処理を定義
drop.addEventListener('drop', function(e) {
// 他のアプリから渡されたテキストを取得
var msg = e.dataTransfer.getData("text/plain");
// 取得したデータをページに反映
drop.textContent = msg;
e.preventDefault();
}, true);
// dragoverイベントをキャンセル
drop.addEventListener('dragover', function(e) {
e.preventDefault();
}, true);
});
</script>
</head>
<body>
<div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div>
</body>
</html>
外部のアプリからデータを受け取るには、DataTransferオブジェクトのgetDataメソッドに、受け取るデータの種類を指定します(1)。指定できるデータの種類には、以下のようなものがあります。
表4:指定できるデータの種類(getDataメソッドの引数)
設定値
概要
text/plain
平のテキスト
text/html
HTML文字列
text/xml
XML文字列
text/uri-list
URI、ファイル名のリスト
ここでは、「text/plain」を指定していますので、ドロップされたデータを平のテキストとして取得します。ここではtextContentプロパティで、取得したテキストをそのままページに反映させていますが、例えばカンマ区切りテキストなどを取得して、これをテーブルとして加工するようなことも可能です。
TIPS 063:ファイルをドラッグ&ドロップする
ドラッグ&ドロップ APIでは、ブラウザの外部からファイルを受け渡しすることもできます。例えば以下は、前回のTIPS55のサンプルを(ファイル入力ボックスではなく)ドラッグ&ドロップでファイルを受け渡せるように書き換えたものです。
[リスト05]ドラッグ&ドロップでファイルを指定(otherDropFile.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>HTML5 TIPS</title>
<script>
window.addEventListener('DOMContentLoaded', function() {
// ドロップ先要素を取得
var drop = document.querySelector('#drop');
// ドロップ時の処理を定義
drop.addEventListener('drop', function(e) {
// ドロップされたファイルを取得(1)
var f = e.dataTransfer.files[0];
// ファイルの読み込みに成功したら、その内容を<img id="result">に反映
var reader = new FileReader();
reader.addEventListener('load', function() {
document.querySelector('#dropped').src = reader.result;
}, false);
// ファイルをData URL形式で取得
reader.readAsDataURL(f);
e.preventDefault();
}, true);
// dragoverイベントをキャンセル
drop.addEventListener('dragover', function(e) {
e.preventDefault();
}, true);
});
</script>
</head>
<body>
<div id="drop" style="background-color:#ffc; width:450px; height:200px;">
<img id="dropped" />
</div>
</body>
</html>
ポイントとなるのは、実に(1)の一点のみです。ドラッグ&ドロップされたファイルは、DataTransferオブジェクトのfilesプロパティでアクセスできます。filesプロパティの戻り値はFileオブジェクトですので、あとはそのままFileReaderオブジェクトのreadAsXxxxxメソッドに引き渡すことが可能です。FileReaderオブジェクトに関する詳細は、前回の記事も合わせて参照してください。
TIPS 064:ドラッグ&ドロップで許可される動作を指定する
effectAllowed/dropEffectプロパティを指定することで、ドラッグ&ドロップ時に想定される動作を明示的に指定できます。これらのプロパティを指定しておくことで、ドラッグ&ドロップ時の動作を制限できるだけでなく、動作に応じてマウスポインタが変化し、視覚的にも現在の操作内容が明確になります。
[リスト06]ドラッグ&ドロップで許可される操作を指定(effect.html)
<script>
window.addEventListener('DOMContentLoaded', function() {
// ドラッグ/ドロップ対象の要素を取得
var drag = document.querySelector('#drag');
var drop = document.querySelector('#drop');
// ドラッグ開始時の処理を定義
drag.addEventListener('dragstart', function(e) {
// 現在の要素にコピーを許可
e.dataTransfer.effectAllowed = 'copy';
e.dataTransfer.setData('text', e.target.id);
}, true);
// ドラッグ中の処理を定義
drop.addEventListener('dragover', function(e) {
e.preventDefault();
// ドロップ領域でコピーを許可
e.dataTransfer.dropEffect = 'copy';
}, true);
// ドロップ時の処理を定義
drop.addEventListener('drop', function(e) {
var id = e.dataTransfer.getData('text');
e.currentTarget.appendChild(document.getElementById(id));
e.preventDefault();
}, true);
});
</script>
まず、effectAllowedプロパティは、ドラッグ元要素で許可される動作を指定します。dragstartイベントリスナーで指定します(1)。以下に、指定できる主な値をまとめておきます。
表5:effectAllowedプロパティの設定値
設定値
概要
none
すべてのドロップ操作を禁止
copy
データをコピー
link
データをリンク
move
データを移動
copyLink
データをコピー、またはリンク
copyMove
データをコピー、または移動
linkMove
データをリンク、または移動
all
すべての操作を許可
そして、effectAllowedプロパティとセットで指定するのがdropEffectedプロパティです(2)。こちらはドロップ先の要素で許可する動作を指定します。以下は、主な設定値です。
表6:dropEeffectプロパティの設定値
設定値
概要
none
すべてのドロップ操作を禁止
copy
データをコピー
link
データをリンク
move
データを移動
dropEffectプロパティには、effectAllowedプロパティで指定した動作に対応する値を指定します。effectAllowed/dropEffectプロパティの値に応じて、マウスポインタも適した形状に変化する点に注目してください。
なお、dropEffectプロパティの値が、effectAllowedプロパティで許可した動作のいずれにも合致しない場合、マウスアイコンもドロップ禁止を表すものとなり、ドロップ操作はキャンセルされます。
TIPS 065:ドラッグアイコンをカスタマイズする
setDragImageメソッドを利用することで、ドラッグ時のアイコン画像を差し替えることもできます。アプリの動作によっては、独自のアイコンによって、より操作の結果を直感的に知らせることができるでしょう。
[リスト07]ドラッグ時のアイコンをカスタマイズするコード(icon.html)
<script>
window.addEventListener('DOMContentLoaded', function() {
// ドラッグ/ドロップ対象の要素を取得
var drag = document.querySelector('#drag');
var drop = document.querySelector('#drop');
// ドラッグ開始時の処理を定義
drag.addEventListener('dragstart', function(e) {
// アイコン画像を準備&ドラッグアイコンとして設定
var icon = document.createElement('img');
icon.src = 'icon.jpg';
e.dataTransfer.setDragImage(icon, 0, 0);
e.dataTransfer.setData('text', e.target.id);
}, true);
...中略...
});
</script>
setDragImageメソッドの引数には「ドラッグアイコン」「X座標」「Y座標」の順で指定します。ドラッグアイコンは、あらかじめImageオブジェクトとして用意しておきます。
X/Y座標は、アイコン画像をマウスポインタの位置からずらしたい場合に利用します。デフォルトでは、マウスポインタ位置にアイコン画像を表示します。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>HTML5 TIPS</title> ...中略... </head> <body> <div id="d1" draggable="true">こんにちは、赤ちゃん!</div> <img id="d2" src="wings.jpg" /> </body> </html>
draggable属性には、true(ドラッグ可能)、false(ドラッグ不可)を指定してください。ただし、以下の要素については、デフォルトでドラッグ可能ですので、draggable属性を明示する必要はありません。
- src属性が指定されている要素
- href属性が指定されている要素
- 選択されたテキスト
確かに、サンプルでも要素にはdraggable属性を付与していないことが確認できます。逆に、これらの要素をドラッグ不可にする場合には、明示的にdraggable属性をfalseにセットしなければなりません。
TIPS 060:要素をドロップ可能にする
要素をドラッグできるようにしただけでは、ほとんど意味がありません。一般的には、ドラッグした要素をどこかにドロップできるような仕組みを設ける必要があります。
例えば以下のサンプルは、画像をドラッグしてあらかじめ決められた領域にドロップし、移動させるための仕組みです。
[リスト02]画像をドラッグ&ドロップで移動するコード(drop.html)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>HTML5 TIPS</title> <script> window.addEventListener('DOMContentLoaded', function() { // ドラッグ対象要素、ドロップ先要素を取得 var drag = document.querySelector('#drag'); var drop = document.querySelector('#drop'); // ドラッグ開始時に、ドラッグする要素のid値をセット(1) drag.addEventListener('dragstart', function(e) { e.dataTransfer.setData('text', e.target.id); }, true); // dragoverイベントをキャンセル(3) drop.addEventListener('dragover', function(e) { e.preventDefault(); }, true); // ドロップ時に、ドラッグ要素をドロップ領域に追加(移動(2)) drop.addEventListener('drop', function(e) { var id = e.dataTransfer.getData('text'); e.currentTarget.appendChild(document.getElementById(id)); e.preventDefault(); }, true); }); </script> </head> <body> <!--ドラッグ可能な画像--> <div style="width:250px; height:70px;"> <img id="drag" src="wings.jpg" draggable="true" /> </div> <!--ドロップ先の領域--> <div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div> </body> </html>
ドラッグ&ドロップに関するイベントとしては、以下のようなものが用意されています。
表2:ドラッグ&ドロップ関連のイベント
分類 | イベント | 発生タイミング |
---|---|---|
ドラッグ | dragstart | ドラッグの開始 |
drag | ドラッグ中 | |
dragend | ドラッグを終了 | |
ドロップ | dragenter | ドラッグ要素がドロップ領域に入った |
dragover | ドラッグ要素がドロップ領域にある | |
dragleave | ドラッグ要素がドロップ領域から出た | |
drop | ドロップした |
最低限、ドラッグ&ドロップ機能を実装するには、この中からdragstart、dragover、dropイベントリスナーを準備する必要があります。dragstartイベントでドラッグ元要素を記録し、dragoverイベントでドラッグ中の処理を、dropイベントでドロップ時の操作を、それぞれ受け持つわけです。
そして、これらのイベントリスナーで中心となるのは、DataTransferオブジェクトです。イベントオブジェクトのdataTransferプロパティ経由でアクセスできます。DataTransferオブジェクトは、ドラッグ&ドロップ時にやりとりするデータを管理するオブジェクトで、以下のようなメンバーを公開しています。
表3:DataTransferオブジェクトの主なメンバー
メンバー | 概要 |
---|---|
setData(key, value) | ドラッグ&ドロップで受け渡しする情報をキー/値の組み合わせで設定 |
getData(key) | メソッドで設定されたデータを、指定のキーで取得 |
clearData() | メソッドで設定されたデータをクリア |
setDragImage(img, x, y) | ドラッグアイコンを指定(x、yでポインタからの相対位置を指定) |
files | 他のアプリからドラッグされたファイルを取得 |
effectAllowed | ドラッグ要素で許可される操作 |
dropEffect | ドロップ領域で許可される操作 |
まず、(1)のdragstartイベントリスナーでは、ドラッグした要素のid値を保存しておきます。この値を(2)のdropイベントリスナーで取り出し、これをキーにドラッグ元要素を操作しています(ここではドラッグ元要素をドラッグ領域の子要素として追加します)。引数keyには、テキスト情報の場合は「text」を、URL/ファイルリストの場合には「url」のいずれかを指定します。
(3)のdragoverイベントリスナーでpreventDefaultメソッドを呼び出しているのは、デフォルトの動作ではブラウザ標準の挙動が優先されてしまい、ドロップ操作が拒否されてしまうからです。そのため、ここで明示的にブラウザの挙動をキャンセルしておきます。
TIPS 061:ドラッグ&ドロップ時のスタイルを設定する
ドラッグ操作時に、操作中であることを視覚的に明確に示すため、ドラッグ元要素やドロップ領域のスタイルを変更することは、よく行われます。
以下では、dragstart/dragenter/dragleave/dropendなどのイベントを利用して、「ドラッグ時にドラッグ要素に枠線を付与し」、「ドロップ領域進入時に領域の背景色を変化」してみましょう。
[リスト03]ドラッグ元要素、ドロップ領域にスタイルを設定するコード(drop2.html)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>HTML5 TIPS</title> <script> window.addEventListener('DOMContentLoaded', function() { // ドラッグ対象要素、ドロップ先要素を取得 var drag = document.querySelector('#drag'); var drop = document.querySelector('#drop'); // ドラッグ開始 drag.addEventListener('dragstart', function(e) { e.dataTransfer.setData('text', e.target.id); // ドラッグ元要素に対して枠線を付与 this.style.border = 'solid 1px #f0f'; }, true); // ドロップ領域に進入時 drop.addEventListener('dragenter', function(e) { // ドロップ領域の背景を変更 this.style.backgroundColor = '#ff0'; e.preventDefault(); }, true); // dragoverイベントをキャンセル drop.addEventListener('dragover', function(e) { e.preventDefault(); }, true); // ドロップ領域から外れた時 drop.addEventListener('dragleave', function(e) { // ドロップ領域の背景を元に戻す this.style.backgroundColor = '#ffc'; e.preventDefault(); }, true); // ドラッグ操作を終えた時 drag.addEventListener('dragend', function(e) { // ドラッグ元要素から枠線を外す this.style.borderStyle = 'none'; e.preventDefault(); }, true); // ドロップ時 drop.addEventListener('drop', function(e) { var id = e.dataTransfer.getData('text'); e.currentTarget.appendChild(document.getElementById(id)); e.preventDefault(); }, true); }); </script> </head> <body> <img id="drag" src="wings.jpg" draggable="true" /> <div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div> </body> </html>
操作自体は、ごく単純です。dragstart/dragendイベントでドラッグ元要素の枠線を、dragenter/dragleaveイベントでドロップ領域の背景色を、それぞれ操作しています。
TIPS 062:他のアプリからテキストデータを受け取る
ドラッグ&ドロップできるのは、ブラウザ(ページ)内部の要素ばかりではありません。他のアプリからドラッグしたテキストやファイルを取得し、ブラウザ内部で処理することもできます。
例えば以下は、外部のアプリで選択したテキストをブラウザ上の決められた領域にドロップする例です。ドロップされたテキストは、そのまま領域内部に表示します。
[リスト04]外部のアプリから選択テキストをドラッグ&ドロップするコード(otherDrop.html)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>HTML5 TIPS</title> <script> window.addEventListener('DOMContentLoaded', function() { // ドロップ先要素を取得 var drop = document.querySelector('#drop'); // ドロップ時の処理を定義 drop.addEventListener('drop', function(e) { // 他のアプリから渡されたテキストを取得 var msg = e.dataTransfer.getData("text/plain"); // 取得したデータをページに反映 drop.textContent = msg; e.preventDefault(); }, true); // dragoverイベントをキャンセル drop.addEventListener('dragover', function(e) { e.preventDefault(); }, true); }); </script> </head> <body> <div id="drop" style="background-color:#ffc; width:450px; height:200px;"></div> </body> </html>
外部のアプリからデータを受け取るには、DataTransferオブジェクトのgetDataメソッドに、受け取るデータの種類を指定します(1)。指定できるデータの種類には、以下のようなものがあります。
表4:指定できるデータの種類(getDataメソッドの引数)
設定値 | 概要 |
---|---|
text/plain | 平のテキスト |
text/html | HTML文字列 |
text/xml | XML文字列 |
text/uri-list | URI、ファイル名のリスト |
ここでは、「text/plain」を指定していますので、ドロップされたデータを平のテキストとして取得します。ここではtextContentプロパティで、取得したテキストをそのままページに反映させていますが、例えばカンマ区切りテキストなどを取得して、これをテーブルとして加工するようなことも可能です。
TIPS 063:ファイルをドラッグ&ドロップする
ドラッグ&ドロップ APIでは、ブラウザの外部からファイルを受け渡しすることもできます。例えば以下は、前回のTIPS55のサンプルを(ファイル入力ボックスではなく)ドラッグ&ドロップでファイルを受け渡せるように書き換えたものです。
[リスト05]ドラッグ&ドロップでファイルを指定(otherDropFile.html)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>HTML5 TIPS</title> <script> window.addEventListener('DOMContentLoaded', function() { // ドロップ先要素を取得 var drop = document.querySelector('#drop'); // ドロップ時の処理を定義 drop.addEventListener('drop', function(e) { // ドロップされたファイルを取得(1) var f = e.dataTransfer.files[0]; // ファイルの読み込みに成功したら、その内容を<img id="result">に反映 var reader = new FileReader(); reader.addEventListener('load', function() { document.querySelector('#dropped').src = reader.result; }, false); // ファイルをData URL形式で取得 reader.readAsDataURL(f); e.preventDefault(); }, true); // dragoverイベントをキャンセル drop.addEventListener('dragover', function(e) { e.preventDefault(); }, true); }); </script> </head> <body> <div id="drop" style="background-color:#ffc; width:450px; height:200px;"> <img id="dropped" /> </div> </body> </html>
ポイントとなるのは、実に(1)の一点のみです。ドラッグ&ドロップされたファイルは、DataTransferオブジェクトのfilesプロパティでアクセスできます。filesプロパティの戻り値はFileオブジェクトですので、あとはそのままFileReaderオブジェクトのreadAsXxxxxメソッドに引き渡すことが可能です。FileReaderオブジェクトに関する詳細は、前回の記事も合わせて参照してください。
TIPS 064:ドラッグ&ドロップで許可される動作を指定する
effectAllowed/dropEffectプロパティを指定することで、ドラッグ&ドロップ時に想定される動作を明示的に指定できます。これらのプロパティを指定しておくことで、ドラッグ&ドロップ時の動作を制限できるだけでなく、動作に応じてマウスポインタが変化し、視覚的にも現在の操作内容が明確になります。
[リスト06]ドラッグ&ドロップで許可される操作を指定(effect.html)
<script> window.addEventListener('DOMContentLoaded', function() { // ドラッグ/ドロップ対象の要素を取得 var drag = document.querySelector('#drag'); var drop = document.querySelector('#drop'); // ドラッグ開始時の処理を定義 drag.addEventListener('dragstart', function(e) { // 現在の要素にコピーを許可 e.dataTransfer.effectAllowed = 'copy'; e.dataTransfer.setData('text', e.target.id); }, true); // ドラッグ中の処理を定義 drop.addEventListener('dragover', function(e) { e.preventDefault(); // ドロップ領域でコピーを許可 e.dataTransfer.dropEffect = 'copy'; }, true); // ドロップ時の処理を定義 drop.addEventListener('drop', function(e) { var id = e.dataTransfer.getData('text'); e.currentTarget.appendChild(document.getElementById(id)); e.preventDefault(); }, true); }); </script>
まず、effectAllowedプロパティは、ドラッグ元要素で許可される動作を指定します。dragstartイベントリスナーで指定します(1)。以下に、指定できる主な値をまとめておきます。
表5:effectAllowedプロパティの設定値
設定値 | 概要 |
---|---|
none | すべてのドロップ操作を禁止 |
copy | データをコピー |
link | データをリンク |
move | データを移動 |
copyLink | データをコピー、またはリンク |
copyMove | データをコピー、または移動 |
linkMove | データをリンク、または移動 |
all | すべての操作を許可 |
そして、effectAllowedプロパティとセットで指定するのがdropEffectedプロパティです(2)。こちらはドロップ先の要素で許可する動作を指定します。以下は、主な設定値です。
表6:dropEeffectプロパティの設定値
設定値 | 概要 |
---|---|
none | すべてのドロップ操作を禁止 |
copy | データをコピー |
link | データをリンク |
move | データを移動 |
dropEffectプロパティには、effectAllowedプロパティで指定した動作に対応する値を指定します。effectAllowed/dropEffectプロパティの値に応じて、マウスポインタも適した形状に変化する点に注目してください。
なお、dropEffectプロパティの値が、effectAllowedプロパティで許可した動作のいずれにも合致しない場合、マウスアイコンもドロップ禁止を表すものとなり、ドロップ操作はキャンセルされます。
TIPS 065:ドラッグアイコンをカスタマイズする
setDragImageメソッドを利用することで、ドラッグ時のアイコン画像を差し替えることもできます。アプリの動作によっては、独自のアイコンによって、より操作の結果を直感的に知らせることができるでしょう。
[リスト07]ドラッグ時のアイコンをカスタマイズするコード(icon.html)
<script> window.addEventListener('DOMContentLoaded', function() { // ドラッグ/ドロップ対象の要素を取得 var drag = document.querySelector('#drag'); var drop = document.querySelector('#drop'); // ドラッグ開始時の処理を定義 drag.addEventListener('dragstart', function(e) { // アイコン画像を準備&ドラッグアイコンとして設定 var icon = document.createElement('img'); icon.src = 'icon.jpg'; e.dataTransfer.setDragImage(icon, 0, 0); e.dataTransfer.setData('text', e.target.id); }, true); ...中略... }); </script>
setDragImageメソッドの引数には「ドラッグアイコン」「X座標」「Y座標」の順で指定します。ドラッグアイコンは、あらかじめImageオブジェクトとして用意しておきます。
X/Y座標は、アイコン画像をマウスポインタの位置からずらしたい場合に利用します。デフォルトでは、マウスポインタ位置にアイコン画像を表示します。
デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- HTML5のドラッグ&ドロップAPI、File API、Web Storage
- JavaScriptでローカルファイルを自在に操る- File API
- プラグインは要らない!音声/動画対応したHTML5- / 要素
- スマホアプリ開発にも便利な位置情報API- Geolocation API-
- クッキーより便利になったブラウザ標準ストレージ- Web Storage
- HTML+JavaScriptだけでブラウザに図形描画- Canvas API-
- サンプルのプログラムコード解説
- HTML+JavaScriptだけでブラウザに図形描画(3)- Canvas API-
- HTML+JavaScriptだけでブラウザに図形描画(2)- Canvas API-
- 「TAURI」で「丸アートお絵描き」アプリを作ろう