HuasoFoundries /
jpgraph
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * JPGraph v4.0.3 |
||
| 5 | */ |
||
| 6 | |||
| 7 | namespace Amenadiel\JpGraph\Plot; |
||
| 8 | |||
| 9 | use Amenadiel\JpGraph\Graph; |
||
| 10 | use Amenadiel\JpGraph\Image; |
||
| 11 | use Amenadiel\JpGraph\Text; |
||
| 12 | use Amenadiel\JpGraph\Util; |
||
| 13 | |||
| 14 | /** |
||
| 15 | * @class GanttBar |
||
| 16 | * // Responsible for formatting individual gantt bars |
||
| 17 | */ |
||
| 18 | class GanttBar extends GanttPlotObject |
||
| 19 | { |
||
| 20 | public $progress; |
||
| 21 | public $leftMark; |
||
| 22 | public $rightMark; |
||
| 23 | private $iEnd; |
||
| 24 | private $iHeightFactor = 0.5; |
||
| 25 | private $iFillColor = 'white'; |
||
| 26 | private $iFrameColor = 'black'; |
||
| 27 | private $iShadow = false; |
||
| 28 | private $iShadowColor = 'darkgray'; |
||
| 29 | private $iShadowWidth = 1; |
||
| 30 | private $iShadowFrame = 'black'; |
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 31 | private $iPattern = GANTT_RDIAG; |
||
| 32 | private $iPatternColor = 'blue'; |
||
| 33 | private $iPatternDensity = 95; |
||
| 34 | private $iBreakStyle = false; |
||
| 35 | private $iBreakLineStyle = 'dotted'; |
||
| 36 | private $iBreakLineWeight = 1; |
||
| 37 | |||
| 38 | /** |
||
| 39 | * CONSTRUCTOR. |
||
| 40 | * |
||
| 41 | * @param mixed $aPos |
||
| 42 | * @param mixed $aLabel |
||
| 43 | * @param mixed $aStart |
||
| 44 | * @param mixed $aEnd |
||
| 45 | * @param mixed $aCaption |
||
| 46 | * @param mixed $aHeightFactor |
||
| 47 | */ |
||
| 48 | public function __construct($aPos, $aLabel, $aStart, $aEnd, $aCaption = '', $aHeightFactor = 0.6) |
||
| 49 | { |
||
| 50 | parent::__construct(); |
||
| 51 | $this->iStart = $aStart; |
||
| 52 | // Is the end date given as a date or as number of days added to start date? |
||
| 53 | if (is_string($aEnd)) { |
||
| 54 | // If end date has been specified without a time we will asssume |
||
| 55 | // end date is at the end of that date |
||
| 56 | if (strpos($aEnd, ':') === false) { |
||
| 57 | $this->iEnd = strtotime($aEnd) + SECPERDAY - 1; |
||
| 58 | } else { |
||
| 59 | $this->iEnd = $aEnd; |
||
| 60 | } |
||
| 61 | } elseif (is_int($aEnd) || is_float($aEnd)) { |
||
| 62 | $this->iEnd = strtotime($aStart) + round($aEnd * SECPERDAY); |
||
| 63 | } |
||
| 64 | $this->iVPos = $aPos; |
||
| 65 | $this->iHeightFactor = $aHeightFactor; |
||
| 66 | $this->title->Set($aLabel); |
||
| 67 | $this->caption = new Text\TextProperty($aCaption); |
||
| 68 | $this->caption->Align('left', 'center'); |
||
| 69 | $this->leftMark = new PlotMark(); |
||
| 70 | $this->leftMark->Hide(); |
||
| 71 | $this->rightMark = new PlotMark(); |
||
| 72 | $this->rightMark->Hide(); |
||
| 73 | $this->progress = new Image\Progress(); |
||
| 74 | } |
||
| 75 | |||
| 76 | /** |
||
| 77 | * PUBLIC METHODS. |
||
| 78 | * |
||
| 79 | * @param mixed $aShadow |
||
| 80 | * @param mixed $aColor |
||
| 81 | */ |
||
| 82 | public function SetShadow($aShadow = true, $aColor = 'gray') |
||
| 83 | { |
||
| 84 | $this->iShadow = $aShadow; |
||
| 85 | $this->iShadowColor = $aColor; |
||
| 86 | } |
||
| 87 | |||
| 88 | public function SetBreakStyle($aFlg = true, $aLineStyle = 'dotted', $aLineWeight = 1) |
||
| 89 | { |
||
| 90 | $this->iBreakStyle = $aFlg; |
||
| 91 | $this->iBreakLineStyle = $aLineStyle; |
||
| 92 | $this->iBreakLineWeight = $aLineWeight; |
||
| 93 | } |
||
| 94 | |||
| 95 | public function GetMaxDate() |
||
| 96 | { |
||
| 97 | return $this->iEnd; |
||
| 98 | } |
||
| 99 | |||
| 100 | public function SetHeight($aHeight) |
||
| 101 | { |
||
| 102 | $this->iHeightFactor = $aHeight; |
||
| 103 | } |
||
| 104 | |||
| 105 | public function SetColor($aColor) |
||
| 106 | { |
||
| 107 | $this->iFrameColor = $aColor; |
||
| 108 | } |
||
| 109 | |||
| 110 | public function SetFillColor($aColor) |
||
| 111 | { |
||
| 112 | $this->iFillColor = $aColor; |
||
| 113 | } |
||
| 114 | |||
| 115 | public function GetAbsHeight($aImg) |
||
| 116 | { |
||
| 117 | if (is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show) { |
||
| 118 | $m = -1; |
||
| 119 | if (is_int($this->iHeightFactor)) { |
||
| 120 | $m = $this->iHeightFactor; |
||
| 121 | } |
||
| 122 | |||
| 123 | if ($this->leftMark->show) { |
||
| 124 | $m = max($m, $this->leftMark->width * 2); |
||
| 125 | } |
||
| 126 | |||
| 127 | if ($this->rightMark->show) { |
||
| 128 | $m = max($m, $this->rightMark->width * 2); |
||
| 129 | } |
||
| 130 | |||
| 131 | return $m; |
||
| 132 | } |
||
| 133 | |||
| 134 | return -1; |
||
| 135 | } |
||
| 136 | |||
| 137 | public function SetPattern($aPattern, $aColor = 'blue', $aDensity = 95) |
||
| 138 | { |
||
| 139 | $this->iPattern = $aPattern; |
||
| 140 | $this->iPatternColor = $aColor; |
||
| 141 | $this->iPatternDensity = $aDensity; |
||
| 142 | } |
||
| 143 | |||
| 144 | public function Stroke($aImg, $aScale) |
||
| 145 | { |
||
| 146 | $factory = new Graph\RectPatternFactory(); |
||
| 147 | $prect = $factory->Create($this->iPattern, $this->iPatternColor); |
||
| 148 | $prect->SetDensity($this->iPatternDensity); |
||
| 149 | |||
| 150 | // If height factor is specified as a float between 0,1 then we take it as meaning |
||
| 151 | // percetage of the scale width between horizontal line. |
||
| 152 | // If it is an integer > 1 we take it to mean the absolute height in pixels |
||
| 153 | if ($this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) { |
||
| 154 | $vs = $aScale->GetVertSpacing() * $this->iHeightFactor; |
||
| 155 | } elseif (is_int($this->iHeightFactor) && $this->iHeightFactor > 2 && $this->iHeightFactor < 200) { |
||
| 156 | $vs = $this->iHeightFactor; |
||
| 157 | } else { |
||
| 158 | Util\JpGraphError::RaiseL(6028, $this->iHeightFactor); |
||
| 159 | // ("Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); |
||
| 160 | } |
||
| 161 | |||
| 162 | // Clip date to min max dates to show |
||
| 163 | $st = $aScale->NormalizeDate($this->iStart); |
||
| 164 | $en = $aScale->NormalizeDate($this->iEnd); |
||
| 165 | |||
| 166 | $limst = max($st, $aScale->iStartDate); |
||
| 167 | $limen = min($en, $aScale->iEndDate); |
||
| 168 | |||
| 169 | $xt = round($aScale->TranslateDate($limst)); |
||
| 170 | $xb = round($aScale->TranslateDate($limen)); |
||
| 171 | $yt = round($aScale->TranslateVertPos($this->iVPos) - $vs - ($aScale->GetVertSpacing() / 2 - $vs / 2)); |
||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
| 172 | $yb = round($aScale->TranslateVertPos($this->iVPos) - ($aScale->GetVertSpacing() / 2 - $vs / 2)); |
||
| 173 | $middle = round($yt + ($yb - $yt) / 2); |
||
| 174 | $this->StrokeActInfo($aImg, $aScale, $middle); |
||
| 175 | |||
| 176 | // CSIM for title |
||
| 177 | if (!empty($this->title->csimtarget)) { |
||
| 178 | $colwidth = $this->title->GetColWidth($aImg); |
||
| 179 | $colstarts = []; |
||
| 180 | $aScale->actinfo->GetColStart($aImg, $colstarts, true); |
||
| 181 | $n = min(safe_count($colwidth), safe_count($this->title->csimtarget)); |
||
| 182 | for ($i = 0; $i < $n; ++$i) { |
||
| 183 | $title_xt = $colstarts[$i]; |
||
| 184 | $title_xb = $title_xt + $colwidth[$i]; |
||
| 185 | $coords = "${title_xt},${yt},${title_xb},${yt},${title_xb},${yb},${title_xt},${yb}"; |
||
| 186 | |||
| 187 | if (!empty($this->title->csimtarget[$i])) { |
||
| 188 | $this->csimarea .= "<area shape=\"poly\" coords=\"${coords}\" href=\"" . $this->title->csimtarget[$i] . '"'; |
||
| 189 | |||
| 190 | if (!empty($this->title->csimwintarget[$i])) { |
||
| 191 | $this->csimarea .= 'target="' . $this->title->csimwintarget[$i] . '" '; |
||
| 192 | } |
||
| 193 | |||
| 194 | if (!empty($this->title->csimalt[$i])) { |
||
| 195 | $tmp = $this->title->csimalt[$i]; |
||
| 196 | $this->csimarea .= " title=\"${tmp}\" alt=\"${tmp}\" "; |
||
| 197 | } |
||
| 198 | $this->csimarea .= " />\n"; |
||
| 199 | } |
||
| 200 | } |
||
| 201 | } |
||
| 202 | |||
| 203 | // Check if the bar is totally outside the current scale range |
||
| 204 | if ($en < $aScale->iStartDate || $st > $aScale->iEndDate) { |
||
| 205 | return; |
||
| 206 | } |
||
| 207 | |||
| 208 | // Remember the positions for the bar |
||
| 209 | $this->SetConstrainPos($xt, $yt, $xb, $yb); |
||
| 210 | |||
| 211 | $prect->ShowFrame(false); |
||
| 212 | $prect->SetBackground($this->iFillColor); |
||
| 213 | if ($this->iBreakStyle) { |
||
| 214 | $aImg->SetColor($this->iFrameColor); |
||
| 215 | $olds = $aImg->SetLineStyle($this->iBreakLineStyle); |
||
| 216 | $oldw = $aImg->SetLineWeight($this->iBreakLineWeight); |
||
| 217 | $aImg->StyleLine($xt, $yt, $xb, $yt); |
||
| 218 | $aImg->StyleLine($xt, $yb, $xb, $yb); |
||
| 219 | $aImg->SetLineStyle($olds); |
||
| 220 | $aImg->SetLineWeight($oldw); |
||
| 221 | } else { |
||
| 222 | if ($this->iShadow) { |
||
| 223 | $aImg->SetColor($this->iFrameColor); |
||
| 224 | $aImg->ShadowRectangle($xt, $yt, $xb, $yb, $this->iFillColor, $this->iShadowWidth, $this->iShadowColor); |
||
| 225 | $prect->SetPos(new Util\Rectangle($xt + 1, $yt + 1, $xb - $xt - $this->iShadowWidth - 2, $yb - $yt - $this->iShadowWidth - 2)); |
||
| 226 | $prect->Stroke($aImg); |
||
| 227 | } else { |
||
| 228 | $prect->SetPos(new Util\Rectangle($xt, $yt, $xb - $xt + 1, $yb - $yt + 1)); |
||
| 229 | $prect->Stroke($aImg); |
||
| 230 | $aImg->SetColor($this->iFrameColor); |
||
| 231 | $aImg->Rectangle($xt, $yt, $xb, $yb); |
||
| 232 | } |
||
| 233 | } |
||
| 234 | // CSIM for bar |
||
| 235 | if (!empty($this->csimtarget)) { |
||
| 236 | $coords = "${xt},${yt},${xb},${yt},${xb},${yb},${xt},${yb}"; |
||
| 237 | $this->csimarea .= "<area shape=\"poly\" coords=\"${coords}\" href=\"" . $this->csimtarget . '"'; |
||
| 238 | |||
| 239 | if (!empty($this->csimwintarget)) { |
||
| 240 | $this->csimarea .= ' target="' . $this->csimwintarget . '" '; |
||
| 241 | } |
||
| 242 | |||
| 243 | if ($this->csimalt != '') { |
||
| 244 | $tmp = $this->csimalt; |
||
| 245 | $this->csimarea .= " title=\"${tmp}\" alt=\"${tmp}\" "; |
||
| 246 | } |
||
| 247 | $this->csimarea .= " />\n"; |
||
| 248 | } |
||
| 249 | |||
| 250 | // Draw progress bar inside activity bar |
||
| 251 | if ($this->progress->iProgress > 0) { |
||
| 252 | $xtp = $aScale->TranslateDate($st); |
||
| 253 | $xbp = $aScale->TranslateDate($en); |
||
| 254 | $len = ($xbp - $xtp) * $this->progress->iProgress; |
||
| 255 | |||
| 256 | $endpos = $xtp + $len; |
||
| 257 | if ($endpos > $xt) { |
||
| 258 | // Take away the length of the progress that is not visible (before the start date) |
||
| 259 | $len -= ($xt - $xtp); |
||
| 260 | |||
| 261 | // Is the the progress bar visible after the start date? |
||
| 262 | if ($xtp < $xt) { |
||
| 263 | $xtp = $xt; |
||
| 264 | } |
||
| 265 | |||
| 266 | // Make sure that the progess bar doesn't extend over the end date |
||
| 267 | if ($xtp + $len - 1 > $xb) { |
||
| 268 | $len = $xb - $xtp; |
||
| 269 | } |
||
| 270 | |||
| 271 | $prog = $factory->Create($this->progress->iPattern, $this->progress->iColor); |
||
| 272 | $prog->SetDensity($this->progress->iDensity); |
||
| 273 | $prog->SetBackground($this->progress->iFillColor); |
||
| 274 | $barheight = ($yb - $yt + 1); |
||
| 275 | if ($this->iShadow) { |
||
| 276 | $barheight -= $this->iShadowWidth; |
||
| 277 | } |
||
| 278 | |||
| 279 | $progressheight = floor($barheight * $this->progress->iHeight); |
||
| 280 | $marg = ceil(($barheight - $progressheight) / 2); |
||
| 281 | $pos = new Util\Rectangle($xtp, $yt + $marg, $len, $barheight - 2 * $marg); |
||
| 282 | $prog->SetPos($pos); |
||
| 283 | $prog->Stroke($aImg); |
||
| 284 | } |
||
| 285 | } |
||
| 286 | |||
| 287 | // We don't plot the end mark if the bar has been capped |
||
| 288 | if ($limst == $st) { |
||
| 289 | $y = $middle; |
||
| 290 | // We treat the RIGHT and LEFT triangle mark a little bi |
||
| 291 | // special so that these marks are placed right under the |
||
| 292 | // bar. |
||
| 293 | if ($this->leftMark->GetType() == MARK_LEFTTRIANGLE) { |
||
| 294 | $y = $yb; |
||
| 295 | } |
||
| 296 | $this->leftMark->Stroke($aImg, $xt, $y); |
||
| 297 | } |
||
| 298 | if ($limen == $en) { |
||
| 299 | $y = $middle; |
||
| 300 | // We treat the RIGHT and LEFT triangle mark a little bi |
||
| 301 | // special so that these marks are placed right under the |
||
| 302 | // bar. |
||
| 303 | if ($this->rightMark->GetType() == MARK_RIGHTTRIANGLE) { |
||
| 304 | $y = $yb; |
||
| 305 | } |
||
| 306 | $this->rightMark->Stroke($aImg, $xb, $y); |
||
| 307 | |||
| 308 | $margin = $this->iCaptionMargin; |
||
| 309 | if ($this->rightMark->show) { |
||
| 310 | $margin += $this->rightMark->GetWidth(); |
||
| 311 | } |
||
| 312 | |||
| 313 | $this->caption->Stroke($aImg, $xb + $margin, $middle); |
||
| 314 | } |
||
| 315 | } |
||
| 316 | } |
||
| 317 |