雑食性雑感雑記

知識の整理場。ため込んだ知識をブログ記事として再構築します。

D3.js で全画面ファイルドラッグ & ドロップ

概要

  • D3.js で File API を用いた全画面ファイルドラッグ & ドロップ機能を追加する。
  • 今回は画像読み込み。
    • ( テキスト読み込みにすればグラフ表示も―― )

サンプル

  • jsdo.it 上に置きました。
  • 画像ファイルを読み込んで表示するサンプル。
  • 画像自体、ドラッグ & ドロップで移動できるようにしてあったりします。


全画面ファイルドラッグ & ドロップ

D3.js 版

  • 上記ページの内容を D3.js に移植してみた。
/**
 * Drag & Drop 機能設定
 *
 * onFileRead にはファイル読み込み完了時の処理を指定。
 * ( onFileRead(filedata) )
 */
function setDragDrop(onFileRead)
{
    var body = d3.select('body');

    // Create overlay
    var overlay = body.append('div')
                      .attr('class', 'overlay')
                      .attr('id', 'overlay')
                      .style('position', 'fixed')
                      .style('top', 0)
                      .style('left', 0)
                      .style('width', '100%')
                      .style('height', '100%')
                      .style('background', 'black')
                      .style('opacity', 0)
                      .style('display', 'none');

    // Create drop mask
    var drop_mask = body.append('div')
                        .attr('class', 'drop_mask')
                        .attr('id', 'drop_mask')
                        .style('position', 'fixed')
                        .style('top', 0)
                        .style('left', 0)
                        .style('width', '100%')
                        .style('height', '100%')
                        .style('opacity', 0)
                        .style('display', 'none')
                        .style('z-index', 9999);

    // Check file API enable
    if (window.File) {
        body.on('dragover', onDragOver);
        drop_mask.on('dragleave', onDragLeave)
                 .on('drop', onDrop);
    } else {
        alert('File API is not supported on this browser.');
    }

    function onDragOver() {
        drop_mask.style('display', 'block');
        overlay.style('display', 'block')
               .transition().duration(200)
               .style('opacity', 0.8);
        d3.event.preventDefault();
    };

    function onDragLeave() {
        drop_mask.style('display', 'none');
        overlay.transition().duration(200)
               .style('opacity', 0)
               .transition().duration(0)
               .style('display', 'none');
        d3.event.preventDefault();
    };

    function onDrop() {
        var files = d3.event.dataTransfer.files;
        if (files.length > 0) {
            var file  = files[0];

            // Only image
            if (!file.type.match('image.*')) {
                return;
            }

            var reader = new FileReader();
            reader.onload = function(evt) {
                // ファイル読み込み時イベント実行
                if (onFileRead) {
                    onFileRead(evt.target.result);
                }
            }
            reader.readAsDataURL(file);
        }

        drop_mask.style('display', 'none');
        overlay.transition().duration(200)
               .style('opacity', 0)
               .transition().duration(0)
               .style('display', 'none');
        d3.event.preventDefault();
    };
}

  • メモ
    • D3.js に依存しない形式で書けば良かったのだが、アニメーションとか面倒なので…。
    • File 読み込み部分は画像専用化してる。readAsText に変更すればテキスト読み込み。

機能を使う。

  • 上記の関数は、読み込み後処理を設定して呼び出す。
setDragDrop(function(image) {
    images.data([{x:0, y:0, width:image_width, height:image_height, image: image}]).enter()
          .append('svg:image')
          .attr('xlink:href', function(d) { return d.image; })
          .attr('x', function(d) { return d.x; })
          .attr('y', function(d) { return d.y; })
          .attr('width',  function(d) { return d.width; })
          .attr('height', function(d) { return d.height; });
});

  • メモ
    • 別途、画像のドラッグ移動を追加したりは jsdo.it に投稿した方参照。