@@ -54,3 +54,86 @@ export const setNodeLocation = (
54
54
return "translate(" + xPosition + "," + yPosition + ")" ;
55
55
}
56
56
} ;
57
+
58
+ // RefreshQueue ensures that don't run a refresh while another refresh
59
+ // is in transition.
60
+ export class RefreshQueue {
61
+ // The queue is an array that contains objects. Each object represents an
62
+ // refresh action and only they have 2 properties:
63
+ // {
64
+ // callback: triggers when it's the first of queue and then it
65
+ // becomes null to prevent that callback executes more
66
+ // than once.
67
+ // delayNextCallback: when callback is executed, queue will subtracts
68
+ // milliseconds from it. When it becomes 0, the entire
69
+ // object is destroyed (shifted) from the array and then
70
+ // the next item (if exists) will be executed similary
71
+ // to this.
72
+ // }
73
+ private static queue : Array < { delayNextCallback : number , callback : any } > = [ ] ;
74
+
75
+ // Contains setInterval ID
76
+ private static runner : number ;
77
+
78
+ // Milliseconds of each iteration
79
+ private static runnerSpeed : number = 100 ;
80
+
81
+ // Developer internal magic number. Time added at end of refresh transition to
82
+ // let DOM and d3 rest before another refresh.
83
+ // 0 creates console and visual errors because getFirstDisplayedAncestor never
84
+ // found the needed id and setNodeLocation receives undefined parameters.
85
+ // Between 50 and 100 milliseconds seems enough for 10 nodes (demo example)
86
+ private static readonly extraDelayBetweenCallbacks : number = 100 ;
87
+
88
+ // Developer internal for debugging RefreshQueue class. Set true to see
89
+ // console "real time" queue of tasks.
90
+ // If there is a cleaner method, remove it!
91
+ private static showQueueLog : boolean = false ;
92
+
93
+ // Adds one refresh action to the queue. When safe callback will be
94
+ // triggered
95
+ public static add ( duration : number , callback : ( ) => any ) {
96
+ this . queue . push (
97
+ {
98
+ delayNextCallback : duration + this . extraDelayBetweenCallbacks ,
99
+ callback : callback
100
+ } ) ;
101
+ this . log ( this . queue . map ( _ => _ . delayNextCallback ) , "<-- New task !!!" ) ;
102
+ if ( ! this . runner ) {
103
+ this . runnerFunction ( ) ;
104
+ //@ts -ignore
105
+ this . runner = setInterval ( ( ) => this . runnerFunction ( ) , this . runnerSpeed ) ;
106
+ }
107
+ }
108
+
109
+ // Each this.runnerSpeed milliseconds it's executed. It stops when finish.
110
+ private static runnerFunction ( ) {
111
+ if ( this . queue [ 0 ] ) {
112
+ // ************************ Callback section ************************
113
+ if ( this . queue [ 0 ] . callback ) {
114
+ this . log ( "Executing task, delaying next task..." ) ;
115
+ try {
116
+ this . queue [ 0 ] . callback ( ) ;
117
+ } catch ( e ) {
118
+ console . error ( e ) ;
119
+ } finally {
120
+ // To prevent trigger callback more than once
121
+ this . queue [ 0 ] . callback = null ;
122
+ }
123
+ }
124
+ // ******************** Delay until next callback ********************
125
+ this . queue [ 0 ] . delayNextCallback -= this . runnerSpeed ;
126
+ this . log ( this . queue . map ( _ => _ . delayNextCallback ) ) ;
127
+ if ( this . queue [ 0 ] . delayNextCallback <= 0 ) {
128
+ this . queue . shift ( ) ;
129
+ }
130
+ } else {
131
+ this . log ( "No task found" ) ;
132
+ clearInterval ( this . runner ) ;
133
+ this . runner = 0 ;
134
+ }
135
+ } ;
136
+
137
+ // Print to console debug data if this.showQueueLog = true
138
+ private static log ( ...msg : any ) { if ( this . showQueueLog ) console . log ( ...msg ) }
139
+ }
0 commit comments