topola
Version:
Topola – online genealogy visualization
300 lines (299 loc) • 14.2 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RelativesChart = void 0;
var ancestor_chart_1 = require("./ancestor-chart");
var id_generator_1 = require("./id-generator");
var descendant_chart_1 = require("./descendant-chart");
var d3_array_1 = require("d3-array");
var chart_util_1 = require("./chart-util");
/** A view of a family that hides one child individual. */
var FilterChildFam = /** @class */ (function () {
function FilterChildFam(fam, childId) {
this.fam = fam;
this.childId = childId;
}
FilterChildFam.prototype.getId = function () {
return this.fam.getId();
};
FilterChildFam.prototype.getFather = function () {
return this.fam.getFather();
};
FilterChildFam.prototype.getMother = function () {
return this.fam.getMother();
};
FilterChildFam.prototype.getChildren = function () {
var children = __spreadArray([], this.fam.getChildren(), true);
var index = children.indexOf(this.childId);
if (index !== -1) {
children.splice(index, 1);
}
return children;
};
return FilterChildFam;
}());
/** Data provider proxy that filters out a specific child individual. */
var FilterChildData = /** @class */ (function () {
function FilterChildData(data, childId) {
this.data = data;
this.childId = childId;
}
FilterChildData.prototype.getIndi = function (id) {
return this.data.getIndi(id);
};
FilterChildData.prototype.getFam = function (id) {
return new FilterChildFam(this.data.getFam(id), this.childId);
};
return FilterChildData;
}());
/** Chart layout showing all relatives of a person. */
var RelativesChart = /** @class */ (function () {
function RelativesChart(inputOptions) {
this.options = __assign({}, inputOptions);
this.options.idGenerator = this.options.idGenerator || new id_generator_1.IdGenerator();
this.util = new chart_util_1.ChartUtil(this.options);
}
RelativesChart.prototype.layOutAncestorDescendants = function (ancestorsRoot, focusedNode) {
var _this = this;
var ancestorData = new Map();
ancestorsRoot.eachAfter(function (node) {
var _a, _b;
if (!node.parent) {
return;
}
var descendantOptions = __assign({}, _this.options);
descendantOptions.startFam = node.data.family.id;
delete descendantOptions.startIndi;
var child = node.id === node.parent.data.spouseParentNodeId
? node.parent.data.spouse.id
: node.parent.data.indi.id;
descendantOptions.data = new FilterChildData(descendantOptions.data, child);
descendantOptions.baseGeneration =
(_this.options.baseGeneration || 0) - node.depth;
var descendantNodes = (0, descendant_chart_1.layOutDescendants)(descendantOptions);
// The id could be modified because of duplicates. This can happen when
// drawing one family in multiple places of the chart).
node.data.id = descendantNodes[0].id;
if (((_a = node.data.indi) === null || _a === void 0 ? void 0 : _a.expander) !== undefined) {
descendantNodes[0].data.indi.expander = node.data.indi.expander;
}
if (((_b = node.data.spouse) === null || _b === void 0 ? void 0 : _b.expander) !== undefined) {
descendantNodes[0].data.spouse.expander = node.data.spouse.expander;
}
var chartInfo = (0, chart_util_1.getChartInfoWithoutMargin)(descendantNodes);
var parentData = (node.children || []).map(function (childNode) {
return ancestorData.get(childNode.data.id);
});
var parentHeight = parentData
.map(function (data) { return data.height; })
.reduce(function (a, b) { return a + b + chart_util_1.V_SPACING; }, 0);
var data = {
descendantNodes: descendantNodes,
width: chartInfo.size[0],
height: chartInfo.size[1] + parentHeight,
x: chartInfo.origin[0],
y: chartInfo.origin[1] + parentHeight,
};
ancestorData.set(node.data.id, data);
});
ancestorsRoot.each(function (node) {
if (!node.parent) {
return;
}
var data = ancestorData.get(node.data.id);
var parentData = ancestorData.get(node.parent.data.id);
data.left =
parentData && !parentData.middle
? !!parentData.left
: node.parent.data.indiParentNodeId === node.id;
data.middle =
(!parentData || !!parentData.middle) &&
node.parent.children.length === 1;
});
ancestorsRoot.each(function (node) {
var data = ancestorData.get(node.data.id);
var thisNode = data ? data.descendantNodes[0] : focusedNode;
(node.children || []).forEach(function (child) {
var childNode = ancestorData.get(child.data.id).descendantNodes[0];
childNode.parent = thisNode;
});
if (node.data.indiParentNodeId && node.children) {
thisNode.data.indiParentNodeId = node.children.find(function (childNode) { return childNode.id === node.data.indiParentNodeId; }).data.id;
}
if (node.data.spouseParentNodeId && node.children) {
thisNode.data.spouseParentNodeId = node.children.find(function (childNode) { return childNode.id === node.data.spouseParentNodeId; }).data.id;
}
});
ancestorsRoot.each(function (node) {
var nodeData = ancestorData.get(node.data.id);
// Lay out the nodes produced by laying out descendants of ancestors
// instead of the ancestor nodes from ancestorsRoot.
var thisNode = nodeData ? nodeData.descendantNodes[0] : focusedNode;
var indiParent = node.children &&
node.children.find(function (child) { return child.id === node.data.indiParentNodeId; });
var spouseParent = node.children &&
node.children.find(function (child) { return child.id === node.data.spouseParentNodeId; });
var nodeX = thisNode.x;
var nodeY = thisNode.y;
var nodeWidth = thisNode.data.width;
var nodeHeight = thisNode.data.height;
var indiWidth = thisNode.data.indi ? thisNode.data.indi.width : 0;
var spouseWidth = thisNode.data.spouse
? thisNode.data.spouse.width
: 0;
// Lay out the individual's ancestors and their descendants.
if (indiParent) {
var data = ancestorData.get(indiParent.data.id);
var parentNode = data.descendantNodes[0];
var parentData = parentNode.data;
var spouseTreeHeight = spouseParent
? ancestorData.get(spouseParent.data.id).height + chart_util_1.V_SPACING
: 0;
var dx_1 = nodeX +
data.x -
nodeWidth / 2 +
indiWidth / 2 +
(data.left ? -data.width - chart_util_1.H_SPACING : chart_util_1.H_SPACING);
var dy_1 = nodeY +
data.y -
nodeHeight / 2 -
data.height +
(data.left ? -chart_util_1.V_SPACING : -spouseTreeHeight - chart_util_1.V_SPACING);
// Move all nodes by (dx, dy). The ancestor node,
// ie. data.descendantNodes[0] is now at (0, 0).
data.descendantNodes.forEach(function (node) {
node.x += dx_1;
node.y += dy_1;
});
// Set the ancestor's horizontal position independently.
var middleX = indiWidth / 2 -
nodeWidth / 2 +
parentData.width / 2 -
(parentData.indi
? parentData.indi.width
: parentData.spouse.width);
if (data.middle) {
parentNode.x = 0;
}
else if (!nodeData || nodeData.middle) {
parentNode.x =
-nodeWidth / 2 - parentData.width / 2 + indiWidth - chart_util_1.H_SPACING / 2;
}
else if (data.left) {
parentNode.x =
nodeX +
(0, d3_array_1.min)([
nodeWidth / 2 -
parentData.width / 2 -
spouseWidth / 2 -
chart_util_1.H_SPACING,
middleX,
]);
}
else {
parentNode.x =
nodeX + (0, d3_array_1.max)([parentData.width / 2 - nodeWidth / 2, middleX]);
}
}
// Lay out the spouse's ancestors and their descendants.
if (spouseParent) {
var data = ancestorData.get(spouseParent.data.id);
var parentNode = data.descendantNodes[0];
var parentData = parentNode.data;
var indiTreeHeight = indiParent
? ancestorData.get(indiParent.data.id).height + chart_util_1.V_SPACING
: 0;
var dx_2 = nodeX +
data.x +
nodeWidth / 2 -
spouseWidth / 2 +
(data.left ? -data.width - chart_util_1.H_SPACING : chart_util_1.H_SPACING);
var dy_2 = nodeY +
data.y -
nodeHeight / 2 -
data.height +
(data.left ? -indiTreeHeight - chart_util_1.V_SPACING : -chart_util_1.V_SPACING);
// Move all nodes by (dx, dy). The ancestor node,
// ie. data.descendantNodes[0] is now at (0, 0).
data.descendantNodes.forEach(function (node) {
node.x += dx_2;
node.y += dy_2;
});
// Set the ancestor's horizontal position independently.
var middleX = nodeWidth / 2 -
spouseWidth / 2 +
parentData.width / 2 -
(parentData.indi
? parentData.indi.width
: parentData.spouse.width);
if (data.middle) {
parentNode.x = 0;
}
else if (!nodeData || nodeData.middle) {
parentNode.x =
nodeWidth / 2 + parentData.width / 2 - spouseWidth + chart_util_1.H_SPACING / 2;
}
else if (data.left) {
parentNode.x =
nodeX + (0, d3_array_1.min)([nodeWidth / 2 - parentData.width / 2, middleX]);
}
else {
parentNode.x =
nodeX +
(0, d3_array_1.max)([
parentData.width / 2 - nodeWidth / 2 + indiWidth / 2 + chart_util_1.H_SPACING,
middleX,
]);
}
}
});
return Array.from(ancestorData.values())
.map(function (data) { return data.descendantNodes; })
.reduce(function (a, b) { return a.concat(b); }, []);
};
RelativesChart.prototype.render = function () {
var _a, _b, _c, _d;
var descendantNodes = (0, descendant_chart_1.layOutDescendants)(this.options);
// Don't use common id generator because these nodes will not be drawn.
var ancestorOptions = Object.assign({}, this.options, {
idGenerator: undefined,
});
var ancestorsRoot = (0, ancestor_chart_1.getAncestorsTree)(ancestorOptions);
// The ancestor root node and first descendant node is the start node.
if (((_a = ancestorsRoot.data.indi) === null || _a === void 0 ? void 0 : _a.expander) !== undefined) {
descendantNodes[0].data.indi.expander =
(_b = ancestorsRoot.data.indi) === null || _b === void 0 ? void 0 : _b.expander;
}
if (((_c = ancestorsRoot.data.spouse) === null || _c === void 0 ? void 0 : _c.expander) !== undefined) {
descendantNodes[0].data.spouse.expander =
(_d = ancestorsRoot.data.spouse) === null || _d === void 0 ? void 0 : _d.expander;
}
var ancestorDescentants = this.layOutAncestorDescendants(ancestorsRoot, descendantNodes[0]);
var nodes = descendantNodes.concat(ancestorDescentants);
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 RelativesChart;
}());
exports.RelativesChart = RelativesChart;