vis-rails 2.0.0 → 2.0.1
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.
- checksums.yaml +4 -4
- data/lib/vis/rails/version.rb +1 -1
- data/vendor/assets/javascripts/vis.js +26 -26
- metadata +16 -85
- data/vendor/assets/vis/DataSet.js +0 -926
- data/vendor/assets/vis/DataView.js +0 -283
- data/vendor/assets/vis/graph/Edge.js +0 -957
- data/vendor/assets/vis/graph/Graph.js +0 -2291
- data/vendor/assets/vis/graph/Groups.js +0 -80
- data/vendor/assets/vis/graph/Images.js +0 -41
- data/vendor/assets/vis/graph/Node.js +0 -966
- data/vendor/assets/vis/graph/Popup.js +0 -132
- data/vendor/assets/vis/graph/css/graph-manipulation.css +0 -128
- data/vendor/assets/vis/graph/css/graph-navigation.css +0 -66
- data/vendor/assets/vis/graph/dotparser.js +0 -829
- data/vendor/assets/vis/graph/graphMixins/ClusterMixin.js +0 -1143
- data/vendor/assets/vis/graph/graphMixins/HierarchicalLayoutMixin.js +0 -311
- data/vendor/assets/vis/graph/graphMixins/ManipulationMixin.js +0 -576
- data/vendor/assets/vis/graph/graphMixins/MixinLoader.js +0 -199
- data/vendor/assets/vis/graph/graphMixins/NavigationMixin.js +0 -205
- data/vendor/assets/vis/graph/graphMixins/SectorsMixin.js +0 -552
- data/vendor/assets/vis/graph/graphMixins/SelectionMixin.js +0 -648
- data/vendor/assets/vis/graph/graphMixins/physics/BarnesHut.js +0 -398
- data/vendor/assets/vis/graph/graphMixins/physics/HierarchialRepulsion.js +0 -64
- data/vendor/assets/vis/graph/graphMixins/physics/PhysicsMixin.js +0 -697
- data/vendor/assets/vis/graph/graphMixins/physics/Repulsion.js +0 -66
- data/vendor/assets/vis/graph/img/acceptDeleteIcon.png +0 -0
- data/vendor/assets/vis/graph/img/addNodeIcon.png +0 -0
- data/vendor/assets/vis/graph/img/backIcon.png +0 -0
- data/vendor/assets/vis/graph/img/connectIcon.png +0 -0
- data/vendor/assets/vis/graph/img/cross.png +0 -0
- data/vendor/assets/vis/graph/img/cross2.png +0 -0
- data/vendor/assets/vis/graph/img/deleteIcon.png +0 -0
- data/vendor/assets/vis/graph/img/downArrow.png +0 -0
- data/vendor/assets/vis/graph/img/editIcon.png +0 -0
- data/vendor/assets/vis/graph/img/leftArrow.png +0 -0
- data/vendor/assets/vis/graph/img/minus.png +0 -0
- data/vendor/assets/vis/graph/img/plus.png +0 -0
- data/vendor/assets/vis/graph/img/rightArrow.png +0 -0
- data/vendor/assets/vis/graph/img/upArrow.png +0 -0
- data/vendor/assets/vis/graph/img/zoomExtends.png +0 -0
- data/vendor/assets/vis/graph/shapes.js +0 -225
- data/vendor/assets/vis/graph3d/Graph3d.js +0 -3306
- data/vendor/assets/vis/module/exports.js +0 -65
- data/vendor/assets/vis/module/header.js +0 -24
- data/vendor/assets/vis/module/imports.js +0 -31
- data/vendor/assets/vis/shim.js +0 -252
- data/vendor/assets/vis/timeline/Range.js +0 -532
- data/vendor/assets/vis/timeline/TimeStep.js +0 -466
- data/vendor/assets/vis/timeline/Timeline.js +0 -851
- data/vendor/assets/vis/timeline/component/Component.js +0 -52
- data/vendor/assets/vis/timeline/component/CurrentTime.js +0 -128
- data/vendor/assets/vis/timeline/component/CustomTime.js +0 -182
- data/vendor/assets/vis/timeline/component/Group.js +0 -470
- data/vendor/assets/vis/timeline/component/ItemSet.js +0 -1332
- data/vendor/assets/vis/timeline/component/TimeAxis.js +0 -389
- data/vendor/assets/vis/timeline/component/css/animation.css +0 -33
- data/vendor/assets/vis/timeline/component/css/currenttime.css +0 -5
- data/vendor/assets/vis/timeline/component/css/customtime.css +0 -6
- data/vendor/assets/vis/timeline/component/css/item.css +0 -107
- data/vendor/assets/vis/timeline/component/css/itemset.css +0 -33
- data/vendor/assets/vis/timeline/component/css/labelset.css +0 -36
- data/vendor/assets/vis/timeline/component/css/panel.css +0 -71
- data/vendor/assets/vis/timeline/component/css/timeaxis.css +0 -48
- data/vendor/assets/vis/timeline/component/css/timeline.css +0 -2
- data/vendor/assets/vis/timeline/component/item/Item.js +0 -139
- data/vendor/assets/vis/timeline/component/item/ItemBox.js +0 -230
- data/vendor/assets/vis/timeline/component/item/ItemPoint.js +0 -190
- data/vendor/assets/vis/timeline/component/item/ItemRange.js +0 -262
- data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +0 -57
- data/vendor/assets/vis/timeline/img/delete.png +0 -0
- data/vendor/assets/vis/timeline/stack.js +0 -112
- data/vendor/assets/vis/util.js +0 -990
@@ -1,311 +0,0 @@
|
|
1
|
-
var HierarchicalLayoutMixin = {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
_resetLevels : function() {
|
6
|
-
for (var nodeId in this.nodes) {
|
7
|
-
if (this.nodes.hasOwnProperty(nodeId)) {
|
8
|
-
var node = this.nodes[nodeId];
|
9
|
-
if (node.preassignedLevel == false) {
|
10
|
-
node.level = -1;
|
11
|
-
}
|
12
|
-
}
|
13
|
-
}
|
14
|
-
},
|
15
|
-
|
16
|
-
/**
|
17
|
-
* This is the main function to layout the nodes in a hierarchical way.
|
18
|
-
* It checks if the node details are supplied correctly
|
19
|
-
*
|
20
|
-
* @private
|
21
|
-
*/
|
22
|
-
_setupHierarchicalLayout : function() {
|
23
|
-
if (this.constants.hierarchicalLayout.enabled == true && this.nodeIndices.length > 0) {
|
24
|
-
if (this.constants.hierarchicalLayout.direction == "RL" || this.constants.hierarchicalLayout.direction == "DU") {
|
25
|
-
this.constants.hierarchicalLayout.levelSeparation *= -1;
|
26
|
-
}
|
27
|
-
else {
|
28
|
-
this.constants.hierarchicalLayout.levelSeparation = Math.abs(this.constants.hierarchicalLayout.levelSeparation);
|
29
|
-
}
|
30
|
-
// get the size of the largest hubs and check if the user has defined a level for a node.
|
31
|
-
var hubsize = 0;
|
32
|
-
var node, nodeId;
|
33
|
-
var definedLevel = false;
|
34
|
-
var undefinedLevel = false;
|
35
|
-
|
36
|
-
for (nodeId in this.nodes) {
|
37
|
-
if (this.nodes.hasOwnProperty(nodeId)) {
|
38
|
-
node = this.nodes[nodeId];
|
39
|
-
if (node.level != -1) {
|
40
|
-
definedLevel = true;
|
41
|
-
}
|
42
|
-
else {
|
43
|
-
undefinedLevel = true;
|
44
|
-
}
|
45
|
-
if (hubsize < node.edges.length) {
|
46
|
-
hubsize = node.edges.length;
|
47
|
-
}
|
48
|
-
}
|
49
|
-
}
|
50
|
-
|
51
|
-
// if the user defined some levels but not all, alert and run without hierarchical layout
|
52
|
-
if (undefinedLevel == true && definedLevel == true) {
|
53
|
-
alert("To use the hierarchical layout, nodes require either no predefined levels or levels have to be defined for all nodes.");
|
54
|
-
this.zoomExtent(true,this.constants.clustering.enabled);
|
55
|
-
if (!this.constants.clustering.enabled) {
|
56
|
-
this.start();
|
57
|
-
}
|
58
|
-
}
|
59
|
-
else {
|
60
|
-
// setup the system to use hierarchical method.
|
61
|
-
this._changeConstants();
|
62
|
-
|
63
|
-
// define levels if undefined by the users. Based on hubsize
|
64
|
-
if (undefinedLevel == true) {
|
65
|
-
this._determineLevels(hubsize);
|
66
|
-
}
|
67
|
-
// check the distribution of the nodes per level.
|
68
|
-
var distribution = this._getDistribution();
|
69
|
-
|
70
|
-
// place the nodes on the canvas. This also stablilizes the system.
|
71
|
-
this._placeNodesByHierarchy(distribution);
|
72
|
-
|
73
|
-
// start the simulation.
|
74
|
-
this.start();
|
75
|
-
}
|
76
|
-
}
|
77
|
-
},
|
78
|
-
|
79
|
-
|
80
|
-
/**
|
81
|
-
* This function places the nodes on the canvas based on the hierarchial distribution.
|
82
|
-
*
|
83
|
-
* @param {Object} distribution | obtained by the function this._getDistribution()
|
84
|
-
* @private
|
85
|
-
*/
|
86
|
-
_placeNodesByHierarchy : function(distribution) {
|
87
|
-
var nodeId, node;
|
88
|
-
|
89
|
-
// start placing all the level 0 nodes first. Then recursively position their branches.
|
90
|
-
for (nodeId in distribution[0].nodes) {
|
91
|
-
if (distribution[0].nodes.hasOwnProperty(nodeId)) {
|
92
|
-
node = distribution[0].nodes[nodeId];
|
93
|
-
if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") {
|
94
|
-
if (node.xFixed) {
|
95
|
-
node.x = distribution[0].minPos;
|
96
|
-
node.xFixed = false;
|
97
|
-
|
98
|
-
distribution[0].minPos += distribution[0].nodeSpacing;
|
99
|
-
}
|
100
|
-
}
|
101
|
-
else {
|
102
|
-
if (node.yFixed) {
|
103
|
-
node.y = distribution[0].minPos;
|
104
|
-
node.yFixed = false;
|
105
|
-
|
106
|
-
distribution[0].minPos += distribution[0].nodeSpacing;
|
107
|
-
}
|
108
|
-
}
|
109
|
-
this._placeBranchNodes(node.edges,node.id,distribution,node.level);
|
110
|
-
}
|
111
|
-
}
|
112
|
-
|
113
|
-
// stabilize the system after positioning. This function calls zoomExtent.
|
114
|
-
this._stabilize();
|
115
|
-
},
|
116
|
-
|
117
|
-
|
118
|
-
/**
|
119
|
-
* This function get the distribution of levels based on hubsize
|
120
|
-
*
|
121
|
-
* @returns {Object}
|
122
|
-
* @private
|
123
|
-
*/
|
124
|
-
_getDistribution : function() {
|
125
|
-
var distribution = {};
|
126
|
-
var nodeId, node, level;
|
127
|
-
|
128
|
-
// we fix Y because the hierarchy is vertical, we fix X so we do not give a node an x position for a second time.
|
129
|
-
// the fix of X is removed after the x value has been set.
|
130
|
-
for (nodeId in this.nodes) {
|
131
|
-
if (this.nodes.hasOwnProperty(nodeId)) {
|
132
|
-
node = this.nodes[nodeId];
|
133
|
-
node.xFixed = true;
|
134
|
-
node.yFixed = true;
|
135
|
-
if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") {
|
136
|
-
node.y = this.constants.hierarchicalLayout.levelSeparation*node.level;
|
137
|
-
}
|
138
|
-
else {
|
139
|
-
node.x = this.constants.hierarchicalLayout.levelSeparation*node.level;
|
140
|
-
}
|
141
|
-
if (!distribution.hasOwnProperty(node.level)) {
|
142
|
-
distribution[node.level] = {amount: 0, nodes: {}, minPos:0, nodeSpacing:0};
|
143
|
-
}
|
144
|
-
distribution[node.level].amount += 1;
|
145
|
-
distribution[node.level].nodes[node.id] = node;
|
146
|
-
}
|
147
|
-
}
|
148
|
-
|
149
|
-
// determine the largest amount of nodes of all levels
|
150
|
-
var maxCount = 0;
|
151
|
-
for (level in distribution) {
|
152
|
-
if (distribution.hasOwnProperty(level)) {
|
153
|
-
if (maxCount < distribution[level].amount) {
|
154
|
-
maxCount = distribution[level].amount;
|
155
|
-
}
|
156
|
-
}
|
157
|
-
}
|
158
|
-
|
159
|
-
// set the initial position and spacing of each nodes accordingly
|
160
|
-
for (level in distribution) {
|
161
|
-
if (distribution.hasOwnProperty(level)) {
|
162
|
-
distribution[level].nodeSpacing = (maxCount + 1) * this.constants.hierarchicalLayout.nodeSpacing;
|
163
|
-
distribution[level].nodeSpacing /= (distribution[level].amount + 1);
|
164
|
-
distribution[level].minPos = distribution[level].nodeSpacing - (0.5 * (distribution[level].amount + 1) * distribution[level].nodeSpacing);
|
165
|
-
}
|
166
|
-
}
|
167
|
-
|
168
|
-
return distribution;
|
169
|
-
},
|
170
|
-
|
171
|
-
|
172
|
-
/**
|
173
|
-
* this function allocates nodes in levels based on the recursive branching from the largest hubs.
|
174
|
-
*
|
175
|
-
* @param hubsize
|
176
|
-
* @private
|
177
|
-
*/
|
178
|
-
_determineLevels : function(hubsize) {
|
179
|
-
var nodeId, node;
|
180
|
-
|
181
|
-
// determine hubs
|
182
|
-
for (nodeId in this.nodes) {
|
183
|
-
if (this.nodes.hasOwnProperty(nodeId)) {
|
184
|
-
node = this.nodes[nodeId];
|
185
|
-
if (node.edges.length == hubsize) {
|
186
|
-
node.level = 0;
|
187
|
-
}
|
188
|
-
}
|
189
|
-
}
|
190
|
-
|
191
|
-
// branch from hubs
|
192
|
-
for (nodeId in this.nodes) {
|
193
|
-
if (this.nodes.hasOwnProperty(nodeId)) {
|
194
|
-
node = this.nodes[nodeId];
|
195
|
-
if (node.level == 0) {
|
196
|
-
this._setLevel(1,node.edges,node.id);
|
197
|
-
}
|
198
|
-
}
|
199
|
-
}
|
200
|
-
},
|
201
|
-
|
202
|
-
|
203
|
-
/**
|
204
|
-
* Since hierarchical layout does not support:
|
205
|
-
* - smooth curves (based on the physics),
|
206
|
-
* - clustering (based on dynamic node counts)
|
207
|
-
*
|
208
|
-
* We disable both features so there will be no problems.
|
209
|
-
*
|
210
|
-
* @private
|
211
|
-
*/
|
212
|
-
_changeConstants : function() {
|
213
|
-
this.constants.clustering.enabled = false;
|
214
|
-
this.constants.physics.barnesHut.enabled = false;
|
215
|
-
this.constants.physics.hierarchicalRepulsion.enabled = true;
|
216
|
-
this._loadSelectedForceSolver();
|
217
|
-
this.constants.smoothCurves = false;
|
218
|
-
this._configureSmoothCurves();
|
219
|
-
},
|
220
|
-
|
221
|
-
|
222
|
-
/**
|
223
|
-
* This is a recursively called function to enumerate the branches from the largest hubs and place the nodes
|
224
|
-
* on a X position that ensures there will be no overlap.
|
225
|
-
*
|
226
|
-
* @param edges
|
227
|
-
* @param parentId
|
228
|
-
* @param distribution
|
229
|
-
* @param parentLevel
|
230
|
-
* @private
|
231
|
-
*/
|
232
|
-
_placeBranchNodes : function(edges, parentId, distribution, parentLevel) {
|
233
|
-
for (var i = 0; i < edges.length; i++) {
|
234
|
-
var childNode = null;
|
235
|
-
if (edges[i].toId == parentId) {
|
236
|
-
childNode = edges[i].from;
|
237
|
-
}
|
238
|
-
else {
|
239
|
-
childNode = edges[i].to;
|
240
|
-
}
|
241
|
-
|
242
|
-
// if a node is conneceted to another node on the same level (or higher (means lower level))!, this is not handled here.
|
243
|
-
var nodeMoved = false;
|
244
|
-
if (this.constants.hierarchicalLayout.direction == "UD" || this.constants.hierarchicalLayout.direction == "DU") {
|
245
|
-
if (childNode.xFixed && childNode.level > parentLevel) {
|
246
|
-
childNode.xFixed = false;
|
247
|
-
childNode.x = distribution[childNode.level].minPos;
|
248
|
-
nodeMoved = true;
|
249
|
-
}
|
250
|
-
}
|
251
|
-
else {
|
252
|
-
if (childNode.yFixed && childNode.level > parentLevel) {
|
253
|
-
childNode.yFixed = false;
|
254
|
-
childNode.y = distribution[childNode.level].minPos;
|
255
|
-
nodeMoved = true;
|
256
|
-
}
|
257
|
-
}
|
258
|
-
|
259
|
-
if (nodeMoved == true) {
|
260
|
-
distribution[childNode.level].minPos += distribution[childNode.level].nodeSpacing;
|
261
|
-
if (childNode.edges.length > 1) {
|
262
|
-
this._placeBranchNodes(childNode.edges,childNode.id,distribution,childNode.level);
|
263
|
-
}
|
264
|
-
}
|
265
|
-
}
|
266
|
-
},
|
267
|
-
|
268
|
-
|
269
|
-
/**
|
270
|
-
* this function is called recursively to enumerate the barnches of the largest hubs and give each node a level.
|
271
|
-
*
|
272
|
-
* @param level
|
273
|
-
* @param edges
|
274
|
-
* @param parentId
|
275
|
-
* @private
|
276
|
-
*/
|
277
|
-
_setLevel : function(level, edges, parentId) {
|
278
|
-
for (var i = 0; i < edges.length; i++) {
|
279
|
-
var childNode = null;
|
280
|
-
if (edges[i].toId == parentId) {
|
281
|
-
childNode = edges[i].from;
|
282
|
-
}
|
283
|
-
else {
|
284
|
-
childNode = edges[i].to;
|
285
|
-
}
|
286
|
-
if (childNode.level == -1 || childNode.level > level) {
|
287
|
-
childNode.level = level;
|
288
|
-
if (edges.length > 1) {
|
289
|
-
this._setLevel(level+1, childNode.edges, childNode.id);
|
290
|
-
}
|
291
|
-
}
|
292
|
-
}
|
293
|
-
},
|
294
|
-
|
295
|
-
|
296
|
-
/**
|
297
|
-
* Unfix nodes
|
298
|
-
*
|
299
|
-
* @private
|
300
|
-
*/
|
301
|
-
_restoreNodes : function() {
|
302
|
-
for (nodeId in this.nodes) {
|
303
|
-
if (this.nodes.hasOwnProperty(nodeId)) {
|
304
|
-
this.nodes[nodeId].xFixed = false;
|
305
|
-
this.nodes[nodeId].yFixed = false;
|
306
|
-
}
|
307
|
-
}
|
308
|
-
}
|
309
|
-
|
310
|
-
|
311
|
-
};
|
@@ -1,576 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* Created by Alex on 2/4/14.
|
3
|
-
*/
|
4
|
-
|
5
|
-
var manipulationMixin = {
|
6
|
-
|
7
|
-
/**
|
8
|
-
* clears the toolbar div element of children
|
9
|
-
*
|
10
|
-
* @private
|
11
|
-
*/
|
12
|
-
_clearManipulatorBar : function() {
|
13
|
-
while (this.manipulationDiv.hasChildNodes()) {
|
14
|
-
this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);
|
15
|
-
}
|
16
|
-
},
|
17
|
-
|
18
|
-
/**
|
19
|
-
* Manipulation UI temporarily overloads certain functions to extend or replace them. To be able to restore
|
20
|
-
* these functions to their original functionality, we saved them in this.cachedFunctions.
|
21
|
-
* This function restores these functions to their original function.
|
22
|
-
*
|
23
|
-
* @private
|
24
|
-
*/
|
25
|
-
_restoreOverloadedFunctions : function() {
|
26
|
-
for (var functionName in this.cachedFunctions) {
|
27
|
-
if (this.cachedFunctions.hasOwnProperty(functionName)) {
|
28
|
-
this[functionName] = this.cachedFunctions[functionName];
|
29
|
-
}
|
30
|
-
}
|
31
|
-
},
|
32
|
-
|
33
|
-
/**
|
34
|
-
* Enable or disable edit-mode.
|
35
|
-
*
|
36
|
-
* @private
|
37
|
-
*/
|
38
|
-
_toggleEditMode : function() {
|
39
|
-
this.editMode = !this.editMode;
|
40
|
-
var toolbar = document.getElementById("graph-manipulationDiv");
|
41
|
-
var closeDiv = document.getElementById("graph-manipulation-closeDiv");
|
42
|
-
var editModeDiv = document.getElementById("graph-manipulation-editMode");
|
43
|
-
if (this.editMode == true) {
|
44
|
-
toolbar.style.display="block";
|
45
|
-
closeDiv.style.display="block";
|
46
|
-
editModeDiv.style.display="none";
|
47
|
-
closeDiv.onclick = this._toggleEditMode.bind(this);
|
48
|
-
}
|
49
|
-
else {
|
50
|
-
toolbar.style.display="none";
|
51
|
-
closeDiv.style.display="none";
|
52
|
-
editModeDiv.style.display="block";
|
53
|
-
closeDiv.onclick = null;
|
54
|
-
}
|
55
|
-
this._createManipulatorBar()
|
56
|
-
},
|
57
|
-
|
58
|
-
/**
|
59
|
-
* main function, creates the main toolbar. Removes functions bound to the select event. Binds all the buttons of the toolbar.
|
60
|
-
*
|
61
|
-
* @private
|
62
|
-
*/
|
63
|
-
_createManipulatorBar : function() {
|
64
|
-
// remove bound functions
|
65
|
-
if (this.boundFunction) {
|
66
|
-
this.off('select', this.boundFunction);
|
67
|
-
}
|
68
|
-
if (this.edgeBeingEdited !== undefined) {
|
69
|
-
this.edgeBeingEdited._disableControlNodes();
|
70
|
-
this.edgeBeingEdited = undefined;
|
71
|
-
this.selectedControlNode = null;
|
72
|
-
}
|
73
|
-
|
74
|
-
// restore overloaded functions
|
75
|
-
this._restoreOverloadedFunctions();
|
76
|
-
|
77
|
-
// resume calculation
|
78
|
-
this.freezeSimulation = false;
|
79
|
-
|
80
|
-
// reset global variables
|
81
|
-
this.blockConnectingEdgeSelection = false;
|
82
|
-
this.forceAppendSelection = false;
|
83
|
-
|
84
|
-
if (this.editMode == true) {
|
85
|
-
while (this.manipulationDiv.hasChildNodes()) {
|
86
|
-
this.manipulationDiv.removeChild(this.manipulationDiv.firstChild);
|
87
|
-
}
|
88
|
-
// add the icons to the manipulator div
|
89
|
-
this.manipulationDiv.innerHTML = "" +
|
90
|
-
"<span class='graph-manipulationUI add' id='graph-manipulate-addNode'>" +
|
91
|
-
"<span class='graph-manipulationLabel'>"+this.constants.labels['add'] +"</span></span>" +
|
92
|
-
"<div class='graph-seperatorLine'></div>" +
|
93
|
-
"<span class='graph-manipulationUI connect' id='graph-manipulate-connectNode'>" +
|
94
|
-
"<span class='graph-manipulationLabel'>"+this.constants.labels['link'] +"</span></span>";
|
95
|
-
if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) {
|
96
|
-
this.manipulationDiv.innerHTML += "" +
|
97
|
-
"<div class='graph-seperatorLine'></div>" +
|
98
|
-
"<span class='graph-manipulationUI edit' id='graph-manipulate-editNode'>" +
|
99
|
-
"<span class='graph-manipulationLabel'>"+this.constants.labels['editNode'] +"</span></span>";
|
100
|
-
}
|
101
|
-
else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) {
|
102
|
-
this.manipulationDiv.innerHTML += "" +
|
103
|
-
"<div class='graph-seperatorLine'></div>" +
|
104
|
-
"<span class='graph-manipulationUI edit' id='graph-manipulate-editEdge'>" +
|
105
|
-
"<span class='graph-manipulationLabel'>"+this.constants.labels['editEdge'] +"</span></span>";
|
106
|
-
}
|
107
|
-
if (this._selectionIsEmpty() == false) {
|
108
|
-
this.manipulationDiv.innerHTML += "" +
|
109
|
-
"<div class='graph-seperatorLine'></div>" +
|
110
|
-
"<span class='graph-manipulationUI delete' id='graph-manipulate-delete'>" +
|
111
|
-
"<span class='graph-manipulationLabel'>"+this.constants.labels['del'] +"</span></span>";
|
112
|
-
}
|
113
|
-
|
114
|
-
|
115
|
-
// bind the icons
|
116
|
-
var addNodeButton = document.getElementById("graph-manipulate-addNode");
|
117
|
-
addNodeButton.onclick = this._createAddNodeToolbar.bind(this);
|
118
|
-
var addEdgeButton = document.getElementById("graph-manipulate-connectNode");
|
119
|
-
addEdgeButton.onclick = this._createAddEdgeToolbar.bind(this);
|
120
|
-
if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) {
|
121
|
-
var editButton = document.getElementById("graph-manipulate-editNode");
|
122
|
-
editButton.onclick = this._editNode.bind(this);
|
123
|
-
}
|
124
|
-
else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) {
|
125
|
-
var editButton = document.getElementById("graph-manipulate-editEdge");
|
126
|
-
editButton.onclick = this._createEditEdgeToolbar.bind(this);
|
127
|
-
}
|
128
|
-
if (this._selectionIsEmpty() == false) {
|
129
|
-
var deleteButton = document.getElementById("graph-manipulate-delete");
|
130
|
-
deleteButton.onclick = this._deleteSelected.bind(this);
|
131
|
-
}
|
132
|
-
var closeDiv = document.getElementById("graph-manipulation-closeDiv");
|
133
|
-
closeDiv.onclick = this._toggleEditMode.bind(this);
|
134
|
-
|
135
|
-
this.boundFunction = this._createManipulatorBar.bind(this);
|
136
|
-
this.on('select', this.boundFunction);
|
137
|
-
}
|
138
|
-
else {
|
139
|
-
this.editModeDiv.innerHTML = "" +
|
140
|
-
"<span class='graph-manipulationUI edit editmode' id='graph-manipulate-editModeButton'>" +
|
141
|
-
"<span class='graph-manipulationLabel'>" + this.constants.labels['edit'] + "</span></span>";
|
142
|
-
var editModeButton = document.getElementById("graph-manipulate-editModeButton");
|
143
|
-
editModeButton.onclick = this._toggleEditMode.bind(this);
|
144
|
-
}
|
145
|
-
},
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
/**
|
150
|
-
* Create the toolbar for adding Nodes
|
151
|
-
*
|
152
|
-
* @private
|
153
|
-
*/
|
154
|
-
_createAddNodeToolbar : function() {
|
155
|
-
// clear the toolbar
|
156
|
-
this._clearManipulatorBar();
|
157
|
-
if (this.boundFunction) {
|
158
|
-
this.off('select', this.boundFunction);
|
159
|
-
}
|
160
|
-
|
161
|
-
// create the toolbar contents
|
162
|
-
this.manipulationDiv.innerHTML = "" +
|
163
|
-
"<span class='graph-manipulationUI back' id='graph-manipulate-back'>" +
|
164
|
-
"<span class='graph-manipulationLabel'>" + this.constants.labels['back'] + " </span></span>" +
|
165
|
-
"<div class='graph-seperatorLine'></div>" +
|
166
|
-
"<span class='graph-manipulationUI none' id='graph-manipulate-back'>" +
|
167
|
-
"<span id='graph-manipulatorLabel' class='graph-manipulationLabel'>" + this.constants.labels['addDescription'] + "</span></span>";
|
168
|
-
|
169
|
-
// bind the icon
|
170
|
-
var backButton = document.getElementById("graph-manipulate-back");
|
171
|
-
backButton.onclick = this._createManipulatorBar.bind(this);
|
172
|
-
|
173
|
-
// we use the boundFunction so we can reference it when we unbind it from the "select" event.
|
174
|
-
this.boundFunction = this._addNode.bind(this);
|
175
|
-
this.on('select', this.boundFunction);
|
176
|
-
},
|
177
|
-
|
178
|
-
|
179
|
-
/**
|
180
|
-
* create the toolbar to connect nodes
|
181
|
-
*
|
182
|
-
* @private
|
183
|
-
*/
|
184
|
-
_createAddEdgeToolbar : function() {
|
185
|
-
// clear the toolbar
|
186
|
-
this._clearManipulatorBar();
|
187
|
-
this._unselectAll(true);
|
188
|
-
this.freezeSimulation = true;
|
189
|
-
|
190
|
-
if (this.boundFunction) {
|
191
|
-
this.off('select', this.boundFunction);
|
192
|
-
}
|
193
|
-
|
194
|
-
this._unselectAll();
|
195
|
-
this.forceAppendSelection = false;
|
196
|
-
this.blockConnectingEdgeSelection = true;
|
197
|
-
|
198
|
-
this.manipulationDiv.innerHTML = "" +
|
199
|
-
"<span class='graph-manipulationUI back' id='graph-manipulate-back'>" +
|
200
|
-
"<span class='graph-manipulationLabel'>" + this.constants.labels['back'] + " </span></span>" +
|
201
|
-
"<div class='graph-seperatorLine'></div>" +
|
202
|
-
"<span class='graph-manipulationUI none' id='graph-manipulate-back'>" +
|
203
|
-
"<span id='graph-manipulatorLabel' class='graph-manipulationLabel'>" + this.constants.labels['linkDescription'] + "</span></span>";
|
204
|
-
|
205
|
-
// bind the icon
|
206
|
-
var backButton = document.getElementById("graph-manipulate-back");
|
207
|
-
backButton.onclick = this._createManipulatorBar.bind(this);
|
208
|
-
|
209
|
-
// we use the boundFunction so we can reference it when we unbind it from the "select" event.
|
210
|
-
this.boundFunction = this._handleConnect.bind(this);
|
211
|
-
this.on('select', this.boundFunction);
|
212
|
-
|
213
|
-
// temporarily overload functions
|
214
|
-
this.cachedFunctions["_handleTouch"] = this._handleTouch;
|
215
|
-
this.cachedFunctions["_handleOnRelease"] = this._handleOnRelease;
|
216
|
-
this._handleTouch = this._handleConnect;
|
217
|
-
this._handleOnRelease = this._finishConnect;
|
218
|
-
|
219
|
-
// redraw to show the unselect
|
220
|
-
this._redraw();
|
221
|
-
},
|
222
|
-
|
223
|
-
/**
|
224
|
-
* create the toolbar to edit edges
|
225
|
-
*
|
226
|
-
* @private
|
227
|
-
*/
|
228
|
-
_createEditEdgeToolbar : function() {
|
229
|
-
// clear the toolbar
|
230
|
-
this._clearManipulatorBar();
|
231
|
-
|
232
|
-
if (this.boundFunction) {
|
233
|
-
this.off('select', this.boundFunction);
|
234
|
-
}
|
235
|
-
|
236
|
-
this.edgeBeingEdited = this._getSelectedEdge();
|
237
|
-
this.edgeBeingEdited._enableControlNodes();
|
238
|
-
|
239
|
-
this.manipulationDiv.innerHTML = "" +
|
240
|
-
"<span class='graph-manipulationUI back' id='graph-manipulate-back'>" +
|
241
|
-
"<span class='graph-manipulationLabel'>" + this.constants.labels['back'] + " </span></span>" +
|
242
|
-
"<div class='graph-seperatorLine'></div>" +
|
243
|
-
"<span class='graph-manipulationUI none' id='graph-manipulate-back'>" +
|
244
|
-
"<span id='graph-manipulatorLabel' class='graph-manipulationLabel'>" + this.constants.labels['editEdgeDescription'] + "</span></span>";
|
245
|
-
|
246
|
-
// bind the icon
|
247
|
-
var backButton = document.getElementById("graph-manipulate-back");
|
248
|
-
backButton.onclick = this._createManipulatorBar.bind(this);
|
249
|
-
|
250
|
-
// temporarily overload functions
|
251
|
-
this.cachedFunctions["_handleTouch"] = this._handleTouch;
|
252
|
-
this.cachedFunctions["_handleOnRelease"] = this._handleOnRelease;
|
253
|
-
this.cachedFunctions["_handleTap"] = this._handleTap;
|
254
|
-
this.cachedFunctions["_handleDragStart"] = this._handleDragStart;
|
255
|
-
this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag;
|
256
|
-
this._handleTouch = this._selectControlNode;
|
257
|
-
this._handleTap = function () {};
|
258
|
-
this._handleOnDrag = this._controlNodeDrag;
|
259
|
-
this._handleDragStart = function () {}
|
260
|
-
this._handleOnRelease = this._releaseControlNode;
|
261
|
-
|
262
|
-
// redraw to show the unselect
|
263
|
-
this._redraw();
|
264
|
-
},
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
/**
|
271
|
-
* the function bound to the selection event. It checks if you want to connect a cluster and changes the description
|
272
|
-
* to walk the user through the process.
|
273
|
-
*
|
274
|
-
* @private
|
275
|
-
*/
|
276
|
-
_selectControlNode : function(pointer) {
|
277
|
-
this.edgeBeingEdited.controlNodes.from.unselect();
|
278
|
-
this.edgeBeingEdited.controlNodes.to.unselect();
|
279
|
-
this.selectedControlNode = this.edgeBeingEdited._getSelectedControlNode(this._XconvertDOMtoCanvas(pointer.x),this._YconvertDOMtoCanvas(pointer.y));
|
280
|
-
if (this.selectedControlNode !== null) {
|
281
|
-
this.selectedControlNode.select();
|
282
|
-
this.freezeSimulation = true;
|
283
|
-
}
|
284
|
-
this._redraw();
|
285
|
-
},
|
286
|
-
|
287
|
-
/**
|
288
|
-
* the function bound to the selection event. It checks if you want to connect a cluster and changes the description
|
289
|
-
* to walk the user through the process.
|
290
|
-
*
|
291
|
-
* @private
|
292
|
-
*/
|
293
|
-
_controlNodeDrag : function(event) {
|
294
|
-
var pointer = this._getPointer(event.gesture.center);
|
295
|
-
if (this.selectedControlNode !== null && this.selectedControlNode !== undefined) {
|
296
|
-
this.selectedControlNode.x = this._XconvertDOMtoCanvas(pointer.x);
|
297
|
-
this.selectedControlNode.y = this._YconvertDOMtoCanvas(pointer.y);
|
298
|
-
}
|
299
|
-
this._redraw();
|
300
|
-
},
|
301
|
-
|
302
|
-
_releaseControlNode : function(pointer) {
|
303
|
-
var newNode = this._getNodeAt(pointer);
|
304
|
-
if (newNode != null) {
|
305
|
-
if (this.edgeBeingEdited.controlNodes.from.selected == true) {
|
306
|
-
this._editEdge(newNode.id, this.edgeBeingEdited.to.id);
|
307
|
-
this.edgeBeingEdited.controlNodes.from.unselect();
|
308
|
-
}
|
309
|
-
if (this.edgeBeingEdited.controlNodes.to.selected == true) {
|
310
|
-
this._editEdge(this.edgeBeingEdited.from.id, newNode.id);
|
311
|
-
this.edgeBeingEdited.controlNodes.to.unselect();
|
312
|
-
}
|
313
|
-
}
|
314
|
-
else {
|
315
|
-
this.edgeBeingEdited._restoreControlNodes();
|
316
|
-
}
|
317
|
-
this.freezeSimulation = false;
|
318
|
-
this._redraw();
|
319
|
-
},
|
320
|
-
|
321
|
-
/**
|
322
|
-
* the function bound to the selection event. It checks if you want to connect a cluster and changes the description
|
323
|
-
* to walk the user through the process.
|
324
|
-
*
|
325
|
-
* @private
|
326
|
-
*/
|
327
|
-
_handleConnect : function(pointer) {
|
328
|
-
if (this._getSelectedNodeCount() == 0) {
|
329
|
-
var node = this._getNodeAt(pointer);
|
330
|
-
if (node != null) {
|
331
|
-
if (node.clusterSize > 1) {
|
332
|
-
alert("Cannot create edges to a cluster.")
|
333
|
-
}
|
334
|
-
else {
|
335
|
-
this._selectObject(node,false);
|
336
|
-
// create a node the temporary line can look at
|
337
|
-
this.sectors['support']['nodes']['targetNode'] = new Node({id:'targetNode'},{},{},this.constants);
|
338
|
-
this.sectors['support']['nodes']['targetNode'].x = node.x;
|
339
|
-
this.sectors['support']['nodes']['targetNode'].y = node.y;
|
340
|
-
this.sectors['support']['nodes']['targetViaNode'] = new Node({id:'targetViaNode'},{},{},this.constants);
|
341
|
-
this.sectors['support']['nodes']['targetViaNode'].x = node.x;
|
342
|
-
this.sectors['support']['nodes']['targetViaNode'].y = node.y;
|
343
|
-
this.sectors['support']['nodes']['targetViaNode'].parentEdgeId = "connectionEdge";
|
344
|
-
|
345
|
-
// create a temporary edge
|
346
|
-
this.edges['connectionEdge'] = new Edge({id:"connectionEdge",from:node.id,to:this.sectors['support']['nodes']['targetNode'].id}, this, this.constants);
|
347
|
-
this.edges['connectionEdge'].from = node;
|
348
|
-
this.edges['connectionEdge'].connected = true;
|
349
|
-
this.edges['connectionEdge'].smooth = true;
|
350
|
-
this.edges['connectionEdge'].selected = true;
|
351
|
-
this.edges['connectionEdge'].to = this.sectors['support']['nodes']['targetNode'];
|
352
|
-
this.edges['connectionEdge'].via = this.sectors['support']['nodes']['targetViaNode'];
|
353
|
-
|
354
|
-
this.cachedFunctions["_handleOnDrag"] = this._handleOnDrag;
|
355
|
-
this._handleOnDrag = function(event) {
|
356
|
-
var pointer = this._getPointer(event.gesture.center);
|
357
|
-
this.sectors['support']['nodes']['targetNode'].x = this._XconvertDOMtoCanvas(pointer.x);
|
358
|
-
this.sectors['support']['nodes']['targetNode'].y = this._YconvertDOMtoCanvas(pointer.y);
|
359
|
-
this.sectors['support']['nodes']['targetViaNode'].x = 0.5 * (this._XconvertDOMtoCanvas(pointer.x) + this.edges['connectionEdge'].from.x);
|
360
|
-
this.sectors['support']['nodes']['targetViaNode'].y = this._YconvertDOMtoCanvas(pointer.y);
|
361
|
-
};
|
362
|
-
|
363
|
-
this.moving = true;
|
364
|
-
this.start();
|
365
|
-
}
|
366
|
-
}
|
367
|
-
}
|
368
|
-
},
|
369
|
-
|
370
|
-
_finishConnect : function(pointer) {
|
371
|
-
if (this._getSelectedNodeCount() == 1) {
|
372
|
-
|
373
|
-
// restore the drag function
|
374
|
-
this._handleOnDrag = this.cachedFunctions["_handleOnDrag"];
|
375
|
-
delete this.cachedFunctions["_handleOnDrag"];
|
376
|
-
|
377
|
-
// remember the edge id
|
378
|
-
var connectFromId = this.edges['connectionEdge'].fromId;
|
379
|
-
|
380
|
-
// remove the temporary nodes and edge
|
381
|
-
delete this.edges['connectionEdge'];
|
382
|
-
delete this.sectors['support']['nodes']['targetNode'];
|
383
|
-
delete this.sectors['support']['nodes']['targetViaNode'];
|
384
|
-
|
385
|
-
var node = this._getNodeAt(pointer);
|
386
|
-
if (node != null) {
|
387
|
-
if (node.clusterSize > 1) {
|
388
|
-
alert("Cannot create edges to a cluster.")
|
389
|
-
}
|
390
|
-
else {
|
391
|
-
this._createEdge(connectFromId,node.id);
|
392
|
-
this._createManipulatorBar();
|
393
|
-
}
|
394
|
-
}
|
395
|
-
this._unselectAll();
|
396
|
-
}
|
397
|
-
},
|
398
|
-
|
399
|
-
|
400
|
-
/**
|
401
|
-
* Adds a node on the specified location
|
402
|
-
*/
|
403
|
-
_addNode : function() {
|
404
|
-
if (this._selectionIsEmpty() && this.editMode == true) {
|
405
|
-
var positionObject = this._pointerToPositionObject(this.pointerPosition);
|
406
|
-
var defaultData = {id:util.randomUUID(),x:positionObject.left,y:positionObject.top,label:"new",allowedToMoveX:true,allowedToMoveY:true};
|
407
|
-
if (this.triggerFunctions.add) {
|
408
|
-
if (this.triggerFunctions.add.length == 2) {
|
409
|
-
var me = this;
|
410
|
-
this.triggerFunctions.add(defaultData, function(finalizedData) {
|
411
|
-
me.nodesData.add(finalizedData);
|
412
|
-
me._createManipulatorBar();
|
413
|
-
me.moving = true;
|
414
|
-
me.start();
|
415
|
-
});
|
416
|
-
}
|
417
|
-
else {
|
418
|
-
alert(this.constants.labels['addError']);
|
419
|
-
this._createManipulatorBar();
|
420
|
-
this.moving = true;
|
421
|
-
this.start();
|
422
|
-
}
|
423
|
-
}
|
424
|
-
else {
|
425
|
-
this.nodesData.add(defaultData);
|
426
|
-
this._createManipulatorBar();
|
427
|
-
this.moving = true;
|
428
|
-
this.start();
|
429
|
-
}
|
430
|
-
}
|
431
|
-
},
|
432
|
-
|
433
|
-
|
434
|
-
/**
|
435
|
-
* connect two nodes with a new edge.
|
436
|
-
*
|
437
|
-
* @private
|
438
|
-
*/
|
439
|
-
_createEdge : function(sourceNodeId,targetNodeId) {
|
440
|
-
if (this.editMode == true) {
|
441
|
-
var defaultData = {from:sourceNodeId, to:targetNodeId};
|
442
|
-
if (this.triggerFunctions.connect) {
|
443
|
-
if (this.triggerFunctions.connect.length == 2) {
|
444
|
-
var me = this;
|
445
|
-
this.triggerFunctions.connect(defaultData, function(finalizedData) {
|
446
|
-
me.edgesData.add(finalizedData);
|
447
|
-
me.moving = true;
|
448
|
-
me.start();
|
449
|
-
});
|
450
|
-
}
|
451
|
-
else {
|
452
|
-
alert(this.constants.labels["linkError"]);
|
453
|
-
this.moving = true;
|
454
|
-
this.start();
|
455
|
-
}
|
456
|
-
}
|
457
|
-
else {
|
458
|
-
this.edgesData.add(defaultData);
|
459
|
-
this.moving = true;
|
460
|
-
this.start();
|
461
|
-
}
|
462
|
-
}
|
463
|
-
},
|
464
|
-
|
465
|
-
/**
|
466
|
-
* connect two nodes with a new edge.
|
467
|
-
*
|
468
|
-
* @private
|
469
|
-
*/
|
470
|
-
_editEdge : function(sourceNodeId,targetNodeId) {
|
471
|
-
if (this.editMode == true) {
|
472
|
-
var defaultData = {id: this.edgeBeingEdited.id, from:sourceNodeId, to:targetNodeId};
|
473
|
-
if (this.triggerFunctions.editEdge) {
|
474
|
-
if (this.triggerFunctions.editEdge.length == 2) {
|
475
|
-
var me = this;
|
476
|
-
this.triggerFunctions.editEdge(defaultData, function(finalizedData) {
|
477
|
-
me.edgesData.update(finalizedData);
|
478
|
-
me.moving = true;
|
479
|
-
me.start();
|
480
|
-
});
|
481
|
-
}
|
482
|
-
else {
|
483
|
-
alert(this.constants.labels["linkError"]);
|
484
|
-
this.moving = true;
|
485
|
-
this.start();
|
486
|
-
}
|
487
|
-
}
|
488
|
-
else {
|
489
|
-
this.edgesData.update(defaultData);
|
490
|
-
this.moving = true;
|
491
|
-
this.start();
|
492
|
-
}
|
493
|
-
}
|
494
|
-
},
|
495
|
-
|
496
|
-
/**
|
497
|
-
* Create the toolbar to edit the selected node. The label and the color can be changed. Other colors are derived from the chosen color.
|
498
|
-
*
|
499
|
-
* @private
|
500
|
-
*/
|
501
|
-
_editNode : function() {
|
502
|
-
if (this.triggerFunctions.edit && this.editMode == true) {
|
503
|
-
var node = this._getSelectedNode();
|
504
|
-
var data = {id:node.id,
|
505
|
-
label: node.label,
|
506
|
-
group: node.group,
|
507
|
-
shape: node.shape,
|
508
|
-
color: {
|
509
|
-
background:node.color.background,
|
510
|
-
border:node.color.border,
|
511
|
-
highlight: {
|
512
|
-
background:node.color.highlight.background,
|
513
|
-
border:node.color.highlight.border
|
514
|
-
}
|
515
|
-
}};
|
516
|
-
if (this.triggerFunctions.edit.length == 2) {
|
517
|
-
var me = this;
|
518
|
-
this.triggerFunctions.edit(data, function (finalizedData) {
|
519
|
-
me.nodesData.update(finalizedData);
|
520
|
-
me._createManipulatorBar();
|
521
|
-
me.moving = true;
|
522
|
-
me.start();
|
523
|
-
});
|
524
|
-
}
|
525
|
-
else {
|
526
|
-
alert(this.constants.labels["editError"]);
|
527
|
-
}
|
528
|
-
}
|
529
|
-
else {
|
530
|
-
alert(this.constants.labels["editBoundError"]);
|
531
|
-
}
|
532
|
-
},
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
/**
|
538
|
-
* delete everything in the selection
|
539
|
-
*
|
540
|
-
* @private
|
541
|
-
*/
|
542
|
-
_deleteSelected : function() {
|
543
|
-
if (!this._selectionIsEmpty() && this.editMode == true) {
|
544
|
-
if (!this._clusterInSelection()) {
|
545
|
-
var selectedNodes = this.getSelectedNodes();
|
546
|
-
var selectedEdges = this.getSelectedEdges();
|
547
|
-
if (this.triggerFunctions.del) {
|
548
|
-
var me = this;
|
549
|
-
var data = {nodes: selectedNodes, edges: selectedEdges};
|
550
|
-
if (this.triggerFunctions.del.length = 2) {
|
551
|
-
this.triggerFunctions.del(data, function (finalizedData) {
|
552
|
-
me.edgesData.remove(finalizedData.edges);
|
553
|
-
me.nodesData.remove(finalizedData.nodes);
|
554
|
-
me._unselectAll();
|
555
|
-
me.moving = true;
|
556
|
-
me.start();
|
557
|
-
});
|
558
|
-
}
|
559
|
-
else {
|
560
|
-
alert(this.constants.labels["deleteError"])
|
561
|
-
}
|
562
|
-
}
|
563
|
-
else {
|
564
|
-
this.edgesData.remove(selectedEdges);
|
565
|
-
this.nodesData.remove(selectedNodes);
|
566
|
-
this._unselectAll();
|
567
|
-
this.moving = true;
|
568
|
-
this.start();
|
569
|
-
}
|
570
|
-
}
|
571
|
-
else {
|
572
|
-
alert(this.constants.labels["deleteClusterError"]);
|
573
|
-
}
|
574
|
-
}
|
575
|
-
}
|
576
|
-
};
|