人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

jquery ui draggableの配置について困っております。

ピース画像をdraggableにし、別の大きな画像に配置するという
福笑いのパズルのようなサイトを作成しようとしています。
ピースの数が多いため縦一列に配置しようと思うのですが
ピースをドラッグすると他のピースが上に詰まるようにしたいと考えております。

※参考サイト
http://www.openspc2.org/JavaScript/Ajax/jQuery_study/ver1.2.6/chapter06/001/sample02/index.html

この参考サイトでも実現可能なのですが、最新のjsファイルを使うと上に詰まる動作が出来なくなったため
別の方法で考えております。ちょうどSortableでピースを縦に並べて、そこからdragして別の画像の任意の場所へドロップするようなイメージです。

プラグインなどではドラッグ&ドロップでレイアウトを変更できるようなものもあるのですが
別の画像にピースを当てはめたいという動作が実現できません。

何か良いアイデアや参考になるサイトがございましたらご教授下さい。
大変お手数おかけいたしますがよろしくお願いいたします。

●質問者: hossiiii
●カテゴリ:ウェブ制作
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

質問者から

説明が長くなってしまいましたが、draggable可能な要素を動的に自動整列する方法をご教授下さい。よろしくお願いいたします。


1 ● gatchan
●166ポイント

Sortable | jQuery UI
http://jqueryui.com/sortable/
---
普通にUIの.jsを読み込んで、単純に、

$( "#sortable" ).sortable();
$( "#sortable" ).disableSelection(); //おまけ:テキスト選択を無効にする

で標準的にできると思いますが、これでは違いますか?
アイテム群のliタグを含んだラッパーのulタグに対して、sortable()メソッド。

HTML

<ul id="sortable">
 <li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 1</li>
 <li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 2</li>
 <li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 3</li>
 <li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 4</li>
 <li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 5</li>
 <li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 6</li>
 <li class="ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s"></span>Item 7</li>
</ul>

すみません、ソースはそのままですw


gatchanさんのコメント
ごめんなさい、たぶんちょっと違う気がしてきました...。

hossiiiiさんのコメント
早急なご回答ありがとうございます。 試してみたのですが、コメント頂いた通り少しやりたい事と異なっておりました。 回答頂いた状態から ?それぞれの要素をdragしたい ??がdragされたら以下の要素が上に詰まるように再配置したい 質問の内容が分かりずらい点があり申し訳ありませんでした。 その他不明な点がございましたらコメント下さい。 よろしくお願いいたします。

gatchanさんのコメント
お早うございます。 レス頂いたら何かしらすり合わせができると思いましたが...。 一応、sortable()で、?と?の条件は満たしていますよね? >> 試してみたのですが、コメント頂いた通り少しやりたい事と異なっておりました。<< どう違うのかがわかりません...。 おそらくですが、 ?のタイミング、つまり、ドラッグしたものをどこにドロップするに関わらず、下の要素は上に詰まる。 ただ、これならばsortable()に関わらず、ドラッグスタートみたいなイベントにコールバックで上にズラス処理を入れる、ってことを普通は考えるかな。 すみません、今のところこれくらいしか言えません...;D

hossiiiiさんのコメント
gatchan様 おはようございます ご連絡ありがとうございます。 大変失礼致しました。私が作ったサンプルの構文が間違えており 動作していないだけでした。失礼なコメントお許しください。 おっしゃる通り?と?を満たしております。 >おそらくですが、 >?のタイミング、つまり、ドラッグしたものをどこにドロップするに関わらず、下の要素は上に詰まる。 この通りでございます。 sortable()は使わずドラッグスタートをトリガーにして、ドラッグされた以下の要素をドラッグした要素のhight分だけ上に表示し直すという事ですね。 アイデアありがとう御座います。 条件分岐や繰り返し処理が複雑になりそうな気がしますね。 もし良いサンプルなどがございましたらご教授頂けると助かります。 貴重なコメントありがとう御座いました。

gatchanさんのコメント
なるほど、回答者の皆さんなんとか質問の内容が理解できたようですね。良かったと思います。 私も同じようなサンプルできましたが、今更なので上げません。stopイベントのタイミングでいいんですねw 最初のサンプルのタイミングだと、startだと思ったんですけどw 今回は期待に添えずすみませんw なのでポイントは他の方へ。

hossiiiiさんのコメント
gatchan様 コメントありがとうございます。 こちらの説明の不備でいろいろご迷惑をおかけしました。 サンプルの作成も本当にありがとうございました。 今後ともどうぞよろしくお願いいたします。

gatchanさんのコメント
えっと、どうしたいのかがちょっとわかったので、ちょっと書いてみました。 http://jsfiddle.net/QqqSW/ なるべくDOMの再描画とかはせずに、トラバースと移動(CSSの変更)にしています。 ドロッパブルにドロップ後にまた、戻す時は、そうするんだろう、と思って止めてたんですが、特にいらなかったのですね。。。 まあご参考まで。

hossiiiiさんのコメント
gatchan様 ありがとうございます。 こちらも私の実現したい要件をすべて叶えて頂けております。 ドラッグの要素がゆっくり上に詰まっていく感じがすごくいいですね。 参考にさせて頂きます。

gatchanさんのコメント
animate(propaerties, duration) のdurationには1500にしてますが、わかりやすいようにしただけですので、適宜変えてもらえれば。 参考になれば幸いです。 あと、基本的なTipsとして、どの場合でもそうですが、DOMの操作というのは本来(無視できる程度ですが)重いものになります。DOMの追加、削除など。なのでスクリプトの設計時にまずそれらを避ける、あるいは、できるだけキャッシュを使いまわす、CSSのプロパティで動かす/変える、と言った具合です。 ましてや、何万回のループは顕著になります。まあちょっとしたアプリケーションでない限りそこまでしないと思いますが...。 今はモバイル対応も考えることも多く、その場合割りとJSの動作は多少というか、結構落ちます。特にアニメーション周り(まあ元々負荷が高い処理です)。 という感じですw ありがとうございました:D

2 ● Lhankor_Mhy
●168ポイント ベストアンサー

コメント欄の思いつきどおりやってみました。
うーん、なんかあれですねえ。
http://jsfiddle.net/TWfq2/


a-kuma3さんのコメント
うへ、何でこんなに短くなるん ><

a-kuma3さんのコメント
ああ、移動元と移動先の要素の offset を同じにしておけば、計算しなおす必要が無いのか!

Lhankor_Mhyさんのコメント
おお、タッチの差だったあぶないw ドラッグするたびにDOMにゴミがたまっていくことに気付きました。CSSでごまかしてるから、ブラウザ依存ありそうだし、なんかアレなんですよね。

hossiiiiさんのコメント
Lhankor_Mhy 様 まさに求めていた動きをしています。 感動しました。本当にありがとうございます。 またコードもシンプルでありがたいです。 もしよろしければ、どのようなロジックで動作しているのか 簡単に説明頂けないでしょうか? 特にprependとoffsetあたりが自分には理解出来ませんでした。

Lhankor_Mhyさんのコメント
ああ、気付かなかった。なるほど、親要素のoffsetを拾っておかないといけないのか。「なんかズレるなあ」ぐらいにしか考えてなかったw

hossiiiiさんのコメント
コメントありがとうございます。 すみません、何か気が付く所があったのでしょうか? 私は純粋に分からなかっただけで・・動作には本当に満足しています もし気づいた事があれば教えて欲しいです。 お手数おかけして申し訳ありません。

Lhankor_Mhyさんのコメント
何点か修正しました。DOMゴミとCSS依存を解消したと思います。我ながらよく動いてたなアレ。 http://jsfiddle.net/TWfq2/2/ 簡単ですがご説明します。 >|| var wrapper = $('#wrapper'); var target = $(this); wrapper.prepend(target); //ラッパ要素の先頭ににドラッグ要素を追加 target.parent('.draggableWrapper').children().unwrap() //絶対配置用divがあれば削除 .end().end() //フィルタリセット .css('left',ui.offset.left - wrapper.offset().left) //ドラッグ要素座標をラッパ要素座標で修正してCSS操作 .css('top',ui.offset.top - wrapper.offset().top) //ドラッグ要素座標をラッパ要素座標で修正してCSS操作 .wrap('<div style="position:absolute;" class="draggableWrapper"></div>'); //絶対配置用divでラッピング ||< prependメソッドを使っているのは、appendではドラッグ要素の前に別の要素があるため、座標が影響されて位置がずれてしまうからです。 あと、本当にどうでもいいことですが、全部メソッドチェインで書けることに気付いてしまいました。不覚です。

a-kuma3さんのコメント
あ、これか。 >http://api.jquery.com/prepend/> If a single element selected this way is inserted into a single location elsewhere in the DOM, it will be moved into the target (not cloned): << コンテンツを差し込む、というイメージしかなかった >.prepend() >> あと、本当にどうでもいいことですが、全部メソッドチェインで書けることに気付いてしまいました。不覚です。 << さすがに、.end().end() は、苦しいんじゃ <tt>:-)</tt> # 面白いけど。

Lhankor_Mhyさんのコメント
メソッドチェイン原理主義者なめんな。変数宣言以外ワンラインじゃ。 >|| var wrapper, target; (target = $(this)).prependTo(wrapper = $('#wrapper')) .parent('.draggableWrapper').children().unwrap() .end().end() .css('left',ui.offset.left - wrapper.offset().left) .css('top',ui.offset.top - wrapper.offset().top) .wrap('<div style="position:absolute;" class="draggableWrapper"></div>'); ||<

hossiiiiさんのコメント
ご連絡が遅くなってしまい申し訳ありません。 説明および改良したコードまでありがとう御座いました。 早速リンクを見てみたのですがjavascriptの中に記載されている draggableWrapperというクラスcssに無かったのでローカルで 確認する事が出来ませんでした。。 http://jsfiddle.net/TWfq2/2/ もし可能でしたらcss部分もご教授頂けると嬉しいです。 長期に渡りご対応頂きありがとうございます。

Lhankor_Mhyさんのコメント
インラインでスタイルが書いているのですが、動作しませんでしたでしょうか。 一応、書き直しておきますが、動作しない原因はCSSではないような気がしますね。 http://jsfiddle.net/TWfq2/3/

hossiiiiさんのコメント
Lhankor_Mhy 様 書き直して頂いたもので動きました!ありがとうございます。 2番目の方でも動作するのですね。私の確認のしかたが良くなかったのだと思います。 誠にありがとう御座いました。

3 ● a-kuma3
●166ポイント

かなり力技のような気もしますが、それっぽい動きになってます。
jsFiddle で、動作確認をしたのがこちら。
http://jsfiddle.net/a_kuma3/2wc9t/1/embedded/result/

こんな感じのソースです。

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>

<script>
$(function(){
 var element_from = $("#from").get()[0];
 var element_to = $("#to").get()[0];
 var diff_top = element_from.offsetTop - element_to.offsetTop;
 var diff_left = element_from.offsetLeft - element_to.offsetLeft;
 var opt = {
 stop: function(event, ui) {
 $(".dArea").draggable("destroy");
 var t = ui.helper.get()[0];
 if (t.parentNode === element_from) {
 prev_top = t.offsetTop;
 prev_left = t.offsetLeft;
 t.parentNode.removeChild(t);
 t.style.position = "absolute";
 element_to.appendChild(t);
 t.style.top = prev_top + diff_top + "px";
 t.style.left = prev_left + diff_left + "px";
 }
 $("#from > .dArea").css("position", "static")
 $(".dArea").draggable(opt);
 }
 }
 $(".dArea").draggable(opt);
});
</script>
<style>
.dArea {
 background-color: greenyellow;
 border: 2px solid limegreen;
 width:140px;
 height:50px;
}
div#from {
 position: absolute;
 width: 200px;
 border: solid 1px green;
 top: 3em;
 height: 300px;
}
div#to {
 position: absolute;
 width: 200px;
 border: solid 1px red;
 top: 3em;
 left: 300px;
 height: 300px;
}
</style>
</head>
<body>

<br><br>

<div id="from">
<div class="dArea">(1) ここがドラッグできます</div>
<div class="dArea">(2) ここがドラッグできます</div>
<div class="dArea">(3) ここがドラッグできます</div>
<div class="dArea">(4) ここがドラッグできます</div>
</div>
<div id="to">
</div>

</body>
</html>

Draggable な要素を動かし終わったときに、

  1. 一旦、Draggable を破棄
  2. 動かした要素を、別の要素の下にぶら下げる
  3. まだ動かしていない Draggable な要素の position を static にする(これで、詰まる)
  4. あらためて、Draggable を指定する

という処理をしています。


hossiiiiさんのコメント
a-kuma3様 動作確認しました。 こちらもまさしく期待している動きでした。 更に内容の説明もありがとうございます。 分かりやすいコードで不慣れな自分でも理解出来ました。 ベストアンサーはタッチの差で投稿頂いたのと シンプルなコードからLhankor_Mhy 様にしようと思うのですが 今後作成していく中で不具合があった場合の バックアップ用のコードとして利用させて頂きます。 前回の質問に引き続き誠にありがとう御座いました。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ