mkdocs-nodegraph 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1158 @@
1
+ <html>
2
+ <head>
3
+ <meta charset="utf-8">
4
+ {% if cdn_resources=="local" %}
5
+
6
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis-network/9.1.2/dist/dist/vis-network.min.css" integrity="sha512-WgxfT5LWjfszlPHXRmBWHkV2eceiWTOBvrKCNbdgDYTHrT2AeLCGbF4sZlZw3UMN3WtL0tGUoIAKsu8mllg/XA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/vis-network/9.1.2/dist/vis-network.min.js" integrity="sha512-LnvoEWDFrqGHlHmDD2101OrLcbsfkrzoSpvtSQtxK3RMnRV0eOkhhBN2dXHKRrUU8p2DGRTk35n4O8nWSVe1mQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
8
+ {% if select_menu or filter_menu %}
9
+ <link href="lib/tom-select/tom-select.css" rel="stylesheet">
10
+ <script src="lib/tom-select/tom-select.complete.min.js"></script>
11
+ {% endif %}
12
+ {% elif cdn_resources=="in_line" %}
13
+ <style>{% include 'lib/vis-9.1.2/vis-network.css' %}</style>
14
+ <script>{% include 'lib/vis-9.1.2/vis-network.min.js' %}</script>
15
+ {% if select_menu or filter_menu %}
16
+ <style>{% include 'lib/tom-select/tom-select.css' %}</style>
17
+ <script>{% include 'lib/tom-select/tom-select.complete.min.js' %}</script>
18
+ {% endif %}
19
+ {% elif cdn_resources=="remote" %}
20
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis-network/9.1.2/dist/dist/vis-network.min.css" integrity="sha512-WgxfT5LWjfszlPHXRmBWHkV2eceiWTOBvrKCNbdgDYTHrT2AeLCGbF4sZlZw3UMN3WtL0tGUoIAKsu8mllg/XA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
21
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/vis-network/9.1.2/dist/vis-network.min.js" integrity="sha512-LnvoEWDFrqGHlHmDD2101OrLcbsfkrzoSpvtSQtxK3RMnRV0eOkhhBN2dXHKRrUU8p2DGRTk35n4O8nWSVe1mQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
22
+ {# <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/vis-network/9.0.4/dist/dist/vis-network.min.css" integrity="sha512-+5tJeVsSE2tSnmKB5SWOD0GsYA5dOP0B/FSv7I2GYhdOcyjJq81Q1St3qgJgInwreAdNuw0KGJ0FOaxOJ0E4yw==" crossorigin="anonymous" referrerpolicy="no-referrer" />#}
23
+ {# <script src="https://cdnjs.cloudflare.com/ajax/libs/vis-network/9.0.4/dist/vis-network.js"#}
24
+ {# integrity="sha512-CEbUhbSq35hCqBH8ckfAkH1Tcua5NEywtEzwiJ+BUC4EIZkC7vyta3ivZu/WqJhK1qHTurO3hwHsErU3HHjwIA=="#}
25
+ {# crossorigin="anonymous"#}
26
+ {# referrerpolicy="no-referrer"></script>#}
27
+ {% if select_menu or filter_menu %}
28
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tom-select/2.0.0-rc.4/css/tom-select.min.css" integrity="sha512-43fHB3GLgZfz8QXl1RPQ8O66oIgv3po9cJ5erMt1c4QISq9dYb195T3vr5ImnJPXuVroKcGBPXBFKETW8jrPNQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
29
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tom-select/2.0.0-rc.4/js/tom-select.complete.js" integrity="sha512-jeF9CfnvzDiw9G9xiksVjxR2lib44Gnovvkv+3CgCG6NXCD4gqlA5nDAVW5WjpA+i+/zKsUWV5xNEbW1X/HH0Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
30
+ {% endif %}
31
+
32
+ {% endif %}
33
+ <center>
34
+ <h1>{{heading}}</h1>
35
+ </center>
36
+
37
+
38
+ <script
39
+ src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js"
40
+ integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf"
41
+ crossorigin="anonymous"
42
+ ></script>
43
+
44
+
45
+ <center>
46
+ <h1>{{heading}}</h1>
47
+ </center>
48
+ <style type="text/css">
49
+
50
+ #mynetwork {
51
+ width: {{width}};
52
+ height: {{height}};
53
+ background-color: {{bgcolor}};
54
+ position: absolute;
55
+ border: 1px solid {{bgcolor}};
56
+ float: left;
57
+ z-index: 1;
58
+ }
59
+
60
+ {% if nodes|length > 100 and physics_enabled %}
61
+
62
+ #bar {
63
+ position:absolute;
64
+ top:0px;
65
+ left:0px;
66
+ width:20px;
67
+ height:20px;
68
+ margin:auto auto auto auto;
69
+ border-radius:11px;
70
+ border:2px solid rgba(30,30,30,0.05);
71
+ background: rgb(0, 173, 246); /* Old browsers */
72
+ box-shadow: 2px 0px 4px rgba(0,0,0,0.4);
73
+ }
74
+
75
+ #border {
76
+ position:absolute;
77
+ top:10px;
78
+ left:10px;
79
+ width:500px;
80
+ height:23px;
81
+ margin:auto auto auto auto;
82
+ box-shadow: 0px 0px 4px rgba(0,0,0,0.2);
83
+ border-radius:10px;
84
+ }
85
+
86
+ #text {
87
+ position:absolute;
88
+ top:8px;
89
+ left:530px;
90
+ width:30px;
91
+ height:50px;
92
+ margin:auto auto auto auto;
93
+ font-size:22px;
94
+ color: #000000;
95
+ }
96
+
97
+ div.outerBorder {
98
+ position:relative;
99
+ top:400px;
100
+ width:600px;
101
+ height:44px;
102
+ margin:auto auto auto auto;
103
+ border:8px solid rgba(0,0,0,0.1);
104
+ background: rgb(252,252,252); /* Old browsers */
105
+ background: -moz-linear-gradient(top, rgba(252,252,252,1) 0%, rgba(237,237,237,1) 100%); /* FF3.6+ */
106
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(252,252,252,1)), color-stop(100%,rgba(237,237,237,1))); /* Chrome,Safari4+ */
107
+ background: -webkit-linear-gradient(top, rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* Chrome10+,Safari5.1+ */
108
+ background: -o-linear-gradient(top, rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* Opera 11.10+ */
109
+ background: -ms-linear-gradient(top, rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* IE10+ */
110
+ background: linear-gradient(to bottom, rgba(252,252,252,1) 0%,rgba(237,237,237,1) 100%); /* W3C */
111
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfcfc', endColorstr='#ededed',GradientType=0 ); /* IE6-9 */
112
+ border-radius:72px;
113
+ box-shadow: 0px 0px 10px rgba(0,0,0,0.2);
114
+ }
115
+ {% endif %}
116
+
117
+ {% if conf %}
118
+ #config {
119
+ float: left;
120
+ width: 400px;
121
+ height: 600px;
122
+ }
123
+ {% endif %}
124
+
125
+ {% if tooltip_link %}
126
+ /* position absolute is important and the container has to be relative or absolute as well. */
127
+ div.popup {
128
+ position:absolute;
129
+ top:0px;
130
+ left:0px;
131
+ display:none;
132
+ background-color:#f5f4ed;
133
+ -moz-border-radius: 3px;
134
+ -webkit-border-radius: 3px;
135
+ border-radius: 3px;
136
+ border: 1px solid #808074;
137
+ box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
138
+ }
139
+
140
+ /* hide the original tooltip */
141
+ .vis-tooltip {
142
+ display:none;
143
+ }
144
+ {% endif %}
145
+
146
+
147
+ body {
148
+ margin: 0;
149
+ padding: 0;
150
+ }
151
+
152
+ .card {
153
+ display: absolute;
154
+ min-height: 100vh;
155
+ }
156
+
157
+ .left-panel {
158
+ background: #222222a6;
159
+ width: 210px;
160
+ position: absolute;
161
+ z-index: 2;
162
+ border-radius: 10px;
163
+ }
164
+
165
+ .left-panel.collapsed {
166
+ width: 30px;
167
+ background: #22222200;
168
+ }
169
+ .left-panel.collapsed .panel-content {
170
+ opacity: 0;
171
+ visibility: hidden;
172
+ }
173
+ .collapse-btn {
174
+ position: absolute;
175
+ width: 30px;
176
+ height: 30px;
177
+ right: 0%;
178
+ padding: 2px 2px;
179
+ color: whitesmoke;
180
+ background: #222222a6;
181
+ border: none;
182
+ border-radius: 4px;
183
+ cursor: pointer;
184
+ transition: 0.3s;
185
+ user-select: none;
186
+ }
187
+
188
+ .collapse-btn:hover {
189
+ background: #747988;
190
+ }
191
+
192
+ .panel-content {
193
+ flex-direction: column;
194
+ padding: 5px;
195
+ gap: 10px;
196
+ margin-bottom: 20px;
197
+ margin-top: 30px;
198
+ }
199
+
200
+ .physics-btn {
201
+ font-size: 13px;
202
+ position: relative;
203
+ z-index: 1000;
204
+ padding: 9px 9px;
205
+ margin: 3px;
206
+ background-color: hsl(122, 39%, 49%);
207
+ color: white;
208
+ border: none;
209
+ border-radius: 2px;
210
+ width: 200px;
211
+ cursor: pointer;
212
+ }
213
+
214
+ .physics-btn:hover {
215
+ background-color:hsl(121, 47%, 57%);
216
+ }
217
+
218
+ .save-btn {
219
+ font-size: 13px;
220
+ position: relative;
221
+ z-index: 1000;
222
+ padding: 9px 9px;
223
+ margin: 3px;
224
+ background-color: hsl(194, 42%, 45%);
225
+ color: white;
226
+ border: none;
227
+ border-radius: 2px;
228
+ width: 200px;
229
+ cursor: pointer;
230
+ }
231
+
232
+ .save-btn:hover {
233
+ background-color: hsl(194, 41%, 53%);
234
+ }
235
+
236
+ .reset-btn {
237
+ font-size: 14px;
238
+ position: relative;
239
+ z-index: 1000;
240
+ padding: 9px 9px;
241
+ margin: 3px;
242
+ background-color: hsl(0, 0%, 40%);
243
+ color: white;
244
+ border: none;
245
+ width: 200px;
246
+ border-radius: 2px;
247
+ cursor: pointer;
248
+ }
249
+
250
+ .reset-btn:hover {
251
+ background-color: hsl(0, 0%, 50%);
252
+ }
253
+
254
+ input {
255
+ accent-color: gray;
256
+ }
257
+
258
+ </style>
259
+ </head>
260
+
261
+
262
+ <body>
263
+ <div class="card" style="width: 100%">
264
+ {% if select_menu %}
265
+ <div id="select-menu" class="card-header">
266
+ <div class="row no-gutters">
267
+ <div class="col-10 pb-2">
268
+ <select
269
+ class="form-select"
270
+ aria-label="Default select example"
271
+ onchange="selectNode([value]);"
272
+ id="select-node"
273
+ placeholder="Select node..."
274
+ >
275
+ <option selected>Select a Node by ID</option>
276
+ {% for node in nodes %}
277
+ <option value="{{ node.id }}">{{node.id}}</option>
278
+ {% endfor %}
279
+ </select>
280
+ </div>
281
+ <div class="col-2 pb-2">
282
+ <button type="button" class="btn btn-primary btn-block" onclick="neighbourhoodHighlight({nodes: []});">Reset Selection</button>
283
+ </div>
284
+ </div>
285
+ </div>
286
+ {% endif %}
287
+ {% if filter_menu %}
288
+ <div id="filter-menu" class="card-header">
289
+ <div class="row no-gutters">
290
+ <div class="col-3 pb-2">
291
+ <select
292
+ class="form-select"
293
+ aria-label="Default select example"
294
+ onchange="updateFilter(value, 'item')"
295
+ id="select-item"
296
+ >
297
+ <option value="">Select a network item</option>
298
+ <option value="edge">edge</option>
299
+ <option value="node">node</option>
300
+ </select>
301
+ </div>
302
+ <div class="col-3 pb-2">
303
+ <select
304
+ class="form-select"
305
+ aria-label="Default select example"
306
+ onchange="updateFilter(value, 'property')"
307
+ id="select-property"
308
+ >
309
+ <option value="">Select a property...</option>
310
+ </select>
311
+ </div>
312
+ <div class="col-3 pb-2">
313
+ <select
314
+ class="form-select"
315
+ aria-label="Default select example"
316
+ id="select-value"
317
+ >
318
+ <option value="">Select value(s)...</option>
319
+ </select>
320
+ </div>
321
+ <div class="col-1 pb-2">
322
+ <button type="button" class="btn btn-primary btn-block" onclick="highlightFilter(filter);">Filter</button>
323
+ </div>
324
+ <div class="col-2 pb-2">
325
+ <button type="button" class="btn btn-primary btn-block" onclick="clearFilter(true)">Reset Selection</button>
326
+ </div>
327
+ </div>
328
+ </div>
329
+ {% endif %}
330
+
331
+ <div class="left-panel" id="leftPanel">
332
+ <button class="collapse-btn" onclick="togglePanel('leftPanel')">
333
+ <svg width="28px" height="28px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
334
+ <path d="M 11 3.9 V 20.3 M 6 7.4 H 8 M 6 10.9 H 8 M 6 14.5 H 8 M 6.2 20.3 H 17.8 C 18.9 20.3 19.5 20.3 19.9 20.1 C 20.3 19.8 20.6 19.5 20.8 19 C 21 18.6 21 17.9 21 16.6 V 7.7 C 21 6.4 21 5.7 20.8 5.2 C 20.6 4.7 20.3 4.4 19.9 4.1 C 19.5 3.9 18.9 3.9 17.8 3.9 H 6.2 C 5.1 3.9 4.5 3.9 4.1 4.1 C 3.7 4.4 3.4 4.7 3.2 5.2 C 3 5.7 3 6.4 3 7.7 V 16.6 C 3 17.9 3 18.6 3.2 19 C 3.4 19.5 3.7 19.8 4.1 20.1 C 4.5 20.3 5.1 20.3 6.2 20.3 Z" stroke="whitesmoke" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
335
+ </svg>
336
+ </button>
337
+
338
+ <div class="panel-content">
339
+
340
+ <button class="physics-btn" id="btn_physics" >Physics: ON</button>
341
+ <button class="save-btn" id="btn_save_node_positions" >Save</button>
342
+ <button class="reset-btn" id="btn_reset_preferences" >Reset</button>
343
+
344
+ <span id="text_gravitationalConstant" style="
345
+ opacity: 0.9;
346
+ top: 0px;
347
+ left: 0px;
348
+ position: relative;
349
+ font-size: 16px;
350
+ font-weight: bold;
351
+ color: #4CAF50;">
352
+ Gravitational Constant
353
+ </span>
354
+ <input id="slider_gravitationalConstant"
355
+ type="range"
356
+ min="-5000"
357
+ max="1100"
358
+ style="
359
+ color: gray;
360
+ opacity: 0.5;
361
+ width: 200px;">
362
+ </input>
363
+
364
+ <span id="text_centralGravity" style="
365
+ opacity: 0.9;
366
+ top: 0px;
367
+ left: 0px;
368
+ position: relative;
369
+ font-size: 16px;
370
+ font-weight: bold;
371
+ color: #4CAF50;">
372
+ CentralGravity
373
+ </span>
374
+ <input id="slider_centralGravity"
375
+ type="range"
376
+ min="0"
377
+ max="100"
378
+ style="
379
+ opacity: 0.5;
380
+ width: 200px;">
381
+ </input>
382
+
383
+ <span id="text_springConstant" style="
384
+ opacity: 0.9;
385
+ top: 0px;
386
+ left: 0px;
387
+ position: relative;
388
+ font-size: 16px;
389
+ font-weight: bold;
390
+ color: #4CAF50;">
391
+ Spring Constant
392
+ </span>
393
+ <input id="slider_springConstant"
394
+ type="range"
395
+ min="0"
396
+ max="100"
397
+ style="
398
+ opacity: 0.5;
399
+ width: 200px;">
400
+ </input>
401
+
402
+ <span id="text_damping" style="
403
+ opacity: 0.9;
404
+ top: 0px;
405
+ left: 0px;
406
+ position: relative;
407
+ font-size: 16px;
408
+ font-weight: bold;
409
+ color: #4CAF50;">
410
+ Damping
411
+ </span>
412
+ <input id="slider_damping"
413
+ type="range"
414
+ min="0"
415
+ max="50"
416
+ style="
417
+ opacity: 0.5;
418
+ width: 200px;">
419
+ </input>
420
+
421
+ <span id="text_fontSize" style="
422
+ opacity: 0.9;
423
+ top: 0px;
424
+ left: 0px;
425
+ position: relative;
426
+ font-size: 16px;
427
+ font-weight: bold;
428
+ color: #4CAF50;">
429
+ Font Size
430
+ </span>
431
+ <input id="slider_fontSize"
432
+ type="range"
433
+ min="30"
434
+ max="200"
435
+ style="
436
+ opacity: 0.5;
437
+ width: 200px;">
438
+ </input>
439
+
440
+ <span id="text_nodeSize" style="
441
+ opacity: 0.9;
442
+ top: 0px;
443
+ left: 0px;
444
+ position: relative;
445
+ font-size: 16px;
446
+ font-weight: bold;
447
+ color: #4CAF50;">
448
+ Node Size
449
+ </span>
450
+ <input id="slider_nodeSize"
451
+ type="range"
452
+ min="1"
453
+ max="100"
454
+ style="
455
+ opacity: 0.5;
456
+ width: 200px;">
457
+ </input>
458
+
459
+ <span id="text_edgeLength" style="
460
+ opacity: 0.9;
461
+ top: 0px;
462
+ left: 0px;
463
+ position: relative;
464
+ font-size: 16px;
465
+ font-weight: bold;
466
+ color: #4CAF50;">
467
+ Edge Length
468
+ </span>
469
+ <input id="slider_edgeLength"
470
+ type="range"
471
+ min="1"
472
+ max="100"
473
+ style="
474
+ opacity: 0.5;
475
+ width: 200px;">
476
+ </input>
477
+
478
+
479
+ <span id="text_edgeWidth" style="
480
+ opacity: 0.9;
481
+ top: 0px;
482
+ left: 0px;
483
+ position: relative;
484
+ font-size: 16px;
485
+ font-weight: bold;
486
+ color: #4CAF50;">
487
+ Edge Width
488
+ </span>
489
+ <input id="slider_edgeWidth"
490
+ type="range"
491
+ min="1"
492
+ max="100"
493
+ style="
494
+ opacity: 0.5;
495
+ width: 200px;">
496
+ </input>
497
+
498
+ </div>
499
+ </div>
500
+
501
+
502
+ <div id="mynetwork" class="card-body"></div>
503
+ </div>
504
+
505
+
506
+ {% if conf %}
507
+ <div id="config"></div>
508
+ {% endif %}
509
+
510
+ <script>
511
+ function togglePanel(panelId) {
512
+ const panel = document.getElementById(panelId);
513
+ panel.classList.toggle('collapsed');
514
+
515
+ //// Update button text based on panel state
516
+ // const button = panel.querySelector('.collapse-btn');
517
+ // if (panelId === 'leftPanel') {
518
+ // button.image = "./_sources/svgs/sidebar.svg";
519
+ // // button.textContent = panel.classList.contains('collapsed') ? '' : '';
520
+ // } else {
521
+ // button.image = "./_sources/svgs/sidebar.svg";
522
+ // // button.textContent = panel.classList.contains('collapsed') ? '' : '';
523
+ // }
524
+ }
525
+
526
+ togglePanel('leftPanel');
527
+ </script>
528
+
529
+ <script type="text/javascript">
530
+
531
+ // initialize global variables.
532
+ var edges;
533
+ var nodes;
534
+ var allNodes;
535
+ var allEdges;
536
+ var nodeColors;
537
+ var originalNodes;
538
+ var network;
539
+ var container;
540
+ var options, data;
541
+ var filter = {
542
+ item : '',
543
+ property : '',
544
+ value : []
545
+ };
546
+
547
+ {% if select_menu %}
548
+ new TomSelect("#select-node",{
549
+ create: false,
550
+ sortField: {
551
+ field: "text",
552
+ direction: "asc"
553
+ }
554
+ });
555
+ {% endif %}
556
+
557
+ {% if filter_menu %}
558
+ // explicitly using onItemAdd and this function as we need to save multiple values
559
+ let updateValueFilter = function() {
560
+ return function () {
561
+ filter['value'].push(arguments[0])
562
+ }
563
+ }
564
+
565
+ let valueControl = new TomSelect("#select-value",{
566
+ maxItems: null,
567
+ valueField: 'id',
568
+ labelField: 'title',
569
+ searchField: 'title',
570
+ create: false,
571
+ sortField: {
572
+ field: "text",
573
+ direction: "asc"
574
+ },
575
+ onItemAdd: updateValueFilter()
576
+ });
577
+
578
+ let addValues = function() {
579
+ return function () {
580
+ // clear the current value options and add the selected attribute values
581
+ // tom-select handles duplicates
582
+ let selectedProperty = arguments[0];
583
+ valueControl.clear();
584
+ valueControl.clearOptions();
585
+ filter['value'] = []
586
+ if (filter['item'] === 'node') {
587
+ for (let each in allNodes) {
588
+ valueControl.addOption({
589
+ id:allNodes[each][selectedProperty],
590
+ title:allNodes[each][selectedProperty]
591
+ })
592
+ }
593
+ }
594
+ else if (filter['item'] === 'edge') {
595
+ for (let each in allEdges) {
596
+ valueControl.addOption({
597
+ id:allEdges[each][selectedProperty],
598
+ title:allEdges[each][selectedProperty]
599
+ })
600
+ }
601
+ }
602
+ }
603
+ };
604
+
605
+ let propControl = new TomSelect("#select-property",{
606
+ valueField: 'id',
607
+ labelField: 'title',
608
+ searchField: 'title',
609
+ create: false,
610
+ sortField: {
611
+ field: "text",
612
+ direction: "asc"
613
+ },
614
+ onItemAdd: addValues()
615
+ });
616
+
617
+ let addProperties = function() {
618
+ return function () {
619
+ // loops through the selected network item and adds the attributes to dropdown
620
+ // tom-select handles duplicates
621
+ clearFilter(false)
622
+ if (arguments[0] === 'edge') {
623
+ for (let each in allEdges) {
624
+ if (allEdges.hasOwnProperty(each)) {
625
+ for (let eachProp in allEdges[each]) {
626
+ if (allEdges[each].hasOwnProperty(eachProp)) {
627
+ propControl.addOption({id: eachProp, title: eachProp})
628
+ }
629
+ }
630
+ }
631
+ }
632
+ }
633
+ else if (arguments[0] === 'node') {
634
+ for (let each in allNodes) {
635
+ if (allNodes.hasOwnProperty(each)) {
636
+ for (let eachProp in allNodes[each]) {
637
+ if (allNodes[each].hasOwnProperty(eachProp)
638
+ && (eachProp !== 'hidden' && eachProp !== 'savedLabel'
639
+ && eachProp !== 'hiddenLabel')) {
640
+ propControl.addOption({id: eachProp, title: eachProp})
641
+
642
+ }
643
+ }
644
+ }
645
+ }
646
+ }
647
+ }
648
+ };
649
+
650
+ let itemControl = new TomSelect("#select-item",{
651
+ create: false,
652
+ sortField:{
653
+ field: "text",
654
+ direction: "asc"
655
+ },
656
+ onItemAdd: addProperties()
657
+ });
658
+
659
+ function clearFilter(reset) {
660
+ // utility function to clear all the selected filter options
661
+ // if reset is set to true, the existing filter will be removed
662
+ // else, only the dropdown options are cleared
663
+ propControl.clear();
664
+ propControl.clearOptions();
665
+ valueControl.clear();
666
+ valueControl.clearOptions();
667
+ filter = {
668
+ item : '',
669
+ property : '',
670
+ value : []
671
+ }
672
+ if (reset) {
673
+ itemControl.clear();
674
+ filterHighlight({nodes: []})
675
+ }
676
+ }
677
+
678
+ function updateFilter(value, key) {
679
+ // key could be 'item' or 'property' and value is as selected in dropdown
680
+ filter[key] = value
681
+ }
682
+
683
+ {% endif %}
684
+
685
+ // This method is responsible for drawing the graph, returns the drawn network
686
+ function drawGraph() {
687
+ var container = document.getElementById('mynetwork');
688
+
689
+ {% if use_DOT %}
690
+
691
+ var DOTstring = "{{dot_lang|safe}}";
692
+ var parsedData = vis.network.convertDot(DOTstring);
693
+
694
+ data = {
695
+ nodes: parsedData.nodes,
696
+ edges: parsedData.edges
697
+ }
698
+
699
+ var options = parsedData.options;
700
+ options.nodes = {
701
+ shape: "dot"
702
+ }
703
+
704
+ {% else %}
705
+
706
+ // parsing and collecting nodes and edges from the python
707
+ nodes = new vis.DataSet({{nodes|tojson}});
708
+ edges = new vis.DataSet({{edges|tojson}});
709
+
710
+ nodeColors = {};
711
+ allNodes = nodes.get({ returnType: "Object" });
712
+ for (nodeId in allNodes) {
713
+ nodeColors[nodeId] = allNodes[nodeId].color;
714
+ }
715
+
716
+ // load node positions
717
+ var node_positions = {};
718
+ function saveNodePositions(){
719
+ localStorage.setItem('node_positions', JSON.stringify(node_positions));
720
+ }
721
+ const savedPositions = localStorage.getItem('node_positions');
722
+ if (savedPositions) {
723
+ const positions = JSON.parse(savedPositions);
724
+ // Update each node with its saved po
725
+ Object.keys(positions).forEach(nodeId => {
726
+ if (nodeId in allNodes){
727
+ allNodes[nodeId].x = positions[nodeId].x;
728
+ allNodes[nodeId].y = positions[nodeId].y;
729
+ }
730
+ });
731
+ }
732
+
733
+ allEdges = edges.get({ returnType: "Object" });
734
+ // adding nodes and edges to the graph
735
+ data = {nodes: nodes, edges: edges};
736
+
737
+ var options = {{options|safe}};
738
+
739
+ {% endif %}
740
+
741
+
742
+ {% if conf %}
743
+ // if this network requires displaying the configure window,
744
+ // put it in its div
745
+ options.configure["container"] = document.getElementById("config");
746
+ {% endif %}
747
+
748
+
749
+ var viewState = {};
750
+
751
+ var default_preferences = {
752
+ "centralGravity": 8,
753
+ "damping": 20,
754
+ "edgeLength": 4,
755
+ "edgeWidth": 6,
756
+ "fontSize": 43,
757
+ "gravitationalConstant": 437,
758
+ "nodeSize": 11,
759
+ "physics": true,
760
+ "springConstant": 5,
761
+ };
762
+
763
+ var preferences = {
764
+ "centralGravity": 8,
765
+ "damping": 20,
766
+ "edgeLength": 4,
767
+ "edgeWidth": 6,
768
+ "fontSize": 43,
769
+ "gravitationalConstant": 437,
770
+ "nodeSize": 11,
771
+ "physics": true,
772
+ "springConstant": 5,
773
+ };
774
+
775
+ storedPreferences = localStorage.getItem('preferences');
776
+ if (storedPreferences !== null) {
777
+ var savedPreferences = JSON.parse(storedPreferences);
778
+ preferences = savedPreferences;
779
+ }
780
+
781
+ const left_panel = document.getElementById('leftPanel');
782
+ const left_panel_content = left_panel.querySelector('.panel-content');
783
+
784
+ network = new vis.Network(container, data, options);
785
+ network.on("click", function(params) {
786
+ if (params.nodes.length > 0) {
787
+ var node = this.body.data.nodes.get(params.nodes[0]);
788
+ if (node.url) {
789
+ if (params.event.srcEvent.ctrlKey) {
790
+ window.open(node.url, '_blank');
791
+ }else {
792
+ window.location.href = node.url;
793
+ }
794
+ }
795
+ }
796
+ toggleSaveNodePositions()
797
+ });
798
+
799
+ function loadViewState(){
800
+ var savedState = JSON.parse(localStorage.getItem('networkViewState'));
801
+ if (savedState) {
802
+ network.moveTo({
803
+ position: savedState.position,
804
+ scale: savedState.scale
805
+ });
806
+ }
807
+ }
808
+
809
+ function saveViewState(){
810
+ var viewPosition = network.getViewPosition();
811
+ var scale = network.getScale();
812
+ var viewState = {
813
+ position: viewPosition,
814
+ scale: scale
815
+ };
816
+ localStorage.setItem('networkViewState', JSON.stringify(viewState));
817
+ }
818
+
819
+ function savePreferences(){
820
+ localStorage.setItem('preferences', JSON.stringify(preferences));
821
+ }
822
+
823
+ function loadPhysics(){
824
+ var btn = document.getElementById('btn_physics');
825
+ if (preferences.physics == true) {
826
+ network.setOptions( { physics: true } );
827
+ btn.innerHTML = 'Physics: ON';
828
+ } else {
829
+ network.setOptions( { physics: false } );
830
+ btn.innerHTML = 'Physics: OFF';
831
+ }
832
+ }
833
+
834
+ // Add Button and Slider to Control the Physics
835
+ function togglePhysics() {
836
+ var btn = document.getElementById('btn_physics');
837
+ var physics = !network.physics.options.enabled;
838
+ network.physics.enabled = physics;
839
+
840
+ if (physics) {
841
+ preferences.physics = true;
842
+ network.setOptions( { physics: true } );
843
+ btn.innerHTML = 'Physics: ON';
844
+ } else {
845
+ preferences.physics = false;
846
+ network.setOptions( { physics: false } );
847
+ btn.innerHTML = 'Physics: OFF';
848
+ }
849
+ savePreferences();
850
+ }
851
+
852
+ // Physics
853
+ const btn_physics = document.getElementById('btn_physics');
854
+ btn_physics.onclick = togglePhysics;
855
+
856
+ // Save as Startup
857
+ const btn_save_node_positions = document.getElementById('btn_save_node_positions');
858
+ btn_save_node_positions.onclick = toggleSaveNodePositions;
859
+
860
+ function toggleSaveNodePositions() {
861
+ node_positions = network.getPositions();
862
+ saveNodePositions();
863
+ savePreferences();
864
+ saveViewState();
865
+ }
866
+
867
+ // Reset
868
+ const btn_reset_preferences = document.getElementById('btn_reset_preferences');
869
+ btn_reset_preferences.onclick = resetPreferences;
870
+
871
+ // gravitationalConstant
872
+ const slider_gravitationalConstant = document.getElementById('slider_gravitationalConstant');
873
+ slider_gravitationalConstant.value = preferences.gravitationalConstant;
874
+ slider_gravitationalConstant.oninput = on_slider_gravitationalConstant_input;
875
+
876
+ function on_slider_gravitationalConstant_input() {
877
+ var gravitationalConstant = document.getElementById('slider_gravitationalConstant').value;
878
+ preferences.gravitationalConstant = gravitationalConstant;
879
+ value = gravitationalConstant -1100;
880
+ network.setOptions( { physics: {"forceAtlas2Based": {gravitationalConstant: value} }} );
881
+ savePreferences();
882
+ }
883
+
884
+ // centralGravity
885
+ const slider_centralGravity = document.getElementById('slider_centralGravity');
886
+ slider_centralGravity.value = preferences.centralGravity;
887
+ slider_centralGravity.oninput = on_slider_centralGravity_input;
888
+
889
+ function on_slider_centralGravity_input() {
890
+ var centralGravity = document.getElementById('slider_centralGravity').value;
891
+ preferences.centralGravity = centralGravity;
892
+ value = centralGravity * 0.001;
893
+ network.setOptions( { physics: {"forceAtlas2Based": {centralGravity: value} }} );
894
+ savePreferences();
895
+ }
896
+
897
+ // sprintConstant
898
+ const slider_springConstant = document.getElementById('slider_springConstant');
899
+ slider_springConstant.value = preferences.springConstant;
900
+ slider_springConstant.oninput = on_slider_springConstant_input;
901
+
902
+ function on_slider_springConstant_input() {
903
+ var springConstant = document.getElementById('slider_springConstant').value;
904
+ preferences.springConstant = springConstant;
905
+ value = springConstant * 0.01;
906
+ network.setOptions( { physics: {"forceAtlas2Based": {springConstant: value} }} );
907
+ savePreferences();
908
+ }
909
+
910
+ // Damping
911
+ const slider_damping = document.getElementById('slider_damping');
912
+ slider_damping.value = preferences.damping;
913
+ slider_damping.oninput = on_slider_damping_input;
914
+
915
+ function on_slider_damping_input() {
916
+ var damping = document.getElementById('slider_damping').value;
917
+ preferences.damping = damping;
918
+ value = damping * 0.01;
919
+ network.setOptions( { physics: {"forceAtlas2Based": {damping: value} }} );
920
+ savePreferences();
921
+ }
922
+
923
+ // fontSize
924
+ const slider_fontSize = document.getElementById('slider_fontSize');
925
+ slider_fontSize.value = preferences.fontSize;
926
+ slider_fontSize.oninput = on_slider_fontSize_input;
927
+
928
+ function on_slider_fontSize_input() {
929
+ var font_size = document.getElementById('slider_fontSize').value;
930
+ preferences.fontSize = font_size;
931
+ network.setOptions( { nodes: {"font": {size: parseFloat(font_size)} }} );
932
+ savePreferences();
933
+ }
934
+
935
+ // nodeSize
936
+ const slider_nodeSize = document.getElementById('slider_nodeSize');
937
+ slider_nodeSize.value = preferences.nodeSize;
938
+ slider_nodeSize.oninput = on_slider_nodeSize_input;
939
+
940
+ var nodes_backup = data.nodes.get();
941
+
942
+ function on_slider_nodeSize_input() {
943
+ var node_size = document.getElementById('slider_nodeSize').value;
944
+ preferences.nodeSize = node_size;
945
+ value = node_size * 0.1;
946
+ data.nodes.update(nodes_backup);
947
+ var nodes = data.nodes.get();
948
+ for (var i = 0; i < nodes.length; i++) {
949
+ mysize = nodes[i].size * value
950
+ nodes[i].size = mysize;
951
+ }
952
+ data.nodes.update(nodes);
953
+ savePreferences();
954
+ }
955
+
956
+ // edgeLength
957
+ const slider_edgeLength = document.getElementById('slider_edgeLength');
958
+ slider_edgeLength.value = preferences.edgeLength;
959
+ slider_edgeLength.oninput = on_slider_edge_input;
960
+
961
+ // edgeWidth
962
+ const slider_edgeWidth = document.getElementById('slider_edgeWidth');
963
+ slider_edgeWidth.value = preferences.edgeWidth;
964
+ slider_edgeWidth.oninput = on_slider_edge_input;
965
+
966
+ var edges_backup = data.edges.get();
967
+
968
+ function on_slider_edge_input() {
969
+ var edge_length = document.getElementById('slider_edgeLength').value;
970
+ var edge_width = document.getElementById('slider_edgeWidth').value;
971
+ preferences.edgeLength = edge_length;
972
+ preferences.edgeWidth = edge_width;
973
+ data.edges.update(edges_backup);
974
+ var edges = data.edges.get();
975
+ for (var i = 0; i < edges.length; i++) {
976
+ edges[i].length = edges[i].length * edge_length * 0.1;
977
+ edges[i].width = edges[i].width * edge_width * 0.1;
978
+ }
979
+ data.edges.update(edges);
980
+ savePreferences();
981
+ };
982
+
983
+ function loadPreferences(){
984
+ on_slider_gravitationalConstant_input();
985
+ on_slider_centralGravity_input();
986
+ on_slider_springConstant_input();
987
+ on_slider_damping_input();
988
+ on_slider_fontSize_input();
989
+ on_slider_nodeSize_input();
990
+ on_slider_edge_input();
991
+ loadPhysics();
992
+ loadViewState();
993
+ }
994
+
995
+ function resetPreferences(){
996
+ document.getElementById('btn_physics').value = default_preferences.physics;
997
+ document.getElementById('slider_gravitationalConstant').value = default_preferences.gravitationalConstant;
998
+ document.getElementById('slider_centralGravity').value = default_preferences.centralGravity;
999
+ document.getElementById('slider_springConstant').value = default_preferences.springConstant;
1000
+ document.getElementById('slider_damping').value = default_preferences.damping;
1001
+ document.getElementById('slider_fontSize').value = default_preferences.fontSize;
1002
+ document.getElementById('slider_nodeSize').value = default_preferences.nodeSize;
1003
+ document.getElementById('slider_edgeLength').value = default_preferences.edgeLength;
1004
+ document.getElementById('slider_edgeWidth').value = default_preferences.edgeWidth;
1005
+
1006
+ allNodes = nodes.get({ returnType: "Object" });
1007
+ for (nodeId in allNodes) {
1008
+ nodeColors[nodeId] = allNodes[nodeId].color;
1009
+ }
1010
+ data = {nodes: nodes, edges: edges};
1011
+
1012
+ network = new vis.Network(container, data, options);
1013
+ network.on("click", function(params) {
1014
+ if (params.nodes.length > 0) {
1015
+ var node = this.body.data.nodes.get(params.nodes[0]);
1016
+ if (node.url) {
1017
+ if (params.event.srcEvent.ctrlKey) {
1018
+ window.open(node.url, '_blank');
1019
+ }else {
1020
+ window.location.href = node.url;
1021
+ }
1022
+ }
1023
+ }
1024
+ toggleSaveNodePositions()
1025
+ });
1026
+
1027
+ viewState = {"position":{"x":122.26498687735877,"y":1344.4657619150016},"scale":0.14563667453404308}
1028
+ localStorage.setItem('networkViewState', JSON.stringify(viewState));
1029
+ network.moveTo({
1030
+ position: viewState.position,
1031
+ scale: viewState.scale
1032
+ });
1033
+
1034
+ // preferences.physics = true;
1035
+
1036
+ node_positions = {};
1037
+ saveNodePositions();
1038
+
1039
+ preferences = {
1040
+ "centralGravity": 8,
1041
+ "damping": 20,
1042
+ "edgeLength": 4,
1043
+ "edgeWidth": 6,
1044
+ "fontSize": 43,
1045
+ "gravitationalConstant": 437,
1046
+ "nodeSize": 11,
1047
+ "physics": true,
1048
+ "springConstant": 5,
1049
+ };
1050
+ savePreferences();
1051
+
1052
+ loadPreferences();
1053
+ }
1054
+
1055
+ loadPreferences();
1056
+
1057
+ // seet physic on / off by dragStart dragEnd
1058
+ // network.on("dragStart", function(params) {
1059
+ // if (params.nodes.length > 0) {
1060
+ // network.setOptions( { physics: true } );
1061
+ // }
1062
+ // });
1063
+
1064
+ // network.on("dragEnd", function(params) {
1065
+ // if (params.nodes.length > 0) {
1066
+
1067
+ // network.setOptions( { physics: false } );
1068
+
1069
+ // }
1070
+ // });
1071
+
1072
+ // setTimeout(function() {
1073
+ // network.setOptions( { physics: false } );
1074
+ // }, 12000);
1075
+
1076
+
1077
+
1078
+
1079
+ {% if neighborhood_highlight %}
1080
+ network.on("click", neighbourhoodHighlight);
1081
+ {% endif %}
1082
+
1083
+ {% if select_menu %}
1084
+ network.on("selectNode", neighbourhoodHighlight);
1085
+ {% endif %}
1086
+
1087
+ {% if tooltip_link %}
1088
+ // make a custom popup
1089
+ var popup = document.createElement("div");
1090
+ popup.className = 'popup';
1091
+ popupTimeout = null;
1092
+ popup.addEventListener('mouseover', function () {
1093
+ console.log(popup)
1094
+ if (popupTimeout !== null) {
1095
+ clearTimeout(popupTimeout);
1096
+ popupTimeout = null;
1097
+ }
1098
+ });
1099
+ popup.addEventListener('mouseout', function () {
1100
+ if (popupTimeout === null) {
1101
+ hidePopup();
1102
+ }
1103
+ });
1104
+ container.appendChild(popup);
1105
+
1106
+
1107
+ // use the popup event to show
1108
+ network.on("showPopup", function (params) {
1109
+ showPopup(params);
1110
+ });
1111
+
1112
+ // use the hide event to hide it
1113
+ network.on("hidePopup", function (params) {
1114
+ hidePopup();
1115
+ });
1116
+
1117
+ // hiding the popup through css
1118
+ function hidePopup() {
1119
+ popupTimeout = setTimeout(function () { popup.style.display = 'none'; }, 500);
1120
+ }
1121
+
1122
+ // showing the popup
1123
+ function showPopup(nodeId) {
1124
+ // get the data from the vis.DataSet
1125
+ var nodeData = nodes.get([nodeId]);
1126
+ popup.innerHTML = nodeData[0].title;
1127
+
1128
+ // get the position of the node
1129
+ var posCanvas = network.getPositions([nodeId])[nodeId];
1130
+
1131
+ // get the bounding box of the node
1132
+ var boundingBox = network.getBoundingBox(nodeId);
1133
+
1134
+ //position tooltip:
1135
+ posCanvas.x = posCanvas.x + 0.5 * (boundingBox.right - boundingBox.left);
1136
+
1137
+ // convert coordinates to the DOM space
1138
+ var posDOM = network.canvasToDOM(posCanvas);
1139
+
1140
+ // Give it an offset
1141
+ posDOM.x += 10;
1142
+ posDOM.y -= 20;
1143
+
1144
+ // show and place the tooltip.
1145
+ popup.style.display = 'block';
1146
+ popup.style.top = posDOM.y + 'px';
1147
+ popup.style.left = posDOM.x + 'px';
1148
+ }
1149
+ {% endif %}
1150
+
1151
+
1152
+ return network;
1153
+
1154
+ }
1155
+ drawGraph();
1156
+ </script>
1157
+ </body>
1158
+ </html>