UNPKG

topola

Version:

Topola – online genealogy visualization

175 lines (174 loc) 6.38 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DescendantChart = exports.DUMMY_ROOT_NODE_ID = void 0; exports.layOutDescendants = layOutDescendants; var d3_hierarchy_1 = require("d3-hierarchy"); var api_1 = require("./api"); var chart_util_1 = require("./chart-util"); var id_generator_1 = require("./id-generator"); exports.DUMMY_ROOT_NODE_ID = 'DUMMY_ROOT_NODE'; function layOutDescendants(options, layoutOptions) { if (layoutOptions === void 0) { layoutOptions = {}; } var descendants = new DescendantChart(options); var descendantsRoot = descendants.createHierarchy(); return removeDummyNode(new chart_util_1.ChartUtil(options).layOutChart(descendantsRoot, layoutOptions)); } /** Removes the dummy root node if it was added in createHierarchy(). */ function removeDummyNode(allNodes) { if (allNodes[0].id !== exports.DUMMY_ROOT_NODE_ID) { return allNodes; } var nodes = allNodes.slice(1); // Move first node to (0, 0) coordinates. var dx = -nodes[0].x; var dy = -nodes[0].y; nodes.forEach(function (node) { if (node.parent && node.parent.id === exports.DUMMY_ROOT_NODE_ID && !node.data.additionalMarriage) { node.parent = null; } node.x += dx; node.y += dy; node.data.generation--; }); return nodes; } /** Returns the spouse of the given individual in the given family. */ function getSpouse(indiId, fam) { if (fam.getFather() === indiId) { return fam.getMother(); } return fam.getFather(); } /** Renders a descendants chart. */ var DescendantChart = /** @class */ (function () { function DescendantChart(options) { this.options = options; this.util = new chart_util_1.ChartUtil(options); } DescendantChart.prototype.getNodes = function (id) { var _this = this; var indi = this.options.data.getIndi(id); var famIds = indi.getFamiliesAsSpouse(); if (!famIds.length) { // Single person. return [ { id: id, indi: { id: id, }, }, ]; } // Marriages. var nodes = famIds.map(function (famId) { var entry = { id: famId, indi: { id: id, }, family: { id: famId, }, }; var fam = _this.options.data.getFam(famId); var spouse = getSpouse(id, fam); if (spouse) { entry.spouse = { id: spouse }; } return entry; }); nodes.slice(1).forEach(function (node) { node.additionalMarriage = true; }); return nodes; }; DescendantChart.prototype.getFamNode = function (famId) { var node = { id: famId, family: { id: famId } }; var fam = this.options.data.getFam(famId); var father = fam.getFather(); if (father) { node.indi = { id: father }; } var mother = fam.getMother(); if (mother) { node.spouse = { id: mother }; } return node; }; /** Creates a d3 hierarchy from the input data. */ DescendantChart.prototype.createHierarchy = function () { var _this = this; var _a; var parents = []; var nodes = this.options.startIndi ? this.getNodes(this.options.startIndi) : [this.getFamNode(this.options.startFam)]; var idGenerator = this.options.idGenerator || new id_generator_1.IdGenerator(); nodes.forEach(function (node) { return (node.id = idGenerator.getId(node.id)); }); // If there are multiple root nodes, i.e. the start individual has multiple // marriages, create a dummy root node. // After layout is complete, the dummy node will be removed. if (nodes.length > 1) { var dummyNode_1 = { id: exports.DUMMY_ROOT_NODE_ID, height: 1, width: 1, }; parents.push(dummyNode_1); nodes.forEach(function (node) { return (node.parentId = dummyNode_1.id); }); } parents.push.apply(parents, nodes); var stack = []; nodes.forEach(function (node) { if (node.family) { stack.push(node); } }); var _loop_1 = function () { var entry = stack.pop(); var fam = this_1.options.data.getFam(entry.family.id); var children = fam.getChildren(); var collapsed = (_a = this_1.options.collapsedFamily) === null || _a === void 0 ? void 0 : _a.has(entry.id); if (children.length) { entry.family.expander = collapsed ? api_1.ExpanderState.PLUS : api_1.ExpanderState.MINUS; } if (!collapsed) { children.forEach(function (childId) { var childNodes = _this.getNodes(childId); childNodes.forEach(function (node) { node.parentId = entry.id; if (node.family) { node.id = "".concat(idGenerator.getId(node.family.id)); stack.push(node); } }); parents.push.apply(parents, childNodes); }); } }; var this_1 = this; while (stack.length) { _loop_1(); } return (0, d3_hierarchy_1.stratify)()(parents); }; /** * Renders the tree, calling the provided renderer to draw boxes for * individuals. */ DescendantChart.prototype.render = function () { var root = this.createHierarchy(); var nodes = removeDummyNode(this.util.layOutChart(root)); var animationPromise = this.util.renderChart(nodes); var info = (0, chart_util_1.getChartInfo)(nodes); this.util.updateSvgDimensions(info); return Object.assign(info, { animationPromise: animationPromise }); }; return DescendantChart; }()); exports.DescendantChart = DescendantChart;