1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | var __extends = (this && this.__extends) || (function () {
|
7 | var extendStatics = function (d, b) {
|
8 | extendStatics = Object.setPrototypeOf ||
|
9 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
10 | function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
11 | return extendStatics(d, b);
|
12 | };
|
13 | return function (d, b) {
|
14 | extendStatics(d, b);
|
15 | function __() { this.constructor = d; }
|
16 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
17 | };
|
18 | })();
|
19 | Object.defineProperty(exports, "__esModule", { value: true });
|
20 | exports.GForceLayout = void 0;
|
21 | var base_1 = require("./base");
|
22 | var util_1 = require("../util");
|
23 | var proccessToFunc = function (value, defaultV) {
|
24 | var func;
|
25 | if (!value) {
|
26 | func = function (d) {
|
27 | return defaultV || 1;
|
28 | };
|
29 | }
|
30 | else if (util_1.isNumber(value)) {
|
31 | func = function (d) {
|
32 | return value;
|
33 | };
|
34 | }
|
35 | else {
|
36 | func = value;
|
37 | }
|
38 | return func;
|
39 | };
|
40 |
|
41 |
|
42 |
|
43 | var GForceLayout = (function (_super) {
|
44 | __extends(GForceLayout, _super);
|
45 | function GForceLayout(options) {
|
46 | var _this = _super.call(this) || this;
|
47 |
|
48 | _this.maxIteration = 1000;
|
49 |
|
50 | _this.edgeStrength = 200;
|
51 |
|
52 | _this.nodeStrength = 1000;
|
53 |
|
54 | _this.coulombDisScale = 0.005;
|
55 |
|
56 | _this.damping = 0.9;
|
57 |
|
58 | _this.maxSpeed = 1000;
|
59 |
|
60 | _this.minMovement = 0.5;
|
61 |
|
62 | _this.interval = 0.02;
|
63 |
|
64 | _this.factor = 1;
|
65 |
|
66 | _this.linkDistance = 1;
|
67 |
|
68 | _this.gravity = 10;
|
69 |
|
70 | _this.preventOverlap = true;
|
71 |
|
72 | _this.tick = function () { };
|
73 | _this.nodes = [];
|
74 | _this.edges = [];
|
75 | _this.width = 300;
|
76 | _this.height = 300;
|
77 | _this.nodeMap = {};
|
78 | _this.nodeIdxMap = {};
|
79 | _this.updateCfg(options);
|
80 | return _this;
|
81 | }
|
82 | GForceLayout.prototype.getDefaultCfg = function () {
|
83 | return {
|
84 | maxIteration: 500,
|
85 | gravity: 10,
|
86 | enableTick: true,
|
87 | };
|
88 | };
|
89 | |
90 |
|
91 |
|
92 | GForceLayout.prototype.execute = function () {
|
93 | var self = this;
|
94 | var nodes = self.nodes;
|
95 | if (self.timeInterval !== undefined && typeof window !== 'undefined') {
|
96 | window.clearInterval(self.timeInterval);
|
97 | }
|
98 | if (!nodes || nodes.length === 0) {
|
99 | return;
|
100 | }
|
101 | if (!self.width && typeof window !== 'undefined') {
|
102 | self.width = window.innerWidth;
|
103 | }
|
104 | if (!self.height && typeof window !== 'undefined') {
|
105 | self.height = window.innerHeight;
|
106 | }
|
107 | if (!self.center) {
|
108 | self.center = [self.width / 2, self.height / 2];
|
109 | }
|
110 | var center = self.center;
|
111 | if (nodes.length === 1) {
|
112 | nodes[0].x = center[0];
|
113 | nodes[0].y = center[1];
|
114 | return;
|
115 | }
|
116 | var nodeMap = {};
|
117 | var nodeIdxMap = {};
|
118 | nodes.forEach(function (node, i) {
|
119 | if (!util_1.isNumber(node.x))
|
120 | node.x = Math.random() * self.width;
|
121 | if (!util_1.isNumber(node.y))
|
122 | node.y = Math.random() * self.height;
|
123 | nodeMap[node.id] = node;
|
124 | nodeIdxMap[node.id] = i;
|
125 | });
|
126 | self.nodeMap = nodeMap;
|
127 | self.nodeIdxMap = nodeIdxMap;
|
128 | self.linkDistance = proccessToFunc(self.linkDistance, 1);
|
129 | self.nodeStrength = proccessToFunc(self.nodeStrength, 1);
|
130 | self.edgeStrength = proccessToFunc(self.edgeStrength, 1);
|
131 |
|
132 | var nodeSize = self.nodeSize;
|
133 | var nodeSizeFunc;
|
134 | if (self.preventOverlap) {
|
135 | var nodeSpacing_1 = self.nodeSpacing;
|
136 | var nodeSpacingFunc_1;
|
137 | if (util_1.isNumber(nodeSpacing_1)) {
|
138 | nodeSpacingFunc_1 = function () { return nodeSpacing_1; };
|
139 | }
|
140 | else if (util_1.isFunction(nodeSpacing_1)) {
|
141 | nodeSpacingFunc_1 = nodeSpacing_1;
|
142 | }
|
143 | else {
|
144 | nodeSpacingFunc_1 = function () { return 0; };
|
145 | }
|
146 | if (!nodeSize) {
|
147 | nodeSizeFunc = function (d) {
|
148 | if (d.size) {
|
149 | if (util_1.isArray(d.size)) {
|
150 | var res = d.size[0] > d.size[1] ? d.size[0] : d.size[1];
|
151 | return res + nodeSpacingFunc_1(d);
|
152 | }
|
153 | return d.size + nodeSpacingFunc_1(d);
|
154 | }
|
155 | return 10 + nodeSpacingFunc_1(d);
|
156 | };
|
157 | }
|
158 | else if (util_1.isArray(nodeSize)) {
|
159 | nodeSizeFunc = function (d) {
|
160 | var res = nodeSize[0] > nodeSize[1] ? nodeSize[0] : nodeSize[1];
|
161 | return res + nodeSpacingFunc_1(d);
|
162 | };
|
163 | }
|
164 | else {
|
165 | nodeSizeFunc = function (d) { return nodeSize + nodeSpacingFunc_1(d); };
|
166 | }
|
167 | }
|
168 | self.nodeSize = nodeSizeFunc;
|
169 | var edges = self.edges;
|
170 | self.degrees = util_1.getDegree(nodes.length, self.nodeIdxMap, edges);
|
171 | if (!self.getMass) {
|
172 | self.getMass = function (d) {
|
173 | return self.degrees[self.nodeIdxMap[d.id]];
|
174 | };
|
175 | }
|
176 |
|
177 | self.run();
|
178 | };
|
179 | GForceLayout.prototype.run = function () {
|
180 | var self = this;
|
181 | var nodes = self.nodes;
|
182 | var edges = self.edges;
|
183 | var maxIteration = self.maxIteration;
|
184 | if (typeof window === 'undefined')
|
185 | return;
|
186 | var iter = 0;
|
187 |
|
188 | this.timeInterval = window.setInterval(function () {
|
189 | var accArray = [];
|
190 | var velArray = [];
|
191 | if (!nodes)
|
192 | return;
|
193 | nodes.forEach(function (_, i) {
|
194 | accArray[2 * i] = 0;
|
195 | accArray[2 * i + 1] = 0;
|
196 | velArray[2 * i] = 0;
|
197 | velArray[2 * i + 1] = 0;
|
198 | });
|
199 | self.calRepulsive(accArray, nodes);
|
200 | if (edges)
|
201 | self.calAttractive(accArray, edges);
|
202 | self.calGravity(accArray, nodes);
|
203 | var stepInterval = Math.max(0.02, self.interval - iter * 0.002);
|
204 | self.updateVelocity(accArray, velArray, stepInterval, nodes);
|
205 | var previousPos = [];
|
206 | nodes.forEach(function (node) {
|
207 | previousPos.push({
|
208 | x: node.x,
|
209 | y: node.y,
|
210 | });
|
211 | });
|
212 | self.updatePosition(velArray, stepInterval, nodes);
|
213 | if (self.tick)
|
214 | self.tick();
|
215 |
|
216 | var movement = 0;
|
217 | nodes.forEach(function (node, j) {
|
218 | var vx = node.x - previousPos[j].x;
|
219 | var vy = node.y - previousPos[j].y;
|
220 | movement += Math.sqrt(vx * vx + vy * vy);
|
221 | });
|
222 | movement /= nodes.length;
|
223 | if (movement < self.minMovement) {
|
224 | window.clearInterval(self.timeInterval);
|
225 | if (self.onLayoutEnd)
|
226 | self.onLayoutEnd();
|
227 | }
|
228 | iter++;
|
229 | if (iter > maxIteration) {
|
230 | window.clearInterval(self.timeInterval);
|
231 | if (self.onLayoutEnd)
|
232 | self.onLayoutEnd();
|
233 | }
|
234 | }, 0);
|
235 | };
|
236 | GForceLayout.prototype.calRepulsive = function (accArray, nodes) {
|
237 | var self = this;
|
238 |
|
239 | var getMass = self.getMass;
|
240 | var nodeStrength = self.nodeStrength;
|
241 | var factor = self.factor;
|
242 | var coulombDisScale = self.coulombDisScale;
|
243 | var preventOverlap = self.preventOverlap;
|
244 | var nodeSize = self.nodeSize;
|
245 | nodes.forEach(function (ni, i) {
|
246 | var massi = getMass ? getMass(ni) : 1;
|
247 | nodes.forEach(function (nj, j) {
|
248 | if (i >= j)
|
249 | return;
|
250 |
|
251 | var vecX = ni.x - nj.x;
|
252 | var vecY = ni.y - nj.y;
|
253 | var vecLength = Math.sqrt(vecX * vecX + vecY * vecY) + 0.01;
|
254 | var nVecLength = (vecLength + 0.1) * coulombDisScale;
|
255 | var direX = vecX / vecLength;
|
256 | var direY = vecY / vecLength;
|
257 | var param = (((nodeStrength(ni) + nodeStrength(nj)) / 2) * factor) /
|
258 | (nVecLength * nVecLength);
|
259 | var massj = getMass ? getMass(nj) : 1;
|
260 | accArray[2 * i] += (direX * param) / massi;
|
261 | accArray[2 * i + 1] += (direY * param) / massi;
|
262 | accArray[2 * j] -= (direX * param) / massj;
|
263 | accArray[2 * j + 1] -= (direY * param) / massj;
|
264 | if (preventOverlap && vecLength < (nodeSize(ni) + nodeSize(nj)) / 2) {
|
265 | var paramOverlap = (nodeStrength(ni) + nodeStrength(nj)) / 2 / (vecLength * vecLength);
|
266 | accArray[2 * i] += (direX * paramOverlap) / massi;
|
267 | accArray[2 * i + 1] += (direY * paramOverlap) / massi;
|
268 | accArray[2 * j] -= (direX * paramOverlap) / massj;
|
269 | accArray[2 * j + 1] -= (direY * paramOverlap) / massj;
|
270 | }
|
271 | });
|
272 | });
|
273 | };
|
274 | GForceLayout.prototype.calAttractive = function (accArray, edges) {
|
275 | var self = this;
|
276 |
|
277 | var nodeMap = self.nodeMap;
|
278 | var nodeIdxMap = self.nodeIdxMap;
|
279 | var linkDistance = self.linkDistance;
|
280 | var edgeStrength = self.edgeStrength;
|
281 | var getMass = self.getMass;
|
282 | edges.forEach(function (edge, i) {
|
283 | var sourceNode = nodeMap[edge.source];
|
284 | var targetNode = nodeMap[edge.target];
|
285 | var vecX = targetNode.x - sourceNode.x;
|
286 | var vecY = targetNode.y - sourceNode.y;
|
287 | var vecLength = Math.sqrt(vecX * vecX + vecY * vecY) + 0.01;
|
288 | var direX = vecX / vecLength;
|
289 | var direY = vecY / vecLength;
|
290 | var length = linkDistance(edge) || 1;
|
291 | var diff = length - vecLength;
|
292 | var param = diff * edgeStrength(edge);
|
293 | var sourceIdx = nodeIdxMap[edge.source];
|
294 | var targetIdx = nodeIdxMap[edge.target];
|
295 | var massSource = getMass ? getMass(sourceNode) : 1;
|
296 | var massTarget = getMass ? getMass(targetNode) : 1;
|
297 | accArray[2 * sourceIdx] -= (direX * param) / massSource;
|
298 | accArray[2 * sourceIdx + 1] -= (direY * param) / massSource;
|
299 | accArray[2 * targetIdx] += (direX * param) / massTarget;
|
300 | accArray[2 * targetIdx + 1] += (direY * param) / massTarget;
|
301 | });
|
302 | };
|
303 | GForceLayout.prototype.calGravity = function (accArray, nodes) {
|
304 | var self = this;
|
305 |
|
306 | var center = self.center;
|
307 | var defaultGravity = self.gravity;
|
308 | var degrees = self.degrees;
|
309 | var nodeLength = nodes.length;
|
310 | for (var i = 0; i < nodeLength; i++) {
|
311 | var node = nodes[i];
|
312 | var vecX = node.x - center[0];
|
313 | var vecY = node.y - center[1];
|
314 | var gravity = defaultGravity;
|
315 | if (self.getCenter) {
|
316 | var customCenterOpt = self.getCenter(node, degrees[i]);
|
317 | if (customCenterOpt &&
|
318 | util_1.isNumber(customCenterOpt[0]) &&
|
319 | util_1.isNumber(customCenterOpt[1]) &&
|
320 | util_1.isNumber(customCenterOpt[2])) {
|
321 | vecX = node.x - customCenterOpt[0];
|
322 | vecY = node.y - customCenterOpt[1];
|
323 | gravity = customCenterOpt[2];
|
324 | }
|
325 | }
|
326 | if (!gravity)
|
327 | continue;
|
328 | accArray[2 * i] -= gravity * vecX;
|
329 | accArray[2 * i + 1] -= gravity * vecY;
|
330 | }
|
331 | };
|
332 | GForceLayout.prototype.updateVelocity = function (accArray, velArray, stepInterval, nodes) {
|
333 | var self = this;
|
334 | var param = stepInterval * self.damping;
|
335 |
|
336 | nodes.forEach(function (node, i) {
|
337 | var vx = accArray[2 * i] * param || 0.01;
|
338 | var vy = accArray[2 * i + 1] * param || 0.01;
|
339 | var vLength = Math.sqrt(vx * vx + vy * vy);
|
340 | if (vLength > self.maxSpeed) {
|
341 | var param2 = self.maxSpeed / vLength;
|
342 | vx = param2 * vx;
|
343 | vy = param2 * vy;
|
344 | }
|
345 | velArray[2 * i] = vx;
|
346 | velArray[2 * i + 1] = vy;
|
347 | });
|
348 | };
|
349 | GForceLayout.prototype.updatePosition = function (velArray, stepInterval, nodes) {
|
350 | nodes.forEach(function (node, i) {
|
351 | var distX = velArray[2 * i] * stepInterval;
|
352 | var distY = velArray[2 * i + 1] * stepInterval;
|
353 | node.x += distX;
|
354 | node.y += distY;
|
355 | });
|
356 | };
|
357 | GForceLayout.prototype.stop = function () {
|
358 | if (this.timeInterval && typeof window !== 'undefined') {
|
359 | window.clearInterval(this.timeInterval);
|
360 | }
|
361 | };
|
362 | GForceLayout.prototype.destroy = function () {
|
363 | var self = this;
|
364 | self.stop();
|
365 | self.tick = null;
|
366 | self.nodes = null;
|
367 | self.edges = null;
|
368 | self.destroyed = true;
|
369 | };
|
370 | GForceLayout.prototype.getType = function () {
|
371 | return 'gForce';
|
372 | };
|
373 | return GForceLayout;
|
374 | }(base_1.Base));
|
375 | exports.GForceLayout = GForceLayout;
|
376 |
|
\ | No newline at end of file |