UNPKG

15.5 kBJavaScriptView Raw
1(function (factory) {
2 if (typeof module === "object" && typeof module.exports === "object") {
3 var v = factory(require, exports);
4 if (v !== undefined) module.exports = v;
5 }
6 else if (typeof define === "function" && define.amd) {
7 define(["require", "exports", "../release/go.js", "./GenogramLayout.js"], factory);
8 }
9})(function (require, exports) {
10 'use strict';
11 Object.defineProperty(exports, "__esModule", { value: true });
12 exports.setupParents = exports.setupMarriages = exports.findMarriage = exports.setupDiagram = exports.init = void 0;
13 /*
14 * Copyright (C) 1998-2021 by Northwoods Software Corporation. All Rights Reserved.
15 */
16 var go = require("../release/go.js");
17 var GenogramLayout_js_1 = require("./GenogramLayout.js");
18 function init() {
19 if (window.goSamples)
20 window.goSamples(); // init for these samples -- you don't need to call this
21 var $ = go.GraphObject.make;
22 var myDiagram = $(go.Diagram, 'myDiagramDiv', {
23 initialAutoScale: go.Diagram.Uniform,
24 'undoManager.isEnabled': true,
25 // when a node is selected, draw a big yellow circle behind it
26 nodeSelectionAdornmentTemplate: $(go.Adornment, 'Auto', { layerName: 'Grid' }, // the predefined layer that is behind everything else
27 $(go.Shape, 'Circle', { fill: 'yellow', stroke: null }), $(go.Placeholder)),
28 layout: // use a custom layout, defined below
29 $(GenogramLayout_js_1.GenogramLayout, { direction: 90, layerSpacing: 30, columnSpacing: 10 })
30 });
31 // determine the color for each attribute shape
32 function attrFill(a) {
33 switch (a) {
34 case 'A': return 'green';
35 case 'B': return 'orange';
36 case 'C': return 'red';
37 case 'D': return 'cyan';
38 case 'E': return 'gold';
39 case 'F': return 'pink';
40 case 'G': return 'blue';
41 case 'H': return 'brown';
42 case 'I': return 'purple';
43 case 'J': return 'chartreuse';
44 case 'K': return 'lightgray';
45 case 'L': return 'magenta';
46 case 'S': return 'red';
47 default: return 'transparent';
48 }
49 }
50 // determine the geometry for each attribute shape in a male;
51 // except for the slash these are all squares at each of the four corners of the overall square
52 var tlsq = go.Geometry.parse('F M1 1 l19 0 0 19 -19 0z');
53 var trsq = go.Geometry.parse('F M20 1 l19 0 0 19 -19 0z');
54 var brsq = go.Geometry.parse('F M20 20 l19 0 0 19 -19 0z');
55 var blsq = go.Geometry.parse('F M1 20 l19 0 0 19 -19 0z');
56 var slash = go.Geometry.parse('F M38 0 L40 0 40 2 2 40 0 40 0 38z');
57 function maleGeometry(a) {
58 switch (a) {
59 case 'A': return tlsq;
60 case 'B': return tlsq;
61 case 'C': return tlsq;
62 case 'D': return trsq;
63 case 'E': return trsq;
64 case 'F': return trsq;
65 case 'G': return brsq;
66 case 'H': return brsq;
67 case 'I': return brsq;
68 case 'J': return blsq;
69 case 'K': return blsq;
70 case 'L': return blsq;
71 case 'S': return slash;
72 default: return tlsq;
73 }
74 }
75 // determine the geometry for each attribute shape in a female;
76 // except for the slash these are all pie shapes at each of the four quadrants of the overall circle
77 var tlarc = go.Geometry.parse('F M20 20 B 180 90 20 20 19 19 z');
78 var trarc = go.Geometry.parse('F M20 20 B 270 90 20 20 19 19 z');
79 var brarc = go.Geometry.parse('F M20 20 B 0 90 20 20 19 19 z');
80 var blarc = go.Geometry.parse('F M20 20 B 90 90 20 20 19 19 z');
81 function femaleGeometry(a) {
82 switch (a) {
83 case 'A': return tlarc;
84 case 'B': return tlarc;
85 case 'C': return tlarc;
86 case 'D': return trarc;
87 case 'E': return trarc;
88 case 'F': return trarc;
89 case 'G': return brarc;
90 case 'H': return brarc;
91 case 'I': return brarc;
92 case 'J': return blarc;
93 case 'K': return blarc;
94 case 'L': return blarc;
95 case 'S': return slash;
96 default: return tlarc;
97 }
98 }
99 // two different node templates, one for each sex,
100 // named by the category value in the node data object
101 myDiagram.nodeTemplateMap.add('M', // male
102 $(go.Node, 'Vertical', { locationSpot: go.Spot.Center, locationObjectName: 'ICON' }, $(go.Panel, { name: 'ICON' }, $(go.Shape, 'Square', { width: 40, height: 40, strokeWidth: 2, fill: 'white', portId: '' }), $(go.Panel, {
103 itemTemplate: $(go.Panel, $(go.Shape, { stroke: null, strokeWidth: 0 }, new go.Binding('fill', '', attrFill), new go.Binding('geometry', '', maleGeometry))),
104 margin: 1
105 }, new go.Binding('itemArray', 'a'))), $(go.TextBlock, { textAlign: 'center', maxSize: new go.Size(80, NaN) }, new go.Binding('text', 'n'))));
106 myDiagram.nodeTemplateMap.add('F', // female
107 $(go.Node, 'Vertical', { locationSpot: go.Spot.Center, locationObjectName: 'ICON' }, $(go.Panel, { name: 'ICON' }, $(go.Shape, 'Circle', { width: 40, height: 40, strokeWidth: 2, fill: 'white', portId: '' }), $(go.Panel, {
108 itemTemplate: $(go.Panel, $(go.Shape, { stroke: null, strokeWidth: 0 }, new go.Binding('fill', '', attrFill), new go.Binding('geometry', '', femaleGeometry))),
109 margin: 1
110 }, new go.Binding('itemArray', 'a'))), $(go.TextBlock, { textAlign: 'center', maxSize: new go.Size(80, NaN) }, new go.Binding('text', 'n'))));
111 // the representation of each label node -- nothing shows on a Marriage Link
112 myDiagram.nodeTemplateMap.add('LinkLabel', $(go.Node, { selectable: false, width: 1, height: 1, fromEndSegmentLength: 20 }));
113 myDiagram.linkTemplate = // for parent-child relationships
114 $(go.Link, {
115 routing: go.Link.Orthogonal, curviness: 15,
116 layerName: 'Background', selectable: false,
117 fromSpot: go.Spot.Bottom, toSpot: go.Spot.Top
118 }, $(go.Shape, { strokeWidth: 2 }));
119 myDiagram.linkTemplateMap.add('Marriage', // for marriage relationships
120 $(go.Link, { selectable: false }, $(go.Shape, { strokeWidth: 2, stroke: 'blue' })));
121 // n: name, s: sex, m: mother, f: father, ux: wife, vir: husband, a: attributes/markers
122 setupDiagram(myDiagram, [
123 { key: 0, n: 'Aaron', s: 'M', m: -10, f: -11, ux: 1, a: ['C', 'F', 'K'] },
124 { key: 1, n: 'Alice', s: 'F', m: -12, f: -13, a: ['B', 'H', 'K'] },
125 { key: 2, n: 'Bob', s: 'M', m: 1, f: 0, ux: 3, a: ['C', 'H', 'L'] },
126 { key: 3, n: 'Barbara', s: 'F', a: ['C'] },
127 { key: 4, n: 'Bill', s: 'M', m: 1, f: 0, ux: 5, a: ['E', 'H'] },
128 { key: 5, n: 'Brooke', s: 'F', a: ['B', 'H', 'L'] },
129 { key: 6, n: 'Claire', s: 'F', m: 1, f: 0, a: ['C'] },
130 { key: 7, n: 'Carol', s: 'F', m: 1, f: 0, a: ['C', 'I'] },
131 { key: 8, n: 'Chloe', s: 'F', m: 1, f: 0, vir: 9, a: ['E'] },
132 { key: 9, n: 'Chris', s: 'M', a: ['B', 'H'] },
133 { key: 10, n: 'Ellie', s: 'F', m: 3, f: 2, a: ['E', 'G'] },
134 { key: 11, n: 'Dan', s: 'M', m: 3, f: 2, a: ['B', 'J'] },
135 { key: 12, n: 'Elizabeth', s: 'F', vir: 13, a: ['J'] },
136 { key: 13, n: 'David', s: 'M', m: 5, f: 4, a: ['B', 'H'] },
137 { key: 14, n: 'Emma', s: 'F', m: 5, f: 4, a: ['E', 'G'] },
138 { key: 15, n: 'Evan', s: 'M', m: 8, f: 9, a: ['F', 'H'] },
139 { key: 16, n: 'Ethan', s: 'M', m: 8, f: 9, a: ['D', 'K'] },
140 { key: 17, n: 'Eve', s: 'F', vir: 16, a: ['B', 'F', 'L'] },
141 { key: 18, n: 'Emily', s: 'F', m: 8, f: 9 },
142 { key: 19, n: 'Fred', s: 'M', m: 17, f: 16, a: ['B'] },
143 { key: 20, n: 'Faith', s: 'F', m: 17, f: 16, a: ['L'] },
144 { key: 21, n: 'Felicia', s: 'F', m: 12, f: 13, a: ['H'] },
145 { key: 22, n: 'Frank', s: 'M', m: 12, f: 13, a: ['B', 'H'] },
146 // "Aaron"'s ancestors
147 { key: -10, n: 'Paternal Grandfather', s: 'M', m: -33, f: -32, ux: -11, a: ['A', 'S'] },
148 { key: -11, n: 'Paternal Grandmother', s: 'F', a: ['E', 'S'] },
149 { key: -32, n: 'Paternal Great', s: 'M', ux: -33, a: ['F', 'H', 'S'] },
150 { key: -33, n: 'Paternal Great', s: 'F', a: ['S'] },
151 { key: -40, n: 'Great Uncle', s: 'M', m: -33, f: -32, a: ['F', 'H', 'S'] },
152 { key: -41, n: 'Great Aunt', s: 'F', m: -33, f: -32, a: ['B', 'I', 'S'] },
153 { key: -20, n: 'Uncle', s: 'M', m: -11, f: -10, a: ['A', 'S'] },
154 // "Alice"'s ancestors
155 { key: -12, n: 'Maternal Grandfather', s: 'M', ux: -13, a: ['D', 'L', 'S'] },
156 { key: -13, n: 'Maternal Grandmother', s: 'F', m: -31, f: -30, a: ['H', 'S'] },
157 { key: -21, n: 'Aunt', s: 'F', m: -13, f: -12, a: ['C', 'I'] },
158 { key: -22, n: 'Uncle', s: 'M', ux: -21 },
159 { key: -23, n: 'Cousin', s: 'M', m: -21, f: -22 },
160 { key: -30, n: 'Maternal Great', s: 'M', ux: -31, a: ['D', 'J', 'S'] },
161 { key: -31, n: 'Maternal Great', s: 'F', m: -50, f: -51, a: ['B', 'H', 'L', 'S'] },
162 { key: -42, n: 'Great Uncle', s: 'M', m: -30, f: -31, a: ['C', 'J', 'S'] },
163 { key: -43, n: 'Great Aunt', s: 'F', m: -30, f: -31, a: ['E', 'G', 'S'] },
164 { key: -50, n: 'Maternal Great Great', s: 'F', ux: -51, a: ['D', 'I', 'S'] },
165 { key: -51, n: 'Maternal Great Great', s: 'M', a: ['B', 'H', 'S'] }
166 ], 4 /* focus on this person */);
167 }
168 exports.init = init;
169 // create and initialize the Diagram.model given an array of node data representing people
170 function setupDiagram(diagram, array, focusId) {
171 diagram.model =
172 go.GraphObject.make(go.GraphLinksModel, {
173 linkLabelKeysProperty: 'labelKeys',
174 // this property determines which template is used
175 nodeCategoryProperty: 's',
176 // create all of the nodes for people
177 nodeDataArray: array
178 });
179 setupMarriages(diagram);
180 setupParents(diagram);
181 var node = diagram.findNodeForKey(focusId);
182 if (node !== null) {
183 diagram.select(node);
184 // remove any spouse for the person under focus:
185 // node.linksConnected.each(l => {
186 // if (!l.isLabeledLink) return;
187 // l.opacity = 0;
188 // var spouse = l.getOtherNode(node);
189 // spouse.opacity = 0;
190 // spouse.pickable = false;
191 // });
192 }
193 }
194 exports.setupDiagram = setupDiagram;
195 function findMarriage(diagram, a, b) {
196 var nodeA = diagram.findNodeForKey(a);
197 var nodeB = diagram.findNodeForKey(b);
198 if (nodeA !== null && nodeB !== null) {
199 var it = nodeA.findLinksBetween(nodeB); // in either direction
200 while (it.next()) {
201 var link = it.value;
202 // Link.data.category === "Marriage" means it's a marriage relationship
203 if (link.data !== null && link.data.category === 'Marriage')
204 return link;
205 }
206 }
207 return null;
208 }
209 exports.findMarriage = findMarriage;
210 // now process the node data to determine marriages
211 function setupMarriages(diagram) {
212 var model = diagram.model;
213 var nodeDataArray = model.nodeDataArray;
214 for (var i = 0; i < nodeDataArray.length; i++) {
215 var data = nodeDataArray[i];
216 var key = data.key;
217 if (data.ux !== undefined) {
218 var uxs = [];
219 if (typeof data.ux === 'number')
220 uxs = [data.ux];
221 for (var j = 0; j < uxs.length; j++) {
222 var wife = uxs[j];
223 if (key === wife) {
224 // or warn no reflexive marriages
225 continue;
226 }
227 var link = findMarriage(diagram, key, wife);
228 if (link === null) {
229 // add a label node for the marriage link
230 var mlab = { s: 'LinkLabel' };
231 model.addNodeData(mlab);
232 // add the marriage link itself, also referring to the label node
233 var mdata = { from: key, to: wife, labelKeys: [mlab.key], category: 'Marriage' };
234 model.addLinkData(mdata);
235 }
236 }
237 }
238 if (data.vir !== undefined) {
239 var virs = (typeof data.vir === 'number') ? [data.vir] : data.vir;
240 for (var j = 0; j < virs.length; j++) {
241 var husband = virs[j];
242 if (key === husband) {
243 // or warn no reflexive marriages
244 continue;
245 }
246 var link = findMarriage(diagram, key, husband);
247 if (link === null) {
248 // add a label node for the marriage link
249 var mlab = { s: 'LinkLabel' };
250 model.addNodeData(mlab);
251 // add the marriage link itself, also referring to the label node
252 var mdata = { from: key, to: husband, labelKeys: [mlab.key], category: 'Marriage' };
253 model.addLinkData(mdata);
254 }
255 }
256 }
257 }
258 }
259 exports.setupMarriages = setupMarriages;
260 // process parent-child relationships once all marriages are known
261 function setupParents(diagram) {
262 var model = diagram.model;
263 var nodeDataArray = model.nodeDataArray;
264 for (var i = 0; i < nodeDataArray.length; i++) {
265 var data = nodeDataArray[i];
266 var key = data.key;
267 var mother = data.m;
268 var father = data.f;
269 if (mother !== undefined && father !== undefined) {
270 var link = findMarriage(diagram, mother, father);
271 if (link === null) {
272 // or warn no known mother or no known father or no known marriage between them
273 if (window.console)
274 window.console.log('unknown marriage: ' + mother + ' & ' + father);
275 continue;
276 }
277 var mdata = link.data;
278 var mlabkey = mdata.labelKeys[0];
279 var cdata = { from: mlabkey, to: key };
280 model.addLinkData(cdata);
281 }
282 }
283 }
284 exports.setupParents = setupParents;
285});