HTML5のドラッグ&ドロップAPI、File API、Web Storage

2012年5月8日(火)
飯島 聡(著)山田 祥寛(監修)

デスクトップアプリ風の機能を実装するために

今回は、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)

  <div id="div1" class="div1" draggable="true">ドラッグ可能</div>
  <div id="div2" class="div1" draggable="false">ドラッグ不可能</div>
  <div id="div3" class="div1" >デフォルト</div>
 図1:一番上のdivのみドラッグ可能(クリックで拡大)

ドラッグ対象要素のイベント

ドラッグで何か処理をするためには、ドラッグ対象要素のイベントに対して、ハンドラを設定します。ドラッグ関連のイベントには、以下のようなものがあります。

表1:ドラッグ関連イベント

イベント名 発生タイミング
dragstart ドラッグ開始時
drag ドラッグ中
dragend ドラッグ終了時

以下は、先ほどのサンプルに対してイベントを追加したものです。

[サンプル]ドラッグ要素のイベント処理(HTML5_3_sample2.html)

  //ウィンドウのloadイベントに下記の初期化メソッドinitを関連付ける
  window.addEventListener("load",init,true);
  //初期化メソッド各要素にイベントハンドラを設定する
  function init(){
    var src = document.getElementById("div1");
    //ドラッグ可能のdivにドラッグ関連イベントハンドラを設定
    src.addEventListener("dragstart",dragstart,true);
    src.addEventListener("drag",drag,true);
    src.addEventListener("dragend",dragend,true);
  }
  //ドラッグ開始時のイベントハンドラ
  function dragstart(e){
    //ドラッグ対象の要素の枠線を赤にする
    e.target.style.borderColor = "red";
    //ドラッグ対象の要素のテキストを変更する
    e.target.innerHTML = e.target.id+"をドラッグ開始";
  }
  //ドラッグ中のイベントハンドラ
  function drag(e){
    //ドラッグ対象の要素の背景色を黄色にする
    e.target.style.backgroundColor = "yellow";
    //ドラッグ対象の要素のテキストを変更する(マウスカーソルの座標上表を表示)
    e.target.innerHTML = e.target.id+"をドラッグ中 ("+e.clientX+","+e.clientY+")<br>";
  }
  //ドラッグ終了時のイベントハンドラ
    function dragend(e){
    //ドラッグ対象の要素の背景色を黄緑色(ページロード時の色)にする
    e.target.style.backgroundColor = "chartreuse";
    //ドラッグ対象の要素の枠線を緑色(ページロード時の色)にする
    e.target.style.borderColor = "green";
    //ドラッグ対象の要素のテキストを変更する
  e.target.innerHTML = e.target.id+"をドラッグ終了";
  }

サンプルでは、div要素には枠線が緑で背景色が黄緑となるように、スタイルシートがあたっています。ドラッグ開始時に、ドラッグ対象要素の枠線の色を赤に変更して、ドラッグ中には背景色を黄色にします。ドラッグ終了時にドラッグ対象要素を元の配色に戻しています。また、各イベントで中のテキストをそのイベントの種類を表すように変更しています。ドラッグ中にはマウスカーソル位置情報も表示しています。

実行結果は以下の通りです。

 図2:ドラッグ中(クリックで拡大)

ドラッグ中には、ドラッグ対象要素の色とテキストが変わっています。

 図3:ドラッグ終了(クリックで拡大)

ドラッグ終了時には、ページロード時と同じ配色に戻しています。

ドロップ先の要素のイベント

ドラッグイベントとセットで、ドロップイベントもあります。以下のようなイベントを利用する事で、ドロップ先のイベントに対して処理を行えます。

表2:ドロップ関連イベント

イベント名 発生タイミング
dragenter ドラッグ要素がドロップ先の要素に入った時
dragleave ドラッグ要素がドロップ先の要素から出た時
dragover ドラッグ要素がドロップ先の要素上にある時
drop 要素がドロップされた時

以下のサンプルでは2つのdivをドロップ先として、ハンドラを追加してます。追加した各ハンドラでは、ドロップ先の要素の枠線や背景色や中のテキストを変更しています。

[サンプル]ドロップ先要素のイベント処理(HTML5_3_sample3.html)

  ・・・ ・・・
    //2つのdivにドロップ関連イベントハンドラを設定
    for(var i=2;i<=3;i++){
      var dst = document.getElementById("div"+i);
      dst.addEventListener("dragenter",dragenter,true);
      dst.addEventListener("dragleave",dragleave,true);
      dst.addEventListener("dragover",dragover,true);
      dst.addEventListener("drop",drop,true);
    }
    ・・・ ・・・
  // ドロップ要素に入った時のイベントハンドラ
  function dragenter(e){
    // ドロップ要素の枠線を赤
    e.target.style.borderColor = "red";
    //ドロップ要素の中にイベント種別(dragenter)をテキスト表示
    e.target.innerHTML = e.type;
    //デフォルトのイベント処理をキャンセルする
    e.preventDefault();
  }
  // ドロップ要素から離れた時のイベントハンドラ
  function dragleave(e){
    //ドロップ要素の枠線を緑
    e.target.style.borderColor = "green";
    //ドロップ要素の背景を黄緑
    e.target.style.backgroundColor = "chartreuse";
    //ドロップ要素の中にイベント種別(dragleave)をテキスト表示
    e.target.innerHTML = e.type;
    //デフォルトのイベント処理をキャンセルする
    e.preventDefault();
  }
  // ドロップ要素の中にいる時のイベントハンドラ
  function dragover(e){
    //ドロップ要素の背景をオレンジに
    e.target.style.backgroundColor = "orange";
    //ドロップ要素の中にイベント種別(dragover)をテキスト表示
    e.target.innerHTML = e.type;
    //デフォルトのイベント処理をキャンセルする
    e.preventDefault();
  }
  //ドロップ要素にドロップした時のイベントハンドラ
  function drop(e){
    //ドロップ要素の背景を黄緑
    e.target.style.backgroundColor = "chartreuse";
    //ドロップ要素の枠線を緑
    e.target.style.borderColor = "green";
    //ドロップ要素の中に「ドロップ!」とテキスト表示
    e.target.innerHTML = "ドロップ!";
    //デフォルトのイベント処理をキャンセルする
    e.preventDefault();
  }

以下は、サンプルを実行し、先頭の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メソッドでそれをキャンセルしないとドロップできません。

  • ドラッグ&ドロップAPI、File API、Web StorageのHTMLサンプル

著者
飯島 聡(著)山田 祥寛(監修)
WINGSプロジェクト

有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表:山田祥寛)。おもな活動は、Web開発分野の書籍/雑誌/Web記事の執筆。ほかに海外記事の翻訳、講演なども幅広く手がける。2011年3月時点での登録メンバは36名で、現在もプロジェクトメンバーを募集中。執筆に興味のある方は、どしどしご応募頂きたい。著書多数。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています