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 20389266c0SGreg Roachuse Fisharebest\Webtrees\Auth; 21e5a6b4d4SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 22389266c0SGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrint; 23168ff6f3Sric2016use Fisharebest\Webtrees\I18N; 24168ff6f3Sric2016use Fisharebest\Webtrees\Individual; 25e46b0479SScrutinizer Auto-Fixeruse Fisharebest\Webtrees\Menu; 26389266c0SGreg Roachuse Fisharebest\Webtrees\Tree; 276ccdf4f0SGreg Roachuse Psr\Http\Message\ResponseInterface; 286ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 29389266c0SGreg Roachuse stdClass; 30*f4ba05e3SGreg Roachuse function view; 31168ff6f3Sric2016 32168ff6f3Sric2016/** 33168ff6f3Sric2016 * Class FamilyBookChartModule 34168ff6f3Sric2016 */ 3537eb8894SGreg Roachclass FamilyBookChartModule extends AbstractModule implements ModuleChartInterface 36c1010edaSGreg Roach{ 3749a243cbSGreg Roach use ModuleChartTrait; 3849a243cbSGreg Roach 39389266c0SGreg Roach // Defaults 40389266c0SGreg Roach private const DEFAULT_GENERATIONS = '2'; 41389266c0SGreg Roach private const DEFAULT_DESCENDANT_GENERATIONS = '5'; 42389266c0SGreg Roach private const DEFAULT_MAXIMUM_GENERATIONS = '9'; 43389266c0SGreg Roach 44e759aebbSGreg Roach // Limits 45e759aebbSGreg Roach public const MINIMUM_GENERATIONS = 2; 46e759aebbSGreg Roach public const MAXIMUM_GENERATIONS = 10; 47e759aebbSGreg Roach 48389266c0SGreg Roach /** @var stdClass */ 49389266c0SGreg Roach private $box; 50389266c0SGreg Roach 51389266c0SGreg Roach /** @var bool */ 52389266c0SGreg Roach private $show_spouse; 53389266c0SGreg Roach 54389266c0SGreg Roach /** @var int */ 55389266c0SGreg Roach private $descent; 56389266c0SGreg Roach 57389266c0SGreg Roach /** @var int */ 58389266c0SGreg Roach private $bhalfheight; 59389266c0SGreg Roach 60389266c0SGreg Roach /** @var int */ 61389266c0SGreg Roach private $generations; 62389266c0SGreg Roach 63389266c0SGreg Roach /** @var int */ 64389266c0SGreg Roach private $dgenerations; 65389266c0SGreg Roach 66168ff6f3Sric2016 /** 670cfd6963SGreg Roach * How should this module be identified in the control panel, etc.? 68168ff6f3Sric2016 * 69168ff6f3Sric2016 * @return string 70168ff6f3Sric2016 */ 7149a243cbSGreg Roach public function title(): string 72c1010edaSGreg Roach { 73bbb76c12SGreg Roach /* I18N: Name of a module/chart */ 74bbb76c12SGreg Roach return I18N::translate('Family book'); 75168ff6f3Sric2016 } 76168ff6f3Sric2016 77168ff6f3Sric2016 /** 78168ff6f3Sric2016 * A sentence describing what this module does. 79168ff6f3Sric2016 * 80168ff6f3Sric2016 * @return string 81168ff6f3Sric2016 */ 8249a243cbSGreg Roach public function description(): string 83c1010edaSGreg Roach { 84bbb76c12SGreg Roach /* I18N: Description of the “FamilyBookChart” module */ 85bbb76c12SGreg Roach return I18N::translate('A chart of an individual’s ancestors and descendants, as a family book.'); 86168ff6f3Sric2016 } 87168ff6f3Sric2016 88168ff6f3Sric2016 /** 89377a2979SGreg Roach * CSS class for the URL. 90377a2979SGreg Roach * 91377a2979SGreg Roach * @return string 92377a2979SGreg Roach */ 93377a2979SGreg Roach public function chartMenuClass(): string 94377a2979SGreg Roach { 95377a2979SGreg Roach return 'menu-chart-familybook'; 96377a2979SGreg Roach } 97377a2979SGreg Roach 98377a2979SGreg Roach /** 994eb71cfaSGreg Roach * Return a menu item for this chart - for use in individual boxes. 1004eb71cfaSGreg Roach * 10160bc3e3fSGreg Roach * @param Individual $individual 10260bc3e3fSGreg Roach * 1034eb71cfaSGreg Roach * @return Menu|null 1044eb71cfaSGreg Roach */ 105377a2979SGreg Roach public function chartBoxMenu(Individual $individual): ?Menu 106c1010edaSGreg Roach { 107e6562982SGreg Roach return $this->chartMenu($individual); 108e6562982SGreg Roach } 109e6562982SGreg Roach 110e6562982SGreg Roach /** 111e6562982SGreg Roach * The title for a specific instance of this chart. 112e6562982SGreg Roach * 113e6562982SGreg Roach * @param Individual $individual 114e6562982SGreg Roach * 115e6562982SGreg Roach * @return string 116e6562982SGreg Roach */ 117e6562982SGreg Roach public function chartTitle(Individual $individual): string 118e6562982SGreg Roach { 119e6562982SGreg Roach /* I18N: %s is an individual’s name */ 12039ca88baSGreg Roach return I18N::translate('Family book of %s', $individual->fullName()); 121e6562982SGreg Roach } 122e6562982SGreg Roach 123e6562982SGreg Roach /** 124389266c0SGreg Roach * A form to request the chart parameters. 125389266c0SGreg Roach * 1266ccdf4f0SGreg Roach * @param ServerRequestInterface $request 127389266c0SGreg Roach * @param Tree $tree 128e5a6b4d4SGreg Roach * @param UserInterface $user 129389266c0SGreg Roach * 1306ccdf4f0SGreg Roach * @return ResponseInterface 131389266c0SGreg Roach */ 1326ccdf4f0SGreg Roach public function getChartAction(ServerRequestInterface $request, Tree $tree, UserInterface $user): ResponseInterface 133389266c0SGreg Roach { 1349b5537c3SGreg Roach $ajax = (bool) $request->get('ajax'); 135389266c0SGreg Roach $xref = $request->get('xref', ''); 136389266c0SGreg Roach $individual = Individual::getInstance($xref, $tree); 137389266c0SGreg Roach 138389266c0SGreg Roach Auth::checkIndividualAccess($individual); 1399867b2f0SGreg Roach Auth::checkComponentAccess($this, 'chart', $tree, $user); 140389266c0SGreg Roach 141389266c0SGreg Roach $show_spouse = (bool) $request->get('show_spouse'); 142e759aebbSGreg Roach $generations = (int) $request->get('generations', self::DEFAULT_GENERATIONS); 143e759aebbSGreg Roach $generations = min($generations, self::MAXIMUM_GENERATIONS); 144e759aebbSGreg Roach $generations = max($generations, self::MINIMUM_GENERATIONS); 145389266c0SGreg Roach 146389266c0SGreg Roach // Generations of ancestors/descendants in each mini-tree. 147389266c0SGreg Roach $book_size = (int) $request->get('book_size', 2); 148389266c0SGreg Roach $book_size = min($book_size, 5); 149389266c0SGreg Roach $book_size = max($book_size, 2); 150389266c0SGreg Roach 1519b5537c3SGreg Roach if ($ajax) { 152389266c0SGreg Roach return $this->chart($individual, $generations, $book_size, $show_spouse); 153389266c0SGreg Roach } 154389266c0SGreg Roach 155389266c0SGreg Roach $ajax_url = $this->chartUrl($individual, [ 1569b5537c3SGreg Roach 'ajax' => true, 157389266c0SGreg Roach 'book_size' => $book_size, 158389266c0SGreg Roach 'generations' => $generations, 159e5a6b4d4SGreg Roach 'show_spouse' => $show_spouse, 160389266c0SGreg Roach ]); 161389266c0SGreg Roach 1629b5537c3SGreg Roach return $this->viewResponse('modules/family-book-chart/page', [ 163389266c0SGreg Roach 'ajax_url' => $ajax_url, 164389266c0SGreg Roach 'book_size' => $book_size, 165389266c0SGreg Roach 'generations' => $generations, 166389266c0SGreg Roach 'individual' => $individual, 167e759aebbSGreg Roach 'maximum_generations' => self::MAXIMUM_GENERATIONS, 168e759aebbSGreg Roach 'minimum_generations' => self::MINIMUM_GENERATIONS, 16926684e68SGreg Roach 'module_name' => $this->name(), 170389266c0SGreg Roach 'show_spouse' => $show_spouse, 171389266c0SGreg Roach 'title' => $this->chartTitle($individual), 172389266c0SGreg Roach ]); 173389266c0SGreg Roach } 174389266c0SGreg Roach 175389266c0SGreg Roach /** 176389266c0SGreg Roach * @param Individual $individual 177389266c0SGreg Roach * @param int $generations 178389266c0SGreg Roach * @param int $book_size 179389266c0SGreg Roach * @param bool $show_spouse 180389266c0SGreg Roach * 1816ccdf4f0SGreg Roach * @return ResponseInterface 182389266c0SGreg Roach */ 1836ccdf4f0SGreg Roach public function chart(Individual $individual, int $generations, int $book_size, bool $show_spouse): ResponseInterface 184389266c0SGreg Roach { 185389266c0SGreg Roach $this->box = (object) [ 186cab242e7SGreg Roach 'width' => app(ModuleThemeInterface::class)->parameter('chart-box-x'), 187cab242e7SGreg Roach 'height' => app(ModuleThemeInterface::class)->parameter('chart-box-y'), 188389266c0SGreg Roach ]; 189389266c0SGreg Roach 190389266c0SGreg Roach $this->show_spouse = $show_spouse; 191389266c0SGreg Roach $this->descent = $generations; 192389266c0SGreg Roach $this->generations = $book_size; 193389266c0SGreg Roach 194389266c0SGreg Roach $this->bhalfheight = $this->box->height / 2; 195389266c0SGreg Roach $this->dgenerations = $this->maxDescendencyGenerations($individual, 0); 196389266c0SGreg Roach 197389266c0SGreg Roach if ($this->dgenerations < 1) { 198389266c0SGreg Roach $this->dgenerations = 1; 199389266c0SGreg Roach } 200389266c0SGreg Roach 201389266c0SGreg Roach // @TODO - this is just a wrapper around the old code. 202389266c0SGreg Roach ob_start(); 203389266c0SGreg Roach $this->printFamilyBook($individual, $generations); 204389266c0SGreg Roach $html = ob_get_clean(); 205389266c0SGreg Roach 2066ccdf4f0SGreg Roach return response($html); 207389266c0SGreg Roach } 208389266c0SGreg Roach 209389266c0SGreg Roach /** 210389266c0SGreg Roach * Prints descendency of passed in person 211389266c0SGreg Roach * 212389266c0SGreg Roach * @param int $generation 213389266c0SGreg Roach * @param Individual|null $person 214389266c0SGreg Roach * 215389266c0SGreg Roach * @return float 216389266c0SGreg Roach */ 217389266c0SGreg Roach private function printDescendency($generation, Individual $person = null): float 218389266c0SGreg Roach { 219389266c0SGreg Roach if ($generation > $this->dgenerations) { 220389266c0SGreg Roach return 0; 221389266c0SGreg Roach } 222389266c0SGreg Roach 223389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 224389266c0SGreg Roach $numkids = 0.0; 225389266c0SGreg Roach 226389266c0SGreg Roach // Load children 227389266c0SGreg Roach $children = []; 228389266c0SGreg Roach if ($person instanceof Individual) { 229389266c0SGreg Roach // Count is position from center to left, dgenerations is number of generations 230389266c0SGreg Roach if ($generation < $this->dgenerations) { 231389266c0SGreg Roach // All children, from all partners 23239ca88baSGreg Roach foreach ($person->spouseFamilies() as $family) { 23339ca88baSGreg Roach foreach ($family->children() as $child) { 234389266c0SGreg Roach $children[] = $child; 235389266c0SGreg Roach } 236389266c0SGreg Roach } 237389266c0SGreg Roach } 238389266c0SGreg Roach } 239389266c0SGreg Roach if ($generation < $this->dgenerations) { 240389266c0SGreg Roach if (!empty($children)) { 241389266c0SGreg Roach // real people 242389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 243389266c0SGreg Roach foreach ($children as $i => $child) { 244389266c0SGreg Roach echo '<tr><td>'; 245389266c0SGreg Roach $kids = $this->printDescendency($generation + 1, $child); 246389266c0SGreg Roach $numkids += $kids; 247389266c0SGreg Roach echo '</td>'; 248389266c0SGreg Roach // Print the lines 249389266c0SGreg Roach if (count($children) > 1) { 250389266c0SGreg Roach if ($i === 0) { 251389266c0SGreg Roach // Adjust for the first column on left 252e364afe4SGreg Roach $h = round((($this->box->height * $kids) + 8) / 2); // Assumes border = 1 and padding = 3 253389266c0SGreg Roach // Adjust for other vertical columns 254389266c0SGreg Roach if ($kids > 1) { 255389266c0SGreg Roach $h = ($kids - 1) * 4 + $h; 256389266c0SGreg Roach } 257389266c0SGreg Roach echo '<td class="align-bottom">', 258e837ff07SGreg Roach '<img id="vline_', $child->xref(), '" src="', e(asset('css/images/vline.png')), '" width="3" height="', $h - 4, '"></td>'; 259389266c0SGreg Roach } elseif ($i === count($children) - 1) { 260389266c0SGreg Roach // Adjust for the first column on left 261e364afe4SGreg Roach $h = round((($this->box->height * $kids) + 8) / 2); 262389266c0SGreg Roach // Adjust for other vertical columns 263389266c0SGreg Roach if ($kids > 1) { 264389266c0SGreg Roach $h = ($kids - 1) * 4 + $h; 265389266c0SGreg Roach } 266389266c0SGreg Roach echo '<td class="align-top">', 267e837ff07SGreg Roach '<img class="bvertline" width="3" id="vline_', $child->xref(), '" src="', e(asset('css/images/vline.png')), '" height="', $h - 2, '"></td>'; 268389266c0SGreg Roach } else { 269e837ff07SGreg Roach echo '<td class="align-bottomm"style="background: url(', e(asset('css/images/vline.png')), ');">', 270e837ff07SGreg Roach '<img class="spacer" width="3" src="', e(asset('css/images/spacer.png')), '"></td>'; 271389266c0SGreg Roach } 272389266c0SGreg Roach } 273389266c0SGreg Roach echo '</tr>'; 274389266c0SGreg Roach } 275389266c0SGreg Roach echo '</table>'; 276389266c0SGreg Roach } else { 277389266c0SGreg Roach // Hidden/empty boxes - to preserve the layout 278389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 279389266c0SGreg Roach $numkids += $this->printDescendency($generation + 1, null); 280389266c0SGreg Roach echo '</td></tr></table>'; 281389266c0SGreg Roach } 282389266c0SGreg Roach echo '</td>'; 283389266c0SGreg Roach echo '<td>'; 284389266c0SGreg Roach } 285389266c0SGreg Roach 286389266c0SGreg Roach if ($numkids === 0.0) { 287389266c0SGreg Roach $numkids = 1; 288389266c0SGreg Roach } 289389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td>'; 290389266c0SGreg Roach if ($person instanceof Individual) { 291*f4ba05e3SGreg Roach echo view('chart-box', ['individual' => $person]); 292389266c0SGreg Roach echo '</td><td>', 293e837ff07SGreg Roach '<img class="linef1" src="', e(asset('css/images/hline.png')), '" width="8" height="3">'; 294389266c0SGreg Roach } else { 295389266c0SGreg Roach echo '<div style="width:', $this->box->width + 19, 'px; height:', $this->box->height + 8, 'px;"></div>', 296389266c0SGreg Roach '</td><td>'; 297389266c0SGreg Roach } 298389266c0SGreg Roach 299389266c0SGreg Roach // Print the spouse 300389266c0SGreg Roach if ($generation === 1 && $person instanceof Individual) { 301389266c0SGreg Roach if ($this->show_spouse) { 30239ca88baSGreg Roach foreach ($person->spouseFamilies() as $family) { 30339ca88baSGreg Roach $spouse = $family->spouse($person); 304389266c0SGreg Roach echo '</td></tr><tr><td>'; 305*f4ba05e3SGreg Roach echo view('chart-box', ['individual' => $spouse]); 306389266c0SGreg Roach $numkids += 0.95; 307389266c0SGreg Roach echo '</td><td>'; 308389266c0SGreg Roach } 309389266c0SGreg Roach } 310389266c0SGreg Roach } 311389266c0SGreg Roach echo '</td></tr></table>'; 312389266c0SGreg Roach echo '</td></tr>'; 313389266c0SGreg Roach echo '</table>'; 314389266c0SGreg Roach 315389266c0SGreg Roach return $numkids; 316389266c0SGreg Roach } 317389266c0SGreg Roach 318389266c0SGreg Roach /** 319389266c0SGreg Roach * Prints pedigree of the person passed in 320389266c0SGreg Roach * 321389266c0SGreg Roach * @param Individual $person 322389266c0SGreg Roach * @param int $count 323389266c0SGreg Roach * 324389266c0SGreg Roach * @return void 325389266c0SGreg Roach */ 326e364afe4SGreg Roach private function printPersonPedigree($person, $count): void 327389266c0SGreg Roach { 328389266c0SGreg Roach if ($count >= $this->generations) { 329389266c0SGreg Roach return; 330389266c0SGreg Roach } 331389266c0SGreg Roach 332389266c0SGreg Roach $genoffset = $this->generations; // handle pedigree n generations lines 333389266c0SGreg Roach //-- calculate how tall the lines should be 334e364afe4SGreg Roach $lh = $this->bhalfheight * (2 ** ($genoffset - $count - 1)); 335389266c0SGreg Roach // 336389266c0SGreg Roach //Prints empty table columns for children w/o parents up to the max generation 337389266c0SGreg Roach //This allows vertical line spacing to be consistent 3383b092cb5SGreg Roach if ($person->childFamilies()->isEmpty()) { 339389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 340516bb6deSGreg Roach echo '<div class="wt-chart-box"></div>'; 341389266c0SGreg Roach 342389266c0SGreg Roach //-- recursively get the father’s family 343389266c0SGreg Roach $this->printPersonPedigree($person, $count + 1); 344389266c0SGreg Roach echo '</td><td></tr>'; 345516bb6deSGreg Roach echo '<div class="wt-chart-box"></div>'; 346389266c0SGreg Roach 347389266c0SGreg Roach //-- recursively get the mother’s family 348389266c0SGreg Roach $this->printPersonPedigree($person, $count + 1); 349389266c0SGreg Roach echo '</td><td></tr></table>'; 350389266c0SGreg Roach } 351389266c0SGreg Roach 352389266c0SGreg Roach // Empty box section done, now for regular pedigree 35339ca88baSGreg Roach foreach ($person->childFamilies() as $family) { 354389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-bottom">'; 355389266c0SGreg Roach // Determine line height for two or more spouces 356389266c0SGreg Roach // And then adjust the vertical line for the root person only 357389266c0SGreg Roach $famcount = 0; 358389266c0SGreg Roach if ($this->show_spouse) { 359389266c0SGreg Roach // count number of spouses 3603b092cb5SGreg Roach $famcount += $person->spouseFamilies()->count(); 361389266c0SGreg Roach } 362389266c0SGreg Roach $savlh = $lh; // Save current line height 363389266c0SGreg Roach if ($count == 1 && $genoffset <= $famcount) { 364389266c0SGreg Roach $linefactor = 0; 365389266c0SGreg Roach // genoffset of 2 needs no adjustment 366389266c0SGreg Roach if ($genoffset > 2) { 367389266c0SGreg Roach $tblheight = $this->box->height + 8; 368389266c0SGreg Roach if ($genoffset == 3) { 369389266c0SGreg Roach if ($famcount == 3) { 370389266c0SGreg Roach $linefactor = $tblheight / 2; 371389266c0SGreg Roach } elseif ($famcount > 3) { 372389266c0SGreg Roach $linefactor = $tblheight; 373389266c0SGreg Roach } 374389266c0SGreg Roach } 375389266c0SGreg Roach if ($genoffset == 4) { 376389266c0SGreg Roach if ($famcount == 4) { 377389266c0SGreg Roach $linefactor = $tblheight; 378389266c0SGreg Roach } elseif ($famcount > 4) { 379389266c0SGreg Roach $linefactor = ($famcount - $genoffset) * ($tblheight * 1.5); 380389266c0SGreg Roach } 381389266c0SGreg Roach } 382389266c0SGreg Roach if ($genoffset == 5) { 383389266c0SGreg Roach if ($famcount == 5) { 384389266c0SGreg Roach $linefactor = 0; 385389266c0SGreg Roach } elseif ($famcount > 5) { 386389266c0SGreg Roach $linefactor = $tblheight * ($famcount - $genoffset); 387389266c0SGreg Roach } 388389266c0SGreg Roach } 389389266c0SGreg Roach } 390e364afe4SGreg Roach $lh = (($famcount - 1) * $this->box->height - $linefactor); 391389266c0SGreg Roach if ($genoffset > 5) { 392389266c0SGreg Roach $lh = $savlh; 393389266c0SGreg Roach } 394389266c0SGreg Roach } 395e837ff07SGreg Roach echo '<img class="line3 pvline" src="', e(asset('css/images/vline.png')), '" width="3" height="', $lh, '"></td>', 396389266c0SGreg Roach '<td>', 397e837ff07SGreg Roach '<img class="linef2" src="', e(asset('css/images/hline.png')), '" height="3"></td>', 398389266c0SGreg Roach '<td>'; 399389266c0SGreg Roach $lh = $savlh; // restore original line height 400389266c0SGreg Roach //-- print the father box 401*f4ba05e3SGreg Roach echo view('chart-box', ['individual' => $family->husband()]); 402389266c0SGreg Roach echo '</td>'; 40339ca88baSGreg Roach if ($family->husband()) { 404389266c0SGreg Roach echo '<td>'; 405389266c0SGreg Roach //-- recursively get the father’s family 40639ca88baSGreg Roach $this->printPersonPedigree($family->husband(), $count + 1); 407389266c0SGreg Roach echo '</td>'; 408389266c0SGreg Roach } else { 409389266c0SGreg Roach echo '<td>'; 410389266c0SGreg Roach if ($genoffset > $count) { 411389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 412e364afe4SGreg Roach for ($i = 1; $i < ((2 ** ($genoffset - $count)) / 2); $i++) { 413516bb6deSGreg Roach echo '<div class="wt-chart-box"></div>'; 414389266c0SGreg Roach echo '</tr>'; 415389266c0SGreg Roach } 416389266c0SGreg Roach echo '</table>'; 417389266c0SGreg Roach } 418389266c0SGreg Roach } 419389266c0SGreg Roach echo '</tr><tr>', 420e837ff07SGreg Roach '<td class="align-top"><img class="pvline" alt="" role="presentation" src="', e(asset('css/images/vline.png')), '" width="3" height="', $lh, '"></td>', 421e837ff07SGreg Roach '<td><img class="linef3" alt="" role="presentation" src="', e(asset('css/images/hline.png')), '" height="3"></td>', 422389266c0SGreg Roach '<td>'; 423389266c0SGreg Roach //-- print the mother box 424*f4ba05e3SGreg Roach echo view('chart-box', ['individual' => $family->wife()]); 425389266c0SGreg Roach echo '</td>'; 42639ca88baSGreg Roach if ($family->wife()) { 427389266c0SGreg Roach echo '<td>'; 428389266c0SGreg Roach //-- recursively print the mother’s family 42939ca88baSGreg Roach $this->printPersonPedigree($family->wife(), $count + 1); 430389266c0SGreg Roach echo '</td>'; 431389266c0SGreg Roach } else { 432389266c0SGreg Roach echo '<td>'; 433389266c0SGreg Roach if ($count < $genoffset - 1) { 434389266c0SGreg Roach echo '<table cellspacing="0" cellpadding="0" border="0" >'; 435e364afe4SGreg Roach for ($i = 1; $i < ((2 ** (($genoffset - 1) - $count)) / 2) + 1; $i++) { 436516bb6deSGreg Roach echo '<div class="wt-chart-box"></div>'; 437389266c0SGreg Roach echo '</tr>'; 438516bb6deSGreg Roach echo '<div class="wt-chart-box"></div>'; 439389266c0SGreg Roach echo '</tr>'; 440389266c0SGreg Roach } 441389266c0SGreg Roach echo '</table>'; 442389266c0SGreg Roach } 443389266c0SGreg Roach } 444389266c0SGreg Roach echo '</tr>', 445389266c0SGreg Roach '</table>'; 446389266c0SGreg Roach break; 447389266c0SGreg Roach } 448389266c0SGreg Roach } 449389266c0SGreg Roach 450389266c0SGreg Roach /** 451389266c0SGreg Roach * Calculates number of generations a person has 452e6562982SGreg Roach * 453e6562982SGreg Roach * @param Individual $individual 454389266c0SGreg Roach * @param int $depth 455e6562982SGreg Roach * 456389266c0SGreg Roach * @return int 457e6562982SGreg Roach */ 458389266c0SGreg Roach private function maxDescendencyGenerations(Individual $individual, $depth): int 459e6562982SGreg Roach { 460389266c0SGreg Roach if ($depth > $this->generations) { 461389266c0SGreg Roach return $depth; 462389266c0SGreg Roach } 463389266c0SGreg Roach $maxdc = $depth; 46439ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 46539ca88baSGreg Roach foreach ($family->children() as $child) { 466389266c0SGreg Roach $dc = $this->maxDescendencyGenerations($child, $depth + 1); 467389266c0SGreg Roach if ($dc >= $this->generations) { 468389266c0SGreg Roach return $dc; 469389266c0SGreg Roach } 470389266c0SGreg Roach if ($dc > $maxdc) { 471389266c0SGreg Roach $maxdc = $dc; 472389266c0SGreg Roach } 473389266c0SGreg Roach } 474389266c0SGreg Roach } 475389266c0SGreg Roach $maxdc++; 476389266c0SGreg Roach if ($maxdc == 1) { 477389266c0SGreg Roach $maxdc++; 478389266c0SGreg Roach } 479389266c0SGreg Roach 480389266c0SGreg Roach return $maxdc; 481389266c0SGreg Roach } 482389266c0SGreg Roach 483389266c0SGreg Roach /** 484389266c0SGreg Roach * Print a “Family Book” for an individual 485389266c0SGreg Roach * 486389266c0SGreg Roach * @param Individual $person 487389266c0SGreg Roach * @param int $descent_steps 488389266c0SGreg Roach * 489389266c0SGreg Roach * @return void 490389266c0SGreg Roach */ 491e364afe4SGreg Roach private function printFamilyBook(Individual $person, $descent_steps): void 492389266c0SGreg Roach { 493389266c0SGreg Roach if ($descent_steps == 0) { 494389266c0SGreg Roach return; 495389266c0SGreg Roach } 496389266c0SGreg Roach 497389266c0SGreg Roach echo 498389266c0SGreg Roach '<h3>', 499389266c0SGreg Roach /* I18N: %s is an individual’s name */ 50039ca88baSGreg Roach I18N::translate('Family of %s', $person->fullName()), 501389266c0SGreg Roach '</h3>', 502389266c0SGreg Roach '<table cellspacing="0" cellpadding="0" border="0" ><tr><td class="align-middle">'; 503389266c0SGreg Roach $this->dgenerations = $this->generations; 504389266c0SGreg Roach $this->printDescendency(1, $person); 505389266c0SGreg Roach echo '</td><td class="align-middle">'; 506389266c0SGreg Roach $this->printPersonPedigree($person, 1); 507242a7862SGreg Roach echo '</td></tr></table><br><br><hr class="wt-family-break"><br><br>'; 50839ca88baSGreg Roach foreach ($person->spouseFamilies() as $family) { 50939ca88baSGreg Roach foreach ($family->children() as $child) { 510389266c0SGreg Roach $this->printFamilyBook($child, $descent_steps - 1); 511389266c0SGreg Roach } 512389266c0SGreg Roach } 513e6562982SGreg Roach } 514168ff6f3Sric2016} 515