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.CircularLayout = void 0;
|
21 | var base_1 = require("./base");
|
22 | var util_1 = require("../util");
|
23 | function initHierarchy(nodes, edges, nodeMap, directed) {
|
24 | nodes.forEach(function (_, i) {
|
25 | nodes[i].children = [];
|
26 | nodes[i].parent = [];
|
27 | });
|
28 | if (directed) {
|
29 | edges.forEach(function (e) {
|
30 | var sourceIdx = 0;
|
31 | if (e.source) {
|
32 | sourceIdx = nodeMap[e.source];
|
33 | }
|
34 | var targetIdx = 0;
|
35 | if (e.target) {
|
36 | targetIdx = nodeMap[e.target];
|
37 | }
|
38 | var child = nodes[sourceIdx].children;
|
39 | var parent = nodes[targetIdx].parent;
|
40 | child.push(nodes[targetIdx].id);
|
41 | parent.push(nodes[sourceIdx].id);
|
42 | });
|
43 | }
|
44 | else {
|
45 | edges.forEach(function (e) {
|
46 | var sourceIdx = 0;
|
47 | if (e.source) {
|
48 | sourceIdx = nodeMap[e.source];
|
49 | }
|
50 | var targetIdx = 0;
|
51 | if (e.target) {
|
52 | targetIdx = nodeMap[e.target];
|
53 | }
|
54 | var sourceChildren = nodes[sourceIdx].children;
|
55 | var targetChildren = nodes[targetIdx].children;
|
56 | sourceChildren.push(nodes[targetIdx].id);
|
57 | targetChildren.push(nodes[sourceIdx].id);
|
58 | });
|
59 | }
|
60 | }
|
61 | function connect(a, b, edges) {
|
62 | var m = edges.length;
|
63 | for (var i = 0; i < m; i++) {
|
64 | if ((a.id === edges[i].source && b.id === edges[i].target) ||
|
65 | (b.id === edges[i].source && a.id === edges[i].target)) {
|
66 | return true;
|
67 | }
|
68 | }
|
69 | return false;
|
70 | }
|
71 | function compareDegree(a, b) {
|
72 | var aDegree = a.degree;
|
73 | var bDegree = b.degree;
|
74 | if (aDegree < bDegree) {
|
75 | return -1;
|
76 | }
|
77 | if (aDegree > bDegree) {
|
78 | return 1;
|
79 | }
|
80 | return 0;
|
81 | }
|
82 |
|
83 |
|
84 |
|
85 | var CircularLayout = (function (_super) {
|
86 | __extends(CircularLayout, _super);
|
87 | function CircularLayout(options) {
|
88 | var _this = _super.call(this) || this;
|
89 |
|
90 | _this.radius = null;
|
91 |
|
92 | _this.startRadius = null;
|
93 |
|
94 | _this.endRadius = null;
|
95 |
|
96 | _this.startAngle = 0;
|
97 |
|
98 | _this.endAngle = 2 * Math.PI;
|
99 |
|
100 | _this.clockwise = true;
|
101 |
|
102 | _this.divisions = 1;
|
103 |
|
104 | _this.ordering = null;
|
105 |
|
106 | _this.angleRatio = 1;
|
107 | _this.nodes = [];
|
108 | _this.edges = [];
|
109 | _this.nodeMap = {};
|
110 | _this.degrees = [];
|
111 | _this.width = 300;
|
112 | _this.height = 300;
|
113 | _this.updateCfg(options);
|
114 | return _this;
|
115 | }
|
116 | CircularLayout.prototype.getDefaultCfg = function () {
|
117 | return {
|
118 | radius: null,
|
119 | startRadius: null,
|
120 | endRadius: null,
|
121 | startAngle: 0,
|
122 | endAngle: 2 * Math.PI,
|
123 | clockwise: true,
|
124 | divisions: 1,
|
125 | ordering: null,
|
126 | angleRatio: 1,
|
127 | };
|
128 | };
|
129 | |
130 |
|
131 |
|
132 | CircularLayout.prototype.execute = function () {
|
133 | var self = this;
|
134 | var nodes = self.nodes;
|
135 | var edges = self.edges;
|
136 | var n = nodes.length;
|
137 | if (n === 0) {
|
138 | return;
|
139 | }
|
140 | if (!self.width && typeof window !== 'undefined') {
|
141 | self.width = window.innerWidth;
|
142 | }
|
143 | if (!self.height && typeof window !== 'undefined') {
|
144 | self.height = window.innerHeight;
|
145 | }
|
146 | if (!self.center) {
|
147 | self.center = [self.width / 2, self.height / 2];
|
148 | }
|
149 | var center = self.center;
|
150 | if (n === 1) {
|
151 | nodes[0].x = center[0];
|
152 | nodes[0].y = center[1];
|
153 | return;
|
154 | }
|
155 | var radius = self.radius;
|
156 | var startRadius = self.startRadius;
|
157 | var endRadius = self.endRadius;
|
158 | var divisions = self.divisions;
|
159 | var startAngle = self.startAngle;
|
160 | var endAngle = self.endAngle;
|
161 | var angleStep = (endAngle - startAngle) / n;
|
162 |
|
163 | var nodeMap = {};
|
164 | nodes.forEach(function (node, i) {
|
165 | nodeMap[node.id] = i;
|
166 | });
|
167 | self.nodeMap = nodeMap;
|
168 | var degrees = util_1.getDegree(nodes.length, nodeMap, edges);
|
169 | self.degrees = degrees;
|
170 | if (!radius && !startRadius && !endRadius) {
|
171 | radius = self.height > self.width ? self.width / 2 : self.height / 2;
|
172 | }
|
173 | else if (!startRadius && endRadius) {
|
174 | startRadius = endRadius;
|
175 | }
|
176 | else if (startRadius && !endRadius) {
|
177 | endRadius = startRadius;
|
178 | }
|
179 | var angleRatio = self.angleRatio;
|
180 | var astep = angleStep * angleRatio;
|
181 | var ordering = self.ordering;
|
182 | var layoutNodes = [];
|
183 | if (ordering === 'topology') {
|
184 |
|
185 | layoutNodes = self.topologyOrdering();
|
186 | }
|
187 | else if (ordering === 'topology-directed') {
|
188 |
|
189 | layoutNodes = self.topologyOrdering(true);
|
190 | }
|
191 | else if (ordering === 'degree') {
|
192 |
|
193 | layoutNodes = self.degreeOrdering();
|
194 | }
|
195 | else {
|
196 |
|
197 | layoutNodes = nodes;
|
198 | }
|
199 | var clockwise = self.clockwise;
|
200 | var divN = Math.ceil(n / divisions);
|
201 | for (var i = 0; i < n; ++i) {
|
202 | var r = radius;
|
203 | if (!r && startRadius !== null && endRadius !== null) {
|
204 | r = startRadius + (i * (endRadius - startRadius)) / (n - 1);
|
205 | }
|
206 | if (!r) {
|
207 | r = 10 + (i * 100) / (n - 1);
|
208 | }
|
209 | var angle = startAngle +
|
210 | (i % divN) * astep +
|
211 | ((2 * Math.PI) / divisions) * Math.floor(i / divN);
|
212 | if (!clockwise) {
|
213 | angle =
|
214 | endAngle -
|
215 | (i % divN) * astep -
|
216 | ((2 * Math.PI) / divisions) * Math.floor(i / divN);
|
217 | }
|
218 | layoutNodes[i].x = center[0] + Math.cos(angle) * r;
|
219 | layoutNodes[i].y = center[1] + Math.sin(angle) * r;
|
220 | layoutNodes[i].weight = degrees[i];
|
221 | }
|
222 | return {
|
223 | nodes: layoutNodes,
|
224 | edges: this.edges,
|
225 | };
|
226 | };
|
227 | |
228 |
|
229 |
|
230 |
|
231 | CircularLayout.prototype.topologyOrdering = function (directed) {
|
232 | if (directed === void 0) { directed = false; }
|
233 | var self = this;
|
234 | var degrees = self.degrees;
|
235 | var edges = self.edges;
|
236 | var nodes = self.nodes;
|
237 | var cnodes = util_1.clone(nodes);
|
238 | var nodeMap = self.nodeMap;
|
239 | var orderedCNodes = [cnodes[0]];
|
240 | var resNodes = [nodes[0]];
|
241 | var pickFlags = [];
|
242 | var n = nodes.length;
|
243 | pickFlags[0] = true;
|
244 | initHierarchy(cnodes, edges, nodeMap, directed);
|
245 | var k = 0;
|
246 | cnodes.forEach(function (cnode, i) {
|
247 | if (i !== 0) {
|
248 | if ((i === n - 1 ||
|
249 | degrees[i] !== degrees[i + 1] ||
|
250 | connect(orderedCNodes[k], cnode, edges)) &&
|
251 | !pickFlags[i]) {
|
252 | orderedCNodes.push(cnode);
|
253 | resNodes.push(nodes[nodeMap[cnode.id]]);
|
254 | pickFlags[i] = true;
|
255 | k++;
|
256 | }
|
257 | else {
|
258 | var children = orderedCNodes[k].children;
|
259 | var foundChild = false;
|
260 | for (var j = 0; j < children.length; j++) {
|
261 | var childIdx = nodeMap[children[j]];
|
262 | if (degrees[childIdx] === degrees[i] && !pickFlags[childIdx]) {
|
263 | orderedCNodes.push(cnodes[childIdx]);
|
264 | resNodes.push(nodes[nodeMap[cnodes[childIdx].id]]);
|
265 | pickFlags[childIdx] = true;
|
266 | foundChild = true;
|
267 | break;
|
268 | }
|
269 | }
|
270 | var ii = 0;
|
271 | while (!foundChild) {
|
272 | if (!pickFlags[ii]) {
|
273 | orderedCNodes.push(cnodes[ii]);
|
274 | resNodes.push(nodes[nodeMap[cnodes[ii].id]]);
|
275 | pickFlags[ii] = true;
|
276 | foundChild = true;
|
277 | }
|
278 | ii++;
|
279 | if (ii === n) {
|
280 | break;
|
281 | }
|
282 | }
|
283 | }
|
284 | }
|
285 | });
|
286 | return resNodes;
|
287 | };
|
288 | |
289 |
|
290 |
|
291 |
|
292 | CircularLayout.prototype.degreeOrdering = function () {
|
293 | var self = this;
|
294 | var nodes = self.nodes;
|
295 | var orderedNodes = [];
|
296 | var degrees = self.degrees;
|
297 | nodes.forEach(function (node, i) {
|
298 | node.degree = degrees[i];
|
299 | orderedNodes.push(node);
|
300 | });
|
301 | orderedNodes.sort(compareDegree);
|
302 | return orderedNodes;
|
303 | };
|
304 | CircularLayout.prototype.getType = function () {
|
305 | return 'circular';
|
306 | };
|
307 | return CircularLayout;
|
308 | }(base_1.Base));
|
309 | exports.CircularLayout = CircularLayout;
|
310 |
|
\ | No newline at end of file |