Completed
Push — charts ( 02447f...0e4f4a )
by Greg
22:41 queued 11:35
created

timeline.php (1 issue)

Upgrade to new PHP Analysis Engine

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
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
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; ?>&amp;scale=<?php echo $controller->scale; ?>&amp;remove=<?php echo $pid; ?>&amp;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; ?>&amp;scale=<?php echo $controller->scale; ?>&amp;remove=<?php echo $pid; ?>&amp;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); ?>&amp;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); ?>&amp;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