UNPKG

16.9 kBJavaScriptView Raw
1var __extends = (this && this.__extends) || (function () {
2 var extendStatics = function (d, b) {
3 extendStatics = Object.setPrototypeOf ||
4 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6 return extendStatics(d, b);
7 };
8 return function (d, b) {
9 extendStatics(d, b);
10 function __() { this.constructor = d; }
11 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12 };
13})();
14(function (factory) {
15 if (typeof module === "object" && typeof module.exports === "object") {
16 var v = factory(require, exports);
17 if (v !== undefined) module.exports = v;
18 }
19 else if (typeof define === "function" && define.amd) {
20 define(["require", "exports", "../release/go.js"], factory);
21 }
22})(function (require, exports) {
23 'use strict';
24 Object.defineProperty(exports, "__esModule", { value: true });
25 exports.GenogramLayout = void 0;
26 /*
27 * Copyright (C) 1998-2021 by Northwoods Software Corporation. All Rights Reserved.
28 */
29 var go = require("../release/go.js");
30 // A custom layout that shows the two families related to a person's parents
31 var GenogramLayout = /** @class */ (function (_super) {
32 __extends(GenogramLayout, _super);
33 function GenogramLayout() {
34 var _this = _super.call(this) || this;
35 _this.initializeOption = go.LayeredDigraphLayout.InitDepthFirstIn;
36 _this.spouseSpacing = 30; // minimum space between spouses
37 return _this;
38 }
39 GenogramLayout.prototype.makeNetwork = function (coll) {
40 // generate LayoutEdges for each parent-child Link
41 var net = this.createNetwork();
42 if (coll instanceof go.Diagram) {
43 this.add(net, coll.nodes, true);
44 this.add(net, coll.links, true);
45 }
46 else if (coll instanceof go.Group) {
47 this.add(net, coll.memberParts, false);
48 }
49 else if (coll.iterator) {
50 this.add(net, coll.iterator, false);
51 }
52 return net;
53 };
54 // internal method for creating LayeredDigraphNetwork where husband/wife pairs are represented
55 // by a single LayeredDigraphVertex corresponding to the label Node on the marriage Link
56 GenogramLayout.prototype.add = function (net, coll, nonmemberonly) {
57 var multiSpousePeople = new go.Set();
58 // consider all Nodes in the given collection
59 var it = coll.iterator;
60 var _loop_1 = function () {
61 var node = it.value;
62 if (!(node instanceof go.Node))
63 return "continue";
64 if (!node.isLayoutPositioned || !node.isVisible())
65 return "continue";
66 if (nonmemberonly && node.containingGroup !== null)
67 return "continue";
68 // if it's an unmarried Node, or if it's a Link Label Node, create a LayoutVertex for it
69 if (node.isLinkLabel) {
70 // get marriage Link
71 var link = node.labeledLink;
72 if (link) {
73 var spouseA = link.fromNode;
74 var spouseB = link.toNode;
75 // create vertex representing both husband and wife
76 var vertex = net.addNode(node);
77 // now define the vertex size to be big enough to hold both spouses
78 if (spouseA && spouseB) {
79 vertex.width = spouseA.actualBounds.width + this_1.spouseSpacing + spouseB.actualBounds.width;
80 vertex.height = Math.max(spouseA.actualBounds.height, spouseB.actualBounds.height);
81 vertex.focus = new go.Point(spouseA.actualBounds.width + this_1.spouseSpacing / 2, vertex.height / 2);
82 }
83 }
84 }
85 else {
86 // don't add a vertex for any married person!
87 // instead, code above adds label node for marriage link
88 // assume a marriage Link has a label Node
89 var marriages_1 = 0;
90 node.linksConnected.each(function (l) { if (l.isLabeledLink)
91 marriages_1++; });
92 if (marriages_1 === 0) {
93 var vertex = net.addNode(node);
94 }
95 else if (marriages_1 > 1) {
96 multiSpousePeople.add(node);
97 }
98 }
99 };
100 var this_1 = this;
101 while (it.next()) {
102 _loop_1();
103 }
104 // now do all Links
105 it.reset();
106 var _loop_2 = function () {
107 var link = it.value;
108 if (!(link instanceof go.Link))
109 return "continue";
110 if (!link.isLayoutPositioned || !link.isVisible())
111 return "continue";
112 if (nonmemberonly && link.containingGroup !== null)
113 return "continue";
114 // if it's a parent-child link, add a LayoutEdge for it
115 if (!link.isLabeledLink) {
116 var fromNode = link.fromNode;
117 var toNode = link.toNode;
118 if (fromNode !== null && toNode !== null) {
119 var parent_1 = net.findVertex(fromNode); // should be a label node
120 var child = net.findVertex(toNode);
121 if (parent_1 !== null && child !== null) { // an unmarried child
122 net.linkVertexes(parent_1, child, link);
123 }
124 else if (parent_1 !== null) { // a married child
125 toNode.linksConnected.each(function (l) {
126 if (!l.isLabeledLink)
127 return; // if it has no label node, it's a parent-child link
128 // found the Marriage Link, now get its label Node
129 var mlab = l.labelNodes.first();
130 // parent-child link should connect with the label node,
131 // so the LayoutEdge should connect with the LayoutVertex representing the label node
132 if (mlab !== null) {
133 var mlabvert = net.findVertex(mlab);
134 if (mlabvert !== null) {
135 net.linkVertexes(parent_1, mlabvert, link);
136 }
137 }
138 });
139 }
140 }
141 }
142 };
143 while (it.next()) {
144 _loop_2();
145 }
146 var _loop_3 = function () {
147 // find all collections of people that are indirectly married to each other
148 var node = multiSpousePeople.first();
149 var cohort = new go.Set();
150 this_2.extendCohort(cohort, node);
151 // then encourage them all to be the same generation by connecting them all with a common vertex
152 var dummyvert = net.createVertex();
153 net.addVertex(dummyvert);
154 var marriages = new go.Set();
155 cohort.each(function (n) {
156 n.linksConnected.each(function (l) {
157 marriages.add(l);
158 });
159 });
160 marriages.each(function (link) {
161 // find the vertex for the marriage link (i.e. for the label node)
162 var mlab = link.labelNodes.first();
163 if (mlab !== null) {
164 var v = net.findVertex(mlab);
165 if (v !== null) {
166 net.linkVertexes(dummyvert, v, null);
167 }
168 }
169 });
170 // done with these people, now see if there are any other multiple-married people
171 multiSpousePeople.removeAll(cohort);
172 };
173 var this_2 = this;
174 while (multiSpousePeople.count > 0) {
175 _loop_3();
176 }
177 };
178 // collect all of the people indirectly married with a person
179 GenogramLayout.prototype.extendCohort = function (coll, node) {
180 if (coll.contains(node))
181 return;
182 coll.add(node);
183 var lay = this;
184 node.linksConnected.each(function (l) {
185 if (l.isLabeledLink) { // if it's a marriage link, continue with both spouses
186 if (l.fromNode !== null)
187 lay.extendCohort(coll, l.fromNode);
188 if (l.toNode !== null)
189 lay.extendCohort(coll, l.toNode);
190 }
191 });
192 };
193 GenogramLayout.prototype.assignLayers = function () {
194 _super.prototype.assignLayers.call(this);
195 var horiz = this.direction === 0.0 || this.direction === 180.0;
196 // for every vertex, record the maximum vertex width or height for the vertex's layer
197 var maxsizes = [];
198 var net = this.network;
199 if (net !== null) {
200 var vit = net.vertexes.iterator;
201 while (vit.next()) {
202 var v = vit.value;
203 var lay = v.layer;
204 var max = maxsizes[lay];
205 if (max === undefined)
206 max = 0;
207 var sz = (horiz ? v.width : v.height);
208 if (sz > max)
209 maxsizes[lay] = sz;
210 }
211 vit.reset();
212 // now make sure every vertex has the maximum width or height according to which layer it is in,
213 // and aligned on the left (if horizontal) or the top (if vertical)
214 while (vit.next()) {
215 var v = vit.value;
216 var lay = v.layer;
217 var max = maxsizes[lay];
218 if (horiz) {
219 v.focus = new go.Point(0, v.height / 2);
220 v.width = max;
221 }
222 else {
223 v.focus = new go.Point(v.width / 2, 0);
224 v.height = max;
225 }
226 }
227 // from now on, the LayeredDigraphLayout will think that the Node is bigger than it really is
228 // (other than the ones that are the widest or tallest in their respective layer).
229 }
230 };
231 GenogramLayout.prototype.commitNodes = function () {
232 _super.prototype.commitNodes.call(this);
233 var net = this.network;
234 // position regular nodes
235 if (net !== null) {
236 var vit = net.vertexes.iterator;
237 while (vit.next()) {
238 var v = vit.value;
239 if (v.node !== null && !v.node.isLinkLabel) {
240 v.node.position = new go.Point(v.x, v.y);
241 }
242 }
243 vit.reset();
244 // position the spouses of each marriage vertex
245 var layout = this;
246 while (vit.next()) {
247 var v = vit.value;
248 if (v.node === null)
249 continue;
250 if (!v.node.isLinkLabel)
251 continue;
252 var labnode = v.node;
253 var lablink = labnode.labeledLink;
254 if (lablink !== null) {
255 // In case the spouses are not actually moved, we need to have the marriage link
256 // position the label node, because LayoutVertex.commit() was called above on these vertexes.
257 // Alternatively we could override LayoutVetex.commit to be a no-op for label node vertexes.
258 lablink.invalidateRoute();
259 var spouseA = lablink.fromNode;
260 var spouseB = lablink.toNode;
261 if (spouseA !== null && spouseB != null) {
262 // prefer fathers on the left, mothers on the right
263 if (spouseA.data.s === 'F') { // sex is female
264 var temp = spouseA;
265 spouseA = spouseB;
266 spouseB = temp;
267 }
268 // see if the parents are on the desired sides, to avoid a link crossing
269 var aParentsNode = layout.findParentsMarriageLabelNode(spouseA);
270 var bParentsNode = layout.findParentsMarriageLabelNode(spouseB);
271 if (aParentsNode !== null && bParentsNode !== null && aParentsNode.position.x > bParentsNode.position.x) {
272 // swap the spouses
273 var temp = spouseA;
274 spouseA = spouseB;
275 spouseB = temp;
276 }
277 spouseA.position = new go.Point(v.x, v.y);
278 spouseB.position = new go.Point(v.x + spouseA.actualBounds.width + layout.spouseSpacing, v.y);
279 if (spouseA.opacity === 0) {
280 var pos = new go.Point(v.centerX - spouseA.actualBounds.width / 2, v.y);
281 spouseA.position = pos;
282 spouseB.position = pos;
283 }
284 else if (spouseB.opacity === 0) {
285 var pos = new go.Point(v.centerX - spouseB.actualBounds.width / 2, v.y);
286 spouseA.position = pos;
287 spouseB.position = pos;
288 }
289 }
290 }
291 }
292 vit.reset();
293 var _loop_4 = function () {
294 var v = vit.value;
295 if (v.node === null || v.node.linksConnected.count > 1)
296 return "continue";
297 var mnode = layout.findParentsMarriageLabelNode(v.node);
298 if (mnode !== null && mnode.linksConnected.count === 1) { // if only one child
299 if (layout.network === null)
300 return "continue";
301 var mvert = layout.network.findVertex(mnode);
302 if (mvert !== null) {
303 var newbnds = v.node.actualBounds.copy();
304 newbnds.x = mvert.centerX - v.node.actualBounds.width / 2;
305 // see if there's any empty space at the horizontal mid-point in that layer
306 if (layout.diagram !== null) {
307 var overlaps = layout.diagram.findObjectsIn(newbnds, function (x) { var p = x.part; return (p instanceof go.Part) ? p : null; }, function (p) { return p !== v.node; }, true);
308 if (overlaps.count === 0) {
309 v.node.move(newbnds.position);
310 }
311 }
312 }
313 }
314 };
315 // position only-child nodes to be under the marriage label node
316 while (vit.next()) {
317 _loop_4();
318 }
319 }
320 };
321 GenogramLayout.prototype.findParentsMarriageLabelNode = function (node) {
322 var it = node.findNodesInto();
323 while (it.next()) {
324 var n = it.value;
325 if (n.isLinkLabel)
326 return n;
327 }
328 return null;
329 };
330 return GenogramLayout;
331 }(go.LayeredDigraphLayout));
332 exports.GenogramLayout = GenogramLayout;
333});
334// end GenogramLayout class