1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | function RadialLayout() {
|
22 | go.Layout.call(this);
|
23 | this._root = null;
|
24 | this._layerThickness = 100;
|
25 | this._maxLayers = Infinity;
|
26 | }
|
27 | go.Diagram.inherit(RadialLayout, go.Layout);
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | RadialLayout.prototype.cloneProtected = function(copy) {
|
36 | go.Layout.prototype.cloneProtected.call(this, copy);
|
37 |
|
38 | copy._layerThickness = this._layerThickness;
|
39 | copy._maxLayers = this._maxLayers;
|
40 | };
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | Object.defineProperty(RadialLayout.prototype, "root", {
|
49 | get: function() { return this._root; },
|
50 | set: function(value) {
|
51 | if (this._root !== value) {
|
52 | this._root = value;
|
53 | this.invalidateLayout();
|
54 | }
|
55 | }
|
56 | });
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 | Object.defineProperty(RadialLayout.prototype, "layerThickness", {
|
65 | get: function() { return this._layerThickness; },
|
66 | set: function(value) {
|
67 | if (this._layerThickness !== value) {
|
68 | this._layerThickness = value;
|
69 | this.invalidateLayout();
|
70 | }
|
71 | }
|
72 | });
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | Object.defineProperty(RadialLayout.prototype, "maxLayers", {
|
82 | get: function() { return this._maxLayers; },
|
83 | set: function(value) {
|
84 | if (this._maxLayers !== value) {
|
85 | this._maxLayers = value;
|
86 | this.invalidateLayout();
|
87 | }
|
88 | }
|
89 | });
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | RadialLayout.prototype.createNetwork = function() {
|
97 | var net = new go.LayoutNetwork(this);
|
98 | net.createVertex = function() { return new RadialVertex(net); };
|
99 | return net;
|
100 | }
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | RadialLayout.prototype.doLayout = function(coll) {
|
107 | if (this.network === null) {
|
108 | this.network = this.makeNetwork(coll);
|
109 | }
|
110 | if (this.network.vertexes.count === 0) {
|
111 | this.network = null;
|
112 | return;
|
113 | }
|
114 |
|
115 | if (this.root === null) {
|
116 |
|
117 | var it = this.network.vertexes.iterator;
|
118 | while (it.next()) {
|
119 | var v = it.value;
|
120 | if (v.node !== null && v.sourceEdges.count === 0) {
|
121 | this.root = v.node;
|
122 | break;
|
123 | }
|
124 | }
|
125 | }
|
126 | if (this.root === null) {
|
127 |
|
128 | this.root = this.network.vertexes.first().node;
|
129 | }
|
130 | if (this.root === null) {
|
131 | this.network = null;
|
132 | return;
|
133 | }
|
134 |
|
135 | var rootvert = this.network.findVertex(this.root);
|
136 | if (rootvert === null) throw new Error("RadialLayout.root must be a Node in the LayoutNetwork that the RadialLayout is operating on")
|
137 |
|
138 | this.arrangementOrigin = this.initialOrigin(this.arrangementOrigin);
|
139 | this.findDistances(rootvert);
|
140 |
|
141 |
|
142 | var verts = [];
|
143 | var maxlayer = 0;
|
144 | var it = this.network.vertexes.iterator;
|
145 | while (it.next()) {
|
146 | var v = it.value;
|
147 | v.laid = false;
|
148 | var layer = v.distance;
|
149 | if (layer === Infinity) continue;
|
150 | if (layer > maxlayer) maxlayer = layer;
|
151 | var layerverts = verts[layer];
|
152 | if (layerverts === undefined) {
|
153 | layerverts = [];
|
154 | verts[layer] = layerverts;
|
155 | }
|
156 | layerverts.push(v);
|
157 | }
|
158 |
|
159 |
|
160 | rootvert.centerX = this.arrangementOrigin.x;
|
161 | rootvert.centerY = this.arrangementOrigin.y;
|
162 | this.radlay1(rootvert, 1, 0, 360);
|
163 |
|
164 |
|
165 | this.updateParts();
|
166 | this.network = null;
|
167 | }
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 | RadialLayout.prototype.radlay1 = function(vert, layer, angle, sweep) {
|
179 | if (layer > this.maxLayers) return;
|
180 | var verts = [];
|
181 | vert.vertexes.each(function(v) {
|
182 | if (v.laid) return;
|
183 | if (v.distance === layer) verts.push(v);
|
184 | });
|
185 | var found = verts.length;
|
186 | if (found === 0) return;
|
187 |
|
188 | var radius = layer * this.layerThickness;
|
189 | var separator = sweep / found;
|
190 | var start = angle - sweep / 2 + separator / 2;
|
191 |
|
192 | for (var i = 0; i < found; i++) {
|
193 | var v = verts[i];
|
194 | var a = start + i * separator;
|
195 | if (a < 0) a += 360; else if (a > 360) a -= 360;
|
196 |
|
197 |
|
198 | var p = new go.Point(radius, 0);
|
199 | p.rotate(a);
|
200 | v.centerX = p.x + this.arrangementOrigin.x;
|
201 | v.centerY = p.y + this.arrangementOrigin.y;
|
202 | v.laid = true;
|
203 | v.angle = a;
|
204 | v.sweep = separator;
|
205 | v.radius = radius;
|
206 |
|
207 | this.radlay1(v, layer + 1, a, sweep / found);
|
208 | }
|
209 | };
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 | RadialLayout.prototype.findDistances = function(source) {
|
218 | var diagram = this.diagram;
|
219 |
|
220 | this.network.vertexes.each(function(v) { v.distance = Infinity; });
|
221 |
|
222 | source.distance = 0;
|
223 |
|
224 |
|
225 | var seen = new go.Set();
|
226 | seen.add(source);
|
227 |
|
228 |
|
229 | function leastVertex(coll) {
|
230 | var bestdist = Infinity;
|
231 | var bestvert = null;
|
232 | var it = coll.iterator;
|
233 | while (it.next()) {
|
234 | var v = it.value;
|
235 | var dist = v.distance;
|
236 | if (dist < bestdist) {
|
237 | bestdist = dist;
|
238 | bestvert = v;
|
239 | }
|
240 | }
|
241 | return bestvert;
|
242 | }
|
243 |
|
244 |
|
245 |
|
246 | var finished = new go.Set();
|
247 | while (seen.count > 0) {
|
248 |
|
249 | var least = leastVertex(seen);
|
250 | var leastdist = least.distance;
|
251 |
|
252 | seen.remove(least);
|
253 | finished.add(least);
|
254 |
|
255 | least.edges.each(function(e) {
|
256 | var neighbor = e.getOtherVertex(least);
|
257 |
|
258 | if (finished.contains(neighbor)) return;
|
259 | var neighbordist = neighbor.distance;
|
260 |
|
261 | var dist = leastdist + 1;
|
262 | if (dist < neighbordist) {
|
263 |
|
264 | if (neighbordist == Infinity) {
|
265 | seen.add(neighbor);
|
266 | }
|
267 |
|
268 | neighbor.distance = dist;
|
269 | }
|
270 | });
|
271 | }
|
272 | }
|
273 |
|
274 |
|
275 |
|
276 |
|
277 |
|
278 | RadialLayout.prototype.commitLayout = function() {
|
279 | go.Layout.prototype.commitLayout.call(this);
|
280 |
|
281 | var it = this.network.vertexes.iterator;
|
282 | while (it.next()) {
|
283 | var v = it.value;
|
284 | var n = v.node;
|
285 | if (n !== null) {
|
286 | n.visible = (v.distance <= this.maxLayers);
|
287 | this.rotateNode(n, v.angle, v.sweep, v.radius);
|
288 | }
|
289 | }
|
290 |
|
291 | this.commitLayers();
|
292 | };
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 |
|
303 | RadialLayout.prototype.rotateNode = function(node, angle, sweep, radius) {
|
304 | };
|
305 |
|
306 |
|
307 |
|
308 |
|
309 |
|
310 |
|
311 | RadialLayout.prototype.commitLayers = function() {
|
312 | };
|
313 |
|
314 |
|
315 |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 |
|
321 |
|
322 | function RadialVertex(network) {
|
323 | go.LayoutVertex.call(this, network);
|
324 | this.distance = Infinity;
|
325 | this.laid = false;
|
326 | this.angle = 0;
|
327 | this.sweep = 0;
|
328 | this.radius = 0;
|
329 | }
|
330 | go.Diagram.inherit(RadialVertex, go.LayoutVertex);
|
331 |
|