1 | <?php |
||||||
2 | |||||||
3 | /** |
||||||
4 | * JPGraph v4.0.3 |
||||||
5 | */ |
||||||
6 | |||||||
7 | namespace Amenadiel\JpGraph\Graph; |
||||||
8 | |||||||
9 | use Amenadiel\JpGraph\Text; |
||||||
10 | use Amenadiel\JpGraph\Util; |
||||||
11 | |||||||
12 | /** |
||||||
13 | * @class GanttScale |
||||||
14 | * // Description: Responsible for calculating and showing |
||||||
15 | * // the scale in a gantt chart. This includes providing methods for |
||||||
16 | * // converting dates to position in the chart as well as stroking the |
||||||
17 | * // date headers (days, week, etc). |
||||||
18 | */ |
||||||
19 | class GanttScale |
||||||
20 | { |
||||||
21 | public $minute; |
||||||
22 | public $hour; |
||||||
23 | public $day; |
||||||
24 | public $week; |
||||||
25 | public $month; |
||||||
26 | public $year; |
||||||
27 | public $divider; |
||||||
28 | public $dividerh; |
||||||
29 | public $tableTitle; |
||||||
30 | public $iStartDate = -1; |
||||||
31 | public $iEndDate = -1; |
||||||
32 | // Number of gantt bar position (n.b not necessariliy the same as the number of bars) |
||||||
33 | // we could have on bar in position 1, and one bar in position 5 then there are two |
||||||
34 | // bars but the number of bar positions is 5 |
||||||
35 | public $actinfo; |
||||||
36 | public $iTopPlotMargin = 10; |
||||||
37 | public $iBottomPlotMargin = 15; |
||||||
38 | public $iVertLines = -1; |
||||||
39 | public $iVertHeaderSize = -1; |
||||||
40 | // The width of the labels (defaults to the widest of all labels) |
||||||
41 | private $iLabelWidth; |
||||||
42 | // Out image to stroke the scale to |
||||||
43 | private $iImg; |
||||||
44 | private $iTableHeaderBackgroundColor = 'white'; |
||||||
45 | private $iTableHeaderFrameColor = 'black'; |
||||||
46 | private $iTableHeaderFrameWeight = 1; |
||||||
47 | private $iAvailableHeight = -1; |
||||||
48 | private $iVertSpacing = -1; |
||||||
49 | private $iDateLocale; |
||||||
50 | private $iVertLayout = GANTT_EVEN; |
||||||
51 | private $iUsePlotWeekendBackground = true; |
||||||
52 | private $iWeekStart = 1; // Default to have weekends start on Monday |
||||||
53 | |||||||
54 | /** |
||||||
55 | * CONSTRUCTOR. |
||||||
56 | * |
||||||
57 | * @param mixed $aImg |
||||||
58 | */ |
||||||
59 | public function __construct($aImg) |
||||||
60 | { |
||||||
61 | $this->iImg = $aImg; |
||||||
62 | $this->iDateLocale = new Util\DateLocale(); |
||||||
63 | |||||||
64 | $this->minute = new HeaderProperty(); |
||||||
65 | $this->minute->SetIntervall(15); |
||||||
66 | $this->minute->SetLabelFormatString('i'); |
||||||
67 | $this->minute->SetFont(FF_FONT0); |
||||||
68 | $this->minute->grid->SetColor('gray'); |
||||||
69 | |||||||
70 | $this->hour = new HeaderProperty(); |
||||||
71 | $this->hour->SetFont(FF_FONT0); |
||||||
72 | $this->hour->SetIntervall(6); |
||||||
73 | $this->hour->SetStyle(HOURSTYLE_HM24); |
||||||
74 | $this->hour->SetLabelFormatString('H:i'); |
||||||
75 | $this->hour->grid->SetColor('gray'); |
||||||
76 | |||||||
77 | $this->day = new HeaderProperty(); |
||||||
78 | $this->day->grid->SetColor('gray'); |
||||||
79 | $this->day->SetLabelFormatString('l'); |
||||||
80 | |||||||
81 | $this->week = new HeaderProperty(); |
||||||
82 | $this->week->SetLabelFormatString('w%d'); |
||||||
83 | $this->week->SetFont(FF_FONT1); |
||||||
84 | |||||||
85 | $this->month = new HeaderProperty(); |
||||||
86 | $this->month->SetFont(FF_FONT1, FS_BOLD); |
||||||
87 | |||||||
88 | $this->year = new HeaderProperty(); |
||||||
89 | $this->year->SetFont(FF_FONT1, FS_BOLD); |
||||||
90 | |||||||
91 | $this->divider = new LineProperty(); |
||||||
92 | $this->dividerh = new LineProperty(); |
||||||
93 | $this->dividerh->SetWeight(2); |
||||||
94 | $this->divider->SetWeight(6); |
||||||
95 | $this->divider->SetColor('gray'); |
||||||
96 | $this->divider->SetStyle('fancy'); |
||||||
97 | |||||||
98 | $this->tableTitle = new Text\TextProperty(); |
||||||
99 | $this->tableTitle->Show(false); |
||||||
100 | $this->actinfo = new GanttActivityInfo(); |
||||||
101 | } |
||||||
102 | |||||||
103 | /** |
||||||
104 | * PUBLIC METHODS |
||||||
105 | * // Specify what headers should be visible. |
||||||
106 | * |
||||||
107 | * @param mixed $aFlg |
||||||
108 | */ |
||||||
109 | public function ShowHeaders($aFlg) |
||||||
110 | { |
||||||
111 | $this->day->Show($aFlg & GANTT_HDAY); |
||||||
112 | $this->week->Show($aFlg & GANTT_HWEEK); |
||||||
113 | $this->month->Show($aFlg & GANTT_HMONTH); |
||||||
114 | $this->year->Show($aFlg & GANTT_HYEAR); |
||||||
115 | $this->hour->Show($aFlg & GANTT_HHOUR); |
||||||
116 | $this->minute->Show($aFlg & GANTT_HMIN); |
||||||
117 | |||||||
118 | // Make some default settings of gridlines whihc makes sense |
||||||
119 | if ($aFlg & GANTT_HWEEK) { |
||||||
120 | $this->month->grid->Show(false); |
||||||
121 | $this->year->grid->Show(false); |
||||||
122 | } |
||||||
123 | if ($aFlg & GANTT_HHOUR) { |
||||||
124 | $this->day->grid->SetColor('black'); |
||||||
125 | } |
||||||
126 | } |
||||||
127 | |||||||
128 | // Should the weekend background stretch all the way down in the plotarea |
||||||
129 | public function UseWeekendBackground($aShow) |
||||||
130 | { |
||||||
131 | $this->iUsePlotWeekendBackground = $aShow; |
||||||
132 | } |
||||||
133 | |||||||
134 | // Have a range been specified? |
||||||
135 | public function IsRangeSet() |
||||||
136 | { |
||||||
137 | return $this->iStartDate != -1 && $this->iEndDate != -1; |
||||||
138 | } |
||||||
139 | |||||||
140 | // Should the layout be from top or even? |
||||||
141 | public function SetVertLayout($aLayout) |
||||||
142 | { |
||||||
143 | $this->iVertLayout = $aLayout; |
||||||
144 | } |
||||||
145 | |||||||
146 | // Which locale should be used? |
||||||
147 | public function SetDateLocale($aLocale) |
||||||
148 | { |
||||||
149 | $this->iDateLocale->Set($aLocale); |
||||||
150 | } |
||||||
151 | |||||||
152 | // Number of days we are showing |
||||||
153 | public function GetNumberOfDays() |
||||||
154 | { |
||||||
155 | return round(($this->iEndDate - $this->iStartDate) / SECPERDAY); |
||||||
156 | } |
||||||
157 | |||||||
158 | // The width of the actual plot area |
||||||
159 | public function GetPlotWidth() |
||||||
160 | { |
||||||
161 | $img = $this->iImg; |
||||||
162 | |||||||
163 | return $img->width - $img->left_margin - $img->right_margin; |
||||||
164 | } |
||||||
165 | |||||||
166 | // Specify the width of the titles(labels) for the activities |
||||||
167 | // (This is by default set to the minimum width enought for the |
||||||
168 | // widest title) |
||||||
169 | public function SetLabelWidth($aLabelWidth) |
||||||
170 | { |
||||||
171 | $this->iLabelWidth = $aLabelWidth; |
||||||
172 | } |
||||||
173 | |||||||
174 | // Which day should the week start? |
||||||
175 | // 0==Sun, 1==Monday, 2==Tuesday etc |
||||||
176 | public function SetWeekStart($aStartDay) |
||||||
177 | { |
||||||
178 | $this->iWeekStart = $aStartDay % 7; |
||||||
179 | |||||||
180 | //Recalculate the startday since this will change the week start |
||||||
181 | $this->SetRange($this->iStartDate, $this->iEndDate); |
||||||
182 | } |
||||||
183 | |||||||
184 | // Do we show min scale? |
||||||
185 | public function IsDisplayMinute() |
||||||
186 | { |
||||||
187 | return $this->minute->iShowLabels; |
||||||
188 | } |
||||||
189 | |||||||
190 | // Do we show day scale? |
||||||
191 | public function IsDisplayHour() |
||||||
192 | { |
||||||
193 | return $this->hour->iShowLabels; |
||||||
194 | } |
||||||
195 | |||||||
196 | // Do we show day scale? |
||||||
197 | public function IsDisplayDay() |
||||||
198 | { |
||||||
199 | return $this->day->iShowLabels; |
||||||
200 | } |
||||||
201 | |||||||
202 | // Do we show week scale? |
||||||
203 | public function IsDisplayWeek() |
||||||
204 | { |
||||||
205 | return $this->week->iShowLabels; |
||||||
206 | } |
||||||
207 | |||||||
208 | // Do we show month scale? |
||||||
209 | public function IsDisplayMonth() |
||||||
210 | { |
||||||
211 | return $this->month->iShowLabels; |
||||||
212 | } |
||||||
213 | |||||||
214 | // Do we show year scale? |
||||||
215 | public function IsDisplayYear() |
||||||
216 | { |
||||||
217 | return $this->year->iShowLabels; |
||||||
218 | } |
||||||
219 | |||||||
220 | // Specify spacing (in percent of bar height) between activity bars |
||||||
221 | public function SetVertSpacing($aSpacing) |
||||||
222 | { |
||||||
223 | $this->iVertSpacing = $aSpacing; |
||||||
224 | } |
||||||
225 | |||||||
226 | // Specify scale min and max date either as timestamp or as date strings |
||||||
227 | // Always round to the nearest week boundary |
||||||
228 | public function SetRange($aMin, $aMax) |
||||||
229 | { |
||||||
230 | $this->iStartDate = $this->NormalizeDate($aMin); |
||||||
231 | $this->iEndDate = $this->NormalizeDate($aMax); |
||||||
232 | } |
||||||
233 | |||||||
234 | // Adjust the start and end date so they fit to beginning/ending |
||||||
235 | // of the week taking the specified week start day into account. |
||||||
236 | public function AdjustStartEndDay() |
||||||
237 | { |
||||||
238 | if (!($this->IsDisplayYear() || $this->IsDisplayMonth() || $this->IsDisplayWeek())) { |
||||||
239 | // Don't adjust |
||||||
240 | return; |
||||||
241 | } |
||||||
242 | |||||||
243 | // Get day in week for start and ending date (Sun==0) |
||||||
244 | $ds = strftime('%w', $this->iStartDate); |
||||||
245 | $de = strftime('%w', $this->iEndDate); |
||||||
246 | |||||||
247 | // We want to start on iWeekStart day. But first we subtract a week |
||||||
248 | // if the startdate is "behind" the day the week start at. |
||||||
249 | // This way we ensure that the given start date is always included |
||||||
250 | // in the range. If we don't do this the nearest correct weekday in the week |
||||||
251 | // to start at might be later than the start date. |
||||||
252 | if ($ds < $this->iWeekStart) { |
||||||
253 | $d = strtotime('-7 day', $this->iStartDate); |
||||||
254 | } else { |
||||||
255 | $d = $this->iStartDate; |
||||||
256 | } |
||||||
257 | |||||||
258 | $adjdate = strtotime(($this->iWeekStart - $ds) . ' day', $d/*$this->iStartDate*/); |
||||||
259 | $this->iStartDate = $adjdate; |
||||||
260 | |||||||
261 | // We want to end on the last day of the week |
||||||
262 | $preferredEndDay = ($this->iWeekStart + 6) % 7; |
||||||
263 | if ($preferredEndDay != $de) { |
||||||
264 | // Solve equivalence eq: $de + x ~ $preferredDay (mod 7) |
||||||
265 | $adj = (7 + ($preferredEndDay - $de)) % 7; |
||||||
266 | $adjdate = strtotime("+${adj} day", $this->iEndDate); |
||||||
267 | $this->iEndDate = $adjdate; |
||||||
268 | } |
||||||
269 | } |
||||||
270 | |||||||
271 | // Specify background for the table title area (upper left corner of the table) |
||||||
272 | public function SetTableTitleBackground($aColor) |
||||||
273 | { |
||||||
274 | $this->iTableHeaderBackgroundColor = $aColor; |
||||||
275 | } |
||||||
276 | |||||||
277 | /////////////////////////////////////// |
||||||
278 | // PRIVATE Methods |
||||||
279 | |||||||
280 | // Determine the height of all the scale headers combined |
||||||
281 | public function GetHeaderHeight() |
||||||
282 | { |
||||||
283 | $img = $this->iImg; |
||||||
284 | $height = 1; |
||||||
285 | if ($this->minute->iShowLabels) { |
||||||
286 | $height += $this->minute->GetFontHeight($img); |
||||||
287 | $height += $this->minute->iTitleVertMargin; |
||||||
288 | } |
||||||
289 | if ($this->hour->iShowLabels) { |
||||||
290 | $height += $this->hour->GetFontHeight($img); |
||||||
291 | $height += $this->hour->iTitleVertMargin; |
||||||
292 | } |
||||||
293 | if ($this->day->iShowLabels) { |
||||||
294 | $height += $this->day->GetFontHeight($img); |
||||||
295 | $height += $this->day->iTitleVertMargin; |
||||||
296 | } |
||||||
297 | if ($this->week->iShowLabels) { |
||||||
298 | $height += $this->week->GetFontHeight($img); |
||||||
299 | $height += $this->week->iTitleVertMargin; |
||||||
300 | } |
||||||
301 | if ($this->month->iShowLabels) { |
||||||
302 | $height += $this->month->GetFontHeight($img); |
||||||
303 | $height += $this->month->iTitleVertMargin; |
||||||
304 | } |
||||||
305 | if ($this->year->iShowLabels) { |
||||||
306 | $height += $this->year->GetFontHeight($img); |
||||||
307 | $height += $this->year->iTitleVertMargin; |
||||||
308 | } |
||||||
309 | |||||||
310 | return $height; |
||||||
311 | } |
||||||
312 | |||||||
313 | // Get width (in pixels) for a single day |
||||||
314 | public function GetDayWidth() |
||||||
315 | { |
||||||
316 | return ($this->GetPlotWidth() - $this->iLabelWidth + 1) / $this->GetNumberOfDays(); |
||||||
317 | } |
||||||
318 | |||||||
319 | // Get width (in pixels) for a single hour |
||||||
320 | public function GetHourWidth() |
||||||
321 | { |
||||||
322 | return $this->GetDayWidth() / 24; |
||||||
323 | } |
||||||
324 | |||||||
325 | public function GetMinuteWidth() |
||||||
326 | { |
||||||
327 | return $this->GetHourWidth() / 60; |
||||||
328 | } |
||||||
329 | |||||||
330 | // Nuber of days in a year |
||||||
331 | public function GetNumDaysInYear($aYear) |
||||||
332 | { |
||||||
333 | if ($this->IsLeap($aYear)) { |
||||||
334 | return 366; |
||||||
335 | } |
||||||
336 | |||||||
337 | return 365; |
||||||
338 | } |
||||||
339 | |||||||
340 | // Get week number |
||||||
341 | public function GetWeekNbr($aDate, $aSunStart = true) |
||||||
342 | { |
||||||
343 | // We can't use the internal strftime() since it gets the weeknumber |
||||||
344 | // wrong since it doesn't follow ISO on all systems since this is |
||||||
345 | // system linrary dependent. |
||||||
346 | // Even worse is that this works differently if we are on a Windows |
||||||
347 | // or UNIX box (it even differs between UNIX boxes how strftime() |
||||||
348 | // is natively implemented) |
||||||
349 | // |
||||||
350 | // Credit to Nicolas Hoizey <[email protected]> for this elegant |
||||||
351 | // version of Week Nbr calculation. |
||||||
352 | |||||||
353 | $day = $this->NormalizeDate($aDate); |
||||||
354 | if ($aSunStart) { |
||||||
355 | $day += 60 * 60 * 24; |
||||||
356 | } |
||||||
357 | |||||||
358 | /** |
||||||
359 | * According to ISO-8601 : |
||||||
360 | * "Week 01 of a year is per definition the first week that has the Thursday in this year, |
||||||
361 | * which is equivalent to the week that contains the fourth day of January. |
||||||
362 | * In other words, the first week of a new year is the week that has the majority of its |
||||||
363 | * days in the new year.". |
||||||
364 | * |
||||||
365 | * Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! |
||||||
366 | * |
||||||
367 | * day of year = date("z", $day) + 1 |
||||||
368 | * offset to thursday = 3 - (date("w", $day) + 6) % 7 |
||||||
369 | * first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 |
||||||
370 | * week number = (thursday's day of year - first thursday's day of year) / 7 + 1 |
||||||
371 | * ---------------------------------------------------------------------------*/ |
||||||
372 | $thursday = $day + 60 * 60 * 24 * (3 - (date('w', $day) + 6) % 7); // take week's thursday |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
373 | $week = 1 + (date('z', $thursday) - (11 - date('w', mktime(0, 0, 0, 1, 1, date('Y', $thursday)))) % 7) / 7; |
||||||
0 ignored issues
–
show
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
![]() $thursday of type double is incompatible with the type integer|null expected by parameter $timestamp of date() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
374 | |||||||
375 | return $week; |
||||||
376 | } |
||||||
377 | |||||||
378 | // Is year a leap year? |
||||||
379 | public function IsLeap($aYear) |
||||||
380 | { |
||||||
381 | // Is the year a leap year? |
||||||
382 | //$year = 0+date("Y",$aDate); |
||||||
383 | if ($aYear % 4 == 0) { |
||||||
384 | if (!($aYear % 100 == 0) || ($aYear % 400 == 0)) { |
||||||
385 | return true; |
||||||
386 | } |
||||||
387 | } |
||||||
388 | |||||||
389 | return false; |
||||||
390 | } |
||||||
391 | |||||||
392 | // Get current year |
||||||
393 | public function GetYear($aDate) |
||||||
394 | { |
||||||
395 | return 0 + date('Y', $aDate); |
||||||
396 | } |
||||||
397 | |||||||
398 | // Return number of days in a year |
||||||
399 | public function GetNumDaysInMonth($aMonth, $aYear) |
||||||
400 | { |
||||||
401 | $days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
||||||
402 | $daysl = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; |
||||||
403 | if ($this->IsLeap($aYear)) { |
||||||
404 | return $daysl[$aMonth]; |
||||||
405 | } |
||||||
406 | |||||||
407 | return $days[$aMonth]; |
||||||
408 | } |
||||||
409 | |||||||
410 | // Get day in month |
||||||
411 | public function GetMonthDayNbr($aDate) |
||||||
412 | { |
||||||
413 | return 0 + strftime('%d', $aDate); |
||||||
414 | } |
||||||
415 | |||||||
416 | // Get day in year |
||||||
417 | public function GetYearDayNbr($aDate) |
||||||
418 | { |
||||||
419 | return 0 + strftime('%j', $aDate); |
||||||
420 | } |
||||||
421 | |||||||
422 | // Get month number |
||||||
423 | public function GetMonthNbr($aDate) |
||||||
424 | { |
||||||
425 | return 0 + strftime('%m', $aDate); |
||||||
426 | } |
||||||
427 | |||||||
428 | // Translate a date to screen coordinates (horizontal scale) |
||||||
429 | public function TranslateDate($aDate) |
||||||
430 | { |
||||||
431 | // |
||||||
432 | // In order to handle the problem with Daylight savings time |
||||||
433 | // the scale written with equal number of seconds per day beginning |
||||||
434 | // with the start date. This means that we "cement" the state of |
||||||
435 | // DST as it is in the start date. If later the scale includes the |
||||||
436 | // switchover date (depends on the locale) we need to adjust back |
||||||
437 | // if the date we try to translate has a different DST status since |
||||||
438 | // we would otherwise be off by one hour. |
||||||
439 | $aDate = $this->NormalizeDate($aDate); |
||||||
440 | $tmp = localtime($aDate); |
||||||
0 ignored issues
–
show
It seems like
$aDate can also be of type double and false ; however, parameter $timestamp of localtime() does only seem to accept integer|null , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
441 | $cloc = $tmp[8]; |
||||||
442 | $tmp = localtime($this->iStartDate); |
||||||
443 | $sloc = $tmp[8]; |
||||||
444 | $offset = 0; |
||||||
445 | if ($sloc != $cloc) { |
||||||
446 | if ($sloc) { |
||||||
447 | $offset = 3600; |
||||||
448 | } else { |
||||||
449 | $offset = -3600; |
||||||
450 | } |
||||||
451 | } |
||||||
452 | $img = $this->iImg; |
||||||
453 | |||||||
454 | return ($aDate - $this->iStartDate - $offset) / SECPERDAY * $this->GetDayWidth() + $img->left_margin + $this->iLabelWidth; |
||||||
455 | } |
||||||
456 | |||||||
457 | // Get screen coordinatesz for the vertical position for a bar |
||||||
458 | public function TranslateVertPos($aPos, $atTop = false) |
||||||
459 | { |
||||||
460 | $img = $this->iImg; |
||||||
461 | if ($aPos > $this->iVertLines) { |
||||||
462 | Util\JpGraphError::RaiseL(6015, $aPos); |
||||||
463 | } |
||||||
464 | |||||||
465 | // 'Illegal vertical position %d' |
||||||
466 | if ($this->iVertLayout == GANTT_EVEN) { |
||||||
467 | // Position the top bar at 1 vert spacing from the scale |
||||||
468 | $pos = round($img->top_margin + $this->iVertHeaderSize + ($aPos + 1) * $this->iVertSpacing); |
||||||
469 | } else { |
||||||
470 | // position the top bar at 1/2 a vert spacing from the scale |
||||||
471 | $pos = round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos + 1) * $this->iVertSpacing); |
||||||
472 | } |
||||||
473 | |||||||
474 | if ($atTop) { |
||||||
475 | $pos -= $this->iVertSpacing; |
||||||
476 | } |
||||||
477 | |||||||
478 | return $pos; |
||||||
479 | } |
||||||
480 | |||||||
481 | // What is the vertical spacing? |
||||||
482 | public function GetVertSpacing() |
||||||
483 | { |
||||||
484 | return $this->iVertSpacing; |
||||||
485 | } |
||||||
486 | |||||||
487 | // Convert a date to timestamp |
||||||
488 | public function NormalizeDate($aDate) |
||||||
489 | { |
||||||
490 | if ($aDate === false) { |
||||||
491 | return false; |
||||||
492 | } |
||||||
493 | |||||||
494 | if (is_string($aDate)) { |
||||||
495 | $t = strtotime($aDate); |
||||||
496 | if ($t === false || $t === -1) { |
||||||
497 | Util\JpGraphError::RaiseL(6016, $aDate); |
||||||
498 | //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30"); |
||||||
499 | } |
||||||
500 | |||||||
501 | return $t; |
||||||
502 | } |
||||||
503 | if (is_int($aDate) || is_float($aDate)) { |
||||||
504 | return $aDate; |
||||||
505 | } |
||||||
506 | Util\JpGraphError::RaiseL(6017, $aDate); |
||||||
507 | |||||||
508 | //Unknown date format in GanttScale ($aDate)."); |
||||||
509 | } |
||||||
510 | |||||||
511 | // Convert a time string to minutes |
||||||
512 | |||||||
513 | public function TimeToMinutes($aTimeString) |
||||||
514 | { |
||||||
515 | // Split in hours and minutes |
||||||
516 | $pos = strpos($aTimeString, ':'); |
||||||
517 | $minint = 60; |
||||||
518 | if ($pos === false) { |
||||||
519 | $hourint = $aTimeString; |
||||||
520 | $minint = 0; |
||||||
521 | } else { |
||||||
522 | $hourint = floor(substr($aTimeString, 0, $pos)); |
||||||
0 ignored issues
–
show
substr($aTimeString, 0, $pos) of type string is incompatible with the type double|integer expected by parameter $num of floor() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
523 | $minint = floor(substr($aTimeString, $pos + 1)); |
||||||
524 | } |
||||||
525 | $minint += 60 * $hourint; |
||||||
526 | |||||||
527 | return $minint; |
||||||
528 | } |
||||||
529 | |||||||
530 | // Stroke the day scale (including gridlines) |
||||||
531 | public function StrokeMinutes($aYCoord, $getHeight = false) |
||||||
532 | { |
||||||
533 | $img = $this->iImg; |
||||||
534 | $xt = $img->left_margin + $this->iLabelWidth; |
||||||
535 | $yt = $aYCoord + $img->top_margin; |
||||||
536 | if ($this->minute->iShowLabels) { |
||||||
537 | $img->SetFont($this->minute->iFFamily, $this->minute->iFStyle, $this->minute->iFSize); |
||||||
538 | $yb = $yt + $img->GetFontHeight() + |
||||||
539 | $this->minute->iTitleVertMargin + $this->minute->iFrameWeight; |
||||||
540 | if ($getHeight) { |
||||||
541 | return $yb - $img->top_margin; |
||||||
542 | } |
||||||
543 | $xb = $img->width - $img->right_margin + 1; |
||||||
544 | $img->SetColor($this->minute->iBackgroundColor); |
||||||
545 | $img->FilledRectangle($xt, $yt, $xb, $yb); |
||||||
546 | |||||||
547 | $x = $xt; |
||||||
548 | $img->SetTextAlign('center'); |
||||||
549 | $day = date('w', $this->iStartDate); |
||||||
550 | $minint = $this->minute->GetIntervall(); |
||||||
551 | |||||||
552 | if (60 % $minint !== 0) { |
||||||
553 | Util\JpGraphError::RaiseL(6018, $minint); |
||||||
554 | //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.'); |
||||||
555 | } |
||||||
556 | |||||||
557 | $n = 60 / $minint; |
||||||
558 | $datestamp = $this->iStartDate; |
||||||
559 | $width = $this->GetHourWidth() / $n; |
||||||
560 | if ($width < 8) { |
||||||
561 | // TO small width to draw minute scale |
||||||
562 | Util\JpGraphError::RaiseL(6019, $width); |
||||||
563 | //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.'); |
||||||
564 | } |
||||||
565 | |||||||
566 | $nh = ceil(24 * 60 / $this->TimeToMinutes($this->hour->GetIntervall())); |
||||||
567 | $nd = $this->GetNumberOfDays(); |
||||||
568 | // Convert to intervall to seconds |
||||||
569 | $minint *= 60; |
||||||
570 | for ($j = 0; $j < $nd; ++$j, ++$day, $day %= 7) { |
||||||
571 | for ($k = 0; $k < $nh; ++$k) { |
||||||
572 | for ($i = 0; $i < $n; ++$i, $x += $width, $datestamp += $minint) { |
||||||
573 | if ($day == 6 || $day == 0) { |
||||||
574 | $img->PushColor($this->day->iWeekendBackgroundColor); |
||||||
575 | if ($this->iUsePlotWeekendBackground) { |
||||||
576 | $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $img->height - $img->bottom_margin); |
||||||
577 | } else { |
||||||
578 | $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $yb - $this->day->iFrameWeight); |
||||||
579 | } |
||||||
580 | |||||||
581 | $img->PopColor(); |
||||||
582 | } |
||||||
583 | |||||||
584 | if ($day == 0) { |
||||||
585 | $img->SetColor($this->day->iSundayTextColor); |
||||||
586 | } else { |
||||||
587 | $img->SetColor($this->day->iTextColor); |
||||||
588 | } |
||||||
589 | |||||||
590 | switch ($this->minute->iStyle) { |
||||||
591 | case MINUTESTYLE_CUSTOM: |
||||||
592 | $txt = date($this->minute->iLabelFormStr, $datestamp); |
||||||
593 | |||||||
594 | break; |
||||||
595 | case MINUTESTYLE_MM: |
||||||
596 | default: |
||||||
597 | // 15 |
||||||
598 | $txt = date('i', $datestamp); |
||||||
599 | |||||||
600 | break; |
||||||
601 | } |
||||||
602 | $img->StrokeText(round($x + $width / 2), round($yb - $this->minute->iTitleVertMargin), $txt); |
||||||
603 | |||||||
604 | // Fix a rounding problem the wrong way .. |
||||||
605 | // If we also have hour scale then don't draw the firsta or last |
||||||
606 | // gridline since that will be overwritten by the hour scale gridline if such exists. |
||||||
607 | // However, due to the propagation of rounding of the 'x+=width' term in the loop |
||||||
608 | // this might sometimes be one pixel of so we fix this by not drawing it. |
||||||
609 | // The proper way to fix it would be to re-calculate the scale for each step and |
||||||
610 | // not using the additive term. |
||||||
611 | if (!(($i == $n || $i == 0) && $this->hour->iShowLabels && $this->hour->grid->iShow)) { |
||||||
612 | $img->SetColor($this->minute->grid->iColor); |
||||||
613 | $img->SetLineWeight($this->minute->grid->iWeight); |
||||||
614 | $img->Line($x, $yt, $x, $yb); |
||||||
615 | $this->minute->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin); |
||||||
616 | } |
||||||
617 | } |
||||||
618 | } |
||||||
619 | } |
||||||
620 | $img->SetColor($this->minute->iFrameColor); |
||||||
621 | $img->SetLineWeight($this->minute->iFrameWeight); |
||||||
622 | $img->Rectangle($xt, $yt, $xb, $yb); |
||||||
623 | |||||||
624 | return $yb - $img->top_margin; |
||||||
625 | } |
||||||
626 | |||||||
627 | return $aYCoord; |
||||||
628 | } |
||||||
629 | |||||||
630 | // Stroke the day scale (including gridlines) |
||||||
631 | public function StrokeHours($aYCoord, $getHeight = false) |
||||||
632 | { |
||||||
633 | $img = $this->iImg; |
||||||
634 | $xt = $img->left_margin + $this->iLabelWidth; |
||||||
635 | $yt = $aYCoord + $img->top_margin; |
||||||
636 | if ($this->hour->iShowLabels) { |
||||||
637 | $img->SetFont($this->hour->iFFamily, $this->hour->iFStyle, $this->hour->iFSize); |
||||||
638 | $yb = $yt + $img->GetFontHeight() + |
||||||
639 | $this->hour->iTitleVertMargin + $this->hour->iFrameWeight; |
||||||
640 | if ($getHeight) { |
||||||
641 | return $yb - $img->top_margin; |
||||||
642 | } |
||||||
643 | $xb = $img->width - $img->right_margin + 1; |
||||||
644 | $img->SetColor($this->hour->iBackgroundColor); |
||||||
645 | $img->FilledRectangle($xt, $yt, $xb, $yb); |
||||||
646 | |||||||
647 | $x = $xt; |
||||||
648 | $img->SetTextAlign('center'); |
||||||
649 | $tmp = $this->hour->GetIntervall(); |
||||||
650 | $minint = $this->TimeToMinutes($tmp); |
||||||
651 | if (1440 % $minint !== 0) { |
||||||
652 | Util\JpGraphError::RaiseL(6020, $tmp); |
||||||
653 | //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp); |
||||||
654 | } |
||||||
655 | |||||||
656 | $n = ceil(24 * 60 / $minint); |
||||||
657 | $datestamp = $this->iStartDate; |
||||||
658 | $day = date('w', $this->iStartDate); |
||||||
659 | $doback = !$this->minute->iShowLabels; |
||||||
660 | $width = $this->GetDayWidth() / $n; |
||||||
661 | for ($j = 0; $j < $this->GetNumberOfDays(); ++$j, ++$day, $day %= 7) { |
||||||
662 | for ($i = 0; $i < $n; ++$i, $x += $width) { |
||||||
663 | if ($day == 6 || $day == 0) { |
||||||
664 | $img->PushColor($this->day->iWeekendBackgroundColor); |
||||||
665 | if ($this->iUsePlotWeekendBackground && $doback) { |
||||||
666 | $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $img->height - $img->bottom_margin); |
||||||
667 | } else { |
||||||
668 | $img->FilledRectangle($x, $yt + $this->day->iFrameWeight, $x + $width, $yb - $this->day->iFrameWeight); |
||||||
669 | } |
||||||
670 | |||||||
671 | $img->PopColor(); |
||||||
672 | } |
||||||
673 | |||||||
674 | if ($day == 0) { |
||||||
675 | $img->SetColor($this->day->iSundayTextColor); |
||||||
676 | } else { |
||||||
677 | $img->SetColor($this->day->iTextColor); |
||||||
678 | } |
||||||
679 | |||||||
680 | switch ($this->hour->iStyle) { |
||||||
681 | case HOURSTYLE_HMAMPM: |
||||||
682 | // 1:35pm |
||||||
683 | $txt = date('g:ia', $datestamp); |
||||||
684 | |||||||
685 | break; |
||||||
686 | case HOURSTYLE_H24: |
||||||
687 | // 13 |
||||||
688 | $txt = date('H', $datestamp); |
||||||
689 | |||||||
690 | break; |
||||||
691 | case HOURSTYLE_HAMPM: |
||||||
692 | $txt = date('ga', $datestamp); |
||||||
693 | |||||||
694 | break; |
||||||
695 | case HOURSTYLE_CUSTOM: |
||||||
696 | $txt = date($this->hour->iLabelFormStr, $datestamp); |
||||||
697 | |||||||
698 | break; |
||||||
699 | case HOURSTYLE_HM24: |
||||||
700 | default: |
||||||
701 | $txt = date('H:i', $datestamp); |
||||||
702 | |||||||
703 | break; |
||||||
704 | } |
||||||
705 | $img->StrokeText(round($x + $width / 2), round($yb - $this->hour->iTitleVertMargin), $txt); |
||||||
706 | $img->SetColor($this->hour->grid->iColor); |
||||||
707 | $img->SetLineWeight($this->hour->grid->iWeight); |
||||||
708 | $img->Line($x, $yt, $x, $yb); |
||||||
709 | $this->hour->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin); |
||||||
710 | //$datestamp += $minint*60 |
||||||
711 | $datestamp = mktime( |
||||||
712 | date('H', $datestamp), |
||||||
0 ignored issues
–
show
date('H', $datestamp) of type string is incompatible with the type integer expected by parameter $hour of mktime() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
713 | date('i', $datestamp) + $minint, |
||||||
0 ignored issues
–
show
date('i', $datestamp) + $minint of type double is incompatible with the type integer expected by parameter $minute of mktime() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
714 | 0, |
||||||
715 | date('m', $datestamp), |
||||||
0 ignored issues
–
show
date('m', $datestamp) of type string is incompatible with the type integer expected by parameter $month of mktime() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
716 | date('d', $datestamp) + 1, |
||||||
717 | date('Y', $datestamp) |
||||||
0 ignored issues
–
show
date('Y', $datestamp) 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
![]() |
|||||||
718 | ); |
||||||
719 | } |
||||||
720 | } |
||||||
721 | $img->SetColor($this->hour->iFrameColor); |
||||||
722 | $img->SetLineWeight($this->hour->iFrameWeight); |
||||||
723 | $img->Rectangle($xt, $yt, $xb, $yb); |
||||||
724 | |||||||
725 | return $yb - $img->top_margin; |
||||||
726 | } |
||||||
727 | |||||||
728 | return $aYCoord; |
||||||
729 | } |
||||||
730 | |||||||
731 | // Stroke the day scale (including gridlines) |
||||||
732 | public function StrokeDays($aYCoord, $getHeight = false) |
||||||
733 | { |
||||||
734 | $img = $this->iImg; |
||||||
735 | $daywidth = $this->GetDayWidth(); |
||||||
736 | $xt = $img->left_margin + $this->iLabelWidth; |
||||||
737 | $yt = $aYCoord + $img->top_margin; |
||||||
738 | if ($this->day->iShowLabels) { |
||||||
739 | $img->SetFont($this->day->iFFamily, $this->day->iFStyle, $this->day->iFSize); |
||||||
740 | $yb = $yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; |
||||||
741 | if ($getHeight) { |
||||||
742 | return $yb - $img->top_margin; |
||||||
743 | } |
||||||
744 | $xb = $img->width - $img->right_margin + 1; |
||||||
745 | $img->SetColor($this->day->iBackgroundColor); |
||||||
746 | $img->FilledRectangle($xt, $yt, $xb, $yb); |
||||||
747 | |||||||
748 | $x = $xt; |
||||||
749 | $img->SetTextAlign('center'); |
||||||
750 | $day = date('w', $this->iStartDate); |
||||||
751 | $datestamp = $this->iStartDate; |
||||||
752 | |||||||
753 | $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels); |
||||||
754 | |||||||
755 | setlocale(LC_TIME, $this->iDateLocale->iLocale); |
||||||
756 | |||||||
757 | for ($i = 0; $i < $this->GetNumberOfDays(); ++$i, $x += $daywidth, ++$day, $day %= 7) { |
||||||
758 | if ($day == 6 || $day == 0) { |
||||||
759 | $img->SetColor($this->day->iWeekendBackgroundColor); |
||||||
760 | if ($this->iUsePlotWeekendBackground && $doback) { |
||||||
761 | $img->FilledRectangle( |
||||||
762 | $x, |
||||||
763 | $yt + $this->day->iFrameWeight, |
||||||
764 | $x + $daywidth, |
||||||
765 | $img->height - $img->bottom_margin |
||||||
766 | ); |
||||||
767 | } else { |
||||||
768 | $img->FilledRectangle( |
||||||
769 | $x, |
||||||
770 | $yt + $this->day->iFrameWeight, |
||||||
771 | $x + $daywidth, |
||||||
772 | $yb - $this->day->iFrameWeight |
||||||
773 | ); |
||||||
774 | } |
||||||
775 | } |
||||||
776 | |||||||
777 | $mn = strftime('%m', $datestamp); |
||||||
778 | if ($mn[0] == '0') { |
||||||
779 | $mn = $mn[1]; |
||||||
780 | } |
||||||
781 | |||||||
782 | switch ($this->day->iStyle) { |
||||||
783 | case DAYSTYLE_LONG: |
||||||
784 | // "Monday" |
||||||
785 | $txt = strftime('%A', $datestamp); |
||||||
786 | |||||||
787 | break; |
||||||
788 | case DAYSTYLE_SHORT: |
||||||
789 | // "Mon" |
||||||
790 | $txt = strftime('%a', $datestamp); |
||||||
791 | |||||||
792 | break; |
||||||
793 | case DAYSTYLE_SHORTDAYDATE1: |
||||||
794 | // "Mon 23/6" |
||||||
795 | $txt = strftime('%a %d/' . $mn, $datestamp); |
||||||
796 | |||||||
797 | break; |
||||||
798 | case DAYSTYLE_SHORTDAYDATE2: |
||||||
799 | // "Mon 23 Jun" |
||||||
800 | $txt = strftime('%a %d %b', $datestamp); |
||||||
801 | |||||||
802 | break; |
||||||
803 | case DAYSTYLE_SHORTDAYDATE3: |
||||||
804 | // "Mon 23 Jun 2003" |
||||||
805 | $txt = strftime('%a %d %b %Y', $datestamp); |
||||||
806 | |||||||
807 | break; |
||||||
808 | case DAYSTYLE_LONGDAYDATE1: |
||||||
809 | // "Monday 23 Jun" |
||||||
810 | $txt = strftime('%A %d %b', $datestamp); |
||||||
811 | |||||||
812 | break; |
||||||
813 | case DAYSTYLE_LONGDAYDATE2: |
||||||
814 | // "Monday 23 Jun 2003" |
||||||
815 | $txt = strftime('%A %d %b %Y', $datestamp); |
||||||
816 | |||||||
817 | break; |
||||||
818 | case DAYSTYLE_SHORTDATE1: |
||||||
819 | // "23/6" |
||||||
820 | $txt = strftime('%d/' . $mn, $datestamp); |
||||||
821 | |||||||
822 | break; |
||||||
823 | case DAYSTYLE_SHORTDATE2: |
||||||
824 | // "23 Jun" |
||||||
825 | $txt = strftime('%d %b', $datestamp); |
||||||
826 | |||||||
827 | break; |
||||||
828 | case DAYSTYLE_SHORTDATE3: |
||||||
829 | // "Mon 23" |
||||||
830 | $txt = strftime('%a %d', $datestamp); |
||||||
831 | |||||||
832 | break; |
||||||
833 | case DAYSTYLE_SHORTDATE4: |
||||||
834 | // "23" |
||||||
835 | $txt = strftime('%d', $datestamp); |
||||||
836 | |||||||
837 | break; |
||||||
838 | case DAYSTYLE_CUSTOM: |
||||||
839 | // Custom format |
||||||
840 | $txt = strftime($this->day->iLabelFormStr, $datestamp); |
||||||
841 | |||||||
842 | break; |
||||||
843 | case DAYSTYLE_ONELETTER: |
||||||
844 | default: |
||||||
845 | // "M" |
||||||
846 | $txt = strftime('%A', $datestamp); |
||||||
847 | $txt = strtoupper($txt[0]); |
||||||
848 | |||||||
849 | break; |
||||||
850 | } |
||||||
851 | |||||||
852 | if ($day == 0) { |
||||||
853 | $img->SetColor($this->day->iSundayTextColor); |
||||||
854 | } else { |
||||||
855 | $img->SetColor($this->day->iTextColor); |
||||||
856 | } |
||||||
857 | |||||||
858 | $img->StrokeText( |
||||||
859 | round($x + $daywidth / 2 + 1), |
||||||
860 | round($yb - $this->day->iTitleVertMargin), |
||||||
861 | $txt |
||||||
862 | ); |
||||||
863 | $img->SetColor($this->day->grid->iColor); |
||||||
864 | $img->SetLineWeight($this->day->grid->iWeight); |
||||||
865 | $img->Line($x, $yt, $x, $yb); |
||||||
866 | $this->day->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin); |
||||||
867 | $datestamp = mktime(0, 0, 0, date('m', $datestamp), date('d', $datestamp) + 1, date('Y', $datestamp)); |
||||||
0 ignored issues
–
show
date('Y', $datestamp) 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
![]() date('m', $datestamp) of type string is incompatible with the type integer expected by parameter $month of mktime() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
868 | //$datestamp += SECPERDAY; |
||||||
869 | } |
||||||
870 | $img->SetColor($this->day->iFrameColor); |
||||||
871 | $img->SetLineWeight($this->day->iFrameWeight); |
||||||
872 | $img->Rectangle($xt, $yt, $xb, $yb); |
||||||
873 | |||||||
874 | return $yb - $img->top_margin; |
||||||
875 | } |
||||||
876 | |||||||
877 | return $aYCoord; |
||||||
878 | } |
||||||
879 | |||||||
880 | // Stroke week header and grid |
||||||
881 | public function StrokeWeeks($aYCoord, $getHeight = false) |
||||||
882 | { |
||||||
883 | if ($this->week->iShowLabels) { |
||||||
884 | $img = $this->iImg; |
||||||
885 | $yt = $aYCoord + $img->top_margin; |
||||||
886 | $img->SetFont($this->week->iFFamily, $this->week->iFStyle, $this->week->iFSize); |
||||||
887 | $yb = $yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; |
||||||
888 | |||||||
889 | if ($getHeight) { |
||||||
890 | return $yb - $img->top_margin; |
||||||
891 | } |
||||||
892 | |||||||
893 | $xt = $img->left_margin + $this->iLabelWidth; |
||||||
894 | $weekwidth = $this->GetDayWidth() * 7; |
||||||
895 | $wdays = $this->iDateLocale->GetDayAbb(); |
||||||
0 ignored issues
–
show
|
|||||||
896 | $xb = $img->width - $img->right_margin + 1; |
||||||
897 | $week = $this->iStartDate; |
||||||
898 | $weeknbr = $this->GetWeekNbr($week); |
||||||
899 | $img->SetColor($this->week->iBackgroundColor); |
||||||
900 | $img->FilledRectangle($xt, $yt, $xb, $yb); |
||||||
901 | $img->SetColor($this->week->grid->iColor); |
||||||
902 | $x = $xt; |
||||||
903 | if ($this->week->iStyle == WEEKSTYLE_WNBR) { |
||||||
904 | $img->SetTextAlign('center'); |
||||||
905 | $txtOffset = $weekwidth / 2 + 1; |
||||||
906 | } elseif ($this->week->iStyle == WEEKSTYLE_FIRSTDAY || |
||||||
907 | $this->week->iStyle == WEEKSTYLE_FIRSTDAY2 || |
||||||
908 | $this->week->iStyle == WEEKSTYLE_FIRSTDAYWNBR || |
||||||
909 | $this->week->iStyle == WEEKSTYLE_FIRSTDAY2WNBR) { |
||||||
910 | $img->SetTextAlign('left'); |
||||||
911 | $txtOffset = 3; |
||||||
912 | } else { |
||||||
913 | Util\JpGraphError::RaiseL(6021); |
||||||
914 | //("Unknown formatting style for week."); |
||||||
915 | } |
||||||
916 | |||||||
917 | for ($i = 0; $i < $this->GetNumberOfDays() / 7; ++$i, $x += $weekwidth) { |
||||||
918 | $img->PushColor($this->week->iTextColor); |
||||||
919 | |||||||
920 | if ($this->week->iStyle == WEEKSTYLE_WNBR) { |
||||||
921 | $txt = sprintf($this->week->iLabelFormStr, $weeknbr); |
||||||
922 | } elseif ($this->week->iStyle == WEEKSTYLE_FIRSTDAY || |
||||||
923 | $this->week->iStyle == WEEKSTYLE_FIRSTDAYWNBR) { |
||||||
924 | $txt = date('j/n', $week); |
||||||
925 | } elseif ($this->week->iStyle == WEEKSTYLE_FIRSTDAY2 || |
||||||
926 | $this->week->iStyle == WEEKSTYLE_FIRSTDAY2WNBR) { |
||||||
927 | $monthnbr = date('n', $week) - 1; |
||||||
928 | $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); |
||||||
929 | $txt = date('j', $week) . ' ' . $shortmonth; |
||||||
930 | } |
||||||
931 | |||||||
932 | if ($this->week->iStyle == WEEKSTYLE_FIRSTDAYWNBR || |
||||||
933 | $this->week->iStyle == WEEKSTYLE_FIRSTDAY2WNBR) { |
||||||
934 | $w = sprintf($this->week->iLabelFormStr, $weeknbr); |
||||||
935 | $txt .= ' ' . $w; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
936 | } |
||||||
937 | |||||||
938 | $img->StrokeText( |
||||||
939 | round($x + $txtOffset), |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
940 | round($yb - $this->week->iTitleVertMargin), |
||||||
941 | $txt |
||||||
942 | ); |
||||||
943 | |||||||
944 | $week = strtotime('+7 day', $week); |
||||||
945 | $weeknbr = $this->GetWeekNbr($week); |
||||||
946 | $img->PopColor(); |
||||||
947 | $img->SetLineWeight($this->week->grid->iWeight); |
||||||
948 | $img->Line($x, $yt, $x, $yb); |
||||||
949 | $this->week->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin); |
||||||
950 | } |
||||||
951 | $img->SetColor($this->week->iFrameColor); |
||||||
952 | $img->SetLineWeight($this->week->iFrameWeight); |
||||||
953 | $img->Rectangle($xt, $yt, $xb, $yb); |
||||||
954 | |||||||
955 | return $yb - $img->top_margin; |
||||||
956 | } |
||||||
957 | |||||||
958 | return $aYCoord; |
||||||
959 | } |
||||||
960 | |||||||
961 | // Format the mont scale header string |
||||||
962 | public function GetMonthLabel($aMonthNbr, $year) |
||||||
963 | { |
||||||
964 | $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); |
||||||
965 | $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); |
||||||
966 | switch ($this->month->iStyle) { |
||||||
967 | case MONTHSTYLE_SHORTNAME: |
||||||
968 | $m = $sn; |
||||||
969 | |||||||
970 | break; |
||||||
971 | case MONTHSTYLE_LONGNAME: |
||||||
972 | $m = $ln; |
||||||
973 | |||||||
974 | break; |
||||||
975 | case MONTHSTYLE_SHORTNAMEYEAR2: |
||||||
976 | $m = $sn . " '" . substr('' . $year, 2); |
||||||
977 | |||||||
978 | break; |
||||||
979 | case MONTHSTYLE_SHORTNAMEYEAR4: |
||||||
980 | $m = $sn . ' ' . $year; |
||||||
981 | |||||||
982 | break; |
||||||
983 | case MONTHSTYLE_LONGNAMEYEAR2: |
||||||
984 | $m = $ln . " '" . substr('' . $year, 2); |
||||||
985 | |||||||
986 | break; |
||||||
987 | case MONTHSTYLE_LONGNAMEYEAR4: |
||||||
988 | $m = $ln . ' ' . $year; |
||||||
989 | |||||||
990 | break; |
||||||
991 | case MONTHSTYLE_FIRSTLETTER: |
||||||
992 | $m = $sn[0]; |
||||||
993 | |||||||
994 | break; |
||||||
995 | } |
||||||
996 | |||||||
997 | return $m; |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
998 | } |
||||||
999 | |||||||
1000 | // Stroke month scale and gridlines |
||||||
1001 | public function StrokeMonths($aYCoord, $getHeight = false) |
||||||
1002 | { |
||||||
1003 | if ($this->month->iShowLabels) { |
||||||
1004 | $img = $this->iImg; |
||||||
1005 | $img->SetFont($this->month->iFFamily, $this->month->iFStyle, $this->month->iFSize); |
||||||
1006 | $yt = $aYCoord + $img->top_margin; |
||||||
1007 | $yb = $yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; |
||||||
1008 | if ($getHeight) { |
||||||
1009 | return $yb - $img->top_margin; |
||||||
1010 | } |
||||||
1011 | $monthnbr = $this->GetMonthNbr($this->iStartDate) - 1; |
||||||
1012 | $xt = $img->left_margin + $this->iLabelWidth; |
||||||
1013 | $xb = $img->width - $img->right_margin + 1; |
||||||
1014 | |||||||
1015 | $img->SetColor($this->month->iBackgroundColor); |
||||||
1016 | $img->FilledRectangle($xt, $yt, $xb, $yb); |
||||||
1017 | |||||||
1018 | $img->SetLineWeight($this->month->grid->iWeight); |
||||||
1019 | $img->SetColor($this->month->iTextColor); |
||||||
1020 | $year = 0 + strftime('%Y', $this->iStartDate); |
||||||
1021 | $img->SetTextAlign('center'); |
||||||
1022 | if ($this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate) |
||||||
1023 | && $this->GetYear($this->iStartDate) == $this->GetYear($this->iEndDate)) { |
||||||
1024 | $monthwidth = $this->GetDayWidth() * ($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1); |
||||||
1025 | } else { |
||||||
1026 | $monthwidth = $this->GetDayWidth() * ($this->GetNumDaysInMonth($monthnbr, $year) - $this->GetMonthDayNbr($this->iStartDate) + 1); |
||||||
1027 | } |
||||||
1028 | // Is it enough space to stroke the first month? |
||||||
1029 | $monthName = $this->GetMonthLabel($monthnbr, $year); |
||||||
1030 | if ($monthwidth >= 1.2 * $img->GetTextWidth($monthName)) { |
||||||
1031 | $img->SetColor($this->month->iTextColor); |
||||||
1032 | $img->StrokeText( |
||||||
1033 | round($xt + $monthwidth / 2 + 1), |
||||||
1034 | round($yb - $this->month->iTitleVertMargin), |
||||||
1035 | $monthName |
||||||
1036 | ); |
||||||
1037 | } |
||||||
1038 | $x = $xt + $monthwidth; |
||||||
1039 | while ($x < $xb) { |
||||||
1040 | $img->SetColor($this->month->grid->iColor); |
||||||
1041 | $img->Line($x, $yt, $x, $yb); |
||||||
1042 | $this->month->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin); |
||||||
1043 | ++$monthnbr; |
||||||
1044 | if ($monthnbr == 12) { |
||||||
1045 | $monthnbr = 0; |
||||||
1046 | ++$year; |
||||||
1047 | } |
||||||
1048 | $monthName = $this->GetMonthLabel($monthnbr, $year); |
||||||
1049 | $monthwidth = $this->GetDayWidth() * $this->GetNumDaysInMonth($monthnbr, $year); |
||||||
1050 | if ($x + $monthwidth < $xb) { |
||||||
1051 | $w = $monthwidth; |
||||||
1052 | } else { |
||||||
1053 | $w = $xb - $x; |
||||||
1054 | } |
||||||
1055 | |||||||
1056 | if ($w >= 1.2 * $img->GetTextWidth($monthName)) { |
||||||
1057 | $img->SetColor($this->month->iTextColor); |
||||||
1058 | $img->StrokeText( |
||||||
1059 | round($x + $w / 2 + 1), |
||||||
1060 | round($yb - $this->month->iTitleVertMargin), |
||||||
1061 | $monthName |
||||||
1062 | ); |
||||||
1063 | } |
||||||
1064 | $x += $monthwidth; |
||||||
1065 | } |
||||||
1066 | $img->SetColor($this->month->iFrameColor); |
||||||
1067 | $img->SetLineWeight($this->month->iFrameWeight); |
||||||
1068 | $img->Rectangle($xt, $yt, $xb, $yb); |
||||||
1069 | |||||||
1070 | return $yb - $img->top_margin; |
||||||
1071 | } |
||||||
1072 | |||||||
1073 | return $aYCoord; |
||||||
1074 | } |
||||||
1075 | |||||||
1076 | // Stroke year scale and gridlines |
||||||
1077 | public function StrokeYears($aYCoord, $getHeight = false) |
||||||
1078 | { |
||||||
1079 | if ($this->year->iShowLabels) { |
||||||
1080 | $img = $this->iImg; |
||||||
1081 | $yt = $aYCoord + $img->top_margin; |
||||||
1082 | $img->SetFont($this->year->iFFamily, $this->year->iFStyle, $this->year->iFSize); |
||||||
1083 | $yb = $yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; |
||||||
1084 | |||||||
1085 | if ($getHeight) { |
||||||
1086 | return $yb - $img->top_margin; |
||||||
1087 | } |
||||||
1088 | |||||||
1089 | $xb = $img->width - $img->right_margin + 1; |
||||||
1090 | $xt = $img->left_margin + $this->iLabelWidth; |
||||||
1091 | $year = $this->GetYear($this->iStartDate); |
||||||
1092 | $img->SetColor($this->year->iBackgroundColor); |
||||||
1093 | $img->FilledRectangle($xt, $yt, $xb, $yb); |
||||||
1094 | $img->SetLineWeight($this->year->grid->iWeight); |
||||||
1095 | $img->SetTextAlign('center'); |
||||||
1096 | if ($year == $this->GetYear($this->iEndDate)) { |
||||||
1097 | $yearwidth = $this->GetDayWidth() * ($this->GetYearDayNbr($this->iEndDate) - $this->GetYearDayNbr($this->iStartDate) + 1); |
||||||
1098 | } else { |
||||||
1099 | $yearwidth = $this->GetDayWidth() * ($this->GetNumDaysInYear($year) - $this->GetYearDayNbr($this->iStartDate) + 1); |
||||||
1100 | } |
||||||
1101 | |||||||
1102 | // The space for a year must be at least 20% bigger than the actual text |
||||||
1103 | // so we allow 10% margin on each side |
||||||
1104 | if ($yearwidth >= 1.20 * $img->GetTextWidth('' . $year)) { |
||||||
1105 | $img->SetColor($this->year->iTextColor); |
||||||
1106 | $img->StrokeText( |
||||||
1107 | round($xt + $yearwidth / 2 + 1), |
||||||
1108 | round($yb - $this->year->iTitleVertMargin), |
||||||
1109 | $year |
||||||
1110 | ); |
||||||
1111 | } |
||||||
1112 | $x = $xt + $yearwidth; |
||||||
1113 | while ($x < $xb) { |
||||||
1114 | $img->SetColor($this->year->grid->iColor); |
||||||
1115 | $img->Line($x, $yt, $x, $yb); |
||||||
1116 | $this->year->grid->Stroke($img, $x, $yb, $x, $img->height - $img->bottom_margin); |
||||||
1117 | ++$year; |
||||||
1118 | $yearwidth = $this->GetDayWidth() * $this->GetNumDaysInYear($year); |
||||||
1119 | if ($x + $yearwidth < $xb) { |
||||||
1120 | $w = $yearwidth; |
||||||
1121 | } else { |
||||||
1122 | $w = $xb - $x; |
||||||
1123 | } |
||||||
1124 | |||||||
1125 | if ($w >= 1.2 * $img->GetTextWidth('' . $year)) { |
||||||
1126 | $img->SetColor($this->year->iTextColor); |
||||||
1127 | $img->StrokeText( |
||||||
1128 | round($x + $w / 2 + 1), |
||||||
1129 | round($yb - $this->year->iTitleVertMargin), |
||||||
1130 | $year |
||||||
1131 | ); |
||||||
1132 | } |
||||||
1133 | $x += $yearwidth; |
||||||
1134 | } |
||||||
1135 | $img->SetColor($this->year->iFrameColor); |
||||||
1136 | $img->SetLineWeight($this->year->iFrameWeight); |
||||||
1137 | $img->Rectangle($xt, $yt, $xb, $yb); |
||||||
1138 | |||||||
1139 | return $yb - $img->top_margin; |
||||||
1140 | } |
||||||
1141 | |||||||
1142 | return $aYCoord; |
||||||
1143 | } |
||||||
1144 | |||||||
1145 | // Stroke table title (upper left corner) |
||||||
1146 | public function StrokeTableHeaders($aYBottom) |
||||||
1147 | { |
||||||
1148 | $img = $this->iImg; |
||||||
1149 | $xt = $img->left_margin; |
||||||
1150 | $yt = $img->top_margin; |
||||||
1151 | $xb = $xt + $this->iLabelWidth; |
||||||
1152 | $yb = $aYBottom + $img->top_margin; |
||||||
1153 | |||||||
1154 | if ($this->tableTitle->iShow) { |
||||||
1155 | $img->SetColor($this->iTableHeaderBackgroundColor); |
||||||
1156 | $img->FilledRectangle($xt, $yt, $xb, $yb); |
||||||
1157 | $this->tableTitle->Align('center', 'top'); |
||||||
1158 | $this->tableTitle->Stroke($img, $xt + ($xb - $xt) / 2 + 1, $yt + 2); |
||||||
1159 | $img->SetColor($this->iTableHeaderFrameColor); |
||||||
1160 | $img->SetLineWeight($this->iTableHeaderFrameWeight); |
||||||
1161 | $img->Rectangle($xt, $yt, $xb, $yb); |
||||||
1162 | } |
||||||
1163 | |||||||
1164 | $this->actinfo->Stroke($img, $xt, $yt, $xb, $yb, $this->tableTitle->iShow); |
||||||
1165 | |||||||
1166 | // Draw the horizontal dividing line |
||||||
1167 | $this->dividerh->Stroke($img, $xt, $yb, $img->width - $img->right_margin, $yb); |
||||||
1168 | |||||||
1169 | // Draw the vertical dividing line |
||||||
1170 | // We do the width "manually" since we want the line only to grow |
||||||
1171 | // to the left |
||||||
1172 | $fancy = $this->divider->iStyle == 'fancy'; |
||||||
1173 | if ($fancy) { |
||||||
1174 | $this->divider->iStyle = 'solid'; |
||||||
1175 | } |
||||||
1176 | |||||||
1177 | $tmp = $this->divider->iWeight; |
||||||
1178 | $this->divider->iWeight = 1; |
||||||
1179 | $y = $img->height - $img->bottom_margin; |
||||||
1180 | for ($i = 0; $i < $tmp; ++$i) { |
||||||
1181 | $this->divider->Stroke($img, $xb - $i, $yt, $xb - $i, $y); |
||||||
1182 | } |
||||||
1183 | |||||||
1184 | // Should we draw "fancy" divider |
||||||
1185 | if ($fancy) { |
||||||
1186 | $img->SetLineWeight(1); |
||||||
1187 | $img->SetColor($this->iTableHeaderFrameColor); |
||||||
1188 | $img->Line($xb, $yt, $xb, $y); |
||||||
1189 | $img->Line($xb - $tmp + 1, $yt, $xb - $tmp + 1, $y); |
||||||
1190 | $img->SetColor('white'); |
||||||
1191 | $img->Line($xb - $tmp + 2, $yt, $xb - $tmp + 2, $y); |
||||||
1192 | } |
||||||
1193 | } |
||||||
1194 | |||||||
1195 | // Main entry point to stroke scale |
||||||
1196 | public function Stroke() |
||||||
1197 | { |
||||||
1198 | if (!$this->IsRangeSet()) { |
||||||
1199 | Util\JpGraphError::RaiseL(6022); |
||||||
1200 | //("Gantt scale has not been specified."); |
||||||
1201 | } |
||||||
1202 | $img = $this->iImg; |
||||||
1203 | |||||||
1204 | // If minutes are displayed then hour interval must be 1 |
||||||
1205 | if ($this->IsDisplayMinute() && $this->hour->GetIntervall() > 1) { |
||||||
1206 | Util\JpGraphError::RaiseL(6023); |
||||||
1207 | //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).'); |
||||||
1208 | } |
||||||
1209 | |||||||
1210 | // Stroke all headers. As argument we supply the offset from the |
||||||
1211 | // top which depends on any previous headers |
||||||
1212 | |||||||
1213 | // First find out the height of each header |
||||||
1214 | $offy = $this->StrokeYears(0, true); |
||||||
1215 | $offm = $this->StrokeMonths($offy, true); |
||||||
1216 | $offw = $this->StrokeWeeks($offm, true); |
||||||
1217 | $offd = $this->StrokeDays($offw, true); |
||||||
1218 | $offh = $this->StrokeHours($offd, true); |
||||||
1219 | $offmin = $this->StrokeMinutes($offh, true); |
||||||
1220 | |||||||
1221 | // ... then we can stroke them in the "backwards order to ensure that |
||||||
1222 | // the larger scale gridlines is stroked over the smaller scale gridline |
||||||
1223 | $this->StrokeMinutes($offh); |
||||||
1224 | $this->StrokeHours($offd); |
||||||
1225 | $this->StrokeDays($offw); |
||||||
1226 | $this->StrokeWeeks($offm); |
||||||
1227 | $this->StrokeMonths($offy); |
||||||
1228 | $this->StrokeYears(0); |
||||||
1229 | |||||||
1230 | // Now when we now the oaverall size of the scale headers |
||||||
1231 | // we can stroke the overall table headers |
||||||
1232 | $this->StrokeTableHeaders($offmin); |
||||||
1233 | |||||||
1234 | // Now we can calculate the correct scaling factor for each vertical position |
||||||
1235 | $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; |
||||||
1236 | |||||||
1237 | $this->iVertHeaderSize = $offmin; |
||||||
1238 | if ($this->iVertSpacing == -1) { |
||||||
1239 | $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; |
||||||
1240 | } |
||||||
1241 | } |
||||||
1242 | } |
||||||
1243 |