デスクトップアプリ風の機能を実装するために
今回は、HTML5の新機能のうち、ドラッグ&ドロップAPI、File API、Web Storageを説明します。サンプル一式は、会員限定特典としてダウンロードできます。記事末尾をご確認ください。
従来、Webアプリケーションがデスクトップアプリケーションに劣る点として、操作性が悪い、ローカルファイルの読み込みができない、という点が挙げられます。
近年では、それらの問題を解決したAdobe Flash、Microsoft Silverlightを用いた、リッチインターネットアプリケーション(RIA)も登場しています。しかし、プラグインを必要とするWebアプリケーションでは、以下のような問題もあります。
- iOSなど対応するプラグインが提供されていない環境が少なくない
- 制作側にHTML(HTML、CSS、JavaScript)以外のスキルも要求される
- HTML側からプラグインコンテンツにアクセスするのが困難
HTML5とその周辺技術では、これらの問題も解決する新機能やAPIがいくつか策定されています。今回はそのうち以下のものについて説明します。
(1)ドラッグ&ドロップAPI
ドラッグ&ドロップは、マウスでオブジェクトをつかみながら移動して(ドラッグ)、他の場所に置く(ドロップ)操作です。PCのデスクトップでは日常的に使用されますが、ブラウザでも同様の操作を利用しようというものです。
(2)File API
File APIを利用する事で、ローカルファイルの読み込みができます。具体的には、これまでアップロードに使用されてきた、<input type="file">要素や、ローカルファイルからブラウザへのドラッグ&ドロップによって、任意のファイルをJavaScriptで処理できるようになります。
(3)Web Storage
ブラウザにキーと値のセットで、データを保存するストレージです。クッキーとも似ていますが、より大きなサイズのデータを格納できる、有効期限がない、などの点で改善されています。
Webアプリをドラッグ&ドロップ対応する - ドラッグ&ドロップAPI
ドラッグ&ドロップは、デスクトップで、オブジェクトの移動操作を行う直観的なUIとしてよく利用されます。ドラッグ&ドロップAPIは、このドラッグ&ドロップ操作をWebページで実現するためのHTML5新機能です。
HTML側での準備
ドラッグ&ドロップを利用するには、まず、ドラッグされる要素のdraggable属性をtrueにします。draggable属性はほとんどの要素でfalse(ドラッグ無効)が既定ですが、画像とリンクのみtrue(ドラッグ有効)となっています。
なお、現時点でOperaはドラッグ&ドロップ未対応、IE9はdraggable属性未対応です。
[サンプル]ドラッグを有効化するコード(HTML5_3_sample1.html)
1 | <div id="div1" class="div1" draggable="true">ドラッグ可能</div> |
2 | <div id="div2" class="div1" draggable="false">ドラッグ不可能</div> |
3 | <div id="div3" class="div1" >デフォルト</div> |
 |
図1:一番上のdivのみドラッグ可能(クリックで拡大) |
ドラッグ対象要素のイベント
ドラッグで何か処理をするためには、ドラッグ対象要素のイベントに対して、ハンドラを設定します。ドラッグ関連のイベントには、以下のようなものがあります。
表1:ドラッグ関連イベント
イベント名 |
発生タイミング |
dragstart |
ドラッグ開始時 |
drag |
ドラッグ中 |
dragend |
ドラッグ終了時 |
以下は、先ほどのサンプルに対してイベントを追加したものです。
[サンプル]ドラッグ要素のイベント処理(HTML5_3_sample2.html)
01 | //ウィンドウのloadイベントに下記の初期化メソッドinitを関連付ける |
02 | window.addEventListener("load",init,true); |
03 | //初期化メソッド各要素にイベントハンドラを設定する |
05 | var src = document.getElementById("div1"); |
06 | //ドラッグ可能のdivにドラッグ関連イベントハンドラを設定 |
07 | src.addEventListener("dragstart",dragstart,true); |
08 | src.addEventListener("drag",drag,true); |
09 | src.addEventListener("dragend",dragend,true); |
14 | e.target.style.borderColor = "red"; |
16 | e.target.innerHTML = e.target.id+"をドラッグ開始"; |
21 | e.target.style.backgroundColor = "yellow"; |
22 | //ドラッグ対象の要素のテキストを変更する(マウスカーソルの座標上表を表示) |
23 | e.target.innerHTML = e.target.id+"をドラッグ中 ("+e.clientX+","+e.clientY+")<br>"; |
27 | //ドラッグ対象の要素の背景色を黄緑色(ページロード時の色)にする |
28 | e.target.style.backgroundColor = "chartreuse"; |
29 | //ドラッグ対象の要素の枠線を緑色(ページロード時の色)にする |
30 | e.target.style.borderColor = "green"; |
32 | e.target.innerHTML = e.target.id+"をドラッグ終了"; |
サンプルでは、div要素には枠線が緑で背景色が黄緑となるように、スタイルシートがあたっています。ドラッグ開始時に、ドラッグ対象要素の枠線の色を赤に変更して、ドラッグ中には背景色を黄色にします。ドラッグ終了時にドラッグ対象要素を元の配色に戻しています。また、各イベントで中のテキストをそのイベントの種類を表すように変更しています。ドラッグ中にはマウスカーソル位置情報も表示しています。
実行結果は以下の通りです。
 |
図2:ドラッグ中(クリックで拡大) |
ドラッグ中には、ドラッグ対象要素の色とテキストが変わっています。
 |
図3:ドラッグ終了(クリックで拡大) |
ドラッグ終了時には、ページロード時と同じ配色に戻しています。
ドロップ先の要素のイベント
ドラッグイベントとセットで、ドロップイベントもあります。以下のようなイベントを利用する事で、ドロップ先のイベントに対して処理を行えます。
表2:ドロップ関連イベント
イベント名 |
発生タイミング |
dragenter |
ドラッグ要素がドロップ先の要素に入った時 |
dragleave |
ドラッグ要素がドロップ先の要素から出た時 |
dragover |
ドラッグ要素がドロップ先の要素上にある時 |
drop |
要素がドロップされた時 |
以下のサンプルでは2つのdivをドロップ先として、ハンドラを追加してます。追加した各ハンドラでは、ドロップ先の要素の枠線や背景色や中のテキストを変更しています。
[サンプル]ドロップ先要素のイベント処理(HTML5_3_sample3.html)
02 | //2つのdivにドロップ関連イベントハンドラを設定 |
03 | for(var i=2;i<=3;i++){ |
04 | var dst = document.getElementById("div"+i); |
05 | dst.addEventListener("dragenter",dragenter,true); |
06 | dst.addEventListener("dragleave",dragleave,true); |
07 | dst.addEventListener("dragover",dragover,true); |
08 | dst.addEventListener("drop",drop,true); |
11 | // ドロップ要素に入った時のイベントハンドラ |
14 | e.target.style.borderColor = "red"; |
15 | //ドロップ要素の中にイベント種別(dragenter)をテキスト表示 |
16 | e.target.innerHTML = e.type; |
17 | //デフォルトのイベント処理をキャンセルする |
20 | // ドロップ要素から離れた時のイベントハンドラ |
23 | e.target.style.borderColor = "green"; |
25 | e.target.style.backgroundColor = "chartreuse"; |
26 | //ドロップ要素の中にイベント種別(dragleave)をテキスト表示 |
27 | e.target.innerHTML = e.type; |
28 | //デフォルトのイベント処理をキャンセルする |
31 | // ドロップ要素の中にいる時のイベントハンドラ |
34 | e.target.style.backgroundColor = "orange"; |
35 | //ドロップ要素の中にイベント種別(dragover)をテキスト表示 |
36 | e.target.innerHTML = e.type; |
37 | //デフォルトのイベント処理をキャンセルする |
40 | //ドロップ要素にドロップした時のイベントハンドラ |
43 | e.target.style.backgroundColor = "chartreuse"; |
45 | e.target.style.borderColor = "green"; |
46 | //ドロップ要素の中に「ドロップ!」とテキスト表示 |
47 | e.target.innerHTML = "ドロップ!"; |
48 | //デフォルトのイベント処理をキャンセルする |
以下は、サンプルを実行し、先頭のdiv要素を2番目のdiv要素にドラッグした場合の結果です。
 |
図4:ドロップ先に入った時(クリックで拡大) |
2番目のdiv要素の枠線も赤く変化した事からdragenterが、背景色がオレンジ色に変わった事からdragoverが、それぞれ発生した事を確認できます。
以下は、ドラッグ要素をそのままドラッグしながら2番目のdiv要素の上を通り、3番目のdiv要素の上でドロップした場合の結果です。
 |
図5:ドロップ先から離れた時とドロップした時(クリックで拡大) |
各要素の背景色は黄緑、枠線は緑に戻り、2番目のdiv要素には「dragleave」が、3番目のdiv要素に「ドロップ!」という文字列が表示されます。2番目のdiv要素のdragleaveイベントと3番目のdiv要素のdropイベントが発生した事が確認できます。
なお、全てのイベントハンドラで指定されているpreventDefaultはデフォルトのイベント処理をキャンセルするためのメソッドです。ブラウザのデフォルトのイベント処理では、ドロップを受け付けないため、preventDefaultメソッドでそれをキャンセルしないとドロップできません。