(int)$gen[$b]) ?: strcmp($rankKey($a), $rankKey($b)) ?: ($a <=> $b); }); $order = array_merge($order, $rest); $mapIds = static function (array $ids) use ($onTree): array { $out = []; foreach ($ids as $x) { $x = (int)$x; if (isset($onTree[$x])) { $out[] = (string)$x; } } return array_values(array_unique($out)); }; $datum = []; foreach ($order as $pid) { if (!isset($people[$pid]) || !is_array($people[$pid])) { continue; } $p = $people[$pid]; $parents = $mapIds($links['parents'][$pid] ?? []); $spouses = $mapIds($links['spouses'][$pid] ?? []); $kids = $mapIds($links['children'][$pid] ?? []); // 子女按长幼排序:库按 rels.children 的数组顺序摆左右 $kidsInt = array_map('intval', $kids); usort($kidsInt, static fn(int $a, int $b): int => strcmp($rankKey($a), $rankKey($b)) ?: ($a <=> $b)); $kids = array_map('strval', $kidsInt); $g = strtolower((string)($p['gender'] ?? '')); $gender = $g === 'm' ? 'M' : ($g === 'f' ? 'F' : 'U'); $datum[] = [ 'id' => (string)$pid, 'data' => [ 'gender' => $gender, 'name' => \App\Nickname::display((int)$meId, $p) ?: (string)($p['name'] ?? ''), 'label' => \App\Kinship::label($graph, (int)$meId, $pid, $people), 'avatar' => avatar_url($p['avatar'] ?? null), // 「我」在图上高亮;中心那个人另有标记($focusId) 'me' => $pid === (int)$focusId, 'is_me_viewer' => $pid === (int)$meId, 'ph' => (int)($p['is_placeholder'] ?? 0) === 1, ], 'rels' => [ 'parents' => $parents, 'spouses' => $spouses, 'children' => $kids, ], ]; } // ⚠️ v24 第 12 条曾在每人数据上挂一个 `branch`("他的姻亲没画在本图上"的人名), // 用来给卡片加一个"⇄ 姻亲"入口。用户 2026-10-03 第 7 条把那个按钮撤了 // (改成"点姓名 = 以他为中心"),所以这份计算**连同渲染一起删掉了** —— // 留着只会是"服务端算了一个没人用的字段",日后读代码的人还得反查它干嘛的。 // (如果哪天又要"姻亲入口",从 git 历史里捞这一段即可。) $canChart = count($datum) > 1; } $meName = (string)($people[$meId]['name'] ?? '自己'); $datumJson = json_encode( $datum ?? [], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); ?>

我的家谱
还没连上任何亲属关系 到「」的资料页,把父母、配偶、子女填进去, 这张家谱就会自动长出来。兄弟姐妹不用单独填 —— 只要你们有同一对父母,就会自动认出来。