These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * webtrees: online genealogy |
||
4 | * Copyright (C) 2016 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 | */ |
||
16 | namespace Fisharebest\Webtrees; |
||
17 | |||
18 | use Fisharebest\Webtrees\Controller\TimelineController; |
||
19 | use Fisharebest\Webtrees\Functions\Functions; |
||
20 | use Fisharebest\Webtrees\Functions\FunctionsPrint; |
||
21 | |||
22 | global $WT_TREE; |
||
0 ignored issues
–
show
|
|||
23 | |||
24 | $basexoffset = 0; |
||
25 | $baseyoffset = 0; |
||
26 | |||
27 | define('WT_SCRIPT_NAME', 'timeline.php'); |
||
28 | require './includes/session.php'; |
||
29 | |||
30 | $controller = new TimelineController; |
||
31 | $controller |
||
32 | ->restrictAccess(in_array('timeline_chart', Module::getActiveCharts($WT_TREE))) |
||
33 | ->pageHeader() |
||
34 | ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL) |
||
35 | ->addInlineJavascript('autocomplete();'); |
||
36 | |||
37 | ?> |
||
38 | <script> |
||
39 | var internet_explorer = typeof(document.all) !== 'undefined'; // mouse handling is different in IE |
||
40 | var ob = null; |
||
41 | var Y = 0; |
||
42 | var X = 0; |
||
43 | var oldx = 0; |
||
44 | var oldlinew = 0; |
||
45 | var personnum = 0; |
||
46 | var type = 0; |
||
47 | var boxmean = 0; |
||
48 | |||
49 | function ageCursorMouseDown(divbox, num) { |
||
50 | ob = divbox; |
||
51 | personnum = num; |
||
52 | type = 0; |
||
53 | X = ob.offsetLeft; |
||
54 | Y = ob.offsetTop; |
||
55 | if (internet_explorer) { |
||
56 | oldx = event.clientX + document.documentElement.scrollLeft; |
||
57 | } |
||
58 | } |
||
59 | |||
60 | function factMouseDown(divbox, num, mean) { |
||
61 | ob = divbox; |
||
62 | personnum = num; |
||
63 | boxmean = mean; |
||
64 | type = 1; |
||
65 | oldx = ob.offsetLeft; |
||
66 | if (internet_explorer) { |
||
67 | oldlinew = event.clientX + document.documentElement.scrollLeft; |
||
68 | } else { |
||
69 | oldlinew = 0; |
||
70 | } |
||
71 | } |
||
72 | |||
73 | document.onmousemove = function (e) { |
||
74 | if (ob === null) { |
||
75 | return true; |
||
76 | } |
||
77 | var tldiv = document.getElementById("timeline_chart"); |
||
78 | var newx = 0; |
||
79 | var newy = 0; |
||
80 | if (type === 0) { |
||
81 | // age boxes |
||
82 | if (internet_explorer) { |
||
83 | newy = event.clientY + document.documentElement.scrollTop - tldiv.offsetTop; |
||
84 | newx = event.clientX + document.documentElement.scrollLeft - tldiv.offsetLeft; |
||
85 | } else { |
||
86 | newy = e.pageY - tldiv.offsetTop; |
||
87 | newx = e.pageX - tldiv.offsetLeft; |
||
88 | if (oldx === 0) { |
||
89 | oldx = newx; |
||
90 | } |
||
91 | } |
||
92 | if (newy < topy - bheight / 2) { |
||
93 | newy = topy - bheight / 2; |
||
94 | } |
||
95 | if (newy > bottomy) { |
||
96 | newy = bottomy - 1; |
||
97 | } |
||
98 | ob.style.top = newy + "px"; |
||
99 | var tyear = (newy + bheight - 4 - topy + scale) / scale + baseyear; |
||
100 | var year = Math.floor(tyear); |
||
101 | var month = Math.floor(tyear * 12 - year * 12); |
||
102 | var day = Math.floor(tyear * 365 - year * 365 - month * 30); |
||
103 | var mstamp = year * 365 + month * 30 + day; |
||
104 | var bdstamp = birthyears[personnum] * 365 + birthmonths[personnum] * 30 + birthdays[personnum]; |
||
105 | var daydiff = mstamp - bdstamp; |
||
106 | var ba = 1; |
||
107 | if (daydiff < 0) { |
||
108 | ba = -1; |
||
109 | daydiff = (bdstamp - mstamp); |
||
110 | } |
||
111 | var yage = Math.floor(daydiff / 365); |
||
112 | var mage = Math.floor((daydiff - yage * 365) / 30); |
||
113 | var dage = Math.floor(daydiff - yage * 365 - mage * 30); |
||
114 | if (dage < 0) { |
||
115 | mage = mage - 1; |
||
116 | } |
||
117 | if (dage < -30) { |
||
118 | dage = 30 + dage; |
||
119 | } |
||
120 | if (mage < 0) { |
||
121 | yage = yage - 1; |
||
122 | } |
||
123 | if (mage < -11) { |
||
124 | mage = 12 + mage; |
||
125 | } |
||
126 | var yearform = document.getElementById('yearform' + personnum); |
||
127 | var ageform = document.getElementById('ageform' + personnum); |
||
128 | yearform.innerHTML = year + " " + month + " <?php echo mb_substr(I18N::translate('Month:'), 0, 1); ?> " + day + " <?php echo mb_substr(I18N::translate('Day:'), 0, 1); ?>"; |
||
129 | if (ba * yage > 1 || ba * yage < -1 || ba * yage === 0) { |
||
130 | ageform.innerHTML = (ba * yage) + " <?php echo mb_substr(I18N::translate('years'), 0, 1); ?> " + (ba * mage) + " <?php echo mb_substr(I18N::translate('Month:'), 0, 1); ?> " + (ba * dage) + " <?php echo mb_substr(I18N::translate('Day:'), 0, 1); ?>"; |
||
131 | } else { |
||
132 | ageform.innerHTML = (ba * yage) + " <?php echo mb_substr(I18N::translate('Year:'), 0, 1); ?> " + (ba * mage) + " <?php echo mb_substr(I18N::translate('Month:'), 0, 1); ?> " + (ba * dage) + " <?php echo mb_substr(I18N::translate('Day:'), 0, 1); ?>"; |
||
133 | } |
||
134 | var line = document.getElementById('ageline' + personnum); |
||
135 | var temp = newx - oldx; |
||
136 | |||
137 | var textDirection = jQuery('html').attr('dir'); |
||
138 | if (textDirection === 'rtl') { |
||
139 | temp = temp * -1; |
||
140 | } |
||
141 | line.style.width = (line.width + temp) + "px"; |
||
142 | oldx = newx; |
||
143 | return false; |
||
144 | } else { |
||
145 | // fact boxes |
||
146 | var linewidth; |
||
147 | if (internet_explorer) { |
||
148 | newy = event.clientY + document.documentElement.scrollTop - tldiv.offsetTop; |
||
149 | newx = event.clientX + document.documentElement.scrollLeft - tldiv.offsetLeft; |
||
150 | linewidth = event.clientX + document.documentElement.scrollLeft; |
||
151 | } else { |
||
152 | newy = e.pageY - tldiv.offsetTop; |
||
153 | newx = e.pageX - tldiv.offsetLeft; |
||
154 | if (oldx === 0) { |
||
155 | oldx = newx; |
||
156 | } |
||
157 | linewidth = e.pageX; |
||
158 | } |
||
159 | // get diagnal line box |
||
160 | var dbox = document.getElementById('dbox' + personnum); |
||
161 | var etopy; |
||
162 | var ebottomy; |
||
163 | // set up limits |
||
164 | if (boxmean - 175 < topy) { |
||
165 | etopy = topy; |
||
166 | } else { |
||
167 | etopy = boxmean - 175; |
||
168 | } |
||
169 | if (boxmean + 175 > bottomy) { |
||
170 | ebottomy = bottomy; |
||
171 | } else { |
||
172 | ebottomy = boxmean + 175; |
||
173 | } |
||
174 | // check if in the bounds of the limits |
||
175 | if (newy < etopy) { |
||
176 | newy = etopy; |
||
177 | } |
||
178 | if (newy > ebottomy) { |
||
179 | newy = ebottomy; |
||
180 | } |
||
181 | // calculate the change in Y position |
||
182 | var dy = newy - ob.offsetTop; |
||
183 | // check if we are above the starting point and switch the background image |
||
184 | var textDirection = jQuery('html').attr('dir'); |
||
185 | |||
186 | if (newy < boxmean) { |
||
187 | if (textDirection === 'rtl') { |
||
188 | dbox.style.backgroundImage = "url('<?php echo Theme::theme()->parameter('image-dline2'); ?>')"; |
||
189 | dbox.style.backgroundPosition = "0% 0%"; |
||
190 | } else { |
||
191 | dbox.style.backgroundImage = "url('<?php echo Theme::theme()->parameter('image-dline'); ?>')"; |
||
192 | dbox.style.backgroundPosition = "0% 100%"; |
||
193 | } |
||
194 | dy = -dy; |
||
195 | dbox.style.top = (newy + bheight / 3) + "px"; |
||
196 | } else { |
||
197 | if (textDirection === 'rtl') { |
||
198 | dbox.style.backgroundImage = "url('<?php echo Theme::theme()->parameter('image-dline'); ?>')"; |
||
199 | dbox.style.backgroundPosition = "0% 100%"; |
||
200 | } else { |
||
201 | dbox.style.backgroundImage = "url('<?php echo Theme::theme()->parameter('image-dline2'); ?>')"; |
||
202 | dbox.style.backgroundPosition = "0% 0%"; |
||
203 | } |
||
204 | |||
205 | dbox.style.top = (boxmean + bheight / 3) + "px"; |
||
206 | } |
||
207 | // the new X posistion moves the same as the y position |
||
208 | if (textDirection === 'rtl') { |
||
209 | newx = dbox.offsetRight + Math.abs(newy - boxmean); |
||
210 | } else { |
||
211 | newx = dbox.offsetLeft + Math.abs(newy - boxmean); |
||
212 | } |
||
213 | // set the X position of the box |
||
214 | if (textDirection === 'rtl') { |
||
215 | ob.style.right = newx + "px"; |
||
216 | } else { |
||
217 | ob.style.left = newx + "px"; |
||
218 | } |
||
219 | // set new top positions |
||
220 | ob.style.top = newy + "px"; |
||
221 | // get the width for the diagnal box |
||
222 | var newwidth = (ob.offsetLeft - dbox.offsetLeft); |
||
223 | // set the width |
||
224 | dbox.style.width = newwidth + "px"; |
||
225 | if (textDirection === 'rtl') { |
||
226 | dbox.style.right = (dbox.offsetRight - newwidth) + 'px'; |
||
227 | } |
||
228 | dbox.style.height = newwidth + "px"; |
||
229 | // change the line width to the change in the mouse X position |
||
230 | line = document.getElementById('boxline' + personnum); |
||
231 | if (oldlinew !== 0) { |
||
232 | line.width = line.width + (linewidth - oldlinew); |
||
233 | } |
||
234 | oldlinew = linewidth; |
||
235 | oldx = newx; |
||
236 | return false; |
||
237 | } |
||
238 | }; |
||
239 | |||
240 | document.onmouseup = function () { |
||
241 | ob = null; |
||
242 | oldx = 0; |
||
243 | } |
||
244 | |||
245 | </script> |
||
246 | <h2><?php echo I18N::translate('Timeline'); ?></h2> |
||
247 | <form name="people" action="?"> |
||
248 | <input type="hidden" name="ged" value="<?php echo $WT_TREE->getNameHtml(); ?>"> |
||
249 | <table> |
||
250 | <tr> |
||
251 | <?php |
||
252 | $i = 0; |
||
253 | $count = count($controller->people); |
||
254 | $half = $count; |
||
255 | if ($count > 5) { |
||
256 | $half = ceil($count / 2); |
||
257 | } |
||
258 | $half++; |
||
259 | foreach ($controller->people as $p => $indi) { |
||
260 | $pid = $indi->getXref(); |
||
261 | $col = $p % 6; |
||
262 | if ($i === $half) { |
||
263 | echo "</tr><tr>"; |
||
264 | } |
||
265 | $i++; |
||
266 | ?> |
||
267 | <td class="person<?php echo $col; ?>" style="padding: 5px;"> |
||
268 | <?php |
||
269 | if ($indi && $indi->canShow()) { |
||
270 | echo $indi->getSexImage('large'); |
||
271 | ?> |
||
272 | <a href="<?php echo $indi->getHtmlUrl(); ?>"> <?php echo $indi->getFullName(); ?><br> |
||
273 | <?php echo $indi->getAddName(); ?><br> |
||
274 | </a> |
||
275 | <input type="hidden" name="pids[<?php echo $p; ?>]" value="<?php echo Filter::escapeHtml($pid); ?>"> |
||
276 | <a href="timeline.php?<?php echo $controller->pidlinks; ?>&scale=<?php echo $controller->scale; ?>&remove=<?php echo $pid; ?>&ged=<?php echo $WT_TREE->getNameUrl(); ?>" > |
||
277 | <span class="details1"><?php echo I18N::translate('Remove individual'); ?></span></a> |
||
278 | <?php if (!empty($controller->birthyears[$pid])) { ?> |
||
279 | <span class="details1"><br> |
||
280 | <?php echo /* I18N: an age indicator, which can be dragged around the screen */ I18N::translate('Show an age cursor?'); ?> |
||
281 | <input type="checkbox" name="agebar<?php echo $p; ?>" value="ON" onclick="jQuery('#agebox<?php echo $p; ?>').toggle();"> |
||
282 | </span> |
||
283 | <?php } ?> |
||
284 | <br> |
||
285 | <?php |
||
286 | } else { |
||
287 | echo '<div class="error">', I18N::translate('This information is private and cannot be shown.'), '</div>'; |
||
288 | ?> |
||
289 | <input type="hidden" name="pids[<?php echo $p; ?>]" value="<?php echo Filter::escapeHtml($pid); ?>"> |
||
290 | <br> |
||
291 | <a href="timeline.php?<?php echo $controller->pidlinks; ?>&scale=<?php echo $controller->scale; ?>&remove=<?php echo $pid; ?>&ged=<?php echo $WT_TREE->getNameUrl(); ?>" > |
||
292 | <span class="details1"><?php echo I18N::translate('Remove individual'); ?></span></a> |
||
293 | <br> |
||
294 | <?php } ?> |
||
295 | </td> |
||
296 | <?php } ?> |
||
297 | <td class="list_value" style="padding: 5px;"> |
||
298 | <?php echo I18N::translate('Add another individual to the chart'), '<br>'; ?> |
||
299 | <input class="pedigree_form" data-autocomplete-type="INDI" type="text" size="5" id="newpid" name="pids[]"> |
||
300 | <?php echo FunctionsPrint::printFindIndividualLink('newpid'); ?> |
||
301 | <br> |
||
302 | <br> |
||
303 | |||
304 | <div style="text-align: center;"><input type="submit" value="<?php echo I18N::translate('Add'); ?>"></div> |
||
305 | </td> |
||
306 | <?php |
||
307 | if (count($controller->people) > 0) { |
||
308 | $scalemod = round($controller->scale * .2) + 1; |
||
309 | ?> |
||
310 | <td class="list_value" style="padding: 5px;"> |
||
311 | <a href="<?php echo WT_SCRIPT_NAME . "?" . $controller->pidlinks . "scale=" . ($controller->scale + $scalemod); ?>&ged=<?php echo $WT_TREE->getNameUrl(); ?>" class="icon-zoomin" title="<?php echo I18N::translate('Zoom in'); ?>"></a><br> |
||
312 | <a href="<?php echo WT_SCRIPT_NAME . "?" . $controller->pidlinks . "scale=" . ($controller->scale - $scalemod); ?>&ged=<?php echo $WT_TREE->getNameUrl(); ?>" class="icon-zoomout" title="<?php echo I18N::translate('Zoom out'); ?>"></a><br> |
||
313 | <input type="button" value="<?php echo I18N::translate('reset'); ?>" onclick="window.location = 'timeline.php?ged=<?php echo $WT_TREE->getNameUrl(); ?>';"> |
||
314 | </td> |
||
315 | <?php } ?> |
||
316 | </tr> |
||
317 | </table> |
||
318 | </form> |
||
319 | <br> |
||
320 | <?php |
||
321 | if (count($controller->people) > 0) { |
||
322 | ?> |
||
323 | <div id="timeline_chart"> |
||
324 | <!-- print the timeline line image --> |
||
325 | <div id="line" style="position:absolute; <?php echo I18N::direction() === 'ltr' ? 'left: ' . ($basexoffset + 22) : "right: " . ($basexoffset + 22); ?>px; top: <?php echo $baseyoffset; ?>px;"> |
||
326 | <img src="<?php echo Theme::theme()->parameter('image-vline'); ?>" width="3" height="<?php echo $baseyoffset + ($controller->topyear - $controller->baseyear) * $controller->scale; ?>" alt=""> |
||
327 | </div> |
||
328 | <!-- print divs for the grid --> |
||
329 | <div id="scale<?php echo $controller->baseyear; ?>" style="position:absolute; <?php echo I18N::direction() === 'ltr' ? "left: $basexoffset" : "right: $basexoffset"; ?>px; top: <?php echo $baseyoffset - 5; ?>px; font-size: 7pt; text-align: <?php echo I18N::direction() === 'ltr' ? 'left' : 'right'; ?>;"> |
||
330 | <?php echo $controller->baseyear . '—'; ?> |
||
331 | </div> |
||
332 | <?php |
||
333 | // at a scale of 25 or higher, show every year |
||
334 | $mod = 25 / $controller->scale; |
||
335 | if ($mod < 1) { |
||
336 | $mod = 1; |
||
337 | } |
||
338 | for ($i = $controller->baseyear + 1; $i < $controller->topyear; $i++) { |
||
339 | if ($i % $mod === 0) { |
||
340 | echo '<div id="scale' . $i . '" style="position:absolute; ' . (I18N::direction() === 'ltr' ? 'left: ' . $basexoffset : 'right: ' . $basexoffset) . 'px; top:' . ($baseyoffset + (($i - $controller->baseyear) * $controller->scale) - $controller->scale / 2) . 'px; font-size: 7pt; text-align:' . (I18N::direction() === 'ltr' ? 'left' : 'right') . ';">'; |
||
341 | echo $i . '—'; |
||
342 | echo '</div>'; |
||
343 | } |
||
344 | } |
||
345 | echo '<div id="scale' . $controller->topyear . '" style="position:absolute; ' . (I18N::direction() === 'ltr' ? 'left: ' . $basexoffset : 'right: ' . $basexoffset) . 'px; top:' . ($baseyoffset + (($controller->topyear - $controller->baseyear) * $controller->scale)) . 'px; font-size: 7pt; text-align:' . (I18N::direction() === 'ltr' ? 'left' : 'right') . ';">'; |
||
346 | echo $controller->topyear . '—'; |
||
347 | echo '</div>'; |
||
348 | Functions::sortFacts($controller->indifacts); |
||
349 | $factcount = 0; |
||
350 | foreach ($controller->indifacts as $fact) { |
||
351 | $controller->printTimeFact($fact); |
||
352 | $factcount++; |
||
353 | } |
||
354 | |||
355 | // print the age boxes |
||
356 | foreach ($controller->people as $p => $indi) { |
||
357 | $pid = $indi->getXref(); |
||
358 | $ageyoffset = $baseyoffset + ($controller->bheight * $p); |
||
359 | $col = $p % 6; |
||
360 | ?> |
||
361 | <div id="agebox<?php echo $p; ?>" style="cursor:move; position:absolute; <?php echo I18N::direction() === 'ltr' ? 'left: ' . ($basexoffset + 20) : 'right: ' . ($basexoffset + 20); ?>px; top:<?php echo $ageyoffset; ?>px; height:<?php echo $controller->bheight; ?>px; display:none;" onmousedown="ageCursorMouseDown(this, <?php echo $p; ?>);"> |
||
362 | <table cellspacing="0" cellpadding="0"> |
||
363 | <tr> |
||
364 | <td> |
||
365 | <img src="<?php echo Theme::theme()->parameter('image-hline'); ?>" name="ageline<?php echo $p; ?>" id="ageline<?php echo $p; ?>" width="25" height="3" alt=""> |
||
366 | </td> |
||
367 | <td> |
||
368 | <?php |
||
369 | $tyear = round(($ageyoffset + ($controller->bheight / 2)) / $controller->scale) + $controller->baseyear; |
||
370 | if (!empty($controller->birthyears[$pid])) { |
||
371 | $tage = $tyear - $controller->birthyears[$pid]; |
||
372 | ?> |
||
373 | <table class="person<?php echo $col; ?>" style="cursor: hand;"> |
||
374 | <tr> |
||
375 | <td><?php echo I18N::translate('Year:'); ?> |
||
376 | <span id="yearform<?php echo $p; ?>" class="field"> |
||
377 | <?php echo $tyear; ?> |
||
378 | </span> |
||
379 | </td> |
||
380 | <td>(<?php echo I18N::translate('Age'); ?> |
||
381 | <span id="ageform<?php echo $p; ?>" class="field"><?php echo $tage; ?></span>) |
||
382 | </td> |
||
383 | </tr> |
||
384 | </table> |
||
385 | <?php } ?> |
||
386 | </td> |
||
387 | </tr> |
||
388 | </table> |
||
389 | <br><br><br> |
||
390 | </div> |
||
391 | <br><br><br><br> |
||
392 | <?php } ?> |
||
393 | <script> |
||
394 | var bottomy = <?php echo $baseyoffset + ($controller->topyear - $controller->baseyear) * $controller->scale; ?>-5; |
||
395 | var topy = <?php echo $baseyoffset; ?>; |
||
396 | var baseyear = <?php echo $controller->baseyear - (25 / $controller->scale); ?>; |
||
397 | var birthyears = []; |
||
398 | var birthmonths = []; |
||
399 | var birthdays = []; |
||
400 | <?php |
||
401 | foreach ($controller->people as $c => $indi) { |
||
402 | $pid = $indi->getXref(); |
||
403 | if (!empty($controller->birthyears[$pid])) { |
||
404 | echo 'birthyears[' . $c . ']=' . $controller->birthyears[$pid] . ';'; |
||
405 | } |
||
406 | if (!empty($controller->birthmonths[$pid])) { |
||
407 | echo 'birthmonths[' . $c . ']=' . $controller->birthmonths[$pid] . ';'; |
||
408 | } |
||
409 | if (!empty($controller->birthdays[$pid])) { |
||
410 | echo 'birthdays[' . $c . ']=' . $controller->birthdays[$pid] . ';'; |
||
411 | } |
||
412 | } |
||
413 | ?> |
||
414 | |||
415 | var bheight = <?php echo $controller->bheight; ?>; |
||
416 | var scale = <?php echo $controller->scale; ?>; |
||
417 | </script> |
||
418 | </div> |
||
419 | <?php } ?> |
||
420 | <script> |
||
421 | timeline_chart_div = document.getElementById("timeline_chart"); |
||
422 | if (timeline_chart_div) { |
||
423 | timeline_chart_div.style.height = '<?php echo $baseyoffset + ($controller->topyear - $controller->baseyear) * $controller->scale * 1.1; ?>px'; |
||
424 | } |
||
425 | </script> |
||
426 |
Instead of relying on
global
state, we recommend one of these alternatives:1. Pass all data via parameters
2. Create a class that maintains your state