webページでドラッグ操作。jquery-uiを使う。

web開発において、ドラッグ操作したい場面に遭遇しました。
その際に、jquery-uiというドラッグ操作に対応したライブラリがあることを知ったので、使い方をここに書き留めていこうと思います。

どういうことがしたいのか。。。

webページにおいて、ドラッグ&ドロップでリストに順次追加していくようなページを作りたかった。

つまりはこういうことです。
ドラッグしたコンテンツをドロップエリアに落として、コンテンツのリストを作成したいというわけです。

まずは、jquery-uiを読み込む

どのCDNが早いのかという議論は置いておいて、とりあえずgoogleからCDNを読み込みます。
当然、jquery本体は読み込み済みであることが前提です。

<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

Google Hosted Librariesを見ると、jquery-ui.min.jsを読み込むのは当然のこと、同時にjquery-ui.cssも読み込むと書いてあります。
なんのためにjquery-ui.cssを読み込むのかは、分かり次第追記します。(私がやろうとしていることは、jquery-ui.cssなしでもできました。)

jquery-uiでドラッグする

以下のように要素に対して.draggable()を適用することで、色々なことができます。

ドラッグを可能にする

付与した要素が動きます。マウスを離せばその場に留まります。

$('#target_id').draggable();

ドラッグの有効 <=> 無効の切り替え

$('#target_id').draggable( 'enable' );
$('#target_id').draggable( 'disable' );

cloneを作成します

私がやりたかったのはこれ。
付与した要素本体は移動せず、そのクローンがドラッグされます。

$('#target_id').draggable( { helper: 'clone'} );

ドロップ側を作る

ドラッグできることが確認できたら、今度は受け皿を作ります。

ドロップ可能にする

$('#target_id').droppable();

イベント

droppableを付与した要素には、色々なタイミングで呼ばれるコールバック関数を付与することができる。

$('#target_id').droppable( { activate: function( event, ui ) {} } );
$('#target_id').droppable( { create: function( event, ui ) {} } );
$('#target_id').droppable( { deactivate: function( event, ui ) {} } );
$('#target_id').droppable( { drop: function( event, ui ) {} } );
$('#target_id').droppable( { out: function( event, ui ) {} } );
$('#target_id').droppable( { over: function( event, ui ) {} } );

・activate

draggable要素がドラッグを開始した時に呼ばれる関数をセットできる。
引数 :
     event – Type:Event
     ui – Type:Object(引数uiから、ドラッグされている要素の情報が取れる)
          draggable – Type:jQuery, ドラッグされている要素。
          helper – Type:jQuery, ヘルパーの要素。
          position – Type:Object, ドラッグされている要素の現在の位置。型はObjectで{ top, left }の形で格納されている。
          offset – Type:Object, ドラッグされている要素のオフセット。(オフセットは、draggable()にてつけることが可能)型はObjectで{ top, left }の形で格納されている。

・create

draggable要素が作成された時。
引数 :
     event – Type:Event
     ui – Type:Object, オブジェクト型であるが、中身は空である。他の関数との統一性の観点から、空のオブジェクトが渡される。

・deactivate

draggable要素がドラッグをやめた時に呼ばれる関数をセット。
引数はactivateと同様なため、簡略化。
引数 :
     event – Type:Event
     ui – Type:Object(引数uiから、ドラッグされている要素の情報が取れる)
          draggable – Type:jQuery
          helper – Type:jQuery
          position – Type:Object, { top, left }。
          offset – Type:Object, { top, left }。

・drop

draggable要素がドロップされた時に発火する関数を指定。
引数はactivateと同様なため、簡略化。
引数 :
     event – Type:Event
     ui – Type:Object(引数uiから、ドラッグされている要素の情報が取れる)
          draggable – Type:jQuery
          helper – Type:jQuery
          position – Type:Object, { top, left }。
          offset – Type:Object, { top, left }。

・out

draggable要素がdroppable要素から外れた時。
引数 :
     event – Type:Event
     ui – Type:Object, オブジェクト型であるが、中身は空である。他の関数との統一性の観点から、空のオブジェクトが渡される。

・over

draggable要素がdroppable要素の上に乗った時。
引数はactivateと同様なため、簡略化。
引数 :
     event – Type:Event
     ui – Type:Object(引数uiから、ドラッグされている要素の情報が取れる)
          draggable – Type:jQuery
          helper – Type:jQuery
          position – Type:Object, { top, left }。
          offset – Type:Object, { top, left }。

draggableの使えるオプション色々

clone: String   cloneを作成

上でも紹介しましたが、ドラッグしたい要素本体はその場に留めておいて、代わりにそのcloneを動かします。元に戻すときは、helper: ‘original’とします。

$('#target_id').draggable( { helper: 'clone' } );

revert: Boolean or String   マウスを離した時のエフェクト

取れる引数はBoolean or String。true, false, ‘valid’ or ‘invalid’。

通常ですと、draggable要素を途中で離すとその場で消えます

revert: true とすることで、途中で離した際に元の場所にすぅっと吸い込まれるようなエフェクトとなる。
revert: ‘invalid’ とすると、draggable要素がdroppable要素にドロップされなかった際にのみ、元の場所の戻るエフェクトが掛かる。
revert: ‘valid’ はinvalidの逆で、適切な場所にドロップされたときのみ元の場所に戻るエフェクトが掛かる。

$('#target_id').draggable( { revert: true } );

cursor: String  ドラッグ中のカーソル形状の指定

ドラッグ中のカーソル形状を指定できます。cssのcursorプロパティに載っているものが使えます。
pointer(リンクカーソル), crosshair(十字カーソル), move(移動カーソル), …

$('#target_id').draggable( { revert: true } );

cursorAt: {Object}   ドラッグ時のカーソルの位置

ドラッグ時のカーソルの位置を指定します。
というより、「draggable要素のどの場所を掴むか」という捉え方の方が良いかと思います。

$('#target_id').draggable( { top: pos_top, left: pos_left, right: pos_right, bottom: pos_bottom } );

droppableの使えるオプション色々

accept: Boolean function(draggable){}, String ドロップの受け入れを設定

ハッシュはBooleanを返す関数か、jQueryセレクタです。
関数の場合は、draggableオブジェクト(jQuery)が引数で入ってくるので、内部でごちゃごちゃして、受け入れる場合はtrueを、そうでない場合はfalseをreturnします。

function is_drop_accept( draggable ) {
    if ( ... ) return true;
    else return false;
}
$('#target_id').draggable( { accept: is_drop_accept } );
$('#target_id').draggable( { accept: '.acceptable' } );

tolerance: String ドロップイン判定

draggable要素がdroppable要素に入ったと判定する基準を設定できる。
デフォルトは’intersect’。個人的には’pointer’が使いやすいかなと。

‘fit’ : 完全に合わさったとき。
‘intersect’ : 半分以上draggable要素が入ったとき。
‘pointer’ : ポインタが入ったとき。
‘touch’ : 接触したとき。少しでもdraggable要素が重なったら。

$('#target_id').droppable( { tolerance: 'pointer' } );

小ネタ:ドラッグ時に中心を掴んでみる

何となくドラッグ時に、要素の中心を掴みたくなったので、
cursorAtを用いて要素の中心を掴めるようにしてみる。

$('#target_id').each( function() {
     var h_2 = $(this).outerHeight() / 2;
     var w_2 = $(this).outerWidth() / 2;
     $(this).draggable( { cursorAt: {top:h_2, left:w_2} } );
});

サンプルコード

思いつきで書いたので、間違っていても怒らないでください。

<body>
    <div id='drag_target'>この要素をドラッグしたい。</div>
    <div id='drop_target'>ここにドロップしてね。</div>
    <script>
    // ドロップした時に呼ばれる関数。
    // ドロップされたら、落とされた要素の内容を自身に追加してみる。
    function drop_callback( event, ui ) { // ドロップした時に呼ばれる関数。
        $(this).append( ui.draggable.clone() ); // cloneしないと元の要素がdrop後に消える。
    }
    $('#drag_target').draggable( { helper: 'clone', opacity: 0.5 } ); // cloneで元の要素を残したままドラッグ、ドラッグ中は半透明に。
    $('#drop_target').droppable( drop: drop_callback } ):
    </script>
</body>

こんな感じでしょうか。