これが解決した。
先に 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 以外は全部「ノード中心じゃダメ」なとこが複雑になる原因、なのと、あと「複数ノード」に対する移動なのでね。)