vis-rails 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +5 -13
  2. data/lib/vis/rails/version.rb +1 -1
  3. data/vendor/assets/component/emitter.js +162 -0
  4. data/vendor/assets/javascripts/vis.js +1 -0
  5. data/vendor/assets/vis/DataSet.js +8 -2
  6. data/vendor/assets/vis/DataView.js +8 -4
  7. data/vendor/assets/vis/graph/Edge.js +210 -78
  8. data/vendor/assets/vis/graph/Graph.js +474 -652
  9. data/vendor/assets/vis/graph/Node.js +119 -82
  10. data/vendor/assets/vis/graph/css/graph-manipulation.css +128 -0
  11. data/vendor/assets/vis/graph/css/graph-navigation.css +62 -0
  12. data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +1141 -0
  13. data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +296 -0
  14. data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +433 -0
  15. data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +201 -0
  16. data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +173 -0
  17. data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +552 -0
  18. data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +558 -0
  19. data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +373 -0
  20. data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +64 -0
  21. data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +513 -0
  22. data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +66 -0
  23. data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
  24. data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
  25. data/vendor/assets/vis/graph/img/backIcon.png +0 -0
  26. data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
  27. data/vendor/assets/vis/graph/img/cross.png +0 -0
  28. data/vendor/assets/vis/graph/img/cross2.png +0 -0
  29. data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
  30. data/vendor/assets/vis/graph/img/downArrow.png +0 -0
  31. data/vendor/assets/vis/graph/img/editIcon.png +0 -0
  32. data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
  33. data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
  34. data/vendor/assets/vis/graph/img/upArrow.png +0 -0
  35. data/vendor/assets/vis/module/exports.js +0 -2
  36. data/vendor/assets/vis/module/header.js +2 -2
  37. data/vendor/assets/vis/module/imports.js +1 -2
  38. data/vendor/assets/vis/timeline/Controller.js +56 -45
  39. data/vendor/assets/vis/timeline/Range.js +68 -62
  40. data/vendor/assets/vis/timeline/Stack.js +11 -13
  41. data/vendor/assets/vis/timeline/TimeStep.js +43 -38
  42. data/vendor/assets/vis/timeline/Timeline.js +215 -93
  43. data/vendor/assets/vis/timeline/component/Component.js +19 -3
  44. data/vendor/assets/vis/timeline/component/CurrentTime.js +1 -1
  45. data/vendor/assets/vis/timeline/component/CustomTime.js +39 -120
  46. data/vendor/assets/vis/timeline/component/GroupSet.js +35 -1
  47. data/vendor/assets/vis/timeline/component/ItemSet.js +272 -9
  48. data/vendor/assets/vis/timeline/component/RootPanel.js +59 -47
  49. data/vendor/assets/vis/timeline/component/TimeAxis.js +10 -0
  50. data/vendor/assets/vis/timeline/component/css/item.css +53 -22
  51. data/vendor/assets/vis/timeline/component/item/Item.js +40 -5
  52. data/vendor/assets/vis/timeline/component/item/ItemBox.js +3 -1
  53. data/vendor/assets/vis/timeline/component/item/ItemPoint.js +3 -1
  54. data/vendor/assets/vis/timeline/component/item/ItemRange.js +67 -3
  55. data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +37 -9
  56. data/vendor/assets/vis/timeline/img/delete.png +0 -0
  57. data/vendor/assets/vis/util.js +169 -30
  58. metadata +39 -12
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Created by Alex on 2/10/14.
3
+ */
4
+
5
+
6
+ var graphMixinLoaders = {
7
+
8
+ /**
9
+ * Load a mixin into the graph object
10
+ *
11
+ * @param {Object} sourceVariable | this object has to contain functions.
12
+ * @private
13
+ */
14
+ _loadMixin : function(sourceVariable) {
15
+ for (var mixinFunction in sourceVariable) {
16
+ if (sourceVariable.hasOwnProperty(mixinFunction)) {
17
+ Graph.prototype[mixinFunction] = sourceVariable[mixinFunction];
18
+ }
19
+ }
20
+ },
21
+
22
+
23
+ /**
24
+ * removes a mixin from the graph object.
25
+ *
26
+ * @param {Object} sourceVariable | this object has to contain functions.
27
+ * @private
28
+ */
29
+ _clearMixin : function(sourceVariable) {
30
+ for (var mixinFunction in sourceVariable) {
31
+ if (sourceVariable.hasOwnProperty(mixinFunction)) {
32
+ Graph.prototype[mixinFunction] = undefined;
33
+ }
34
+ }
35
+ },
36
+
37
+
38
+ /**
39
+ * Mixin the physics system and initialize the parameters required.
40
+ *
41
+ * @private
42
+ */
43
+ _loadPhysicsSystem : function() {
44
+ this._loadMixin(physicsMixin);
45
+ this._loadSelectedForceSolver();
46
+ if (this.constants.configurePhysics == true) {
47
+ this._loadPhysicsConfiguration();
48
+ }
49
+ },
50
+
51
+
52
+
53
+
54
+ /**
55
+ * Mixin the cluster system and initialize the parameters required.
56
+ *
57
+ * @private
58
+ */
59
+ _loadClusterSystem : function() {
60
+ this.clusterSession = 0;
61
+ this.hubThreshold = 5;
62
+ this._loadMixin(ClusterMixin);
63
+ },
64
+
65
+
66
+ /**
67
+ * Mixin the sector system and initialize the parameters required
68
+ *
69
+ * @private
70
+ */
71
+ _loadSectorSystem : function() {
72
+ this.sectors = { },
73
+ this.activeSector = ["default"];
74
+ this.sectors["active"] = { },
75
+ this.sectors["active"]["default"] = {"nodes":{},
76
+ "edges":{},
77
+ "nodeIndices":[],
78
+ "formationScale": 1.0,
79
+ "drawingNode": undefined };
80
+ this.sectors["frozen"] = {},
81
+ this.sectors["support"] = {"nodes":{},
82
+ "edges":{},
83
+ "nodeIndices":[],
84
+ "formationScale": 1.0,
85
+ "drawingNode": undefined };
86
+
87
+ this.nodeIndices = this.sectors["active"]["default"]["nodeIndices"]; // the node indices list is used to speed up the computation of the repulsion fields
88
+
89
+ this._loadMixin(SectorMixin);
90
+ },
91
+
92
+
93
+ /**
94
+ * Mixin the selection system and initialize the parameters required
95
+ *
96
+ * @private
97
+ */
98
+ _loadSelectionSystem : function() {
99
+ this.selectionObj = { };
100
+
101
+ this._loadMixin(SelectionMixin);
102
+ },
103
+
104
+
105
+ /**
106
+ * Mixin the navigationUI (User Interface) system and initialize the parameters required
107
+ *
108
+ * @private
109
+ */
110
+ _loadManipulationSystem : function() {
111
+ // reset global variables -- these are used by the selection of nodes and edges.
112
+ this.blockConnectingEdgeSelection = false;
113
+ this.forceAppendSelection = false
114
+
115
+ if (this.constants.dataManipulation.enabled == true) {
116
+ // load the manipulator HTML elements. All styling done in css.
117
+ if (this.manipulationDiv === undefined) {
118
+ this.manipulationDiv = document.createElement('div');
119
+ this.manipulationDiv.className = 'graph-manipulationDiv';
120
+ this.manipulationDiv.id = 'graph-manipulationDiv';
121
+ if (this.editMode == true) {
122
+ this.manipulationDiv.style.display = "block";
123
+ }
124
+ else {
125
+ this.manipulationDiv.style.display = "none";
126
+ }
127
+ this.containerElement.insertBefore(this.manipulationDiv, this.frame);
128
+ }
129
+
130
+ if (this.editModeDiv === undefined) {
131
+ this.editModeDiv = document.createElement('div');
132
+ this.editModeDiv.className = 'graph-manipulation-editMode';
133
+ this.editModeDiv.id = 'graph-manipulation-editMode';
134
+ if (this.editMode == true) {
135
+ this.editModeDiv.style.display = "none";
136
+ }
137
+ else {
138
+ this.editModeDiv.style.display = "block";
139
+ }
140
+ this.containerElement.insertBefore(this.editModeDiv, this.frame);
141
+ }
142
+
143
+ if (this.closeDiv === undefined) {
144
+ this.closeDiv = document.createElement('div');
145
+ this.closeDiv.className = 'graph-manipulation-closeDiv';
146
+ this.closeDiv.id = 'graph-manipulation-closeDiv';
147
+ this.closeDiv.style.display = this.manipulationDiv.style.display;
148
+ this.containerElement.insertBefore(this.closeDiv, this.frame);
149
+ }
150
+
151
+ // load the manipulation functions
152
+ this._loadMixin(manipulationMixin);
153
+
154
+ // create the manipulator toolbar
155
+ this._createManipulatorBar();
156
+ }
157
+ else {
158
+ if (this.manipulationDiv !== undefined) {
159
+ // removes all the bindings and overloads
160
+ this._createManipulatorBar();
161
+ // remove the manipulation divs
162
+ this.containerElement.removeChild(this.manipulationDiv);
163
+ this.containerElement.removeChild(this.editModeDiv);
164
+ this.containerElement.removeChild(this.closeDiv);
165
+
166
+ this.manipulationDiv = undefined;
167
+ this.editModeDiv = undefined;
168
+ this.closeDiv = undefined;
169
+ // remove the mixin functions
170
+ this._clearMixin(manipulationMixin);
171
+ }
172
+ }
173
+ },
174
+
175
+
176
+ /**
177
+ * Mixin the navigation (User Interface) system and initialize the parameters required
178
+ *
179
+ * @private
180
+ */
181
+ _loadNavigationControls : function() {
182
+ this._loadMixin(NavigationMixin);
183
+
184
+ // the clean function removes the button divs, this is done to remove the bindings.
185
+ this._cleanNavigation();
186
+ if (this.constants.navigation.enabled == true) {
187
+ this._loadNavigationElements();
188
+ }
189
+ },
190
+
191
+
192
+ /**
193
+ * Mixin the hierarchical layout system.
194
+ *
195
+ * @private
196
+ */
197
+ _loadHierarchySystem : function() {
198
+ this._loadMixin(HierarchicalLayoutMixin);
199
+ }
200
+
201
+ }
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Created by Alex on 1/22/14.
3
+ */
4
+
5
+ var NavigationMixin = {
6
+
7
+ _cleanNavigation : function() {
8
+ // clean up previosu navigation items
9
+ var wrapper = document.getElementById('graph-navigation_wrapper');
10
+ if (wrapper != null) {
11
+ this.containerElement.removeChild(wrapper);
12
+ }
13
+ document.onmouseup = null;
14
+ },
15
+
16
+ /**
17
+ * Creation of the navigation controls nodes. They are drawn over the rest of the nodes and are not affected by scale and translation
18
+ * they have a triggerFunction which is called on click. If the position of the navigation controls is dependent
19
+ * on this.frame.canvas.clientWidth or this.frame.canvas.clientHeight, we flag horizontalAlignLeft and verticalAlignTop false.
20
+ * This means that the location will be corrected by the _relocateNavigation function on a size change of the canvas.
21
+ *
22
+ * @private
23
+ */
24
+ _loadNavigationElements : function() {
25
+ this._cleanNavigation();
26
+
27
+ this.navigationDivs = {};
28
+ var navigationDivs = ['up','down','left','right','zoomIn','zoomOut','zoomExtends'];
29
+ var navigationDivActions = ['_moveUp','_moveDown','_moveLeft','_moveRight','_zoomIn','_zoomOut','zoomExtent'];
30
+
31
+ this.navigationDivs['wrapper'] = document.createElement('div');
32
+ this.navigationDivs['wrapper'].id = "graph-navigation_wrapper";
33
+ this.containerElement.insertBefore(this.navigationDivs['wrapper'],this.frame);
34
+
35
+ for (var i = 0; i < navigationDivs.length; i++) {
36
+ this.navigationDivs[navigationDivs[i]] = document.createElement('div');
37
+ this.navigationDivs[navigationDivs[i]].id = "graph-navigation_" + navigationDivs[i];
38
+ this.navigationDivs[navigationDivs[i]].className = "graph-navigation " + navigationDivs[i];
39
+ this.navigationDivs['wrapper'].appendChild(this.navigationDivs[navigationDivs[i]]);
40
+ this.navigationDivs[navigationDivs[i]].onmousedown = this[navigationDivActions[i]].bind(this);
41
+ }
42
+
43
+ document.onmouseup = this._stopMovement.bind(this);
44
+ },
45
+
46
+ /**
47
+ * this stops all movement induced by the navigation buttons
48
+ *
49
+ * @private
50
+ */
51
+ _stopMovement : function() {
52
+ this._xStopMoving();
53
+ this._yStopMoving();
54
+ this._stopZoom();
55
+ },
56
+
57
+
58
+ /**
59
+ * stops the actions performed by page up and down etc.
60
+ *
61
+ * @param event
62
+ * @private
63
+ */
64
+ _preventDefault : function(event) {
65
+ if (event !== undefined) {
66
+ if (event.preventDefault) {
67
+ event.preventDefault();
68
+ } else {
69
+ event.returnValue = false;
70
+ }
71
+ }
72
+ },
73
+
74
+
75
+ /**
76
+ * move the screen up
77
+ * By using the increments, instead of adding a fixed number to the translation, we keep fluent and
78
+ * instant movement. The onKeypress event triggers immediately, then pauses, then triggers frequently
79
+ * To avoid this behaviour, we do the translation in the start loop.
80
+ *
81
+ * @private
82
+ */
83
+ _moveUp : function(event) {
84
+ console.log("here")
85
+ this.yIncrement = this.constants.keyboard.speed.y;
86
+ this.start(); // if there is no node movement, the calculation wont be done
87
+ this._preventDefault(event);
88
+ },
89
+
90
+
91
+ /**
92
+ * move the screen down
93
+ * @private
94
+ */
95
+ _moveDown : function(event) {
96
+ this.yIncrement = -this.constants.keyboard.speed.y;
97
+ this.start(); // if there is no node movement, the calculation wont be done
98
+ this._preventDefault(event);
99
+ },
100
+
101
+
102
+ /**
103
+ * move the screen left
104
+ * @private
105
+ */
106
+ _moveLeft : function(event) {
107
+ this.xIncrement = this.constants.keyboard.speed.x;
108
+ this.start(); // if there is no node movement, the calculation wont be done
109
+ this._preventDefault(event);
110
+ },
111
+
112
+
113
+ /**
114
+ * move the screen right
115
+ * @private
116
+ */
117
+ _moveRight : function(event) {
118
+ this.xIncrement = -this.constants.keyboard.speed.y;
119
+ this.start(); // if there is no node movement, the calculation wont be done
120
+ this._preventDefault(event);
121
+ },
122
+
123
+
124
+ /**
125
+ * Zoom in, using the same method as the movement.
126
+ * @private
127
+ */
128
+ _zoomIn : function(event) {
129
+ this.zoomIncrement = this.constants.keyboard.speed.zoom;
130
+ this.start(); // if there is no node movement, the calculation wont be done
131
+ this._preventDefault(event);
132
+ },
133
+
134
+
135
+ /**
136
+ * Zoom out
137
+ * @private
138
+ */
139
+ _zoomOut : function() {
140
+ this.zoomIncrement = -this.constants.keyboard.speed.zoom;
141
+ this.start(); // if there is no node movement, the calculation wont be done
142
+ this._preventDefault(event);
143
+ },
144
+
145
+
146
+ /**
147
+ * Stop zooming and unhighlight the zoom controls
148
+ * @private
149
+ */
150
+ _stopZoom : function() {
151
+ this.zoomIncrement = 0;
152
+ },
153
+
154
+
155
+ /**
156
+ * Stop moving in the Y direction and unHighlight the up and down
157
+ * @private
158
+ */
159
+ _yStopMoving : function() {
160
+ this.yIncrement = 0;
161
+ },
162
+
163
+
164
+ /**
165
+ * Stop moving in the X direction and unHighlight left and right.
166
+ * @private
167
+ */
168
+ _xStopMoving : function() {
169
+ this.xIncrement = 0;
170
+ }
171
+
172
+
173
+ };
@@ -0,0 +1,552 @@
1
+ /**
2
+ * Creation of the SectorMixin var.
3
+ *
4
+ * This contains all the functions the Graph object can use to employ the sector system.
5
+ * The sector system is always used by Graph, though the benefits only apply to the use of clustering.
6
+ * If clustering is not used, there is no overhead except for a duplicate object with references to nodes and edges.
7
+ *
8
+ * Alex de Mulder
9
+ * 21-01-2013
10
+ */
11
+ var SectorMixin = {
12
+
13
+ /**
14
+ * This function is only called by the setData function of the Graph object.
15
+ * This loads the global references into the active sector. This initializes the sector.
16
+ *
17
+ * @private
18
+ */
19
+ _putDataInSector : function() {
20
+ this.sectors["active"][this._sector()].nodes = this.nodes;
21
+ this.sectors["active"][this._sector()].edges = this.edges;
22
+ this.sectors["active"][this._sector()].nodeIndices = this.nodeIndices;
23
+ },
24
+
25
+
26
+ /**
27
+ * /**
28
+ * This function sets the global references to nodes, edges and nodeIndices back to
29
+ * those of the supplied (active) sector. If a type is defined, do the specific type
30
+ *
31
+ * @param {String} sectorId
32
+ * @param {String} [sectorType] | "active" or "frozen"
33
+ * @private
34
+ */
35
+ _switchToSector : function(sectorId, sectorType) {
36
+ if (sectorType === undefined || sectorType == "active") {
37
+ this._switchToActiveSector(sectorId);
38
+ }
39
+ else {
40
+ this._switchToFrozenSector(sectorId);
41
+ }
42
+ },
43
+
44
+
45
+ /**
46
+ * This function sets the global references to nodes, edges and nodeIndices back to
47
+ * those of the supplied active sector.
48
+ *
49
+ * @param sectorId
50
+ * @private
51
+ */
52
+ _switchToActiveSector : function(sectorId) {
53
+ this.nodeIndices = this.sectors["active"][sectorId]["nodeIndices"];
54
+ this.nodes = this.sectors["active"][sectorId]["nodes"];
55
+ this.edges = this.sectors["active"][sectorId]["edges"];
56
+ },
57
+
58
+
59
+ /**
60
+ * This function sets the global references to nodes, edges and nodeIndices back to
61
+ * those of the supplied active sector.
62
+ *
63
+ * @param sectorId
64
+ * @private
65
+ */
66
+ _switchToSupportSector : function() {
67
+ this.nodeIndices = this.sectors["support"]["nodeIndices"];
68
+ this.nodes = this.sectors["support"]["nodes"];
69
+ this.edges = this.sectors["support"]["edges"];
70
+ },
71
+
72
+
73
+ /**
74
+ * This function sets the global references to nodes, edges and nodeIndices back to
75
+ * those of the supplied frozen sector.
76
+ *
77
+ * @param sectorId
78
+ * @private
79
+ */
80
+ _switchToFrozenSector : function(sectorId) {
81
+ this.nodeIndices = this.sectors["frozen"][sectorId]["nodeIndices"];
82
+ this.nodes = this.sectors["frozen"][sectorId]["nodes"];
83
+ this.edges = this.sectors["frozen"][sectorId]["edges"];
84
+ },
85
+
86
+
87
+ /**
88
+ * This function sets the global references to nodes, edges and nodeIndices back to
89
+ * those of the currently active sector.
90
+ *
91
+ * @private
92
+ */
93
+ _loadLatestSector : function() {
94
+ this._switchToSector(this._sector());
95
+ },
96
+
97
+
98
+ /**
99
+ * This function returns the currently active sector Id
100
+ *
101
+ * @returns {String}
102
+ * @private
103
+ */
104
+ _sector : function() {
105
+ return this.activeSector[this.activeSector.length-1];
106
+ },
107
+
108
+
109
+ /**
110
+ * This function returns the previously active sector Id
111
+ *
112
+ * @returns {String}
113
+ * @private
114
+ */
115
+ _previousSector : function() {
116
+ if (this.activeSector.length > 1) {
117
+ return this.activeSector[this.activeSector.length-2];
118
+ }
119
+ else {
120
+ throw new TypeError('there are not enough sectors in the this.activeSector array.');
121
+ }
122
+ },
123
+
124
+
125
+ /**
126
+ * We add the active sector at the end of the this.activeSector array
127
+ * This ensures it is the currently active sector returned by _sector() and it reaches the top
128
+ * of the activeSector stack. When we reverse our steps we move from the end to the beginning of this stack.
129
+ *
130
+ * @param newId
131
+ * @private
132
+ */
133
+ _setActiveSector : function(newId) {
134
+ this.activeSector.push(newId);
135
+ },
136
+
137
+
138
+ /**
139
+ * We remove the currently active sector id from the active sector stack. This happens when
140
+ * we reactivate the previously active sector
141
+ *
142
+ * @private
143
+ */
144
+ _forgetLastSector : function() {
145
+ this.activeSector.pop();
146
+ },
147
+
148
+
149
+ /**
150
+ * This function creates a new active sector with the supplied newId. This newId
151
+ * is the expanding node id.
152
+ *
153
+ * @param {String} newId | Id of the new active sector
154
+ * @private
155
+ */
156
+ _createNewSector : function(newId) {
157
+ // create the new sector
158
+ this.sectors["active"][newId] = {"nodes":{},
159
+ "edges":{},
160
+ "nodeIndices":[],
161
+ "formationScale": this.scale,
162
+ "drawingNode": undefined};
163
+
164
+ // create the new sector render node. This gives visual feedback that you are in a new sector.
165
+ this.sectors["active"][newId]['drawingNode'] = new Node(
166
+ {id:newId,
167
+ color: {
168
+ background: "#eaefef",
169
+ border: "495c5e"
170
+ }
171
+ },{},{},this.constants);
172
+ this.sectors["active"][newId]['drawingNode'].clusterSize = 2;
173
+ },
174
+
175
+
176
+ /**
177
+ * This function removes the currently active sector. This is called when we create a new
178
+ * active sector.
179
+ *
180
+ * @param {String} sectorId | Id of the active sector that will be removed
181
+ * @private
182
+ */
183
+ _deleteActiveSector : function(sectorId) {
184
+ delete this.sectors["active"][sectorId];
185
+ },
186
+
187
+
188
+ /**
189
+ * This function removes the currently active sector. This is called when we reactivate
190
+ * the previously active sector.
191
+ *
192
+ * @param {String} sectorId | Id of the active sector that will be removed
193
+ * @private
194
+ */
195
+ _deleteFrozenSector : function(sectorId) {
196
+ delete this.sectors["frozen"][sectorId];
197
+ },
198
+
199
+
200
+ /**
201
+ * Freezing an active sector means moving it from the "active" object to the "frozen" object.
202
+ * We copy the references, then delete the active entree.
203
+ *
204
+ * @param sectorId
205
+ * @private
206
+ */
207
+ _freezeSector : function(sectorId) {
208
+ // we move the set references from the active to the frozen stack.
209
+ this.sectors["frozen"][sectorId] = this.sectors["active"][sectorId];
210
+
211
+ // we have moved the sector data into the frozen set, we now remove it from the active set
212
+ this._deleteActiveSector(sectorId);
213
+ },
214
+
215
+
216
+ /**
217
+ * This is the reverse operation of _freezeSector. Activating means moving the sector from the "frozen"
218
+ * object to the "active" object.
219
+ *
220
+ * @param sectorId
221
+ * @private
222
+ */
223
+ _activateSector : function(sectorId) {
224
+ // we move the set references from the frozen to the active stack.
225
+ this.sectors["active"][sectorId] = this.sectors["frozen"][sectorId];
226
+
227
+ // we have moved the sector data into the active set, we now remove it from the frozen stack
228
+ this._deleteFrozenSector(sectorId);
229
+ },
230
+
231
+
232
+ /**
233
+ * This function merges the data from the currently active sector with a frozen sector. This is used
234
+ * in the process of reverting back to the previously active sector.
235
+ * The data that is placed in the frozen (the previously active) sector is the node that has been removed from it
236
+ * upon the creation of a new active sector.
237
+ *
238
+ * @param sectorId
239
+ * @private
240
+ */
241
+ _mergeThisWithFrozen : function(sectorId) {
242
+ // copy all nodes
243
+ for (var nodeId in this.nodes) {
244
+ if (this.nodes.hasOwnProperty(nodeId)) {
245
+ this.sectors["frozen"][sectorId]["nodes"][nodeId] = this.nodes[nodeId];
246
+ }
247
+ }
248
+
249
+ // copy all edges (if not fully clustered, else there are no edges)
250
+ for (var edgeId in this.edges) {
251
+ if (this.edges.hasOwnProperty(edgeId)) {
252
+ this.sectors["frozen"][sectorId]["edges"][edgeId] = this.edges[edgeId];
253
+ }
254
+ }
255
+
256
+ // merge the nodeIndices
257
+ for (var i = 0; i < this.nodeIndices.length; i++) {
258
+ this.sectors["frozen"][sectorId]["nodeIndices"].push(this.nodeIndices[i]);
259
+ }
260
+ },
261
+
262
+
263
+ /**
264
+ * This clusters the sector to one cluster. It was a single cluster before this process started so
265
+ * we revert to that state. The clusterToFit function with a maximum size of 1 node does this.
266
+ *
267
+ * @private
268
+ */
269
+ _collapseThisToSingleCluster : function() {
270
+ this.clusterToFit(1,false);
271
+ },
272
+
273
+
274
+ /**
275
+ * We create a new active sector from the node that we want to open.
276
+ *
277
+ * @param node
278
+ * @private
279
+ */
280
+ _addSector : function(node) {
281
+ // this is the currently active sector
282
+ var sector = this._sector();
283
+
284
+ // // this should allow me to select nodes from a frozen set.
285
+ // if (this.sectors['active'][sector]["nodes"].hasOwnProperty(node.id)) {
286
+ // console.log("the node is part of the active sector");
287
+ // }
288
+ // else {
289
+ // console.log("I dont know what the fuck happened!!");
290
+ // }
291
+
292
+ // when we switch to a new sector, we remove the node that will be expanded from the current nodes list.
293
+ delete this.nodes[node.id];
294
+
295
+ var unqiueIdentifier = util.randomUUID();
296
+
297
+ // we fully freeze the currently active sector
298
+ this._freezeSector(sector);
299
+
300
+ // we create a new active sector. This sector has the Id of the node to ensure uniqueness
301
+ this._createNewSector(unqiueIdentifier);
302
+
303
+ // we add the active sector to the sectors array to be able to revert these steps later on
304
+ this._setActiveSector(unqiueIdentifier);
305
+
306
+ // we redirect the global references to the new sector's references. this._sector() now returns unqiueIdentifier
307
+ this._switchToSector(this._sector());
308
+
309
+ // finally we add the node we removed from our previous active sector to the new active sector
310
+ this.nodes[node.id] = node;
311
+ },
312
+
313
+
314
+ /**
315
+ * We close the sector that is currently open and revert back to the one before.
316
+ * If the active sector is the "default" sector, nothing happens.
317
+ *
318
+ * @private
319
+ */
320
+ _collapseSector : function() {
321
+ // the currently active sector
322
+ var sector = this._sector();
323
+
324
+ // we cannot collapse the default sector
325
+ if (sector != "default") {
326
+ if ((this.nodeIndices.length == 1) ||
327
+ (this.sectors["active"][sector]["drawingNode"].width*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientWidth) ||
328
+ (this.sectors["active"][sector]["drawingNode"].height*this.scale < this.constants.clustering.screenSizeThreshold * this.frame.canvas.clientHeight)) {
329
+ var previousSector = this._previousSector();
330
+
331
+ // we collapse the sector back to a single cluster
332
+ this._collapseThisToSingleCluster();
333
+
334
+ // we move the remaining nodes, edges and nodeIndices to the previous sector.
335
+ // This previous sector is the one we will reactivate
336
+ this._mergeThisWithFrozen(previousSector);
337
+
338
+ // the previously active (frozen) sector now has all the data from the currently active sector.
339
+ // we can now delete the active sector.
340
+ this._deleteActiveSector(sector);
341
+
342
+ // we activate the previously active (and currently frozen) sector.
343
+ this._activateSector(previousSector);
344
+
345
+ // we load the references from the newly active sector into the global references
346
+ this._switchToSector(previousSector);
347
+
348
+ // we forget the previously active sector because we reverted to the one before
349
+ this._forgetLastSector();
350
+
351
+ // finally, we update the node index list.
352
+ this._updateNodeIndexList();
353
+
354
+ // we refresh the list with calulation nodes and calculation node indices.
355
+ this._updateCalculationNodes();
356
+ }
357
+ }
358
+ },
359
+
360
+
361
+ /**
362
+ * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation().
363
+ *
364
+ * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors
365
+ * | we dont pass the function itself because then the "this" is the window object
366
+ * | instead of the Graph object
367
+ * @param {*} [argument] | Optional: arguments to pass to the runFunction
368
+ * @private
369
+ */
370
+ _doInAllActiveSectors : function(runFunction,argument) {
371
+ if (argument === undefined) {
372
+ for (var sector in this.sectors["active"]) {
373
+ if (this.sectors["active"].hasOwnProperty(sector)) {
374
+ // switch the global references to those of this sector
375
+ this._switchToActiveSector(sector);
376
+ this[runFunction]();
377
+ }
378
+ }
379
+ }
380
+ else {
381
+ for (var sector in this.sectors["active"]) {
382
+ if (this.sectors["active"].hasOwnProperty(sector)) {
383
+ // switch the global references to those of this sector
384
+ this._switchToActiveSector(sector);
385
+ var args = Array.prototype.splice.call(arguments, 1);
386
+ if (args.length > 1) {
387
+ this[runFunction](args[0],args[1]);
388
+ }
389
+ else {
390
+ this[runFunction](argument);
391
+ }
392
+ }
393
+ }
394
+ }
395
+ // we revert the global references back to our active sector
396
+ this._loadLatestSector();
397
+ },
398
+
399
+
400
+ /**
401
+ * This runs a function in all active sectors. This is used in _redraw() and the _initializeForceCalculation().
402
+ *
403
+ * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors
404
+ * | we dont pass the function itself because then the "this" is the window object
405
+ * | instead of the Graph object
406
+ * @param {*} [argument] | Optional: arguments to pass to the runFunction
407
+ * @private
408
+ */
409
+ _doInSupportSector : function(runFunction,argument) {
410
+ if (argument === undefined) {
411
+ this._switchToSupportSector();
412
+ this[runFunction]();
413
+ }
414
+ else {
415
+ this._switchToSupportSector();
416
+ var args = Array.prototype.splice.call(arguments, 1);
417
+ if (args.length > 1) {
418
+ this[runFunction](args[0],args[1]);
419
+ }
420
+ else {
421
+ this[runFunction](argument);
422
+ }
423
+ }
424
+ // we revert the global references back to our active sector
425
+ this._loadLatestSector();
426
+ },
427
+
428
+
429
+ /**
430
+ * This runs a function in all frozen sectors. This is used in the _redraw().
431
+ *
432
+ * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors
433
+ * | we don't pass the function itself because then the "this" is the window object
434
+ * | instead of the Graph object
435
+ * @param {*} [argument] | Optional: arguments to pass to the runFunction
436
+ * @private
437
+ */
438
+ _doInAllFrozenSectors : function(runFunction,argument) {
439
+ if (argument === undefined) {
440
+ for (var sector in this.sectors["frozen"]) {
441
+ if (this.sectors["frozen"].hasOwnProperty(sector)) {
442
+ // switch the global references to those of this sector
443
+ this._switchToFrozenSector(sector);
444
+ this[runFunction]();
445
+ }
446
+ }
447
+ }
448
+ else {
449
+ for (var sector in this.sectors["frozen"]) {
450
+ if (this.sectors["frozen"].hasOwnProperty(sector)) {
451
+ // switch the global references to those of this sector
452
+ this._switchToFrozenSector(sector);
453
+ var args = Array.prototype.splice.call(arguments, 1);
454
+ if (args.length > 1) {
455
+ this[runFunction](args[0],args[1]);
456
+ }
457
+ else {
458
+ this[runFunction](argument);
459
+ }
460
+ }
461
+ }
462
+ }
463
+ this._loadLatestSector();
464
+ },
465
+
466
+
467
+ /**
468
+ * This runs a function in all sectors. This is used in the _redraw().
469
+ *
470
+ * @param {String} runFunction | This is the NAME of a function we want to call in all active sectors
471
+ * | we don't pass the function itself because then the "this" is the window object
472
+ * | instead of the Graph object
473
+ * @param {*} [argument] | Optional: arguments to pass to the runFunction
474
+ * @private
475
+ */
476
+ _doInAllSectors : function(runFunction,argument) {
477
+ var args = Array.prototype.splice.call(arguments, 1);
478
+ if (argument === undefined) {
479
+ this._doInAllActiveSectors(runFunction);
480
+ this._doInAllFrozenSectors(runFunction);
481
+ }
482
+ else {
483
+ if (args.length > 1) {
484
+ this._doInAllActiveSectors(runFunction,args[0],args[1]);
485
+ this._doInAllFrozenSectors(runFunction,args[0],args[1]);
486
+ }
487
+ else {
488
+ this._doInAllActiveSectors(runFunction,argument);
489
+ this._doInAllFrozenSectors(runFunction,argument);
490
+ }
491
+ }
492
+ },
493
+
494
+
495
+ /**
496
+ * This clears the nodeIndices list. We cannot use this.nodeIndices = [] because we would break the link with the
497
+ * active sector. Thus we clear the nodeIndices in the active sector, then reconnect the this.nodeIndices to it.
498
+ *
499
+ * @private
500
+ */
501
+ _clearNodeIndexList : function() {
502
+ var sector = this._sector();
503
+ this.sectors["active"][sector]["nodeIndices"] = [];
504
+ this.nodeIndices = this.sectors["active"][sector]["nodeIndices"];
505
+ },
506
+
507
+
508
+ /**
509
+ * Draw the encompassing sector node
510
+ *
511
+ * @param ctx
512
+ * @param sectorType
513
+ * @private
514
+ */
515
+ _drawSectorNodes : function(ctx,sectorType) {
516
+ var minY = 1e9, maxY = -1e9, minX = 1e9, maxX = -1e9, node;
517
+ for (var sector in this.sectors[sectorType]) {
518
+ if (this.sectors[sectorType].hasOwnProperty(sector)) {
519
+ if (this.sectors[sectorType][sector]["drawingNode"] !== undefined) {
520
+
521
+ this._switchToSector(sector,sectorType);
522
+
523
+ minY = 1e9; maxY = -1e9; minX = 1e9; maxX = -1e9;
524
+ for (var nodeId in this.nodes) {
525
+ if (this.nodes.hasOwnProperty(nodeId)) {
526
+ node = this.nodes[nodeId];
527
+ node.resize(ctx);
528
+ if (minX > node.x - 0.5 * node.width) {minX = node.x - 0.5 * node.width;}
529
+ if (maxX < node.x + 0.5 * node.width) {maxX = node.x + 0.5 * node.width;}
530
+ if (minY > node.y - 0.5 * node.height) {minY = node.y - 0.5 * node.height;}
531
+ if (maxY < node.y + 0.5 * node.height) {maxY = node.y + 0.5 * node.height;}
532
+ }
533
+ }
534
+ node = this.sectors[sectorType][sector]["drawingNode"];
535
+ node.x = 0.5 * (maxX + minX);
536
+ node.y = 0.5 * (maxY + minY);
537
+ node.width = 2 * (node.x - minX);
538
+ node.height = 2 * (node.y - minY);
539
+ node.radius = Math.sqrt(Math.pow(0.5*node.width,2) + Math.pow(0.5*node.height,2));
540
+ node.setScale(this.scale);
541
+ node._drawCircle(ctx);
542
+ }
543
+ }
544
+ }
545
+ },
546
+
547
+ _drawAllSectorNodes : function(ctx) {
548
+ this._drawSectorNodes(ctx,"frozen");
549
+ this._drawSectorNodes(ctx,"active");
550
+ this._loadLatestSector();
551
+ }
552
+ };