xref: /webtrees/app/Statistics/Google/ChartAge.php (revision 8add1155cb77caede54752196ff44696d1346431)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2018 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16declare(strict_types=1);
17
18namespace Fisharebest\Webtrees\Statistics\Google;
19
20use Fisharebest\Webtrees\I18N;
21use Fisharebest\Webtrees\Statistics\AbstractGoogle;
22use Fisharebest\Webtrees\Statistics\Helper\Century;
23use Fisharebest\Webtrees\Tree;
24
25/**
26 *
27 */
28class ChartAge extends AbstractGoogle
29{
30    /**
31     * @var Tree
32     */
33    private $tree;
34
35    /**
36     * @var Century
37     */
38    private $centuryHelper;
39
40    /**
41     * Constructor.
42     *
43     * @param Tree $tree
44     */
45    public function __construct(Tree $tree)
46    {
47        $this->tree          = $tree;
48        $this->centuryHelper = new Century();
49    }
50
51    /**
52     * Returns the related database records.
53     *
54     * @return \stdClass[]
55     */
56    private function queryRecords(): array
57    {
58        return $this->runSql(
59            'SELECT'
60            . ' ROUND(AVG(death.d_julianday2-birth.d_julianday1)/365.25,1) AS age,'
61            . ' FLOOR(death.d_year/100+1) AS century,'
62            . ' i_sex AS sex'
63            . ' FROM'
64            . ' `##dates` AS death,'
65            . ' `##dates` AS birth,'
66            . ' `##individuals` AS indi'
67            . ' WHERE'
68            . ' indi.i_id=birth.d_gid AND'
69            . ' birth.d_gid=death.d_gid AND'
70            . ' death.d_file=' . $this->tree->id() . ' AND'
71            . ' birth.d_file=death.d_file AND'
72            . ' birth.d_file=indi.i_file AND'
73            . " birth.d_fact='BIRT' AND"
74            . " death.d_fact='DEAT' AND"
75            . ' birth.d_julianday1<>0 AND'
76            . " birth.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND"
77            . " death.d_type IN ('@#DGREGORIAN@', '@#DJULIAN@') AND"
78            . ' death.d_julianday1>birth.d_julianday2'
79            . ' GROUP BY century, sex ORDER BY century, sex'
80        );
81    }
82
83    /**
84     * General query on ages.
85     *
86     * @param string $size
87     *
88     * @return string
89     */
90    public function chartAge(string $size = '230x250'): string
91    {
92        $sizes = explode('x', $size);
93        $rows  = $this->queryRecords();
94
95        if (empty($rows)) {
96            return '';
97        }
98
99        $chxl    = '0:|';
100        $countsm = '';
101        $countsf = '';
102        $countsa = '';
103        $out     = [];
104
105        foreach ($rows as $values) {
106            $out[(int) $values->century][$values->sex] = $values->age;
107        }
108
109        foreach ($out as $century => $values) {
110            if ($sizes[0] < 980) {
111                $sizes[0] += 50;
112            }
113            $chxl .= $this->centuryHelper->centuryName($century) . '|';
114
115            $female_age  = $values['F'] ?? 0;
116            $male_age    = $values['M'] ?? 0;
117            $average_age = $female_age + $male_age;
118
119            if ($female_age > 0 && $male_age > 0) {
120                $average_age /= 2.0;
121            }
122
123            $countsf .= $female_age . ',';
124            $countsm .= $male_age . ',';
125            $countsa .= $average_age . ',';
126        }
127
128        $countsm = substr($countsm, 0, -1);
129        $countsf = substr($countsf, 0, -1);
130        $countsa = substr($countsa, 0, -1);
131        $chd     = 't2:' . $countsm . '|' . $countsf . '|' . $countsa;
132        $decades = '';
133
134        for ($i = 0; $i <= 100; $i += 10) {
135            $decades .= '|' . I18N::number($i);
136        }
137
138        $chxl  .= '1:||' . I18N::translate('century') . '|2:' . $decades . '|3:||' . I18N::translate('Age') . '|';
139        $title = I18N::translate('Average age related to death century');
140
141        if (\count($rows) > 6 || mb_strlen($title) < 30) {
142            $chtt = $title;
143        } else {
144            $offset  = 0;
145            $counter = [];
146
147            while ($offset = strpos($title, ' ', $offset + 1)) {
148                $counter[] = $offset;
149            }
150
151            $half = intdiv(\count($counter), 2);
152            $chtt = substr_replace($title, '|', $counter[$half], 1);
153        }
154
155        $chart_url = 'https://chart.googleapis.com/chart?cht=bvg&amp;chs=' . $sizes[0] . 'x' . $sizes[1]
156             . '&amp;chm=D,FF0000,2,0,3,1|N*f1*,000000,0,-1,11,1|N*f1*,000000,1,-1,11,1&amp;chf=bg,s,ffffff00|c,s,ffffff00&amp;chtt='
157             . rawurlencode($chtt) . '&amp;chd=' . $chd . '&amp;chco=0000FF,FFA0CB,FF0000&amp;chbh=20,3&amp;chxt=x,x,y,y&amp;chxl='
158             . rawurlencode($chxl) . '&amp;chdl='
159             . rawurlencode(I18N::translate('Males') . '|' . I18N::translate('Females') . '|' . I18N::translate('Average age at death'));
160
161        return view(
162            'statistics/other/chart-google',
163            [
164                'chart_title' => I18N::translate('Average age related to death century'),
165                'chart_url'   => $chart_url,
166                'sizes'       => $sizes,
167            ]
168        );
169    }
170}
171