1 | |
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | import * as go from '../release/go-module.js';
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | export class FishboneLayout extends go.TreeLayout {
|
28 | |
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | constructor() {
|
35 | super();
|
36 | this.alignment = go.TreeLayout.AlignmentBusBranching;
|
37 | this.setsPortSpot = false;
|
38 | this.setsChildPortSpot = false;
|
39 | }
|
40 |
|
41 | |
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 | public makeNetwork(coll: go.Diagram | go.Group | go.Iterable<go.Part>): go.LayoutNetwork {
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | const net = super.makeNetwork(coll);
|
54 |
|
55 |
|
56 | const verts = new go.List<go.TreeVertex>().addAll(net.vertexes.iterator as go.Iterator<go.TreeVertex>);
|
57 | verts.each(function(v: go.TreeVertex) {
|
58 |
|
59 | if (v.destinationEdges.count === 0) return;
|
60 | if (v.destinationEdges.count % 2 === 1) {
|
61 |
|
62 | const dummy = net.createVertex();
|
63 | dummy.bounds = new go.Rect();
|
64 | dummy.focus = new go.Point();
|
65 | net.addVertex(dummy);
|
66 | net.linkVertexes(v, dummy, null);
|
67 | }
|
68 |
|
69 |
|
70 | const dummy2 = net.createVertex();
|
71 | dummy2.bounds = v.bounds;
|
72 | dummy2.focus = v.focus;
|
73 | net.addVertex(dummy2);
|
74 | net.linkVertexes(v, dummy2, null);
|
75 | });
|
76 | return net;
|
77 | }
|
78 |
|
79 | |
80 |
|
81 |
|
82 | public assignTreeVertexValues(v: go.TreeVertex): void {
|
83 | super.assignTreeVertexValues(v);
|
84 | (v as any)['_direction'] = 0;
|
85 | if (v.parent !== null) {
|
86 |
|
87 |
|
88 | if (v.angle === 0 || v.angle === 180) {
|
89 | v.layerSpacing -= v.bounds.width;
|
90 | } else {
|
91 | v.layerSpacing -= v.bounds.height;
|
92 | }
|
93 | }
|
94 | }
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 | public commitNodes(): void {
|
101 | if (this.network === null) return;
|
102 |
|
103 |
|
104 |
|
105 | this.network.edges.each(function(e) {
|
106 | const link = e.link;
|
107 | if (link === null) return;
|
108 | link.fromSpot = go.Spot.None;
|
109 | link.toSpot = go.Spot.None;
|
110 |
|
111 | const v: go.TreeVertex = e.fromVertex as go.TreeVertex;
|
112 | const w: go.TreeVertex = e.toVertex as go.TreeVertex;
|
113 |
|
114 | if (v.angle === 0) {
|
115 | link.fromSpot = go.Spot.Left;
|
116 | } else if (v.angle === 180) {
|
117 | link.fromSpot = go.Spot.Right;
|
118 | }
|
119 |
|
120 | if (w.angle === 0) {
|
121 | link.toSpot = go.Spot.Left;
|
122 | } else if (w.angle === 180) {
|
123 | link.toSpot = go.Spot.Right;
|
124 | }
|
125 | });
|
126 |
|
127 |
|
128 | let vit = this.network.vertexes.iterator;
|
129 | while (vit.next()) {
|
130 | const v = vit.value as go.TreeVertex;
|
131 | const len = v.children.length;
|
132 | if (len === 0) continue;
|
133 | if (v.parent === null) continue;
|
134 | const dummy2 = v.children[len - 1];
|
135 | v.centerX = dummy2.centerX;
|
136 | v.centerY = dummy2.centerY;
|
137 | }
|
138 |
|
139 | const layout = this;
|
140 | vit = this.network.vertexes.iterator;
|
141 | while (vit.next()) {
|
142 | const v = vit.value as go.TreeVertex;
|
143 | if (v.parent === null) {
|
144 | layout.shift(v);
|
145 | }
|
146 | }
|
147 |
|
148 |
|
149 | super.commitNodes();
|
150 | }
|
151 |
|
152 | |
153 |
|
154 |
|
155 | public commitLinks(): void { }
|
156 |
|
157 | |
158 |
|
159 |
|
160 | public shift(v: go.TreeVertex): void {
|
161 | const p = v.parent;
|
162 | if (p !== null && (v.angle === 90 || v.angle === 270)) {
|
163 | const g = p.parent;
|
164 | if (g !== null) {
|
165 | const shift = v.nodeSpacing;
|
166 | if ((g as any)['_direction'] > 0) {
|
167 | if (g.angle === 90) {
|
168 | if (p.angle === 0) {
|
169 | (v as any)['_direction'] = 1;
|
170 | if (v.angle === 270) this.shiftAll(2, -shift, p, v);
|
171 | } else if (p.angle === 180) {
|
172 | (v as any)['_direction'] = -1;
|
173 | if (v.angle === 90) this.shiftAll(-2, shift, p, v);
|
174 | }
|
175 | } else if (g.angle === 270) {
|
176 | if (p.angle === 0) {
|
177 | (v as any)['_direction'] = 1;
|
178 | if (v.angle === 90) this.shiftAll(2, -shift, p, v);
|
179 | } else if (p.angle === 180) {
|
180 | (v as any)['_direction'] = -1;
|
181 | if (v.angle === 270) this.shiftAll(-2, shift, p, v);
|
182 | }
|
183 | }
|
184 | } else if ((g as any)['_direction'] < 0) {
|
185 | if (g.angle === 90) {
|
186 | if (p.angle === 0) {
|
187 | (v as any)['_direction'] = 1;
|
188 | if (v.angle === 90) this.shiftAll(2, -shift, p, v);
|
189 | } else if (p.angle === 180) {
|
190 | (v as any)['_direction'] = -1;
|
191 | if (v.angle === 270) this.shiftAll(-2, shift, p, v);
|
192 | }
|
193 | } else if (g.angle === 270) {
|
194 | if (p.angle === 0) {
|
195 | (v as any)['_direction'] = 1;
|
196 | if (v.angle === 270) this.shiftAll(2, -shift, p, v);
|
197 | } else if (p.angle === 180) {
|
198 | (v as any)['_direction'] = -1;
|
199 | if (v.angle === 90) this.shiftAll(-2, shift, p, v);
|
200 | }
|
201 | }
|
202 | }
|
203 | } else {
|
204 | const dir = ((p.angle === 0) ? 1 : -1);
|
205 | (v as any)['_direction'] = dir;
|
206 | this.shiftAll(dir, 0, p, v);
|
207 | }
|
208 | }
|
209 | for (let i = 0; i < v.children.length; i++) {
|
210 | const c = v.children[i];
|
211 | this.shift(c);
|
212 | }
|
213 | }
|
214 |
|
215 | |
216 |
|
217 |
|
218 | public shiftAll(direction: number, absolute: number, root: go.TreeVertex, v: go.TreeVertex): void {
|
219 |
|
220 | let locx = v.centerX;
|
221 | locx += direction * Math.abs(root.centerY - v.centerY) / 2;
|
222 | locx += absolute;
|
223 | v.centerX = locx;
|
224 | for (let i = 0; i < v.children.length; i++) {
|
225 | const c = v.children[i];
|
226 | this.shiftAll(direction, absolute, root, c);
|
227 | }
|
228 | }
|
229 |
|
230 | }
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 | export class FishboneLink extends go.Link {
|
237 | public computeAdjusting(): go.EnumValue { return this.adjusting; }
|
238 | |
239 |
|
240 |
|
241 | public computePoints(): boolean {
|
242 | const result = super.computePoints();
|
243 | if (result) {
|
244 |
|
245 | if (this.fromSpot.equals(go.Spot.Right) || this.fromSpot.equals(go.Spot.Left)) {
|
246 | let p1: go.Point;
|
247 |
|
248 | const fromnode = this.fromNode;
|
249 | const fromport = this.fromPort;
|
250 | if (fromnode !== null && fromport !== null && fromnode.findLinksInto().count === 0) {
|
251 |
|
252 | const fromctr = fromport.getDocumentPoint(go.Spot.Center);
|
253 | const fromfar = fromctr.copy();
|
254 | fromfar.x += (this.fromSpot.equals(go.Spot.Left) ? 99999 : -99999);
|
255 | p1 = this.getLinkPointFromPoint(fromnode, fromport, fromctr, fromfar, true).copy();
|
256 |
|
257 | this.setPoint(0, p1);
|
258 | let endseg = this.fromEndSegmentLength;
|
259 | if (isNaN(endseg)) endseg = fromport.fromEndSegmentLength;
|
260 | p1.x += (this.fromSpot.equals(go.Spot.Left)) ? endseg : -endseg;
|
261 | this.setPoint(1, p1);
|
262 | } else {
|
263 | p1 = this.getPoint(1);
|
264 | }
|
265 | const tonode = this.toNode;
|
266 | const toport = this.toPort;
|
267 | if (tonode !== null && toport !== null) {
|
268 | const toctr = toport.getDocumentPoint(go.Spot.Center);
|
269 | const far = toctr.copy();
|
270 | far.x += (this.fromSpot.equals(go.Spot.Left)) ? -99999 / 2 : 99999 / 2;
|
271 | far.y += (toctr.y < p1.y) ? 99999 : -99999;
|
272 | const p2 = this.getLinkPointFromPoint(tonode, toport, toctr, far, false);
|
273 | this.setPoint(2, p2);
|
274 | let dx = Math.abs(p2.y - p1.y) / 2;
|
275 | if (this.fromSpot.equals(go.Spot.Left)) dx = -dx;
|
276 | this.insertPoint(2, new go.Point(p2.x + dx, p1.y));
|
277 | }
|
278 | } else if (this.toSpot.equals(go.Spot.Right) || this.toSpot.equals(go.Spot.Left)) {
|
279 | const p1: go.Point = this.getPoint(1);
|
280 | const fromnode = this.fromNode;
|
281 | const fromport = this.fromPort;
|
282 | if (fromnode !== null && fromport !== null) {
|
283 | const parentlink = fromnode.findLinksInto().first();
|
284 | const fromctr = fromport.getDocumentPoint(go.Spot.Center);
|
285 | const far = fromctr.copy();
|
286 | far.x += (parentlink !== null && parentlink.fromSpot.equals(go.Spot.Left)) ? -99999 / 2 : 99999 / 2;
|
287 | far.y += (fromctr.y < p1.y) ? 99999 : -99999;
|
288 | const p0 = this.getLinkPointFromPoint(fromnode, fromport, fromctr, far, true);
|
289 | this.setPoint(0, p0);
|
290 | let dx = Math.abs(p1.y - p0.y) / 2;
|
291 | if (parentlink !== null && parentlink.fromSpot.equals(go.Spot.Left)) dx = -dx;
|
292 | this.insertPoint(1, new go.Point(p0.x + dx, p1.y));
|
293 | }
|
294 | }
|
295 | }
|
296 | return result;
|
297 | }
|
298 | }
|