jQuery: Cytoscape.js お試せた6.5 (ノードを「本当に」動的に追加 – undocumented な makeLayout の話)

いくらなんでも「ほんとのほんとに毎度ゼロから構築」はないよなぁ、と気になり続けていたがやっと。

jQuery: Cytoscape.js お試せた6 で cy.add で動的に追加していくのがダメだ、と言った。何が起こるかと言えば、「どんなレイアウトを選んでも全部 (0, 0) にノードが配置されてしまう」ことだった。ひとまず諦めていたんだけれど、automove のデモ内に非常に気になるコードを見つけてしまったのである:

 1         // a, b, c; with mid in the middle
 2         cy.$('#a, #b, #c').makeLayout({
 3             name: 'circle',
 4             boundingBox: {
 5                 x1: 0,
 6                 y1: 0,
 7                 x2: 300,
 8                 y2: 300
 9             }
10         }).run();

うーん、makeLayout なんかドキュメントされてないぞ。これが出来るんなら、うまくいけそうな気がする…。

とりあえずこの makeLayoutcy.removecy.add、そしておそらく makeLayouteles にバインドされているのであろうから cy.$() et al の3つと、あと cy.batch() も活用すれば、きっと「合理的な elements の入れ替え」が出来るんではないだろうか?

以下 makeLayout を最初 makelayoutと書いてしまったたった一回の「試行錯誤」だけで書けてしまったヤツ:

 1 <html>
 2 <head jang="ja">
 3 <meta charset="UTF-8">
 4 <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
 5 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.8/cytoscape.min.js"></script>
 6 <style>
 7 #outer {
 8   border-style: none;
 9   border-width: 3em;
10 }
11 #cy {
12   width: 100%;  /* MUST */
13   height: 90%;  /* MUST */
14 }
15 </style>
16 </head>
17 <body>
18 <input type="button" id="toggle" value="Toggle data!"/>
19 <div id="cy"></div>
20 <script>
21 var all_elememts = [
22     // graph 1 elements
23     [
24         { data: { id: 'a' } },
25         { data: { id: 'b' } },
26         { data: { id: 'c' } },
27         { data: { id: 'mid' }, classes: 'mid' },
28         { data: { source: 'a', target: 'mid' } },
29         { data: { source: 'b', target: 'mid' } },
30         { data: { source: 'mid', target: 'c' } },
31         { data: { id: 'd' } },
32         { data: { id: 'e' } },
33         { data: { id: 'f' } },
34         { data: { source: 'e', target: 'f' } },
35         { data: { id: 'g' } },
36         { data: { id: 'h' } },
37         { data: { id: 'i' } },
38         { data: { source: 'h', target: 'i' } }
39     ],
40 
41     // graph 2 elements
42     [
43 	{ data: { id: 'a' } },
44 	{ data: { id: 'b' } },
45 	{ data: { id: 'c' } },
46 	{ data: { id: 'mid' }, classes: 'mid' },
47 	{ data: { source: 'a', target: 'mid' } },
48 	{ data: { source: 'b', target: 'mid' } },
49 	{ data: { source: 'c', target: 'mid' } },
50 	{ data: { id: 'd' } },
51 	{ data: { id: 'e' } },
52 	{ data: { id: 'mid2' }, classes: 'mid' },
53 	{ data: { source: 'd', target: 'mid2' } },
54 	{ data: { source: 'e', target: 'mid2' } },
55 	{ data: { source: 'mid', target: 'mid2' } }
56     ]
57 ];
58 // construct cy with neither elements nor layout
59 var cy = window.cy = cytoscape({
60     container: document.getElementById('cy'),
61     style: [
62         {
63             selector: 'node',
64             style: {
65                 'content': 'data(id)',
66             }
67         },
68     ],
69 });
70 // if button is clicked, (re)set elements and makeLayout
71 var curidx = 0;
72 $('#toggle').on("click", function(evt) {
73     // elements what i want to render
74     var elems = all_elememts[curidx];
75 
76     // ---------------------------------------
77     // cy.batch() et al:
78     //     Allow for manipulation of elements without triggering multiple
79     //     style calculations or multiple redraws.
80     cy.startBatch();
81     // first, remove all existing elements
82     cy.remove(cy.elements());
83     // add new elements
84     cy.add(elems);
85     // layout - 17:20 追記: makeLayout は endBatch() のあとの方がいいみたい。
86     cy.elements().makeLayout({
87         name: "grid",
88         }).run();
89     //
90     cy.endBatch();
91     // ---------------------------------------
92     //
93     curidx = (curidx + 1) % 2;
94 });
95 </script>
96 </body>
97 </html>


イケた…。うーん、こーーーんな大事なこと、ドキュメントしときなさいよ、まったく…。



Related Posts