No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

family-tree-builder.ts 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import { Injectable } from '@angular/core';
  2. import { Family } from '../models/family';
  3. import { MarriageRelation } from '../models/marriage-relation';
  4. import { Kakocho } from '../models/kakocho';
  5. import { FamilyUnit } from '../models/family-unit';
  6. import { FamilyUnitNode } from '../models/family-unit-node';
  7. export interface FamilyTreeNode {
  8. family: Family;
  9. kakocho?: Kakocho;
  10. isDeceased: boolean;
  11. spouses: FamilyTreeNode[];
  12. children: FamilyTreeNode[];
  13. parents: FamilyTreeNode[];
  14. }
  15. @Injectable({
  16. providedIn: 'root',
  17. })
  18. export class FamilyTreeBuilderService {
  19. build(
  20. families: Family[],
  21. marriages: MarriageRelation[],
  22. kakocholist: Kakocho[]
  23. ): FamilyTreeNode[] {
  24. const nodeMap = new Map<string, FamilyTreeNode>();
  25. const kakochoMap = new Map(
  26. kakocholist.map(k => [k.familyId, k])
  27. );
  28. // -----------------------------
  29. // ① ノード生成(ここで統合)
  30. // -----------------------------
  31. families.forEach((family) => {
  32. const kakocho = kakochoMap.get(family.id);
  33. nodeMap.set(family.id, {
  34. family,
  35. kakocho,
  36. isDeceased: !!kakocho,
  37. parents: [],
  38. children: [],
  39. spouses: [],
  40. });
  41. });
  42. // -----------------------------
  43. // ② 親子関係
  44. // -----------------------------
  45. families.forEach((family) => {
  46. const childNode = nodeMap.get(family.id);
  47. if (!childNode) return;
  48. if (family.fatherId) {
  49. const father = nodeMap.get(family.fatherId);
  50. if (father) {
  51. father.children.push(childNode);
  52. childNode.parents.push(father);
  53. }
  54. }
  55. if (family.motherId) {
  56. const mother = nodeMap.get(family.motherId);
  57. if (mother) {
  58. mother.children.push(childNode);
  59. childNode.parents.push(mother);
  60. }
  61. }
  62. });
  63. // -----------------------------
  64. // ③ 配偶者関係(current)
  65. // -----------------------------
  66. marriages
  67. .filter(m => m.status === 'current')
  68. .forEach((m) => {
  69. const p1 = nodeMap.get(m.person1Id);
  70. const p2 = nodeMap.get(m.person2Id);
  71. if (!p1 || !p2) return;
  72. if (!p1.spouses.some(s => s.family.id === p2.family.id)) {
  73. p1.spouses.push(p2);
  74. }
  75. });
  76. // -----------------------------
  77. // ④ spouseIdフォールバック
  78. // -----------------------------
  79. families.forEach((f) => {
  80. if (!f.spouseId) return;
  81. const a = nodeMap.get(f.id);
  82. const b = nodeMap.get(f.spouseId);
  83. if (!a || !b) return;
  84. if (!a.spouses.some(s => s.family.id === b.family.id)) {
  85. a.spouses.push(b);
  86. }
  87. });
  88. return [...nodeMap.values()];
  89. }
  90. // -----------------------------
  91. // Roots
  92. // -----------------------------
  93. getRoots(nodes: FamilyTreeNode[]): FamilyTreeNode[] {
  94. return nodes.filter(node => {
  95. if (node.parents.length > 0) return false;
  96. if (node.spouses.length > 0) {
  97. const spouseId = node.spouses[0].family.id;
  98. return node.family.id < spouseId;
  99. }
  100. return true;
  101. });
  102. }
  103. buildFamilyUnits(
  104. nodes: FamilyTreeNode[]
  105. ): FamilyUnit[] {
  106. const units: FamilyUnit[] = [];
  107. const processed =
  108. new Set<string>();
  109. for (const node of nodes) {
  110. if (node.spouses.length > 0) {
  111. const spouse =
  112. node.spouses[0];
  113. const key =
  114. [
  115. node.family.id,
  116. spouse.family.id
  117. ]
  118. .sort()
  119. .join('-');
  120. if (
  121. processed.has(key)
  122. ) {
  123. continue;
  124. }
  125. processed.add(key);
  126. const children =
  127. nodes
  128. .filter(child => {
  129. const fatherId =
  130. child.family.fatherId;
  131. const motherId =
  132. child.family.motherId;
  133. return (
  134. (
  135. fatherId === node.family.id &&
  136. motherId === spouse.family.id
  137. )
  138. ||
  139. (
  140. fatherId === spouse.family.id &&
  141. motherId === node.family.id
  142. )
  143. );
  144. })
  145. .map(child => child.family);
  146. units.push({
  147. id: key,
  148. husband:
  149. node.family.gender === 'male'
  150. ? node.family
  151. : spouse.family,
  152. wife:
  153. node.family.gender === 'female'
  154. ? node.family
  155. : spouse.family,
  156. children
  157. });
  158. } else {
  159. units.push({
  160. id:
  161. node.family.id,
  162. husband:
  163. node.family.gender === 'male'
  164. ? node.family
  165. : undefined,
  166. wife:
  167. node.family.gender === 'female'
  168. ? node.family
  169. : undefined,
  170. children: []
  171. });
  172. }
  173. }
  174. return units;
  175. }
  176. buildFamilyUnitTree(
  177. units: FamilyUnit[]
  178. ): FamilyUnitNode[] {
  179. const nodeMap =
  180. new Map<string, FamilyUnitNode>();
  181. units.forEach(unit => {
  182. nodeMap.set(unit.id, {
  183. unit,
  184. children: [],
  185. parents: []
  186. });
  187. });
  188. units.forEach(parentUnit => {
  189. parentUnit.children.forEach(child => {
  190. const childUnit =
  191. units.find(u => {
  192. return (
  193. u.husband?.id === child.id ||
  194. u.wife?.id === child.id
  195. );
  196. });
  197. if (!childUnit) {
  198. return;
  199. }
  200. const parentNode =
  201. nodeMap.get(parentUnit.id)!;
  202. const childNode =
  203. nodeMap.get(childUnit.id)!;
  204. parentNode.children.push(
  205. childNode
  206. );
  207. childNode.parents.push(
  208. parentNode
  209. );
  210. });
  211. });
  212. return [
  213. ...nodeMap.values()
  214. ];
  215. }
  216. getUnitRoots(
  217. nodes: FamilyUnitNode[]
  218. ): FamilyUnitNode[] {
  219. return nodes.filter(
  220. x =>
  221. x.parents.length === 0
  222. );
  223. }
  224. }