2012年1月21日土曜日

jQueryでドラッグ&ドロップ

自分用のブログエンジンを作っていて、
要素をドラッグ&ドロップしながら章立てできるようなものにしたいなと思い
要素をどんどん追加していこうと思い、
最初draggable,droppable辺りを利用していたんだけど、
追加したい場所や、追加した要素の順番を変更したりと
sortableが必要だったので少し書いてみる。


何がしたいか?
・ドラッグして要素の追加 ・ドラッグしたものは残す ・ドラッグしたものを変更 ・ドロップする場所は順序変更が可能 これによりコンテンツを編集していく感じ
ソートの準備
まずソートしたい要素に対して
 $(".content-box").sortable({
  placeholder:'ui-state-highlight',
  connectWith: $('.content-box'),
  axis:'y',
  update : function (event,ui) {
   //順序を変更した後
  },
  receive : function (event,ui) {
   //他から要素が追加された場合
  }
 });
と行います。 placeholder:移動する場所に対してのスタイルを指定します。 これで色の変更などを行なって移動を行いやすくします。 connectWith:移動できる場所を自分自身のみにしています。 axis:yを指定して縦方向だけ移動できるようにしています。 update,receiveはイベントですが、 updateは順序を変更した場合のみに発生、receiveは他から要素が入ってきた時です。 receive発生時もupdateは発生します。 一旦はこれだけでcontent-box内の要素の順序変更ができるようになります。
ドラッグしてくる側の設定
ここが一番苦労したというか気づかなかったというか。 ドラッグする側に対してもsortableで対応しないと、ドラッグできないのではないか?と 思ってそうしてたのですが、cloneが効かなかったり、何かとやりたい事に対して うまくいかなかったのですが、まず ドラッグしたい要素に対して、ドラッグをできるようにします。
 // アイテムのドラッグ
 $('.item').draggable({
    cursor: 'move', 
    opacity: 0.7,
    connectToSortable: $('.content-box'),
          helper:'clone'
 });
cursor:カーソルの変更 opacity:移動時の透明度 connectToSortable:指定した場所にはsortableの対象として扱ってくれるので 上記で指定した「ui-state-highlight」をやってくれます。 helper:移動中の表示をコピーにしています。 これに対しては実際はfunctionも扱えるので 移動する時に表示を変えたい場合はfunctionを指定して戻り値でタグを返します。
まぁこれで大体できるんだけど、、、
私の場合はitemの部分とcontent-box内の要素が違います。 この状態で行うとitemのタグがそのまま配置されてしまうので receiveイベントの時に
    var addTag = createContentItem(itemName);
    var dropItem = $(this).children(".item");
    dropItem.after(addTag);
    dropItem.remove();
新しくタグを追加してあげて、ドロップした要素を削除しています。 当初はどちらもsortableを指定しないと要素の追加場所がわからないのではないか? と思って指定していたのですが、片方をドラッグにしてcloneを行えば良い事に気付いたので 後は追加要素を追加削除するだけでした。 connectToSortableに気づいたら非常に簡単にできました。 ただsortableでhelperにclone指定をした場合にうまく動作しなかったのが 少し解せない感じでした。

2012年1月18日水曜日

MacでXtionを動作させる

Macでの動作もしておこうと思ったので

ここ

を参考にしました。

前準備
portが1.9だと失敗したので2.0系のupdateから開始
sudo port selfupdate
sudo port install libtool
sudo port install libusb-devel +universal
かなりインストールに時間がかかりました><。
ドライバ等
本家のunstableからMacOS用の openni-bin-dev-macosx-v1.5.2.23.tar.bz2 nite-bin-macosx-v1.5.2.21.tar.bz2 sensor-bin-macosx-v5.1.0.41.tar.bz2 をダウンロードしてくる。 それぞれinstall.shが存在するのでそれらを実行。これでOKでした。 sudoが必要なものはsudoで行なってください。 通常のSampleはこれで動作するのですがJava実行だと
java.lang.UnsatisfiedLinkError: no OpenNI.jni in java.library.path
が出てしまいます。
java -Djava.library.path=/usr/lib -jar jarファイル
で動作しました。 Mac miniですが640x480だと重くてデータを飛ばせなかった><。

2012年1月9日月曜日

Xtionがやってきた。

Xtionがやってきたので、少し触ってみる。
XtionはKinectと同様にOpenNIを利用したモーションキャプチャーです。
Kinectは現状ではハードウェアが商用利用は不可ですが、Xtionは商用利用が可能です。

特に商用利用が目的ではないのですが、
USBバスで動作するのでこちらを購入したというところが強いのですが、
Kinectで行うとハック感がなくなるかな?というところで、
Xtionにしました。Xtion Pro Liveです。

OpenNIのインストール
まず付属してたDVDだと古そうだったので 本家からPackageを入れます。 古い記事だと64ビットだと動作しないみたいな話がありますが この時点では動作するようです。 Macについては後述しておきました。
どんなものを作るのか?
友人が電子書籍系をやっているのだけど「マイノリティ・リポートやろうぜっ」って感じだったので そういうものを作ろうと思った。 動かすのはiPadのようなタブレットだった。iPadにOpenNIとか非現実的な事だし、 私自身がxcodeでソレ系のアプリを作る気もないし、 とにかく相手にプッシュする方法が必要だったので、 相手がサーバでこっちがクライアントという選択肢だと、 こっちから接続しなきゃいけないし、何かと不便に感じた。 ちょうどRFCにWebSocketが載ったところだったのでこっちをサーバにしてWebSocketを実装する事にした。 Javaで動作するものを作ろうと思ったのでJettyでWebSocketサーバを作成して、 そこから何らかのクライントでWebSocketにアクセスしてもらって通信をやろうと思った。
WebSocketを作る
ここを参考に サーバサイドは作成した。 実際はChatRoom的な管理は必要ないわけだけど、 例えばHTML(WebSocketでアクセスできるもの)で資料を作って それをみんなの端末で見る~。。。なんてI/Fも想定してたりしてなかったり。
HandTrackerを発見!
はじめはサンプルの「UserTracker」を元に作り始めた。 Userを認識してSkeletonCapabilityで骨格を認識させて、 それで手の動きを見ようと考えていたんだけど、 「GestureGenerator」「HandsGenerator」が存在する事を知り ココに「HandTracker」のサンプルがあるので拝借。 ※っていうか最新のパッケージならローカルにも展開されてます。 サンプル読んだおかげで大体の動作は理解できた。 ・Contextやら読み込んで各Generatorを初期化 ・イベントに対してObserverを作成(コールバック) ・ループして ・ノードを更新してノードからデータを取得 ・何かやる みたいな流れみたい。
HandsGeneratorでジェスチャーを認識
このサンプルにGestureGeneratorに対して"Click"とあり、 これがセンサーに向かって手をpullしたり、調べた限りだと"Wave"などを認識できるようなんだけど 「これにLeftとかRightをかあれば楽?」と考えたりもしたけど この辺りを読むと サンプルの通りGestureGeneratorで認識させてからHandsで行うのが通常の使い方みたい。 サンプルは ・GestureGeneratorに"Click"を登録 ・イベント発生でHandsGeneratorのトラッキングを開始 ・Update系のイベントでそのポイントを取得して履歴に残す ・ポイントの履歴を描画 ・手の認識が終わったらGestureGeneratorの"Click"を再度登録 みたいな流れ。 Updateで履歴があるのでこれを使って
 public static SocketType getType(float modX, float modY, float modZ) {

  SocketType type = SocketType.NONE;
  if ( Math.abs(modY) < margin ) {
   if ( modX < (movement*-1) ) {
    type = SocketType.LEFT;
   } else if ( modX > movement ) {
    type = SocketType.RIGHT;
   }
  } else if ( Math.abs(modX) < margin ) {
   if ( modY < (movement*-1) ) {
    type = SocketType.DOWN;
   } else if ( modY > movement ) {
    type = SocketType.UP;
   }
  } else {
   if ( modZ < (movement*-1) ) {
    type = SocketType.ZOOMIN;
   } else if ( modZ > movement ) {
    type = SocketType.ZOOMOUT;
   }
  }
  return type;
 }
みたいな座標の移動量を計算させて、どっちに動いているかを判定 ※SocketTypeってのはオリジナルのEnumです。 あとはソケットで送るだけ。 まぁこれだと調整値によって認識とかしまくりとか認識しないとかさんざんなので もう少し何かする必要があるかな?
感想
何かライブラリ使ってもう少し何かできそうな流れだったけど、 自分で理解するのも含めて作ってみた。 サンプルを理解したところをもう少し書きたかったんだけど、 またそれは別の機会でもあれば。

2012年1月6日金曜日

undefinedという値について

引数に「undefined」って指定してあるのなんで?と言っていた人がいた。 jQueryの話だったけど、JavaScriptの癖(癌)を利用したトリックだと推測。 undefinedはグローバルスコープの変数だから、 引数に対してundefinedを代入して、ローカルスコープに持って来て ロジックによっては処理を早くしたり、 undefinedの値をローカル内で保証できる状況になるという仮説を立てたけど、 「引数間違って指定したら失敗するんじゃね?」 と思ったので試してみた。
<script type="text/javascript">
<!--

function undefinedTest1(arg1) {
 if ( arg1 === undefined ) {
  console.log("1");
 }
}

function undefinedTest2(arg1,undefined) {
 if ( arg1 === undefined ) {
  console.log("2");
 }
}

var val;
console.log("undefined");
undefinedTest1(val);
undefinedTest2(val);

console.log("変数に値を入れてみる");
undefined = true;
undefinedTest1(val);
undefinedTest2(val);

console.log("第2引数に値を入れてみる");
undefinedTest2(val,"test");

// -->
</script>
でコンソールは
undefined
1
2
変数に値を入れてみる
2
第2引数に値を入れてみる
まず、関数が正常に動作している事を確認。 グローバルスコープのundefinedに値を代入すると関数1の値は不可能になり、 間違って引数指定をすると、undefinedに値が代入されて、関数2もアウト。 まぁ十分テストされていれば第2引数の指定はないだろうから危なくはないのかな? 思ったとおりの動きだったのでひとまず満足。