デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI

2013年3月1日(金)
山田 祥寛(YAMADA, Yoshihiro)

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>
図3:ドラッグ時にスタイルを設定(クリックで拡大)

操作自体は、ごく単純です。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>
図4:ドラッグ&ドロップしたテキストを表示(クリックで拡大)
※本サンプルは、IEでは動作しません

外部のアプリからデータを受け取るには、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>
図5:ドラッグ&ドロップしたファイルをページに表示(クリックで拡大)
※本サンプルは、IEでは動作しません

ポイントとなるのは、実に(1)の一点のみです。ドラッグ&ドロップされたファイルは、DataTransferオブジェクトのfilesプロパティでアクセスできます。filesプロパティの戻り値はFileオブジェクトですので、あとはそのままFileReaderオブジェクトのreadAsXxxxxメソッドに引き渡すことが可能です。FileReaderオブジェクトに関する詳細は、前回の記事も合わせて参照してください。

  • デスクトップアプリライクな操作性を実現するドラッグ&ドロップAPI

著者
山田 祥寛(YAMADA, Yoshihiro)
WINGSプロジェクト

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

連載バックナンバー

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

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

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

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