1 | var __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 | ;
|
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
|