1168ff6f3Sric2016<?php 2168ff6f3Sric2016/** 3168ff6f3Sric2016 * webtrees: online genealogy 48fcd0d32SGreg Roach * Copyright (C) 2019 webtrees development team 5168ff6f3Sric2016 * This program is free software: you can redistribute it and/or modify 6168ff6f3Sric2016 * it under the terms of the GNU General Public License as published by 7168ff6f3Sric2016 * the Free Software Foundation, either version 3 of the License, or 8168ff6f3Sric2016 * (at your option) any later version. 9168ff6f3Sric2016 * This program is distributed in the hope that it will be useful, 10168ff6f3Sric2016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11168ff6f3Sric2016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12168ff6f3Sric2016 * GNU General Public License for more details. 13168ff6f3Sric2016 * You should have received a copy of the GNU General Public License 14168ff6f3Sric2016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15168ff6f3Sric2016 */ 16e7f56f2aSGreg Roachdeclare(strict_types=1); 17e7f56f2aSGreg Roach 18168ff6f3Sric2016namespace Fisharebest\Webtrees\Module; 19168ff6f3Sric2016 2026684e68SGreg Roachuse Fisharebest\Webtrees\Auth; 2126684e68SGreg Roachuse Fisharebest\Webtrees\FontAwesome; 2226684e68SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrint; 23168ff6f3Sric2016use Fisharebest\Webtrees\I18N; 24168ff6f3Sric2016use Fisharebest\Webtrees\Individual; 25e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Menu; 2626684e68SGreg Roachuse Fisharebest\Webtrees\Theme; 2726684e68SGreg Roachuse Fisharebest\Webtrees\Tree; 28*9867b2f0SGreg Roachuse Fisharebest\Webtrees\User; 2926684e68SGreg Roachuse Symfony\Component\HttpFoundation\Request; 3026684e68SGreg Roachuse Symfony\Component\HttpFoundation\Response; 31168ff6f3Sric2016 32168ff6f3Sric2016/** 33168ff6f3Sric2016 * Class HourglassChartModule 34168ff6f3Sric2016 */ 3537eb8894SGreg Roachclass HourglassChartModule extends AbstractModule implements ModuleChartInterface 36c1010edaSGreg Roach{ 3749a243cbSGreg Roach use ModuleChartTrait; 3849a243cbSGreg Roach 3926684e68SGreg Roach // Defaults 4026684e68SGreg Roach private const DEFAULT_GENERATIONS = '3'; 4126684e68SGreg Roach private const DEFAULT_MAXIMUM_GENERATIONS = '9'; 4226684e68SGreg Roach 4326684e68SGreg Roach // Limits 4426684e68SGreg Roach private const MINIMUM_GENERATIONS = 2; 4526684e68SGreg Roach 46168ff6f3Sric2016 /** 47168ff6f3Sric2016 * How should this module be labelled on tabs, menus, etc.? 48168ff6f3Sric2016 * 49168ff6f3Sric2016 * @return string 50168ff6f3Sric2016 */ 5149a243cbSGreg Roach public function title(): string 52c1010edaSGreg Roach { 53bbb76c12SGreg Roach /* I18N: Name of a module/chart */ 54bbb76c12SGreg Roach return I18N::translate('Hourglass chart'); 55168ff6f3Sric2016 } 56168ff6f3Sric2016 57168ff6f3Sric2016 /** 58168ff6f3Sric2016 * A sentence describing what this module does. 59168ff6f3Sric2016 * 60168ff6f3Sric2016 * @return string 61168ff6f3Sric2016 */ 6249a243cbSGreg Roach public function description(): string 63c1010edaSGreg Roach { 64bbb76c12SGreg Roach /* I18N: Description of the “HourglassChart” module */ 65bbb76c12SGreg Roach return I18N::translate('An hourglass chart of an individual’s ancestors and descendants.'); 66168ff6f3Sric2016 } 67168ff6f3Sric2016 68168ff6f3Sric2016 /** 69377a2979SGreg Roach * CSS class for the URL. 70377a2979SGreg Roach * 71377a2979SGreg Roach * @return string 72377a2979SGreg Roach */ 73377a2979SGreg Roach public function chartMenuClass(): string 74377a2979SGreg Roach { 75377a2979SGreg Roach return 'menu-chart-hourglass'; 76377a2979SGreg Roach } 77377a2979SGreg Roach 78377a2979SGreg Roach /** 794eb71cfaSGreg Roach * Return a menu item for this chart - for use in individual boxes. 804eb71cfaSGreg Roach * 8160bc3e3fSGreg Roach * @param Individual $individual 8260bc3e3fSGreg Roach * 834eb71cfaSGreg Roach * @return Menu|null 844eb71cfaSGreg Roach */ 85377a2979SGreg Roach public function chartBoxMenu(Individual $individual): ?Menu 86c1010edaSGreg Roach { 87e6562982SGreg Roach return $this->chartMenu($individual); 88e6562982SGreg Roach } 89e6562982SGreg Roach 90e6562982SGreg Roach /** 9126684e68SGreg Roach * A form to request the chart parameters. 92e6562982SGreg Roach * 9326684e68SGreg Roach * @param Request $request 9426684e68SGreg Roach * @param Tree $tree 95*9867b2f0SGreg Roach * @param User $user 96e6562982SGreg Roach * 9726684e68SGreg Roach * @return Response 98e6562982SGreg Roach */ 99*9867b2f0SGreg Roach public function getChartAction(Request $request, Tree $tree, User $user): Response 100e6562982SGreg Roach { 1019b5537c3SGreg Roach $ajax = (bool) $request->get('ajax'); 10226684e68SGreg Roach $xref = $request->get('xref', ''); 10326684e68SGreg Roach $individual = Individual::getInstance($xref, $tree); 10426684e68SGreg Roach 10526684e68SGreg Roach Auth::checkIndividualAccess($individual); 106*9867b2f0SGreg Roach Auth::checkComponentAccess($this, 'chart', $tree, $user); 10726684e68SGreg Roach 10826684e68SGreg Roach $maximum_generations = (int) $tree->getPreference('MAX_DESCENDANCY_GENERATIONS', self::DEFAULT_MAXIMUM_GENERATIONS); 10926684e68SGreg Roach $default_generations = (int) $tree->getPreference('DEFAULT_PEDIGREE_GENERATIONS', self::DEFAULT_GENERATIONS); 11026684e68SGreg Roach 11126684e68SGreg Roach $generations = (int) $request->get('generations', $default_generations); 11226684e68SGreg Roach 11326684e68SGreg Roach $generations = min($generations, $maximum_generations); 11426684e68SGreg Roach $generations = max($generations, self::MINIMUM_GENERATIONS); 11526684e68SGreg Roach 11626684e68SGreg Roach $show_spouse = (bool) $request->get('show_spouse'); 11726684e68SGreg Roach 1189b5537c3SGreg Roach if ($ajax) { 11926684e68SGreg Roach return $this->chart($individual, $generations, $show_spouse); 12026684e68SGreg Roach } 12126684e68SGreg Roach 12226684e68SGreg Roach $ajax_url = $this->chartUrl($individual, [ 1239b5537c3SGreg Roach 'ajax' => true, 12426684e68SGreg Roach ]); 12526684e68SGreg Roach 1269b5537c3SGreg Roach return $this->viewResponse('modules/hourglass-chart/page', [ 12726684e68SGreg Roach 'ajax_url' => $ajax_url, 12826684e68SGreg Roach 'generations' => $generations, 12926684e68SGreg Roach 'individual' => $individual, 13026684e68SGreg Roach 'maximum_generations' => $maximum_generations, 13126684e68SGreg Roach 'minimum_generations' => self::MINIMUM_GENERATIONS, 13226684e68SGreg Roach 'module_name' => $this->name(), 13326684e68SGreg Roach 'show_spouse' => $show_spouse, 13426684e68SGreg Roach 'title' => $this->chartTitle($individual), 13526684e68SGreg Roach ]); 13626684e68SGreg Roach } 13726684e68SGreg Roach 13826684e68SGreg Roach /** 13926684e68SGreg Roach * Generate the initial generations of the chart 14026684e68SGreg Roach * 14126684e68SGreg Roach * @param Request $request 14226684e68SGreg Roach * @param Tree $tree 14326684e68SGreg Roach * 14426684e68SGreg Roach * @return Response 14526684e68SGreg Roach */ 14626684e68SGreg Roach protected function chart(Individual $individual, int $generations, bool $show_spouse): Response 14726684e68SGreg Roach { 14826684e68SGreg Roach ob_start(); 14926684e68SGreg Roach $this->printDescendency($individual, 1, $generations, $show_spouse, true); 15026684e68SGreg Roach $descendants = ob_get_clean(); 15126684e68SGreg Roach 15226684e68SGreg Roach ob_start(); 15326684e68SGreg Roach $this->printPersonPedigree($individual, 1, $generations, $show_spouse); 15426684e68SGreg Roach $ancestors = ob_get_clean(); 15526684e68SGreg Roach 15626684e68SGreg Roach return new Response(view('modules/hourglass-chart/chart', [ 15726684e68SGreg Roach 'descendants' => $descendants, 15826684e68SGreg Roach 'ancestors' => $ancestors, 15926684e68SGreg Roach 'bhalfheight' => (int) (Theme::theme()->parameter('chart-box-y') / 2), 16026684e68SGreg Roach 'module_name' => $this->name(), 16126684e68SGreg Roach ])); 16226684e68SGreg Roach } 16326684e68SGreg Roach 16426684e68SGreg Roach /** 16526684e68SGreg Roach * @param Request $request 16626684e68SGreg Roach * @param Tree $tree 16726684e68SGreg Roach * 16826684e68SGreg Roach * @return Response 16926684e68SGreg Roach */ 17026684e68SGreg Roach public function postAncestorsAction(Request $request, Tree $tree): Response 17126684e68SGreg Roach { 17226684e68SGreg Roach $xref = $request->get('xref', ''); 17326684e68SGreg Roach $individual = Individual::getInstance($xref, $tree); 17426684e68SGreg Roach 17526684e68SGreg Roach Auth::checkIndividualAccess($individual); 17626684e68SGreg Roach 17726684e68SGreg Roach $show_spouse = (bool) $request->get('show_spouse'); 17826684e68SGreg Roach 17926684e68SGreg Roach ob_start(); 18026684e68SGreg Roach $this->printPersonPedigree($individual, 0, 1, $show_spouse); 18126684e68SGreg Roach $html = ob_get_clean(); 18226684e68SGreg Roach 18326684e68SGreg Roach return new Response($html); 18426684e68SGreg Roach } 18526684e68SGreg Roach 18626684e68SGreg Roach /** 18726684e68SGreg Roach * @param Request $request 18826684e68SGreg Roach * @param Tree $tree 18926684e68SGreg Roach * 19026684e68SGreg Roach * @return Response 19126684e68SGreg Roach */ 19226684e68SGreg Roach public function postDescendantsAction(Request $request, Tree $tree): Response 19326684e68SGreg Roach { 19426684e68SGreg Roach $xref = $request->get('xref', ''); 19526684e68SGreg Roach $individual = Individual::getInstance($xref, $tree); 19626684e68SGreg Roach 19726684e68SGreg Roach $show_spouse = (bool) $request->get('show_spouse'); 19826684e68SGreg Roach 19926684e68SGreg Roach ob_start(); 20026684e68SGreg Roach $this->printDescendency($individual, 1, 2, $show_spouse, false); 20126684e68SGreg Roach $html = ob_get_clean(); 20226684e68SGreg Roach 20326684e68SGreg Roach return new Response($html); 20426684e68SGreg Roach } 20526684e68SGreg Roach 20626684e68SGreg Roach /** 20726684e68SGreg Roach * Prints descendency of passed in person 20826684e68SGreg Roach * 20926684e68SGreg Roach * @param Individual $individual Show descendants of this individual 21026684e68SGreg Roach * @param int $generation The current generation number 21126684e68SGreg Roach * @param int $generations Show this number of generations 21226684e68SGreg Roach * @param bool $show_spouse 21326684e68SGreg Roach * @param bool $show_menu 21426684e68SGreg Roach * 21526684e68SGreg Roach * @return void 21626684e68SGreg Roach */ 21726684e68SGreg Roach private function printDescendency(Individual $individual, int $generation, int $generations, bool $show_spouse, bool $show_menu) 21826684e68SGreg Roach { 21926684e68SGreg Roach static $lastGenSecondFam = false; 22026684e68SGreg Roach 22126684e68SGreg Roach if ($generation > $generations) { 22226684e68SGreg Roach return; 22326684e68SGreg Roach } 22426684e68SGreg Roach $pid = $individual->xref(); 22526684e68SGreg Roach $tablealign = 'right'; 22626684e68SGreg Roach $otablealign = 'left'; 22726684e68SGreg Roach if (I18N::direction() === 'rtl') { 22826684e68SGreg Roach $tablealign = 'left'; 22926684e68SGreg Roach $otablealign = 'right'; 23026684e68SGreg Roach } 23126684e68SGreg Roach 23226684e68SGreg Roach //-- put a space between families on the last generation 23326684e68SGreg Roach if ($generation == $generations - 1) { 23426684e68SGreg Roach if ($lastGenSecondFam) { 23526684e68SGreg Roach echo '<br>'; 23626684e68SGreg Roach } 23726684e68SGreg Roach $lastGenSecondFam = true; 23826684e68SGreg Roach } 23926684e68SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" id="table_' . e($pid) . '" class="hourglassChart" style="float:' . $tablealign . '">'; 24026684e68SGreg Roach echo '<tr>'; 24126684e68SGreg Roach echo '<td style="text-align:' . $tablealign . '">'; 24226684e68SGreg Roach $families = $individual->getSpouseFamilies(); 24326684e68SGreg Roach $children = []; 24426684e68SGreg Roach if ($generation < $generations) { 24526684e68SGreg Roach // Put all of the children in a common array 24626684e68SGreg Roach foreach ($families as $family) { 24726684e68SGreg Roach foreach ($family->getChildren() as $child) { 24826684e68SGreg Roach $children[] = $child; 24926684e68SGreg Roach } 25026684e68SGreg Roach } 25126684e68SGreg Roach 25226684e68SGreg Roach $ct = count($children); 25326684e68SGreg Roach if ($ct > 0) { 25426684e68SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" style="position: relative; top: auto; float: ' . $tablealign . ';">'; 25526684e68SGreg Roach for ($i = 0; $i < $ct; $i++) { 25626684e68SGreg Roach $individual2 = $children[$i]; 25726684e68SGreg Roach $chil = $individual2->xref(); 25826684e68SGreg Roach echo '<tr>'; 25926684e68SGreg Roach echo '<td id="td_', e($chil), '" class="', I18N::direction(), '" style="text-align:', $otablealign, '">'; 26026684e68SGreg Roach $this->printDescendency($individual2, $generation + 1, $generations, $show_spouse, false); 26126684e68SGreg Roach echo '</td>'; 26226684e68SGreg Roach 26326684e68SGreg Roach // Print the lines 26426684e68SGreg Roach if ($ct > 1) { 26526684e68SGreg Roach if ($i == 0) { 26626684e68SGreg Roach // First child 26726684e68SGreg Roach echo '<td style="vertical-align:bottom"><img alt="" role="presentation" class="line1 tvertline" id="vline_' . $chil . '" src="' . Theme::theme()->parameter('image-vline') . '" width="3"></td>'; 26826684e68SGreg Roach } elseif ($i == $ct - 1) { 26926684e68SGreg Roach // Last child 27026684e68SGreg Roach echo '<td style="vertical-align:top"><img alt="" role="presentation" class="bvertline" id="vline_' . $chil . '" src="' . Theme::theme()->parameter('image-vline') . '" width="3"></td>'; 27126684e68SGreg Roach } else { 27226684e68SGreg Roach // Middle child 27326684e68SGreg Roach echo '<td style="background: url(\'' . Theme::theme()->parameter('image-vline') . '\');"><img alt="" role="presentation" src="' . Theme::theme()->parameter('image-spacer') . '" width="3"></td>'; 27426684e68SGreg Roach } 27526684e68SGreg Roach } 27626684e68SGreg Roach echo '</tr>'; 27726684e68SGreg Roach } 27826684e68SGreg Roach echo '</table>'; 27926684e68SGreg Roach } 28026684e68SGreg Roach echo '</td>'; 28126684e68SGreg Roach echo '<td class="myCharts" width="', Theme::theme()->parameter('chart-box-x'), '">'; 28226684e68SGreg Roach } 28326684e68SGreg Roach 28426684e68SGreg Roach // Print the descendency expansion arrow 28526684e68SGreg Roach if ($generation == $generations) { 28626684e68SGreg Roach $tbwidth = Theme::theme()->parameter('chart-box-x') + 16; 28726684e68SGreg Roach for ($j = $generation; $j < $generations; $j++) { 28826684e68SGreg Roach echo "<div style='width: ", $tbwidth, "px;'><br></div></td><td style='width:", Theme::theme()->parameter('chart-box-x'), "px'>"; 28926684e68SGreg Roach } 29026684e68SGreg Roach $kcount = 0; 29126684e68SGreg Roach foreach ($families as $family) { 29226684e68SGreg Roach $kcount += $family->getNumberOfChildren(); 29326684e68SGreg Roach } 29426684e68SGreg Roach if ($kcount == 0) { 29526684e68SGreg Roach echo "</td><td style='width:", Theme::theme()->parameter('chart-box-x'), "px'>"; 29626684e68SGreg Roach } else { 29726684e68SGreg Roach echo FontAwesome::linkIcon('arrow-start', I18N::translate('Children'), [ 29826684e68SGreg Roach 'href' => '#', 29926684e68SGreg Roach 'data-route' => 'Descendants', 30026684e68SGreg Roach 'data-xref' => $pid, 30126684e68SGreg Roach 'data-spouses' => $show_spouse, 30226684e68SGreg Roach 'data-tree' => $individual->tree()->name(), 30326684e68SGreg Roach ]); 30426684e68SGreg Roach 30526684e68SGreg Roach //-- move the arrow up to line up with the correct box 30626684e68SGreg Roach if ($show_spouse) { 30726684e68SGreg Roach echo str_repeat('<br><br><br>', count($families)); 30826684e68SGreg Roach } 30926684e68SGreg Roach echo "</td><td style='width:", Theme::theme()->parameter('chart-box-x'), "px'>"; 31026684e68SGreg Roach } 31126684e68SGreg Roach } 31226684e68SGreg Roach 31326684e68SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" id="table2_' . $pid . '"><tr><td> '; 31426684e68SGreg Roach echo FunctionsPrint::printPedigreePerson($individual); 31526684e68SGreg Roach echo '</td><td> <img alt="" role="presentation" class="lineh1" src="' . Theme::theme()->parameter('image-hline') . '" width="7" height="3">'; 31626684e68SGreg Roach 31726684e68SGreg Roach //----- Print the spouse 31826684e68SGreg Roach if ($show_spouse) { 31926684e68SGreg Roach foreach ($families as $family) { 32026684e68SGreg Roach echo "</td></tr><tr><td style='text-align:$otablealign'>"; 32126684e68SGreg Roach echo FunctionsPrint::printPedigreePerson($family->getSpouse($individual)); 32226684e68SGreg Roach echo '</td><td> </td>'; 32326684e68SGreg Roach } 32426684e68SGreg Roach //-- add offset divs to make things line up better 32526684e68SGreg Roach if ($generation == $generations) { 32626684e68SGreg Roach echo "<tr><td colspan '2'><div style='height:", (Theme::theme()->parameter('chart-box-y') / 4), 'px; width:', Theme::theme()->parameter('chart-box-x'), "px;'><br></div>"; 32726684e68SGreg Roach } 32826684e68SGreg Roach } 32926684e68SGreg Roach echo '</td></tr></table>'; 33026684e68SGreg Roach 33126684e68SGreg Roach // For the root individual, print a down arrow that allows changing the root of tree 33226684e68SGreg Roach if ($show_menu && $generation == 1) { 33326684e68SGreg Roach echo '<div class="center" id="childarrow" style="position:absolute; width:', Theme::theme()->parameter('chart-box-x'), 'px;">'; 33426684e68SGreg Roach echo FontAwesome::linkIcon('arrow-down', I18N::translate('Family'), [ 33526684e68SGreg Roach 'href' => '#', 33626684e68SGreg Roach 'id' => 'spouse-child-links', 33726684e68SGreg Roach ]); 33826684e68SGreg Roach echo '<div id="childbox">'; 33926684e68SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" class="person_box"><tr><td> '; 34026684e68SGreg Roach 34126684e68SGreg Roach foreach ($individual->getSpouseFamilies() as $family) { 34226684e68SGreg Roach echo "<span class='name1'>" . I18N::translate('Family') . '</span>'; 34326684e68SGreg Roach $spouse = $family->getSpouse($individual); 34426684e68SGreg Roach if ($spouse !== null) { 34526684e68SGreg Roach echo '<a href="' . e(route('hourglass', [ 34626684e68SGreg Roach 'xref' => $spouse->xref(), 34726684e68SGreg Roach 'generations' => $generations, 34826684e68SGreg Roach 'show_spouse' => (int) $show_spouse, 34926684e68SGreg Roach 'ged' => $spouse->tree()->name(), 35026684e68SGreg Roach ])) . '" class="name1">' . $spouse->getFullName() . '</a>'; 35126684e68SGreg Roach } 35226684e68SGreg Roach foreach ($family->getChildren() as $child) { 35326684e68SGreg Roach echo '<a href="' . e(route('hourglass', [ 35426684e68SGreg Roach 'xref' => $child->xref(), 35526684e68SGreg Roach 'generations' => $generations, 35626684e68SGreg Roach 'show_spouse' => (int) $show_spouse, 35726684e68SGreg Roach 'ged' => $child->tree()->name(), 35826684e68SGreg Roach ])) . '" class="name1">' . $child->getFullName() . '</a>'; 35926684e68SGreg Roach } 36026684e68SGreg Roach } 36126684e68SGreg Roach 36226684e68SGreg Roach //-- print the siblings 36326684e68SGreg Roach foreach ($individual->getChildFamilies() as $family) { 36426684e68SGreg Roach if ($family->getHusband() || $family->getWife()) { 36526684e68SGreg Roach echo "<span class='name1'>" . I18N::translate('Parents') . '</span>'; 36626684e68SGreg Roach $husb = $family->getHusband(); 36726684e68SGreg Roach if ($husb) { 36826684e68SGreg Roach echo '<a href="' . e(route('hourglass', [ 36926684e68SGreg Roach 'xref' => $husb->xref(), 37026684e68SGreg Roach 'generations' => $generations, 37126684e68SGreg Roach 'show_spouse' => (int) $show_spouse, 37226684e68SGreg Roach 'ged' => $husb->tree()->name(), 37326684e68SGreg Roach ])) . '" class="name1">' . $husb->getFullName() . '</a>'; 37426684e68SGreg Roach } 37526684e68SGreg Roach $wife = $family->getWife(); 37626684e68SGreg Roach if ($wife) { 37726684e68SGreg Roach echo '<a href="' . e(route('hourglass', [ 37826684e68SGreg Roach 'xref' => $wife->xref(), 37926684e68SGreg Roach 'generations' => $generations, 38026684e68SGreg Roach 'show_spouse' => (int) $show_spouse, 38126684e68SGreg Roach 'ged' => $wife->tree()->name(), 38226684e68SGreg Roach ])) . '" class="name1">' . $wife->getFullName() . '</a>'; 38326684e68SGreg Roach } 38426684e68SGreg Roach } 38526684e68SGreg Roach 38626684e68SGreg Roach // filter out root person from children array so only siblings remain 38726684e68SGreg Roach $siblings = array_filter($family->getChildren(), function (Individual $x) use ($individual): bool { 38826684e68SGreg Roach return $x !== $individual; 38926684e68SGreg Roach }); 39026684e68SGreg Roach $count_siblings = count($siblings); 39126684e68SGreg Roach if ($count_siblings > 0) { 39226684e68SGreg Roach echo '<span class="name1">'; 39326684e68SGreg Roach echo $count_siblings > 1 ? I18N::translate('Siblings') : I18N::translate('Sibling'); 39426684e68SGreg Roach echo '</span>'; 39526684e68SGreg Roach foreach ($siblings as $child) { 39626684e68SGreg Roach echo '<a href="' . e(route('hourglass', [ 39726684e68SGreg Roach 'xref' => $child->xref(), 39826684e68SGreg Roach 'generations' => $generations, 39926684e68SGreg Roach 'show_spouse' => (int) $show_spouse, 40026684e68SGreg Roach 'ged' => $child->tree()->name(), 40126684e68SGreg Roach ])) . '" class="name1">' . $child->getFullName() . '</a>'; 40226684e68SGreg Roach } 40326684e68SGreg Roach } 40426684e68SGreg Roach } 40526684e68SGreg Roach echo '</td></tr></table>'; 40626684e68SGreg Roach echo '</div>'; 40726684e68SGreg Roach echo '</div>'; 40826684e68SGreg Roach } 40926684e68SGreg Roach echo '</td></tr></table>'; 41026684e68SGreg Roach } 41126684e68SGreg Roach 41226684e68SGreg Roach /** 41326684e68SGreg Roach * Prints pedigree of the person passed in. Which is the descendancy 41426684e68SGreg Roach * 41526684e68SGreg Roach * @param Individual $individual Show the pedigree of this individual 41626684e68SGreg Roach * @param int $generation Current generation number 41726684e68SGreg Roach * @param int $generations Show this number of generations 41826684e68SGreg Roach * @param bool $show_spouse 41926684e68SGreg Roach * 42026684e68SGreg Roach * @return void 42126684e68SGreg Roach */ 42226684e68SGreg Roach private function printPersonPedigree(Individual $individual, int $generation, int $generations, bool $show_spouse) 42326684e68SGreg Roach { 42426684e68SGreg Roach if ($generation >= $generations) { 42526684e68SGreg Roach return; 42626684e68SGreg Roach } 42726684e68SGreg Roach 42826684e68SGreg Roach // handle pedigree n generations lines 42926684e68SGreg Roach $genoffset = $generations; 43026684e68SGreg Roach 43126684e68SGreg Roach $family = $individual->getPrimaryChildFamily(); 43226684e68SGreg Roach 43326684e68SGreg Roach if ($family === null) { 43426684e68SGreg Roach // Prints empty table columns for children w/o parents up to the max generation 43526684e68SGreg Roach // This allows vertical line spacing to be consistent 43626684e68SGreg Roach echo '<table><tr><td> ' . Theme::theme()->individualBoxEmpty() . '</td>'; 43726684e68SGreg Roach echo '<td> '; 43826684e68SGreg Roach // Recursively get the father’s family 43926684e68SGreg Roach $this->printPersonPedigree($individual, $generation + 1, $generations, $show_spouse); 44026684e68SGreg Roach echo '</td></tr>'; 44126684e68SGreg Roach echo '<tr><td> ' . Theme::theme()->individualBoxEmpty() . '</td>'; 44226684e68SGreg Roach echo '<td> '; 44326684e68SGreg Roach // Recursively get the mother’s family 44426684e68SGreg Roach $this->printPersonPedigree($individual, $generation + 1, $generations, $show_spouse); 44526684e68SGreg Roach echo '</td><td> </tr></table>'; 44626684e68SGreg Roach } else { 44726684e68SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" class="hourglassChart">'; 44826684e68SGreg Roach echo '<tr>'; 44926684e68SGreg Roach echo '<td style="vertical-align:bottom"><img alt="" role="presnentation" class="line3 pvline" src="' . Theme::theme()->parameter('image-vline') . '" width="3"></td>'; 45026684e68SGreg Roach echo '<td> <img alt="" role="presentation" class="lineh2" src="' . Theme::theme()->parameter('image-hline') . '" width="7" height="3"></td>'; 45126684e68SGreg Roach echo '<td class="myCharts"> '; 45226684e68SGreg Roach //-- print the father box 45326684e68SGreg Roach echo FunctionsPrint::printPedigreePerson($family->getHusband()); 45426684e68SGreg Roach echo '</td>'; 45526684e68SGreg Roach if ($family->getHusband()) { 45626684e68SGreg Roach $ARID = $family->getHusband()->xref(); 45726684e68SGreg Roach echo '<td id="td_' . e($ARID) . '">'; 45826684e68SGreg Roach 45926684e68SGreg Roach if ($generation == $generations - 1 && $family->getHusband()->getChildFamilies()) { 46026684e68SGreg Roach echo FontAwesome::linkIcon('arrow-end', I18N::translate('Parents'), [ 46126684e68SGreg Roach 'href' => '#', 46226684e68SGreg Roach 'data-route' => 'Ancestors', 46326684e68SGreg Roach 'data-xref' => $ARID, 46426684e68SGreg Roach 'data-spouses' => (int) $show_spouse, 46526684e68SGreg Roach 'data-tree' => $family->getHusband()->tree()->name(), 46626684e68SGreg Roach ]); 46726684e68SGreg Roach } 46826684e68SGreg Roach 46926684e68SGreg Roach $this->printPersonPedigree($family->getHusband(), $generation + 1, $generations, $show_spouse); 47026684e68SGreg Roach echo '</td>'; 47126684e68SGreg Roach } else { 47226684e68SGreg Roach echo '<td> '; 47326684e68SGreg Roach if ($generation < $genoffset - 1) { 47426684e68SGreg Roach echo '<table>'; 47526684e68SGreg Roach for ($i = $generation; $i < ((2 ** (($genoffset - 1) - $generation)) / 2) + 2; $i++) { 47626684e68SGreg Roach echo Theme::theme()->individualBoxEmpty(); 47726684e68SGreg Roach echo '</tr>'; 47826684e68SGreg Roach echo Theme::theme()->individualBoxEmpty(); 47926684e68SGreg Roach echo '</tr>'; 48026684e68SGreg Roach } 48126684e68SGreg Roach echo '</table>'; 48226684e68SGreg Roach } 48326684e68SGreg Roach } 48426684e68SGreg Roach echo 48526684e68SGreg Roach '</tr><tr>', 48626684e68SGreg Roach '<td style="vertical-align:top"><img alt="" role="presentation" class="pvline" src="' . Theme::theme()->parameter('image-vline') . '" width="3"></td>', 48726684e68SGreg Roach '<td> <img alt="" role="presentation" class="lineh3" src="' . Theme::theme()->parameter('image-hline') . '" width="7" height="3"></td>', 48826684e68SGreg Roach '<td class="myCharts"> '; 48926684e68SGreg Roach 49026684e68SGreg Roach echo FunctionsPrint::printPedigreePerson($family->getWife()); 49126684e68SGreg Roach echo '</td>'; 49226684e68SGreg Roach if ($family->getWife()) { 49326684e68SGreg Roach $ARID = $family->getWife()->xref(); 49426684e68SGreg Roach echo '<td id="td_' . e($ARID) . '">'; 49526684e68SGreg Roach 49626684e68SGreg Roach if ($generation == $generations - 1 && $family->getWife()->getChildFamilies()) { 49726684e68SGreg Roach echo FontAwesome::linkIcon('arrow-end', I18N::translate('Parents'), [ 49826684e68SGreg Roach 'href' => '#', 49926684e68SGreg Roach 'data-route' => 'Ancestors', 50026684e68SGreg Roach 'data-xref' => $ARID, 50126684e68SGreg Roach 'data-spouses' => (int) $show_spouse, 50226684e68SGreg Roach 'data-tree' => $family->getWife()->tree()->name(), 50326684e68SGreg Roach ]); 50426684e68SGreg Roach } 50526684e68SGreg Roach 50626684e68SGreg Roach $this->printPersonPedigree($family->getWife(), $generation + 1, $generations, $show_spouse); 50726684e68SGreg Roach echo '</td>'; 50826684e68SGreg Roach } 50926684e68SGreg Roach echo '</tr></table>'; 51026684e68SGreg Roach } 511e6562982SGreg Roach } 512168ff6f3Sric2016} 513