1 | <?php |
||||
2 | |||||
3 | /** |
||||
4 | * JPGraph v4.0.3 |
||||
5 | */ |
||||
6 | |||||
7 | namespace Amenadiel\JpGraph\Util; |
||||
8 | |||||
9 | /* |
||||
10 | * @class DateScaleUtils |
||||
11 | * // Description: Help to create a manual date scale |
||||
12 | */ |
||||
13 | 1 | define('DSUTILS_MONTH', 1); // Major and minor ticks on a monthly basis |
|||
14 | 1 | define('DSUTILS_MONTH1', 1); // Major and minor ticks on a monthly basis |
|||
15 | 1 | define('DSUTILS_MONTH2', 2); // Major ticks on a bi-monthly basis |
|||
16 | 1 | define('DSUTILS_MONTH3', 3); // Major icks on a tri-monthly basis |
|||
17 | 1 | define('DSUTILS_MONTH6', 4); // Major on a six-monthly basis |
|||
18 | 1 | define('DSUTILS_WEEK1', 5); // Major ticks on a weekly basis |
|||
19 | 1 | define('DSUTILS_WEEK2', 6); // Major ticks on a bi-weekly basis |
|||
20 | 1 | define('DSUTILS_WEEK4', 7); // Major ticks on a quod-weekly basis |
|||
21 | 1 | define('DSUTILS_DAY1', 8); // Major ticks on a daily basis |
|||
22 | 1 | define('DSUTILS_DAY2', 9); // Major ticks on a bi-daily basis |
|||
23 | 1 | define('DSUTILS_DAY4', 10); // Major ticks on a qoud-daily basis |
|||
24 | 1 | define('DSUTILS_YEAR1', 11); // Major ticks on a yearly basis |
|||
25 | 1 | define('DSUTILS_YEAR2', 12); // Major ticks on a bi-yearly basis |
|||
26 | 1 | define('DSUTILS_YEAR5', 13); // Major ticks on a five-yearly basis |
|||
27 | |||||
28 | class DateScaleUtils |
||||
29 | { |
||||
30 | public static $iMin = 0; |
||||
31 | public static $iMax = 0; |
||||
32 | |||||
33 | private static $starthour; |
||||
34 | private static $startmonth; |
||||
35 | private static $startday; |
||||
36 | private static $startyear; |
||||
37 | private static $endmonth; |
||||
38 | private static $endyear; |
||||
39 | private static $endday; |
||||
40 | private static $tickPositions = []; |
||||
41 | private static $minTickPositions = []; |
||||
42 | private static $iUseWeeks = true; |
||||
43 | |||||
44 | public static function UseWeekFormat($aFlg) |
||||
45 | { |
||||
46 | self::$iUseWeeks = $aFlg; |
||||
47 | } |
||||
48 | |||||
49 | 1 | public static function doYearly($aType, $aMinor = false) |
|||
50 | { |
||||
51 | 1 | $i = 0; |
|||
52 | 1 | $j = 0; |
|||
53 | 1 | $m = self::$startmonth; |
|||
54 | 1 | $y = self::$startyear; |
|||
55 | |||||
56 | 1 | if (self::$startday == 1) { |
|||
57 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, 1, $y); |
||||
58 | } |
||||
59 | 1 | ++$m; |
|||
60 | |||||
61 | switch ($aType) { |
||||
62 | 1 | case DSUTILS_YEAR1: |
|||
63 | for ($y = self::$startyear; $y <= self::$endyear; ++$y) { |
||||
64 | if ($aMinor) { |
||||
65 | while ($m <= 12) { |
||||
66 | if (!($y == self::$endyear && $m > self::$endmonth)) { |
||||
67 | self::$minTickPositions[$j++] = mktime(0, 0, 0, $m, 1, $y); |
||||
68 | } |
||||
69 | ++$m; |
||||
70 | } |
||||
71 | $m = 1; |
||||
72 | } |
||||
73 | self::$tickPositions[$i++] = mktime(0, 0, 0, 1, 1, $y); |
||||
74 | } |
||||
75 | |||||
76 | break; |
||||
77 | 1 | case DSUTILS_YEAR2: |
|||
78 | 1 | $y = self::$startyear; |
|||
79 | 1 | while ($y <= self::$endyear) { |
|||
80 | 1 | self::$tickPositions[$i++] = mktime(0, 0, 0, 1, 1, $y); |
|||
81 | 1 | for ($k = 0; $k < 1; ++$k) { |
|||
82 | 1 | ++$y; |
|||
83 | 1 | if ($aMinor) { |
|||
84 | self::$minTickPositions[$j++] = mktime(0, 0, 0, 1, 1, $y); |
||||
85 | } |
||||
86 | } |
||||
87 | 1 | ++$y; |
|||
88 | } |
||||
89 | |||||
90 | 1 | break; |
|||
91 | case DSUTILS_YEAR5: |
||||
92 | $y = self::$startyear; |
||||
93 | while ($y <= self::$endyear) { |
||||
94 | self::$tickPositions[$i++] = mktime(0, 0, 0, 1, 1, $y); |
||||
95 | for ($k = 0; $k < 4; ++$k) { |
||||
96 | ++$y; |
||||
97 | if ($aMinor) { |
||||
98 | self::$minTickPositions[$j++] = mktime(0, 0, 0, 1, 1, $y); |
||||
99 | } |
||||
100 | } |
||||
101 | ++$y; |
||||
102 | } |
||||
103 | |||||
104 | break; |
||||
105 | } |
||||
106 | 1 | } |
|||
107 | |||||
108 | public static function doDaily($aType, $aMinor = false) |
||||
109 | { |
||||
110 | $m = self::$startmonth; |
||||
111 | $y = self::$startyear; |
||||
112 | $d = self::$startday; |
||||
113 | $h = self::$starthour; |
||||
114 | $i = 0; |
||||
115 | $j = 0; |
||||
116 | |||||
117 | if ($h == 0) { |
||||
118 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, $d, $y); |
||||
119 | } |
||||
120 | $t = mktime(0, 0, 0, $m, $d, $y); |
||||
121 | |||||
122 | switch ($aType) { |
||||
123 | case DSUTILS_DAY1: |
||||
124 | while ($t <= self::$iMax) { |
||||
125 | $t = strtotime('+1 day', $t); |
||||
126 | self::$tickPositions[$i++] = $t; |
||||
127 | if ($aMinor) { |
||||
128 | self::$minTickPositions[$j++] = strtotime('+12 hours', $t); |
||||
129 | } |
||||
130 | } |
||||
131 | |||||
132 | break; |
||||
133 | case DSUTILS_DAY2: |
||||
134 | while ($t <= self::$iMax) { |
||||
135 | $t = strtotime('+1 day', $t); |
||||
136 | if ($aMinor) { |
||||
137 | self::$minTickPositions[$j++] = $t; |
||||
138 | } |
||||
139 | $t = strtotime('+1 day', $t); |
||||
140 | self::$tickPositions[$i++] = $t; |
||||
141 | } |
||||
142 | |||||
143 | break; |
||||
144 | case DSUTILS_DAY4: |
||||
145 | while ($t <= self::$iMax) { |
||||
146 | for ($k = 0; $k < 3; ++$k) { |
||||
147 | $t = strtotime('+1 day', $t); |
||||
148 | if ($aMinor) { |
||||
149 | self::$minTickPositions[$j++] = $t; |
||||
150 | } |
||||
151 | } |
||||
152 | $t = strtotime('+1 day', $t); |
||||
153 | self::$tickPositions[$i++] = $t; |
||||
154 | } |
||||
155 | |||||
156 | break; |
||||
157 | } |
||||
158 | } |
||||
159 | |||||
160 | public static function doWeekly($aType, $aMinor = false) |
||||
161 | { |
||||
162 | $hpd = 3600 * 24; |
||||
163 | $hpw = 3600 * 24 * 7; |
||||
164 | // Find out week number of min date |
||||
165 | $thursday = self::$iMin + $hpd * (3 - (date('w', self::$iMin) + 6) % 7); |
||||
166 | $week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7; |
||||
0 ignored issues
–
show
Unused Code
introduced
by
![]() date('Y', $thursday) of type string is incompatible with the type integer expected by parameter $year of mktime() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
167 | $daynumber = date('w', self::$iMin); |
||||
168 | if ($daynumber == 0) { |
||||
169 | $daynumber = 7; |
||||
170 | } |
||||
171 | |||||
172 | $m = self::$startmonth; |
||||
173 | $y = self::$startyear; |
||||
174 | $d = self::$startday; |
||||
175 | $i = 0; |
||||
176 | $j = 0; |
||||
177 | // The assumption is that the weeks start on Monday. If the first day |
||||
178 | // is later in the week then the first week tick has to be on the following |
||||
179 | // week. |
||||
180 | if ($daynumber == 1) { |
||||
181 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, $d, $y); |
||||
182 | $t = mktime(0, 0, 0, $m, $d, $y) + $hpw; |
||||
183 | } else { |
||||
184 | $t = mktime(0, 0, 0, $m, $d, $y) + $hpd * (8 - $daynumber); |
||||
185 | } |
||||
186 | |||||
187 | switch ($aType) { |
||||
188 | case DSUTILS_WEEK1: |
||||
189 | $cnt = 0; |
||||
190 | |||||
191 | break; |
||||
192 | case DSUTILS_WEEK2: |
||||
193 | $cnt = 1; |
||||
194 | |||||
195 | break; |
||||
196 | case DSUTILS_WEEK4: |
||||
197 | $cnt = 3; |
||||
198 | |||||
199 | break; |
||||
200 | } |
||||
201 | while ($t <= self::$iMax) { |
||||
202 | self::$tickPositions[$i++] = $t; |
||||
203 | for ($k = 0; $k < $cnt; ++$k) { |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
204 | $t += $hpw; |
||||
205 | if ($aMinor) { |
||||
206 | self::$minTickPositions[$j++] = $t; |
||||
207 | } |
||||
208 | } |
||||
209 | $t += $hpw; |
||||
210 | } |
||||
211 | } |
||||
212 | |||||
213 | public static function doMonthly($aType, $aMinor = false) |
||||
214 | { |
||||
215 | $monthcount = 0; |
||||
216 | $m = self::$startmonth; |
||||
217 | $y = self::$startyear; |
||||
218 | $i = 0; |
||||
219 | $j = 0; |
||||
220 | |||||
221 | // Skip the first month label if it is before the startdate |
||||
222 | if (self::$startday == 1) { |
||||
223 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, 1, $y); |
||||
224 | $monthcount = 1; |
||||
225 | } |
||||
226 | if ($aType == 1) { |
||||
227 | if (self::$startday < 15) { |
||||
228 | self::$minTickPositions[$j++] = mktime(0, 0, 0, $m, 15, $y); |
||||
229 | } |
||||
230 | } |
||||
231 | ++$m; |
||||
232 | |||||
233 | // Loop through all the years included in the scale |
||||
234 | for ($y = self::$startyear; $y <= self::$endyear; ++$y) { |
||||
235 | // Loop through all the months. There are three cases to consider: |
||||
236 | // 1. We are in the first year and must start with the startmonth |
||||
237 | // 2. We are in the end year and we must stop at last month of the scale |
||||
238 | // 3. A year in between where we run through all the 12 months |
||||
239 | $stopmonth = $y == self::$endyear ? self::$endmonth : 12; |
||||
240 | while ($m <= $stopmonth) { |
||||
241 | switch ($aType) { |
||||
242 | case DSUTILS_MONTH1: |
||||
243 | // Set minor tick at the middle of the month |
||||
244 | if ($aMinor) { |
||||
245 | if ($m <= $stopmonth) { |
||||
246 | if (!($y == self::$endyear && $m == $stopmonth && self::$endday < 15)) { |
||||
247 | self::$minTickPositions[$j++] = mktime(0, 0, 0, $m, 15, $y); |
||||
248 | } |
||||
249 | } |
||||
250 | } |
||||
251 | // Major at month |
||||
252 | // Get timestamp of first hour of first day in each month |
||||
253 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, 1, $y); |
||||
254 | |||||
255 | break; |
||||
256 | case DSUTILS_MONTH2: |
||||
257 | if ($aMinor) { |
||||
258 | // Set minor tick at start of each month |
||||
259 | self::$minTickPositions[$j++] = mktime(0, 0, 0, $m, 1, $y); |
||||
260 | } |
||||
261 | |||||
262 | // Major at every second month |
||||
263 | // Get timestamp of first hour of first day in each month |
||||
264 | if ($monthcount % 2 == 0) { |
||||
265 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, 1, $y); |
||||
266 | } |
||||
267 | |||||
268 | break; |
||||
269 | case DSUTILS_MONTH3: |
||||
270 | if ($aMinor) { |
||||
271 | // Set minor tick at start of each month |
||||
272 | self::$minTickPositions[$j++] = mktime(0, 0, 0, $m, 1, $y); |
||||
273 | } |
||||
274 | // Major at every third month |
||||
275 | // Get timestamp of first hour of first day in each month |
||||
276 | if ($monthcount % 3 == 0) { |
||||
277 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, 1, $y); |
||||
278 | } |
||||
279 | |||||
280 | break; |
||||
281 | case DSUTILS_MONTH6: |
||||
282 | if ($aMinor) { |
||||
283 | // Set minor tick at start of each month |
||||
284 | self::$minTickPositions[$j++] = mktime(0, 0, 0, $m, 1, $y); |
||||
285 | } |
||||
286 | // Major at every third month |
||||
287 | // Get timestamp of first hour of first day in each month |
||||
288 | if ($monthcount % 6 == 0) { |
||||
289 | self::$tickPositions[$i++] = mktime(0, 0, 0, $m, 1, $y); |
||||
290 | } |
||||
291 | |||||
292 | break; |
||||
293 | } |
||||
294 | ++$m; |
||||
295 | ++$monthcount; |
||||
296 | } |
||||
297 | $m = 1; |
||||
298 | } |
||||
299 | |||||
300 | // For the case where all dates are within the same month |
||||
301 | // we want to make sure we have at least two ticks on the scale |
||||
302 | // since the scale want work properly otherwise |
||||
303 | if (self::$startmonth == self::$endmonth && self::$startyear == self::$endyear && $aType == 1) { |
||||
304 | self::$tickPositions[$i++] = mktime(0, 0, 0, self::$startmonth + 1, 1, self::$startyear); |
||||
305 | } |
||||
306 | |||||
307 | return [self::$tickPositions, self::$minTickPositions]; |
||||
308 | } |
||||
309 | |||||
310 | 1 | public static function GetTicks($aData, $aType = 1, $aMinor = false, $aEndPoints = false) |
|||
311 | { |
||||
312 | 1 | $n = safe_count($aData); |
|||
313 | |||||
314 | 1 | return self::GetTicksFromMinMax($aData[0], $aData[$n - 1], $aType, $aMinor, $aEndPoints); |
|||
315 | } |
||||
316 | |||||
317 | public static function GetAutoTicks($aMin, $aMax, $aMaxTicks = 10, $aMinor = false) |
||||
318 | { |
||||
319 | $diff = $aMax - $aMin; |
||||
320 | $spd = 3600 * 24; |
||||
321 | $spw = $spd * 7; |
||||
322 | $spm = $spd * 30; |
||||
323 | $spy = $spd * 352; |
||||
324 | |||||
325 | if (self::$iUseWeeks) { |
||||
326 | $w = 'W'; |
||||
327 | } else { |
||||
328 | $w = 'd M'; |
||||
329 | } |
||||
330 | |||||
331 | // Decision table for suitable scales |
||||
332 | // First value: Main decision point |
||||
333 | // Second value: Array of formatting depending on divisor for wanted max number of ticks. <divisor><formatting><format-string>,.. |
||||
334 | $tt = [ |
||||
335 | [$spw, [1, DSUTILS_DAY1, 'd M', 2, DSUTILS_DAY2, 'd M', -1, DSUTILS_DAY4, 'd M']], |
||||
336 | [$spm, [1, DSUTILS_DAY1, 'd M', 2, DSUTILS_DAY2, 'd M', 4, DSUTILS_DAY4, 'd M', 7, DSUTILS_WEEK1, $w, -1, DSUTILS_WEEK2, $w]], |
||||
337 | [$spy, [1, DSUTILS_DAY1, 'd M', 2, DSUTILS_DAY2, 'd M', 4, DSUTILS_DAY4, 'd M', 7, DSUTILS_WEEK1, $w, 14, DSUTILS_WEEK2, $w, 30, DSUTILS_MONTH1, 'M', 60, DSUTILS_MONTH2, 'M', -1, DSUTILS_MONTH3, 'M']], |
||||
338 | [-1, [30, DSUTILS_MONTH1, 'M-Y', 60, DSUTILS_MONTH2, 'M-Y', 90, DSUTILS_MONTH3, 'M-Y', 180, DSUTILS_MONTH6, 'M-Y', 352, DSUTILS_YEAR1, 'Y', 704, DSUTILS_YEAR2, 'Y', -1, DSUTILS_YEAR5, 'Y']], ]; |
||||
339 | |||||
340 | $ntt = safe_count($tt); |
||||
341 | $nd = floor($diff / $spd); |
||||
342 | for ($i = 0; $i < $ntt; ++$i) { |
||||
343 | if ($diff <= $tt[$i][0] || $i == $ntt - 1) { |
||||
344 | $t = $tt[$i][1]; |
||||
345 | $n = safe_count($t) / 3; |
||||
346 | for ($j = 0; $j < $n; ++$j) { |
||||
347 | if ($nd / $t[3 * $j] <= $aMaxTicks || $j == $n - 1) { |
||||
348 | $type = $t[3 * $j + 1]; |
||||
349 | $fs = $t[3 * $j + 2]; |
||||
350 | list($tickPositions, $minTickPositions) = self::GetTicksFromMinMax($aMin, $aMax, $type, $aMinor); |
||||
351 | |||||
352 | return [$fs, $tickPositions, $minTickPositions, $type]; |
||||
353 | } |
||||
354 | } |
||||
355 | } |
||||
356 | } |
||||
357 | } |
||||
358 | |||||
359 | 1 | public static function GetTicksFromMinMax($aMin, $aMax, $aType, $aMinor = false, $aEndPoints = false) |
|||
360 | { |
||||
361 | 1 | self::$starthour = date('G', $aMin); |
|||
362 | 1 | self::$startmonth = date('n', $aMin); |
|||
363 | 1 | self::$startday = date('j', $aMin); |
|||
364 | 1 | self::$startyear = date('Y', $aMin); |
|||
365 | 1 | self::$endmonth = date('n', $aMax); |
|||
366 | 1 | self::$endyear = date('Y', $aMax); |
|||
367 | 1 | self::$endday = date('j', $aMax); |
|||
368 | 1 | self::$iMin = $aMin; |
|||
369 | 1 | self::$iMax = $aMax; |
|||
370 | |||||
371 | 1 | if ($aType <= DSUTILS_MONTH6) { |
|||
372 | self::doMonthly($aType, $aMinor); |
||||
373 | 1 | } elseif ($aType <= DSUTILS_WEEK4) { |
|||
374 | self::doWeekly($aType, $aMinor); |
||||
375 | 1 | } elseif ($aType <= DSUTILS_DAY4) { |
|||
376 | self::doDaily($aType, $aMinor); |
||||
377 | 1 | } elseif ($aType <= DSUTILS_YEAR5) { |
|||
378 | 1 | self::doYearly($aType, $aMinor); |
|||
379 | } else { |
||||
380 | JpGraphError::RaiseL(24003); |
||||
381 | } |
||||
382 | // put a label at the very left data pos |
||||
383 | 1 | if ($aEndPoints) { |
|||
384 | $tickPositions[$i++] = $aData[0]; |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||||
385 | } |
||||
386 | |||||
387 | // put a label at the very right data pos |
||||
388 | 1 | if ($aEndPoints) { |
|||
389 | $tickPositions[$i] = $aData[$n - 1]; |
||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||
390 | } |
||||
391 | |||||
392 | 1 | return [self::$tickPositions, self::$minTickPositions]; |
|||
393 | } |
||||
394 | } |
||||
395 |