-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelpers.js
187 lines (155 loc) · 5.02 KB
/
helpers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/**
* Graphology ForceAtlas2 Helpers
* ===============================
*
* Miscellaneous helper functions.
*/
/**
* Constants.
*/
var PPN = 10,
PPE = 3;
/**
* Very simple Object.assign-like function.
*
* @param {object} target - First object.
* @param {object} [...objects] - Objects to merge.
* @return {object}
*/
exports.assign = function(target) {
target = target || {};
var objects = Array.prototype.slice.call(arguments).slice(1),
i,
k,
l;
for (i = 0, l = objects.length; i < l; i++) {
if (!objects[i])
continue;
for (k in objects[i])
target[k] = objects[i][k];
}
return target;
};
/**
* Function used to validate the given settings.
*
* @param {object} settings - Settings to validate.
* @return {object|null}
*/
exports.validateSettings = function(settings) {
if ('linLogMode' in settings &&
typeof settings.linLogMode !== 'boolean')
return {message: 'the `linLogMode` setting should be a boolean.'};
if ('outboundAttractionDistribution' in settings &&
typeof settings.outboundAttractionDistribution !== 'boolean')
return {message: 'the `outboundAttractionDistribution` setting should be a boolean.'};
if ('adjustSizes' in settings &&
typeof settings.adjustSizes !== 'boolean')
return {message: 'the `adjustSizes` setting should be a boolean.'};
if ('edgeWeightInfluence' in settings &&
typeof settings.edgeWeightInfluence !== 'number' &&
settings.edgeWeightInfluence < 0)
return {message: 'the `edgeWeightInfluence` setting should be a number >= 0.'};
if ('scalingRatio' in settings &&
typeof settings.scalingRatio !== 'number' &&
settings.scalingRatio < 0)
return {message: 'the `scalingRatio` setting should be a number >= 0.'};
if ('strongGravityMode' in settings &&
typeof settings.strongGravityMode !== 'boolean')
return {message: 'the `strongGravityMode` setting should be a boolean.'};
if ('gravity' in settings &&
typeof settings.gravity !== 'number' &&
settings.gravity < 0)
return {message: 'the `gravity` setting should be a number >= 0.'};
if ('slowDown' in settings &&
typeof settings.slowDown !== 'number' &&
settings.slowDown < 0)
return {message: 'the `slowDown` setting should be a number >= 0.'};
if ('barnesHutOptimize' in settings &&
typeof settings.barnesHutOptimize !== 'boolean')
return {message: 'the `barnesHutOptimize` setting should be a boolean.'};
if ('barnesHutTheta' in settings &&
typeof settings.barnesHutTheta !== 'number' &&
settings.barnesHutTheta < 0)
return {message: 'the `barnesHutTheta` setting should be a number >= 0.'};
return null;
};
/**
* Function generating a flat matrix for both nodes & edges of the given graph.
*
* @param {Graph} graph - Target graph.
* @return {object} - Both matrices.
*/
exports.graphToByteArrays = function(graph) {
var nodes = graph.nodes(),
edges = graph.edges(),
order = nodes.length,
size = edges.length,
index = {},
i,
j;
var NodeMatrix = new Float32Array(order * PPN),
EdgeMatrix = new Float32Array(size * PPE);
// Iterate through nodes
for (i = j = 0; i < order; i++) {
// Node index
index[nodes[i]] = j;
// Populating byte array
NodeMatrix[j] = graph.getNodeAttribute(nodes[i], 'x');
NodeMatrix[j + 1] = graph.getNodeAttribute(nodes[i], 'y');
NodeMatrix[j + 2] = 0;
NodeMatrix[j + 3] = 0;
NodeMatrix[j + 4] = 0;
NodeMatrix[j + 5] = 0;
NodeMatrix[j + 6] = 1 + graph.degree(nodes[i]);
NodeMatrix[j + 7] = 1;
NodeMatrix[j + 8] = graph.getNodeAttribute(nodes[i], 'size') || 1;
NodeMatrix[j + 9] = 0;
j += PPN;
}
// Iterate through edges
for (i = j = 0; i < size; i++) {
// Populating byte array
EdgeMatrix[j] = index[graph.source(edges[i])];
EdgeMatrix[j + 1] = index[graph.target(edges[i])];
EdgeMatrix[j + 2] = graph.getEdgeAttribute(edges[i], 'weight') || 0;
j += PPE;
}
return {
nodes: NodeMatrix,
edges: EdgeMatrix
};
};
/**
* Function applying the layout back to the graph.
*
* @param {Graph} graph - Target graph.
* @param {Float32Array} NodeMatrix - Node matrix.
*/
exports.applyLayoutChanges = function(graph, NodeMatrix) {
var nodes = graph.nodes();
for (var i = 0, j = 0, l = NodeMatrix.length; i < l; i += PPN) {
graph.setNodeAttribute(nodes[j], 'x', NodeMatrix[i]);
graph.setNodeAttribute(nodes[j], 'y', NodeMatrix[i + 1]);
j++;
}
};
/**
* Function collecting the layout positions.
*
* @param {Graph} graph - Target graph.
* @param {Float32Array} NodeMatrix - Node matrix.
* @return {object} - Map to node positions.
*/
exports.collectLayoutChanges = function(graph, NodeMatrix) {
var nodes = graph.nodes(),
positions = Object.create(null);
for (var i = 0, j = 0, l = NodeMatrix.length; i < l; i += PPN) {
positions[nodes[j]] = {
x: NodeMatrix[i],
y: NodeMatrix[i + 1]
};
j++;
}
return positions;
};