@@ -79,6 +79,7 @@ export class ForceView extends DOMWidgetView {
79
79
private expandDiv : HTMLDivElement = document . createElement ( "div" ) ;
80
80
private searchDiv : HTMLDivElement = document . createElement ( "div" ) ;
81
81
private detailsDiv : HTMLDivElement = document . createElement ( "div" ) ;
82
+ private physicsDiv : HTMLDivElement = document . createElement ( "div" ) ;
82
83
private nodeDataset : NodeDataSet = new NodeDataSet ( new Array < VisNode > ( ) , { } ) ;
83
84
private edgeDataset : EdgeDataSet = new EdgeDataSet ( new Array < VisEdge > ( ) , { } ) ;
84
85
private visOptions : DynamicObject = { } ;
@@ -105,6 +106,7 @@ export class ForceView extends DOMWidgetView {
105
106
} ;
106
107
private detailsBtn = document . createElement ( "button" ) ;
107
108
private selectedNodeID : string | number = "" ;
109
+ private physicsBtn = document . createElement ( "button" ) ;
108
110
109
111
render ( ) : void {
110
112
this . networkDiv . classList . add ( "network-div" ) ;
@@ -140,7 +142,7 @@ export class ForceView extends DOMWidgetView {
140
142
this . vis = new Network ( this . canvasDiv , dataset , this . visOptions ) ;
141
143
setTimeout ( ( ) => {
142
144
this . vis ?. stopSimulation ( ) ;
143
- } , 1500 ) ; // TODO: make the timeout configurable
145
+ } , this . visOptions . physics . simulationDuration ) ;
144
146
145
147
/*
146
148
To listen to messages sent from the kernel, you can register callback methods in the view class,
@@ -268,7 +270,6 @@ export class ForceView extends DOMWidgetView {
268
270
// no label found, using node id
269
271
node [ "label" ] = id ;
270
272
}
271
-
272
273
this . nodeDataset . update ( [ node ] ) ;
273
274
return ;
274
275
}
@@ -345,7 +346,7 @@ export class ForceView extends DOMWidgetView {
345
346
"data": {
346
347
"label": "to"
347
348
}
348
- }
349
+ }
349
350
*/
350
351
addEdge ( msgData : DynamicObject ) : void {
351
352
// To be able to add an edge, we require the message to have:
@@ -465,14 +466,23 @@ export class ForceView extends DOMWidgetView {
465
466
this . vis ?. on ( "startStabilizing" , ( ) => {
466
467
setTimeout ( ( ) => {
467
468
this . vis ?. stopSimulation ( ) ;
468
- } , 1500 ) ; // TODO: make timeout configurable
469
+ } , this . visOptions . physics . simulationDuration ) ;
469
470
} ) ;
470
471
471
472
this . vis ?. on ( "selectEdge" , ( params ) => {
472
473
params . edges . forEach ( ( value ) => {
473
474
this . handleEdgeClick ( params . edges [ 0 ] ) ;
474
475
} ) ;
475
476
} ) ;
477
+
478
+ this . vis ?. on ( "stabilized" , ( ) => {
479
+ if (
480
+ this . visOptions . physics . disablePhysicsAfterInitialSimulation == true
481
+ ) {
482
+ this . visOptions . physics . enabled = false ;
483
+ this . changeOptions ( ) ;
484
+ }
485
+ } ) ;
476
486
}
477
487
478
488
/**
@@ -495,7 +505,7 @@ export class ForceView extends DOMWidgetView {
495
505
} else {
496
506
node . color = this . visOptions . nodes . color ;
497
507
}
498
- node . borderWidth = 0
508
+ node . borderWidth = 0 ;
499
509
this . nodeDataset . update ( node ) ;
500
510
this . vis ?. stopSimulation ( ) ;
501
511
this . selectedNodeID = "" ;
@@ -569,7 +579,7 @@ export class ForceView extends DOMWidgetView {
569
579
buildTableRows ( data : DynamicObject ) : Array < HTMLElement > {
570
580
const rows : Array < HTMLElement > = new Array < HTMLElement > ( ) ;
571
581
const sorted = Object . entries ( data ) . sort ( ( a , b ) => {
572
- return a [ 0 ] . localeCompare ( b [ 0 ] ) ;
582
+ return a [ 0 ] . localeCompare ( b [ 0 ] ) ;
573
583
} ) ;
574
584
sorted . forEach ( ( entry : Array < any > ) => {
575
585
const row = document . createElement ( "tr" ) ;
@@ -620,11 +630,11 @@ export class ForceView extends DOMWidgetView {
620
630
621
631
this . buildGraphPropertiesTable ( node ) ;
622
632
if ( node . group ) {
623
- node . font = { bold : true } ;
624
- node . opacity = 1
625
- node . borderWidth = 3
633
+ node . font = { bold : true } ;
634
+ node . opacity = 1 ;
635
+ node . borderWidth = 3 ;
626
636
} else {
627
- node . font = { color : "white" } ;
637
+ node . font = { color : "white" } ;
628
638
}
629
639
this . nodeDataset . update ( node ) ;
630
640
this . vis ?. stopSimulation ( ) ;
@@ -702,17 +712,17 @@ export class ForceView extends DOMWidgetView {
702
712
}
703
713
} ) ;
704
714
} else {
705
- //Reset the opacity and border width
706
- this . nodeDataset . forEach ( ( item , id ) => {
707
- const nodeID = id . toString ( ) ;
708
- nodeUpdate . push ( {
709
- id : nodeID ,
710
- opacity : 1 ,
711
- borderWidth : 0
712
- } ) ;
713
- nodeIDs [ id . toString ( ) ] = true ;
714
- } )
715
- } ;
715
+ //Reset the opacity and border width
716
+ this . nodeDataset . forEach ( ( item , id ) => {
717
+ const nodeID = id . toString ( ) ;
718
+ nodeUpdate . push ( {
719
+ id : nodeID ,
720
+ opacity : 1 ,
721
+ borderWidth : 0 ,
722
+ } ) ;
723
+ nodeIDs [ id . toString ( ) ] = true ;
724
+ } ) ;
725
+ }
716
726
717
727
// check current matched nodes and clear all nodes which are no longer matches
718
728
this . nodeIDSearchMatches . forEach ( ( value ) => {
@@ -725,7 +735,8 @@ export class ForceView extends DOMWidgetView {
725
735
borderWidth : selected
726
736
? this . visOptions [ "nodes" ] [ "borderWidthSelected" ]
727
737
: 0 ,
728
- opacity : 0.35 } ) ;
738
+ opacity : 0.35 ,
739
+ } ) ;
729
740
}
730
741
} ) ;
731
742
@@ -766,6 +777,7 @@ export class ForceView extends DOMWidgetView {
766
777
this . expandDiv . classList . add ( "menu-action" , "expand-div" ) ;
767
778
this . searchDiv . classList . add ( "menu-action" , "search-div" ) ;
768
779
this . detailsDiv . classList . add ( "menu-action" , "details-div" ) ;
780
+ this . physicsDiv . classList . add ( "menu-action" , "physics-div" ) ;
769
781
770
782
const searchInput = document . createElement ( "input" ) ;
771
783
searchInput . classList . add ( "search-bar" ) ;
@@ -778,6 +790,29 @@ export class ForceView extends DOMWidgetView {
778
790
this . searchDiv . append ( searchInput ) ;
779
791
rightActions . append ( this . searchDiv ) ;
780
792
793
+ this . physicsBtn . title = "Enable/Disable Graph Physics" ;
794
+ if (
795
+ this . visOptions . physics . enabled == true &&
796
+ this . visOptions . physics . disablePhysicsAfterInitialSimulation == false
797
+ ) {
798
+ this . physicsBtn . innerHTML = feather . icons [ "unlock" ] . toSvg ( ) ;
799
+ } else {
800
+ this . physicsBtn . innerHTML = feather . icons [ "lock" ] . toSvg ( ) ;
801
+ }
802
+ this . physicsDiv . appendChild ( this . physicsBtn ) ;
803
+ rightActions . append ( this . physicsDiv ) ;
804
+
805
+ this . physicsBtn . onclick = ( ) : void => {
806
+ this . visOptions . physics . disablePhysicsAfterInitialSimulation = false ;
807
+ this . visOptions . physics . enabled = ! this . visOptions . physics . enabled ;
808
+ this . changeOptions ( ) ;
809
+ if ( this . visOptions . physics . enabled == true ) {
810
+ this . physicsBtn . innerHTML = feather . icons [ "unlock" ] . toSvg ( ) ;
811
+ } else {
812
+ this . physicsBtn . innerHTML = feather . icons [ "lock" ] . toSvg ( ) ;
813
+ }
814
+ } ;
815
+
781
816
this . detailsBtn . innerHTML = feather . icons [ "list" ] . toSvg ( ) ;
782
817
this . detailsBtn . title = "Details" ;
783
818
this . detailsDiv . appendChild ( this . detailsBtn ) ;
@@ -865,7 +900,6 @@ export class ForceView extends DOMWidgetView {
865
900
animation : true ,
866
901
} ) ;
867
902
} ;
868
-
869
903
const zoomOutButton = document . createElement ( "button" ) ;
870
904
zoomOutButton . title = "Zoom Out" ;
871
905
zoomOutButton . onclick = ( ) => {
0 commit comments