jQuery: Cytoscape.js お試せた18 (座標系の謎が解けて panBy 自在 + zoom の話 + cytoscape.js-autopan-on-drag)

これが解決した。

先に zoom の話。これは「わからん」ということではなくて、「どう使うと普通のズーム操作になるのか」がちょっとピンと来てなかっただけだったりする。基本まぁこんだけなんだと思う:

1 var zoomspeed = 1;
2 // ...
3 cy.zoom(cy.zoom() * (1.0 + zoomspeed / 10));  // Zoom-In
4 cy.zoom(cy.zoom() * (1.0 - zoomspeed / 10));  // Zoom-Out

マウスホイールに反応してズームするのもこれをやってるんだろうと思う。

で、本題の「panBy がワガラン」の件。

一つ前で、nodes.shift() を使ってノードを移動する話を書いた。ただそうすると、「はみ出た」場合が不愉快で。なので、cytoscape.js-autopan-on-drag はワタシにオイシイだろうか、と見てたのね。

結論からは cytoscape.js-autopan-on-drag は「ワタシのケースにはおいしくない」。tapDrag そのものにしか反応してくれないから。(こういうとこがなんか cytoscape.js、今ひとつだと思うんだよなぁ。こんなん pan 操作 API がイベントをトリガーすりゃぁいいと思うんだが、そうしないもんだから拡張が各々勝手に「マウス(タップ)操作」にハンドラ書くことになってるわけだ。)

あとちなみに cytoscape.js-autopan-on-drag は、1. CDN にいない、2. ドキュメントに書かれていないが、cytoscape-undo-redo.js に依存している。この 2. がマズくて、「取り込んでないと死ぬ」こと。書けよ。

てわけで、cytoscape.js-autopan-on-drag は入れとけば「マウス操作だけしてるぶんには」嬉しいので使ってもいいか、とも思うけれど、ひとまずはまぁいいか、ということなんだけれど、上述の cytoscape-undo-redo.js への依存を「知る」ために、chrome のデベロッパツールでソースを読むハメになってな。当然やってることはまさに pan 操作なのでね、ワタシがやりたいことが書かれてるわけさ:

 1         var renderedPosition = node.renderedPosition();
 2         var renderedWidth = node.renderedWidth();
 3         var renderedHeight = node.renderedHeight();
 4         
 5         var maxRenderedX = $(cy.container()).width();
 6         var maxRenderedY = $(cy.container()).height();
 7         
 8         var topLeftRenderedPosition = {
 9           x: renderedPosition.x - renderedWidth / 2,
10           y: renderedPosition.y - renderedHeight / 2
11         };
12 
13         var bottomRightRenderedPosition = {
14           x: renderedPosition.x + renderedWidth / 2,
15           y: renderedPosition.y + renderedHeight / 2
16         };

renderedWidth とか 2 で割ってるとかは気にするな。ワタシも最初これが目に入って混乱しちゃったけれど、「ノードの(中心ではなく)大きさ」を加味してるだけよ。cytoscape.js-autopan-on-drag の責務は「ハミでちゃイヤんぐ」なので、ノード中心だけ見てちゃダメなのだ、てだけのことね。着目すべきは(ワタシの場合は) $(cy.container()).width()$(cy.container()).height() だけだった。これで既に renderedPosition については気付いていたのだから。

なんだよ、それだけか、と。なので、出来なかったこれで書いたコードを正しく書くとこういうこと:

1 var target_ele = ...;  // ターゲットのノード (実際は cy.elements("node") で取って来たノード一つ)
2 var pos = target_ele.renderedPosition();
3 var center = {
4     x: $(cy.container()).width() / 2,
5     y: $(cy.container()).height() / 2
6 };
7 var vec = {x: center.x - pos.x, y: center.y - pos.y};  // pos -> center のベクトル
8 cy.panBy(vec);

なんつーかこういうことなら この公式説明、もっとシンプルにわかりやすく説明出来ないのかな? 「わざとわかりにくく」書いてない? (絵に描けばそもそも一撃だろうし。)

というわけで、ワタシのヤツに実際に適用したヤツ:


Center だけでなく TopLeft、ButtomLeft、BottomRight、TopRight 全部やってる。とてつもなく使い勝手が向上。こいつぁいいや。つーかこれをずっとやりたかったんだよ。(使いかたがわからない人はここ参照。)

というわけでこれらについての実装を知りたければ例によって「フレームのソースを表示」して function _apply_node_finder() を見ておくれ。無論説明したコードより少し(相当?)複雑だが、よく読めばわかるハズ。(それこそ Center 以外は全部「ノード中心じゃダメ」なとこが複雑になる原因、なのと、あと「複数ノード」に対する移動なのでね。)



Related Posts