| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- import { Injectable } from '@angular/core';
-
- import {
- FamilyTreeNode
- } from './family-tree-builder';
-
- import { LayoutNode } from '../models/layoutnode';
- import { Family } from '../models/family';
-
- @Injectable({
- providedIn: 'root'
- })
- export class FamilyTreeLayoutService {
-
- private readonly NODE_WIDTH = 140;
- private readonly NODE_HEIGHT = 70;
-
- private readonly HORIZONTAL_GAP = 200;
- private readonly VERTICAL_GAP = 200;
-
- private readonly SPOUSE_GAP = 180;
-
- private processedCouples = new Set<string>();
- private currentX = 0;
-
-
- buildLayout(
- roots: FamilyTreeNode[]
- ): LayoutNode[] {
-
- this.currentX = 0;
-
- this.processedCouples.clear();
-
- const result: LayoutNode[] = [];
-
- const visited = new Set<string>();
-
- roots.forEach(root => {
-
- this.layoutNode(
- root,
- 0,
- result,
- visited
- );
-
- this.currentX +=
- this.HORIZONTAL_GAP;
- });
-
- return result;
- }
-
- private layoutNode(
- node: FamilyTreeNode,
- depth: number,
- result: LayoutNode[],
- visited: Set<string>
- ): number {
-
- if (visited.has(node.family.id)) {
-
- const existing = result.find(
- x => x.familyId === node.family.id
- );
-
- return existing?.x ?? 0;
- }
-
- visited.add(node.family.id);
-
- const children = node.children;
-
- let x: number;
-
- if (children.length === 0) {
-
- x = this.currentX;
-
- this.currentX +=
- this.HORIZONTAL_GAP;
-
- } else {
-
- const childXs =
- children.map(child =>
- this.layoutNode(
- child,
- depth + 1,
- result,
- visited
- )
- );
-
- x =
- (Math.min(...childXs) +
- Math.max(...childXs))
- / 2;
- }
-
- const y =
- depth *
- this.VERTICAL_GAP;
-
- let spouseX: number | undefined;
- let spouse: Family | undefined;
-
- if (node.spouses.length > 0) {
-
- const spouseNode =
- node.spouses[0];
-
- const coupleKey =
- [
- node.family.id,
- spouseNode.family.id
- ]
- .sort()
- .join('-');
-
- if (
- !this.processedCouples.has(
- coupleKey
- )
- ) {
-
- this.processedCouples.add(
- coupleKey
- );
-
- spouse =
- spouseNode.family;
-
- spouseX =
- x + this.SPOUSE_GAP;
- }
- }
-
- result.push({
-
- familyId: node.family.id,
-
- family: node.family,
-
- spouse,
-
- depth,
-
- x,
- y,
-
- spouseX,
-
- width: this.NODE_WIDTH,
-
- height: this.NODE_HEIGHT
-
- });
-
- return x;
- }
-
- }
|