people tags #387

This commit is contained in:
Hamid Reza Mohammadi 2026-10-03 18:54:32 +03:30
parent 88f39c2bab
commit de304f089c
2 changed files with 40 additions and 1 deletions

View File

@ -35,6 +35,13 @@ else
spouse dashing (finer dots, lighter/grayer) and gets no heart icon, so it doesn't
read as a marriage or as a confirmed shared-parent claim */
.ft-line-sibling { stroke-dasharray: 1,3; stroke: #a0a0a0; }
/* real recorded parent (e.g. a mother) who could not be placed as an
attached spouse-box because she has her own independent position in
the tree (her own recorded ancestry). Drawn as an extra connector to
wherever she actually ended up - distinct dash/color from both the
spouse line (marriage) and the sibling line (unspecified shared
parent), since this one *is* a confirmed parent-child relation. */
.ft-line-second-parent { stroke-dasharray: 6,2; stroke: #a0455c; stroke-width: 1.25; }
.ft-tooltip-panel {
position: absolute; top: 10px; left: 10px; max-width: 300px;
background: #fffdf7; border: 1px solid #8b6b4a; border-radius: 8px;

View File

@ -133,8 +133,23 @@
return false;
}
// A secondary parent (e.g. the mother, when the father was picked as the primary/spine
// parent above) who is themselves a root with no children of their own gets drawn as an
// attached spouse-box right next to the primary parent. But when the secondary parent has
// their OWN recorded ancestors (not uncommon - e.g. two fully-documented royal lines
// marrying), tryAttach refuses to move them next to someone else's position, since they
// already have a real, independent one of their own elsewhere in the tree. That used to
// mean the relation was just dropped - the child only ever showed a line to the primary
// parent. Track those cases here instead, so an extra connector can still be drawn straight
// to wherever that parent actually ended up, once every node has a position (see
// unattachedSecondaryParents below and its use in renderFamilyTree).
var unattachedSecondaryParents = []; // [{parentId, childId}]
Object.keys(secondaryParentOf).forEach(function (childId) {
tryAttach(primaryParentOf[childId], secondaryParentOf[childId]);
var parentId = secondaryParentOf[childId];
var primaryId = primaryParentOf[childId];
if (!tryAttach(primaryId, parentId)) {
unattachedSecondaryParents.push({ parentId: parentId, childId: parseInt(childId, 10) });
}
});
Object.keys(spouseOf).forEach(function (a) {
spouseOf[a].forEach(function (b) {
@ -208,6 +223,7 @@
secondaryParentOf: secondaryParentOf,
attachedList: attachedList,
attachedAsSibling: attachedAsSibling,
unattachedSecondaryParents: unattachedSecondaryParents,
topLevelRoots: topLevelRoots,
nodeX: nodeX,
nodeDepth: nodeDepth
@ -347,6 +363,22 @@
});
});
// extra connector for a recorded second parent who couldn't be drawn attached next to the
// primary parent (see unattachedSecondaryParents in buildLayout) - drawn last, once every
// box (both plain tree nodes and attached ones) has a real position in drawnPos, straight
// from wherever that parent actually ended up to the child. Styled distinctly from the
// primary parent-child line (solid) and from spouse/sibling attachments (both dashed) so it
// doesn't get misread as either - it's a real, independently-documented parent, just not the
// one the chart chose as this child's spine.
layoutInfo.unattachedSecondaryParents.forEach(function (edge) {
var pp = drawnPos[edge.parentId], cp = drawnPos[edge.childId];
if (!pp || !cp) return; // shouldn't happen, but never let a bad edge break the whole chart
var parentH = boxSizeFor(layoutInfo.persons[edge.parentId], BOX_W, BOX_H).h;
var childH = boxSizeFor(layoutInfo.persons[edge.childId], BOX_W, BOX_H).h;
var dy = cp.y > pp.y ? 1 : -1; // usually the child is drawn lower, but not guaranteed
line(pp.x, pp.y + dy * parentH / 2, cp.x, cp.y - dy * childH / 2, 'ft-line ft-line-second-parent');
});
svg.setAttribute('viewBox', '0 0 ' + (maxX + MARGIN) + ' ' + (maxY + MARGIN));
function showDetails(p) {