1<?php 2 3namespace CpChart; 4 5use Exception; 6 7/** 8 * Draw - class extension with drawing methods 9 * 10 * Version : 2.1.4 11 * Made by : Jean-Damien POGOLOTTI 12 * Last Update : 19/01/2014 13 * 14 * This file can be distributed under the license you can find at : 15 * 16 * http://www.pchart.net/license 17 * 18 * You can find the whole class documentation on the pChart web site. 19 */ 20abstract class Draw extends BaseDraw 21{ 22 /** 23 * Draw a polygon 24 * @param array $Points 25 * @param array $Format 26 */ 27 public function drawPolygon(array $Points, array $Format = []) 28 { 29 $R = isset($Format["R"]) ? $Format["R"] : 0; 30 $G = isset($Format["G"]) ? $Format["G"] : 0; 31 $B = isset($Format["B"]) ? $Format["B"] : 0; 32 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 33 $NoFill = isset($Format["NoFill"]) ? $Format["NoFill"] : false; 34 $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : false; 35 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; 36 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; 37 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; 38 $BorderAlpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $Alpha / 2; 39 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 40 $SkipX = isset($Format["SkipX"]) ? $Format["SkipX"] : OUT_OF_SIGHT; 41 $SkipY = isset($Format["SkipY"]) ? $Format["SkipY"] : OUT_OF_SIGHT; 42 43 /* Calling the ImageFilledPolygon() public function over the $Points array will round it */ 44 $Backup = $Points; 45 46 if ($Surrounding != null) { 47 $BorderR = $R + $Surrounding; 48 $BorderG = $G + $Surrounding; 49 $BorderB = $B + $Surrounding; 50 } 51 52 if ($SkipX != OUT_OF_SIGHT) { 53 $SkipX = floor($SkipX); 54 } 55 if ($SkipY != OUT_OF_SIGHT) { 56 $SkipY = floor($SkipY); 57 } 58 59 $RestoreShadow = $this->Shadow; 60 if (!$NoFill) { 61 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 62 $this->Shadow = false; 63 for ($i = 0; $i <= count($Points) - 1; $i = $i + 2) { 64 $Shadow[] = $Points[$i] + $this->ShadowX; 65 $Shadow[] = $Points[$i + 1] + $this->ShadowY; 66 } 67 $this->drawPolygon( 68 $Shadow, 69 [ 70 "R" => $this->ShadowR, 71 "G" => $this->ShadowG, 72 "B" => $this->ShadowB, 73 "Alpha" => $this->Shadowa, 74 "NoBorder" => true 75 ] 76 ); 77 } 78 79 $FillColor = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 80 81 if (count($Points) >= 6) { 82 ImageFilledPolygon($this->Picture, $Points, count($Points) / 2, $FillColor); 83 } 84 } 85 86 if (!$NoBorder) { 87 $Points = $Backup; 88 89 if ($NoFill) { 90 $BorderSettings = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]; 91 } else { 92 $BorderSettings = [ 93 "R" => $BorderR, 94 "G" => $BorderG, 95 "B" => $BorderB, 96 "Alpha" => $BorderAlpha 97 ]; 98 } 99 100 for ($i = 0; $i <= count($Points) - 1; $i = $i + 2) { 101 if (isset($Points[$i + 2]) 102 && !($Points[$i] == $Points[$i + 2] && $Points[$i] == $SkipX) 103 && !($Points[$i + 1] == $Points[$i + 3] && $Points[$i + 1] == $SkipY) 104 ) { 105 $this->drawLine( 106 $Points[$i], 107 $Points[$i + 1], 108 $Points[$i + 2], 109 $Points[$i + 3], 110 $BorderSettings 111 ); 112 } elseif (!($Points[$i] == $Points[0] && $Points[$i] == $SkipX) 113 && !($Points[$i + 1] == $Points[1] && $Points[$i + 1] == $SkipY) 114 ) { 115 $this->drawLine($Points[$i], $Points[$i + 1], $Points[0], $Points[1], $BorderSettings); 116 } 117 } 118 } 119 120 $this->Shadow = $RestoreShadow; 121 } 122 123 /** 124 * Draw a rectangle with rounded corners 125 * @param int $X1 126 * @param int $Y1 127 * @param int $X2 128 * @param int $Y2 129 * @param int|float $Radius 130 * @param array $Format 131 * @return null|integer 132 */ 133 public function drawRoundedRectangle($X1, $Y1, $X2, $Y2, $Radius, array $Format = []) 134 { 135 $R = isset($Format["R"]) ? $Format["R"] : 0; 136 $G = isset($Format["G"]) ? $Format["G"] : 0; 137 $B = isset($Format["B"]) ? $Format["B"] : 0; 138 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 139 140 list($X1, $Y1, $X2, $Y2) = $this->fixBoxCoordinates($X1, $Y1, $X2, $Y2); 141 142 if ($X2 - $X1 < $Radius) { 143 $Radius = floor((($X2 - $X1)) / 2); 144 } 145 if ($Y2 - $Y1 < $Radius) { 146 $Radius = floor((($Y2 - $Y1)) / 2); 147 } 148 149 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "NoBorder" => true]; 150 151 if ($Radius <= 0) { 152 $this->drawRectangle($X1, $Y1, $X2, $Y2, $Color); 153 return 0; 154 } 155 156 if ($this->Antialias) { 157 $this->drawLine($X1 + $Radius, $Y1, $X2 - $Radius, $Y1, $Color); 158 $this->drawLine($X2, $Y1 + $Radius, $X2, $Y2 - $Radius, $Color); 159 $this->drawLine($X2 - $Radius, $Y2, $X1 + $Radius, $Y2, $Color); 160 $this->drawLine($X1, $Y1 + $Radius, $X1, $Y2 - $Radius, $Color); 161 } else { 162 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 163 imageline($this->Picture, $X1 + $Radius, $Y1, $X2 - $Radius, $Y1, $Color); 164 imageline($this->Picture, $X2, $Y1 + $Radius, $X2, $Y2 - $Radius, $Color); 165 imageline($this->Picture, $X2 - $Radius, $Y2, $X1 + $Radius, $Y2, $Color); 166 imageline($this->Picture, $X1, $Y1 + $Radius, $X1, $Y2 - $Radius, $Color); 167 } 168 169 $Step = 360 / (2 * PI * $Radius); 170 for ($i = 0; $i <= 90; $i = $i + $Step) { 171 $X = cos(($i + 180) * PI / 180) * $Radius + $X1 + $Radius; 172 $Y = sin(($i + 180) * PI / 180) * $Radius + $Y1 + $Radius; 173 $this->drawAntialiasPixel($X, $Y, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 174 175 $X = cos(($i + 90) * PI / 180) * $Radius + $X1 + $Radius; 176 $Y = sin(($i + 90) * PI / 180) * $Radius + $Y2 - $Radius; 177 $this->drawAntialiasPixel($X, $Y, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 178 179 $X = cos($i * PI / 180) * $Radius + $X2 - $Radius; 180 $Y = sin($i * PI / 180) * $Radius + $Y2 - $Radius; 181 $this->drawAntialiasPixel($X, $Y, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 182 183 $X = cos(($i + 270) * PI / 180) * $Radius + $X2 - $Radius; 184 $Y = sin(($i + 270) * PI / 180) * $Radius + $Y1 + $Radius; 185 $this->drawAntialiasPixel($X, $Y, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 186 } 187 } 188 189 /** 190 * Draw a rectangle with rounded corners 191 * @param int $X1 192 * @param int $Y1 193 * @param int $X2 194 * @param int $Y2 195 * @param int|float $Radius 196 * @param array $Format 197 * @return null|integer 198 */ 199 public function drawRoundedFilledRectangle($X1, $Y1, $X2, $Y2, $Radius, array $Format = []) 200 { 201 $R = isset($Format["R"]) ? $Format["R"] : 0; 202 $G = isset($Format["G"]) ? $Format["G"] : 0; 203 $B = isset($Format["B"]) ? $Format["B"] : 0; 204 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; 205 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; 206 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; 207 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 208 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 209 210 /* Temporary fix for AA issue */ 211 $Y1 = floor($Y1); 212 $Y2 = floor($Y2); 213 $X1 = floor($X1); 214 $X2 = floor($X2); 215 216 if ($Surrounding != null) { 217 $BorderR = $R + $Surrounding; 218 $BorderG = $G + $Surrounding; 219 $BorderB = $B + $Surrounding; 220 } 221 if ($BorderR == -1) { 222 $BorderR = $R; 223 $BorderG = $G; 224 $BorderB = $B; 225 } 226 227 list($X1, $Y1, $X2, $Y2) = $this->fixBoxCoordinates($X1, $Y1, $X2, $Y2); 228 229 if ($X2 - $X1 < $Radius * 2) { 230 $Radius = floor((($X2 - $X1)) / 4); 231 } 232 if ($Y2 - $Y1 < $Radius * 2) { 233 $Radius = floor((($Y2 - $Y1)) / 4); 234 } 235 236 $RestoreShadow = $this->Shadow; 237 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 238 $this->Shadow = false; 239 $this->drawRoundedFilledRectangle( 240 $X1 + $this->ShadowX, 241 $Y1 + $this->ShadowY, 242 $X2 + $this->ShadowX, 243 $Y2 + $this->ShadowY, 244 $Radius, 245 [ 246 "R" => $this->ShadowR, 247 "G" => $this->ShadowG, 248 "B" => $this->ShadowB, 249 "Alpha" => $this->Shadowa 250 ] 251 ); 252 } 253 254 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "NoBorder" => true]; 255 256 if ($Radius <= 0) { 257 $this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color); 258 return 0; 259 } 260 261 $YTop = $Y1 + $Radius; 262 $YBottom = $Y2 - $Radius; 263 264 $Step = 360 / (2 * PI * $Radius); 265 $Positions = []; 266 $Radius--; 267 $MinY = null; 268 $MaxY = null; 269 for ($i = 0; $i <= 90; $i = $i + $Step) { 270 $Xp1 = cos(($i + 180) * PI / 180) * $Radius + $X1 + $Radius; 271 $Xp2 = cos(((90 - $i) + 270) * PI / 180) * $Radius + $X2 - $Radius; 272 $Yp = floor(sin(($i + 180) * PI / 180) * $Radius + $YTop); 273 if (null === $MinY || $Yp > $MinY) { 274 $MinY = $Yp; 275 } 276 277 if ($Xp1 <= floor($X1)) { 278 $Xp1++; 279 } 280 if ($Xp2 >= floor($X2)) { 281 $Xp2--; 282 } 283 $Xp1++; 284 285 if (!isset($Positions[$Yp])) { 286 $Positions[$Yp]["X1"] = $Xp1; 287 $Positions[$Yp]["X2"] = $Xp2; 288 } else { 289 $Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"] + $Xp1) / 2; 290 $Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"] + $Xp2) / 2; 291 } 292 293 $Xp1 = cos(($i + 90) * PI / 180) * $Radius + $X1 + $Radius; 294 $Xp2 = cos((90 - $i) * PI / 180) * $Radius + $X2 - $Radius; 295 $Yp = floor(sin(($i + 90) * PI / 180) * $Radius + $YBottom); 296 if (null === $MaxY || $Yp < $MaxY) { 297 $MaxY = $Yp; 298 } 299 300 if ($Xp1 <= floor($X1)) { 301 $Xp1++; 302 } 303 if ($Xp2 >= floor($X2)) { 304 $Xp2--; 305 } 306 $Xp1++; 307 308 if (!isset($Positions[$Yp])) { 309 $Positions[$Yp]["X1"] = $Xp1; 310 $Positions[$Yp]["X2"] = $Xp2; 311 } else { 312 $Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"] + $Xp1) / 2; 313 $Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"] + $Xp2) / 2; 314 } 315 } 316 317 $ManualColor = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 318 foreach ($Positions as $Yp => $Bounds) { 319 $X1 = $Bounds["X1"]; 320 $X1Dec = $this->getFirstDecimal($X1); 321 if ($X1Dec != 0) { 322 $X1 = floor($X1) + 1; 323 } 324 $X2 = $Bounds["X2"]; 325 $X2Dec = $this->getFirstDecimal($X2); 326 if ($X2Dec != 0) { 327 $X2 = floor($X2) - 1; 328 } 329 imageline($this->Picture, $X1, $Yp, $X2, $Yp, $ManualColor); 330 } 331 $this->drawFilledRectangle($X1, $MinY + 1, floor($X2), $MaxY - 1, $Color); 332 333 $Radius++; 334 $this->drawRoundedRectangle( 335 $X1, 336 $Y1, 337 $X2 + 1, 338 $Y2 - 1, 339 $Radius, 340 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 341 ); 342 343 $this->Shadow = $RestoreShadow; 344 } 345 346 /** 347 * Draw a rectangle 348 * @param int $X1 349 * @param int $Y1 350 * @param int $X2 351 * @param int $Y2 352 * @param array $Format 353 */ 354 public function drawRectangle($X1, $Y1, $X2, $Y2, array $Format = []) 355 { 356 $R = isset($Format["R"]) ? $Format["R"] : 0; 357 $G = isset($Format["G"]) ? $Format["G"] : 0; 358 $B = isset($Format["B"]) ? $Format["B"] : 0; 359 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 360 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 361 $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : false; 362 363 if ($X1 > $X2) { 364 list($X1, $X2) = [$X2, $X1]; 365 } 366 if ($Y1 > $Y2) { 367 list($Y1, $Y2) = [$Y2, $Y1]; 368 } 369 370 if ($this->Antialias) { 371 if ($NoAngle) { 372 $this->drawLine( 373 $X1 + 1, 374 $Y1, 375 $X2 - 1, 376 $Y1, 377 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 378 ); 379 $this->drawLine( 380 $X2, 381 $Y1 + 1, 382 $X2, 383 $Y2 - 1, 384 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 385 ); 386 $this->drawLine( 387 $X2 - 1, 388 $Y2, 389 $X1 + 1, 390 $Y2, 391 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 392 ); 393 $this->drawLine( 394 $X1, 395 $Y1 + 1, 396 $X1, 397 $Y2 - 1, 398 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 399 ); 400 } else { 401 $this->drawLine( 402 $X1 + 1, 403 $Y1, 404 $X2 - 1, 405 $Y1, 406 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 407 ); 408 $this->drawLine( 409 $X2, 410 $Y1, 411 $X2, 412 $Y2, 413 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 414 ); 415 $this->drawLine( 416 $X2 - 1, 417 $Y2, 418 $X1 + 1, 419 $Y2, 420 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 421 ); 422 $this->drawLine( 423 $X1, 424 $Y1, 425 $X1, 426 $Y2, 427 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 428 ); 429 } 430 } else { 431 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 432 imagerectangle($this->Picture, $X1, $Y1, $X2, $Y2, $Color); 433 } 434 } 435 436 /** 437 * Draw a filled rectangle 438 * @param int $X1 439 * @param int $Y1 440 * @param int $X2 441 * @param int $Y2 442 * @param array $Format 443 */ 444 public function drawFilledRectangle($X1, $Y1, $X2, $Y2, array $Format = []) 445 { 446 $R = isset($Format["R"]) ? $Format["R"] : 0; 447 $G = isset($Format["G"]) ? $Format["G"] : 0; 448 $B = isset($Format["B"]) ? $Format["B"] : 0; 449 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 450 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; 451 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; 452 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; 453 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha; 454 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 455 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 456 $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : null; 457 $Dash = isset($Format["Dash"]) ? $Format["Dash"] : false; 458 $DashStep = isset($Format["DashStep"]) ? $Format["DashStep"] : 4; 459 $DashR = isset($Format["DashR"]) ? $Format["DashR"] : 0; 460 $DashG = isset($Format["DashG"]) ? $Format["DashG"] : 0; 461 $DashB = isset($Format["DashB"]) ? $Format["DashB"] : 0; 462 $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : false; 463 464 if ($Surrounding != null) { 465 $BorderR = $R + $Surrounding; 466 $BorderG = $G + $Surrounding; 467 $BorderB = $B + $Surrounding; 468 } 469 470 if ($X1 > $X2) { 471 list($X1, $X2) = [$X2, $X1]; 472 } 473 if ($Y1 > $Y2) { 474 list($Y1, $Y2) = [$Y2, $Y1]; 475 } 476 477 $RestoreShadow = $this->Shadow; 478 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 479 $this->Shadow = false; 480 $this->drawFilledRectangle( 481 $X1 + $this->ShadowX, 482 $Y1 + $this->ShadowY, 483 $X2 + $this->ShadowX, 484 $Y2 + $this->ShadowY, 485 [ 486 "R" => $this->ShadowR, 487 "G" => $this->ShadowG, 488 "B" => $this->ShadowB, 489 "Alpha" => $this->Shadowa, 490 "Ticks" => $Ticks, 491 "NoAngle" => $NoAngle 492 ] 493 ); 494 } 495 496 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 497 if ($NoAngle) { 498 imagefilledrectangle($this->Picture, ceil($X1) + 1, ceil($Y1), floor($X2) - 1, floor($Y2), $Color); 499 imageline($this->Picture, ceil($X1), ceil($Y1) + 1, ceil($X1), floor($Y2) - 1, $Color); 500 imageline($this->Picture, floor($X2), ceil($Y1) + 1, floor($X2), floor($Y2) - 1, $Color); 501 } else { 502 imagefilledrectangle($this->Picture, ceil($X1), ceil($Y1), floor($X2), floor($Y2), $Color); 503 } 504 if ($Dash) { 505 if ($BorderR != -1) { 506 $iX1 = $X1 + 1; 507 $iY1 = $Y1 + 1; 508 $iX2 = $X2 - 1; 509 $iY2 = $Y2 - 1; 510 } else { 511 $iX1 = $X1; 512 $iY1 = $Y1; 513 $iX2 = $X2; 514 $iY2 = $Y2; 515 } 516 517 $Color = $this->allocateColor($this->Picture, $DashR, $DashG, $DashB, $Alpha); 518 $Y = $iY1 - $DashStep; 519 for ($X = $iX1; $X <= $iX2 + ($iY2 - $iY1); $X = $X + $DashStep) { 520 $Y = $Y + $DashStep; 521 if ($X > $iX2) { 522 $Xa = $X - ($X - $iX2); 523 $Ya = $iY1 + ($X - $iX2); 524 } else { 525 $Xa = $X; 526 $Ya = $iY1; 527 } 528 if ($Y > $iY2) { 529 $Xb = $iX1 + ($Y - $iY2); 530 $Yb = $Y - ($Y - $iY2); 531 } else { 532 $Xb = $iX1; 533 $Yb = $Y; 534 } 535 imageline($this->Picture, $Xa, $Ya, $Xb, $Yb, $Color); 536 } 537 } 538 539 if ($this->Antialias && !$NoBorder) { 540 if ($X1 < ceil($X1)) { 541 $AlphaA = $Alpha * (ceil($X1) - $X1); 542 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $AlphaA); 543 imageline($this->Picture, ceil($X1) - 1, ceil($Y1), ceil($X1) - 1, floor($Y2), $Color); 544 } 545 546 if ($Y1 < ceil($Y1)) { 547 $AlphaA = $Alpha * (ceil($Y1) - $Y1); 548 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $AlphaA); 549 imageline($this->Picture, ceil($X1), ceil($Y1) - 1, floor($X2), ceil($Y1) - 1, $Color); 550 } 551 552 if ($X2 > floor($X2)) { 553 $AlphaA = $Alpha * (.5 - ($X2 - floor($X2))); 554 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $AlphaA); 555 imageline($this->Picture, floor($X2) + 1, ceil($Y1), floor($X2) + 1, floor($Y2), $Color); 556 } 557 558 if ($Y2 > floor($Y2)) { 559 $AlphaA = $Alpha * (.5 - ($Y2 - floor($Y2))); 560 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $AlphaA); 561 imageline($this->Picture, ceil($X1), floor($Y2) + 1, floor($X2), floor($Y2) + 1, $Color); 562 } 563 } 564 565 if ($BorderR != -1) { 566 $this->drawRectangle( 567 $X1, 568 $Y1, 569 $X2, 570 $Y2, 571 [ 572 "R" => $BorderR, 573 "G" => $BorderG, 574 "B" => $BorderB, 575 "Alpha" => $BorderAlpha, 576 "Ticks" => $Ticks, 577 "NoAngle" => $NoAngle 578 ] 579 ); 580 } 581 $this->Shadow = $RestoreShadow; 582 } 583 584 /** 585 * Draw a rectangular marker of the specified size 586 * @param int $X 587 * @param int $Y 588 * @param array $Format 589 */ 590 public function drawRectangleMarker($X, $Y, array $Format = []) 591 { 592 $Size = isset($Format["Size"]) ? $Format["Size"] : 4; 593 594 $HalfSize = floor($Size / 2); 595 $this->drawFilledRectangle($X - $HalfSize, $Y - $HalfSize, $X + $HalfSize, $Y + $HalfSize, $Format); 596 } 597 598 /** 599 * Drawn a spline based on the bezier public function 600 * @param array $Coordinates 601 * @param array $Format 602 * @return array 603 */ 604 public function drawSpline(array $Coordinates, array $Format = []) 605 { 606 $R = isset($Format["R"]) ? $Format["R"] : 0; 607 $G = isset($Format["G"]) ? $Format["G"] : 0; 608 $B = isset($Format["B"]) ? $Format["B"] : 0; 609 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 610 $Force = isset($Format["Force"]) ? $Format["Force"] : 30; 611 $Forces = isset($Format["Forces"]) ? $Format["Forces"] : null; 612 $ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : false; 613 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 614 $PathOnly = isset($Format["PathOnly"]) ? $Format["PathOnly"] : false; 615 $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; 616 617 $Cpt = null; 618 $Mode = null; 619 $Result = []; 620 for ($i = 1; $i <= count($Coordinates) - 1; $i++) { 621 $X1 = $Coordinates[$i - 1][0]; 622 $Y1 = $Coordinates[$i - 1][1]; 623 $X2 = $Coordinates[$i][0]; 624 $Y2 = $Coordinates[$i][1]; 625 626 if ($Forces != null) { 627 $Force = $Forces[$i]; 628 } 629 630 /* First segment */ 631 if ($i == 1) { 632 $Xv1 = $X1; 633 $Yv1 = $Y1; 634 } else { 635 $Angle1 = $this->getAngle($XLast, $YLast, $X1, $Y1); 636 $Angle2 = $this->getAngle($X1, $Y1, $X2, $Y2); 637 $XOff = cos($Angle2 * PI / 180) * $Force + $X1; 638 $YOff = sin($Angle2 * PI / 180) * $Force + $Y1; 639 640 $Xv1 = cos($Angle1 * PI / 180) * $Force + $XOff; 641 $Yv1 = sin($Angle1 * PI / 180) * $Force + $YOff; 642 } 643 644 /* Last segment */ 645 if ($i == count($Coordinates) - 1) { 646 $Xv2 = $X2; 647 $Yv2 = $Y2; 648 } else { 649 $Angle1 = $this->getAngle($X2, $Y2, $Coordinates[$i + 1][0], $Coordinates[$i + 1][1]); 650 $Angle2 = $this->getAngle($X1, $Y1, $X2, $Y2); 651 $XOff = cos(($Angle2 + 180) * PI / 180) * $Force + $X2; 652 $YOff = sin(($Angle2 + 180) * PI / 180) * $Force + $Y2; 653 654 $Xv2 = cos(($Angle1 + 180) * PI / 180) * $Force + $XOff; 655 $Yv2 = sin(($Angle1 + 180) * PI / 180) * $Force + $YOff; 656 } 657 658 $Path = $this->drawBezier($X1, $Y1, $X2, $Y2, $Xv1, $Yv1, $Xv2, $Yv2, $Format); 659 if ($PathOnly) { 660 $Result[] = $Path; 661 } 662 663 $XLast = $X1; 664 $YLast = $Y1; 665 } 666 667 return $Result; 668 } 669 670 /** 671 * Draw a bezier curve with two controls points 672 * @param int $X1 673 * @param int $Y1 674 * @param int $X2 675 * @param int $Y2 676 * @param int $Xv1 677 * @param int $Yv1 678 * @param int $Xv2 679 * @param int $Yv2 680 * @param array $Format 681 * @return array 682 */ 683 public function drawBezier($X1, $Y1, $X2, $Y2, $Xv1, $Yv1, $Xv2, $Yv2, array $Format = []) 684 { 685 $R = isset($Format["R"]) ? $Format["R"] : 0; 686 $G = isset($Format["G"]) ? $Format["G"] : 0; 687 $B = isset($Format["B"]) ? $Format["B"] : 0; 688 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 689 $ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : false; 690 $Segments = isset($Format["Segments"]) ? $Format["Segments"] : null; 691 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 692 $NoDraw = isset($Format["NoDraw"]) ? $Format["NoDraw"] : false; 693 $PathOnly = isset($Format["PathOnly"]) ? $Format["PathOnly"] : false; 694 $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; 695 $DrawArrow = isset($Format["DrawArrow"]) ? $Format["DrawArrow"] : false; 696 $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 10; 697 $ArrowRatio = isset($Format["ArrowRatio"]) ? $Format["ArrowRatio"] : .5; 698 $ArrowTwoHeads = isset($Format["ArrowTwoHeads"]) ? $Format["ArrowTwoHeads"] : false; 699 700 if ($Segments == null) { 701 $Length = $this->getLength($X1, $Y1, $X2, $Y2); 702 $Precision = ($Length * 125) / 1000; 703 } else { 704 $Precision = $Segments; 705 } 706 $P[0]["X"] = $X1; 707 $P[0]["Y"] = $Y1; 708 $P[1]["X"] = $Xv1; 709 $P[1]["Y"] = $Yv1; 710 $P[2]["X"] = $Xv2; 711 $P[2]["Y"] = $Yv2; 712 $P[3]["X"] = $X2; 713 $P[3]["Y"] = $Y2; 714 715 /* Compute the bezier points */ 716 $Q = []; 717 $ID = 0; 718 for ($i = 0; $i <= $Precision; $i = $i + 1) { 719 $u = $i / $Precision; 720 721 $C = []; 722 $C[0] = (1 - $u) * (1 - $u) * (1 - $u); 723 $C[1] = ($u * 3) * (1 - $u) * (1 - $u); 724 $C[2] = 3 * $u * $u * (1 - $u); 725 $C[3] = $u * $u * $u; 726 727 for ($j = 0; $j <= 3; $j++) { 728 if (!isset($Q[$ID])) { 729 $Q[$ID] = []; 730 } 731 if (!isset($Q[$ID]["X"])) { 732 $Q[$ID]["X"] = 0; 733 } 734 if (!isset($Q[$ID]["Y"])) { 735 $Q[$ID]["Y"] = 0; 736 } 737 738 $Q[$ID]["X"] = $Q[$ID]["X"] + $P[$j]["X"] * $C[$j]; 739 $Q[$ID]["Y"] = $Q[$ID]["Y"] + $P[$j]["Y"] * $C[$j]; 740 } 741 $ID++; 742 } 743 $Q[$ID]["X"] = $X2; 744 $Q[$ID]["Y"] = $Y2; 745 746 if (!$NoDraw) { 747 /* Display the control points */ 748 if ($ShowC && !$PathOnly) { 749 $Xv1 = floor($Xv1); 750 $Yv1 = floor($Yv1); 751 $Xv2 = floor($Xv2); 752 $Yv2 = floor($Yv2); 753 754 $this->drawLine($X1, $Y1, $X2, $Y2, ["R" => 0, "G" => 0, "B" => 0, "Alpha" => 30]); 755 756 $MyMarkerSettings = [ 757 "R" => 255, 758 "G" => 0, 759 "B" => 0, 760 "BorderR" => 255, 761 "BorderB" => 255, 762 "BorderG" => 255, 763 "Size" => 4 764 ]; 765 $this->drawRectangleMarker($Xv1, $Yv1, $MyMarkerSettings); 766 $this->drawText($Xv1 + 4, $Yv1, "v1"); 767 $MyMarkerSettings = [ 768 "R" => 0, 769 "G" => 0, 770 "B" => 255, 771 "BorderR" => 255, 772 "BorderB" => 255, 773 "BorderG" => 255, 774 "Size" => 4 775 ]; 776 $this->drawRectangleMarker($Xv2, $Yv2, $MyMarkerSettings); 777 $this->drawText($Xv2 + 4, $Yv2, "v2"); 778 } 779 780 /* Draw the bezier */ 781 $LastX = null; 782 $LastY = null; 783 $Cpt = null; 784 $Mode = null; 785 $ArrowS = []; 786 foreach ($Q as $Point) { 787 $X = $Point["X"]; 788 $Y = $Point["Y"]; 789 790 /* Get the first segment */ 791 if (!count($ArrowS) && $LastX != null && $LastY != null) { 792 $ArrowS["X2"] = $LastX; 793 $ArrowS["Y2"] = $LastY; 794 $ArrowS["X1"] = $X; 795 $ArrowS["Y1"] = $Y; 796 } 797 798 if ($LastX != null && $LastY != null && !$PathOnly) { 799 list($Cpt, $Mode) = $this->drawLine( 800 $LastX, 801 $LastY, 802 $X, 803 $Y, 804 [ 805 "R" => $R, 806 "G" => $G, 807 "B" => $B, 808 "Alpha" => $Alpha, 809 "Ticks" => $Ticks, 810 "Cpt" => $Cpt, 811 "Mode" => $Mode, 812 "Weight" => $Weight 813 ] 814 ); 815 } 816 /* Get the last segment */ 817 $ArrowE["X1"] = $LastX; 818 $ArrowE["Y1"] = $LastY; 819 $ArrowE["X2"] = $X; 820 $ArrowE["Y2"] = $Y; 821 822 $LastX = $X; 823 $LastY = $Y; 824 } 825 826 if ($DrawArrow && !$PathOnly) { 827 $ArrowSettings = [ 828 "FillR" => $R, 829 "FillG" => $G, 830 "FillB" => $B, 831 "Alpha" => $Alpha, 832 "Size" => $ArrowSize, 833 "Ratio" => $ArrowRatio 834 ]; 835 if ($ArrowTwoHeads) { 836 $this->drawArrow($ArrowS["X1"], $ArrowS["Y1"], $ArrowS["X2"], $ArrowS["Y2"], $ArrowSettings); 837 } 838 $this->drawArrow($ArrowE["X1"], $ArrowE["Y1"], $ArrowE["X2"], $ArrowE["Y2"], $ArrowSettings); 839 } 840 } 841 return $Q; 842 } 843 844 /** 845 * Draw a line between two points 846 * @param int|float $X1 847 * @param int|float $Y1 848 * @param int|float $X2 849 * @param int|float $Y2 850 * @param array $Format 851 * @return array|int 852 */ 853 public function drawLine($X1, $Y1, $X2, $Y2, array $Format = []) 854 { 855 $R = isset($Format["R"]) ? $Format["R"] : 0; 856 $G = isset($Format["G"]) ? $Format["G"] : 0; 857 $B = isset($Format["B"]) ? $Format["B"] : 0; 858 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 859 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 860 $Cpt = isset($Format["Cpt"]) ? $Format["Cpt"] : 1; 861 $Mode = isset($Format["Mode"]) ? $Format["Mode"] : 1; 862 $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; 863 $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; 864 865 if ($this->Antialias == false && $Ticks == null) { 866 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 867 $ShadowColor = $this->allocateColor( 868 $this->Picture, 869 $this->ShadowR, 870 $this->ShadowG, 871 $this->ShadowB, 872 $this->Shadowa 873 ); 874 imageline( 875 $this->Picture, 876 $X1 + $this->ShadowX, 877 $Y1 + $this->ShadowY, 878 $X2 + $this->ShadowX, 879 $Y2 + $this->ShadowY, 880 $ShadowColor 881 ); 882 } 883 884 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 885 imageline($this->Picture, $X1, $Y1, $X2, $Y2, $Color); 886 return 0; 887 } 888 889 $Distance = sqrt(($X2 - $X1) * ($X2 - $X1) + ($Y2 - $Y1) * ($Y2 - $Y1)); 890 if ($Distance == 0) { 891 return -1; 892 } 893 894 /* Derivative algorithm for overweighted lines, re-route to polygons primitives */ 895 if ($Weight != null) { 896 $Angle = $this->getAngle($X1, $Y1, $X2, $Y2); 897 $PolySettings = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "BorderAlpha" => $Alpha]; 898 899 if ($Ticks == null) { 900 $Points = []; 901 $Points[] = cos(deg2rad($Angle - 90)) * $Weight + $X1; 902 $Points[] = sin(deg2rad($Angle - 90)) * $Weight + $Y1; 903 $Points[] = cos(deg2rad($Angle + 90)) * $Weight + $X1; 904 $Points[] = sin(deg2rad($Angle + 90)) * $Weight + $Y1; 905 $Points[] = cos(deg2rad($Angle + 90)) * $Weight + $X2; 906 $Points[] = sin(deg2rad($Angle + 90)) * $Weight + $Y2; 907 $Points[] = cos(deg2rad($Angle - 90)) * $Weight + $X2; 908 $Points[] = sin(deg2rad($Angle - 90)) * $Weight + $Y2; 909 910 $this->drawPolygon($Points, $PolySettings); 911 } else { 912 for ($i = 0; $i <= $Distance; $i = $i + $Ticks * 2) { 913 $Xa = (($X2 - $X1) / $Distance) * $i + $X1; 914 $Ya = (($Y2 - $Y1) / $Distance) * $i + $Y1; 915 $Xb = (($X2 - $X1) / $Distance) * ($i + $Ticks) + $X1; 916 $Yb = (($Y2 - $Y1) / $Distance) * ($i + $Ticks) + $Y1; 917 918 $Points = []; 919 $Points[] = cos(deg2rad($Angle - 90)) * $Weight + $Xa; 920 $Points[] = sin(deg2rad($Angle - 90)) * $Weight + $Ya; 921 $Points[] = cos(deg2rad($Angle + 90)) * $Weight + $Xa; 922 $Points[] = sin(deg2rad($Angle + 90)) * $Weight + $Ya; 923 $Points[] = cos(deg2rad($Angle + 90)) * $Weight + $Xb; 924 $Points[] = sin(deg2rad($Angle + 90)) * $Weight + $Yb; 925 $Points[] = cos(deg2rad($Angle - 90)) * $Weight + $Xb; 926 $Points[] = sin(deg2rad($Angle - 90)) * $Weight + $Yb; 927 928 $this->drawPolygon($Points, $PolySettings); 929 } 930 } 931 932 return 1; 933 } 934 935 $XStep = ($X2 - $X1) / $Distance; 936 $YStep = ($Y2 - $Y1) / $Distance; 937 938 for ($i = 0; $i <= $Distance; $i++) { 939 $X = $i * $XStep + $X1; 940 $Y = $i * $YStep + $Y1; 941 942 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]; 943 944 if ($Threshold != null) { 945 foreach ($Threshold as $Key => $Parameters) { 946 if ($Y <= $Parameters["MinX"] && $Y >= $Parameters["MaxX"]) { 947 if (isset($Parameters["R"])) { 948 $RT = $Parameters["R"]; 949 } else { 950 $RT = 0; 951 } 952 if (isset($Parameters["G"])) { 953 $GT = $Parameters["G"]; 954 } else { 955 $GT = 0; 956 } 957 if (isset($Parameters["B"])) { 958 $BT = $Parameters["B"]; 959 } else { 960 $BT = 0; 961 } 962 if (isset($Parameters["Alpha"])) { 963 $AlphaT = $Parameters["Alpha"]; 964 } else { 965 $AlphaT = 0; 966 } 967 $Color = ["R" => $RT, "G" => $GT, "B" => $BT, "Alpha" => $AlphaT]; 968 } 969 } 970 } 971 972 if ($Ticks != null) { 973 if ($Cpt % $Ticks == 0) { 974 $Cpt = 0; 975 if ($Mode == 1) { 976 $Mode = 0; 977 } else { 978 $Mode = 1; 979 } 980 } 981 982 if ($Mode == 1) { 983 $this->drawAntialiasPixel($X, $Y, $Color); 984 } 985 $Cpt++; 986 } else { 987 $this->drawAntialiasPixel($X, $Y, $Color); 988 } 989 } 990 991 return [$Cpt, $Mode]; 992 } 993 994 /** 995 * Draw a circle 996 * @param int $Xc 997 * @param int $Yc 998 * @param int|float $Height 999 * @param int|float $Width 1000 * @param array $Format 1001 */ 1002 public function drawCircle($Xc, $Yc, $Height, $Width, array $Format = []) 1003 { 1004 $R = isset($Format["R"]) ? $Format["R"] : 0; 1005 $G = isset($Format["G"]) ? $Format["G"] : 0; 1006 $B = isset($Format["B"]) ? $Format["B"] : 0; 1007 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 1008 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 1009 1010 $Height = abs($Height); 1011 $Width = abs($Width); 1012 1013 if ($Height == 0) { 1014 $Height = 1; 1015 } 1016 if ($Width == 0) { 1017 $Width = 1; 1018 } 1019 $Xc = floor($Xc); 1020 $Yc = floor($Yc); 1021 1022 $RestoreShadow = $this->Shadow; 1023 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 1024 $this->Shadow = false; 1025 $this->drawCircle( 1026 $Xc + $this->ShadowX, 1027 $Yc + $this->ShadowY, 1028 $Height, 1029 $Width, 1030 [ 1031 "R" => $this->ShadowR, 1032 "G" => $this->ShadowG, 1033 "B" => $this->ShadowB, 1034 "Alpha" => $this->Shadowa, 1035 "Ticks" => $Ticks 1036 ] 1037 ); 1038 } 1039 1040 if ($Width == 0) { 1041 $Width = $Height; 1042 } 1043 if ($R < 0) { 1044 $R = 0; 1045 } if ($R > 255) { 1046 $R = 255; 1047 } 1048 if ($G < 0) { 1049 $G = 0; 1050 } if ($G > 255) { 1051 $G = 255; 1052 } 1053 if ($B < 0) { 1054 $B = 0; 1055 } if ($B > 255) { 1056 $B = 255; 1057 } 1058 1059 $Step = 360 / (2 * PI * max($Width, $Height)); 1060 $Mode = 1; 1061 $Cpt = 1; 1062 for ($i = 0; $i <= 360; $i = $i + $Step) { 1063 $X = cos($i * PI / 180) * $Height + $Xc; 1064 $Y = sin($i * PI / 180) * $Width + $Yc; 1065 1066 if ($Ticks != null) { 1067 if ($Cpt % $Ticks == 0) { 1068 $Cpt = 0; 1069 if ($Mode == 1) { 1070 $Mode = 0; 1071 } else { 1072 $Mode = 1; 1073 } 1074 } 1075 1076 if ($Mode == 1) { 1077 $this->drawAntialiasPixel($X, $Y, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 1078 } 1079 $Cpt++; 1080 } else { 1081 $this->drawAntialiasPixel($X, $Y, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 1082 } 1083 } 1084 $this->Shadow = $RestoreShadow; 1085 } 1086 1087 /** 1088 * Draw a filled circle 1089 * @param int $X 1090 * @param int $Y 1091 * @param int|float $Radius 1092 * @param array $Format 1093 */ 1094 public function drawFilledCircle($X, $Y, $Radius, array $Format = []) 1095 { 1096 $R = isset($Format["R"]) ? $Format["R"] : 0; 1097 $G = isset($Format["G"]) ? $Format["G"] : 0; 1098 $B = isset($Format["B"]) ? $Format["B"] : 0; 1099 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 1100 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; 1101 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; 1102 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; 1103 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha; 1104 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 1105 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 1106 1107 if ($Radius == 0) { 1108 $Radius = 1; 1109 } 1110 if ($Surrounding != null) { 1111 $BorderR = $R + $Surrounding; 1112 $BorderG = $G + $Surrounding; 1113 $BorderB = $B + $Surrounding; 1114 } 1115 $X = floor($X); 1116 $Y = floor($Y); 1117 1118 $Radius = abs($Radius); 1119 1120 $RestoreShadow = $this->Shadow; 1121 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 1122 $this->Shadow = false; 1123 $this->drawFilledCircle( 1124 $X + $this->ShadowX, 1125 $Y + $this->ShadowY, 1126 $Radius, 1127 [ 1128 "R" => $this->ShadowR, 1129 "G" => $this->ShadowG, 1130 "B" => $this->ShadowB, 1131 "Alpha" => $this->Shadowa, 1132 "Ticks" => $Ticks 1133 ] 1134 ); 1135 } 1136 1137 $this->Mask = []; 1138 $Color = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 1139 for ($i = 0; $i <= $Radius * 2; $i++) { 1140 $Slice = sqrt($Radius * $Radius - ($Radius - $i) * ($Radius - $i)); 1141 $XPos = floor($Slice); 1142 $YPos = $Y + $i - $Radius; 1143 $AAlias = $Slice - floor($Slice); 1144 1145 $this->Mask[$X - $XPos][$YPos] = true; 1146 $this->Mask[$X + $XPos][$YPos] = true; 1147 imageline($this->Picture, $X - $XPos, $YPos, $X + $XPos, $YPos, $Color); 1148 } 1149 if ($this->Antialias) { 1150 $this->drawCircle( 1151 $X, 1152 $Y, 1153 $Radius, 1154 $Radius, 1155 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks] 1156 ); 1157 } 1158 $this->Mask = []; 1159 1160 if ($BorderR != -1) { 1161 $this->drawCircle( 1162 $X, 1163 $Y, 1164 $Radius, 1165 $Radius, 1166 [ 1167 "R" => $BorderR, 1168 "G" => $BorderG, 1169 "B" => $BorderB, 1170 "Alpha" => $BorderAlpha, 1171 "Ticks" => $Ticks 1172 ] 1173 ); 1174 } 1175 $this->Shadow = $RestoreShadow; 1176 } 1177 1178 /** 1179 * Write text 1180 * @param int|float $X 1181 * @param int|float $Y 1182 * @param string $Text 1183 * @param array $Format 1184 * @return array 1185 */ 1186 public function drawText($X, $Y, $Text, array $Format = []) 1187 { 1188 $R = isset($Format["R"]) ? $Format["R"] : $this->FontColorR; 1189 $G = isset($Format["G"]) ? $Format["G"] : $this->FontColorG; 1190 $B = isset($Format["B"]) ? $Format["B"] : $this->FontColorB; 1191 $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; 1192 $Align = isset($Format["Align"]) ? $Format["Align"] : TEXT_ALIGN_BOTTOMLEFT; 1193 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->FontColorA; 1194 $FontName = isset($Format["FontName"]) ? $this->loadFont($Format["FontName"], 'fonts') : $this->FontName; 1195 $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; 1196 $ShowOrigine = isset($Format["ShowOrigine"]) ? $Format["ShowOrigine"] : false; 1197 $TOffset = isset($Format["TOffset"]) ? $Format["TOffset"] : 2; 1198 $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : false; 1199 $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 6; 1200 $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : false; 1201 $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 6; 1202 $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 255; 1203 $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 255; 1204 $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 255; 1205 $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 50; 1206 $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; 1207 $BoxBorderR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; 1208 $BoxBorderG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; 1209 $BoxBorderB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; 1210 $BoxBorderAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 50; 1211 $NoShadow = isset($Format["NoShadow"]) ? $Format["NoShadow"] : false; 1212 1213 $Shadow = $this->Shadow; 1214 if ($NoShadow) { 1215 $this->Shadow = false; 1216 } 1217 1218 if ($BoxSurrounding != "") { 1219 $BoxBorderR = $BoxR - $BoxSurrounding; 1220 $BoxBorderG = $BoxG - $BoxSurrounding; 1221 $BoxBorderB = $BoxB - $BoxSurrounding; 1222 $BoxBorderAlpha = $BoxAlpha; 1223 } 1224 1225 if ($ShowOrigine) { 1226 $MyMarkerSettings = [ 1227 "R" => 255, 1228 "G" => 0, 1229 "B" => 0, 1230 "BorderR" => 255, 1231 "BorderB" => 255, 1232 "BorderG" => 255, 1233 "Size" => 4 1234 ]; 1235 $this->drawRectangleMarker($X, $Y, $MyMarkerSettings); 1236 } 1237 1238 $TxtPos = $this->getTextBox($X, $Y, $FontName, $FontSize, $Angle, $Text); 1239 1240 if ($DrawBox && ($Angle == 0 || $Angle == 90 || $Angle == 180 || $Angle == 270)) { 1241 $T[0]["X"] = 0; 1242 $T[0]["Y"] = 0; 1243 $T[1]["X"] = 0; 1244 $T[1]["Y"] = 0; 1245 $T[2]["X"] = 0; 1246 $T[2]["Y"] = 0; 1247 $T[3]["X"] = 0; 1248 $T[3]["Y"] = 0; 1249 if ($Angle == 0) { 1250 $T[0]["X"] = -$TOffset; 1251 $T[0]["Y"] = $TOffset; 1252 $T[1]["X"] = $TOffset; 1253 $T[1]["Y"] = $TOffset; 1254 $T[2]["X"] = $TOffset; 1255 $T[2]["Y"] = -$TOffset; 1256 $T[3]["X"] = -$TOffset; 1257 $T[3]["Y"] = -$TOffset; 1258 } 1259 1260 $X1 = min($TxtPos[0]["X"], $TxtPos[1]["X"], $TxtPos[2]["X"], $TxtPos[3]["X"]) - $BorderOffset + 3; 1261 $Y1 = min($TxtPos[0]["Y"], $TxtPos[1]["Y"], $TxtPos[2]["Y"], $TxtPos[3]["Y"]) - $BorderOffset; 1262 $X2 = max($TxtPos[0]["X"], $TxtPos[1]["X"], $TxtPos[2]["X"], $TxtPos[3]["X"]) + $BorderOffset + 3; 1263 $Y2 = max($TxtPos[0]["Y"], $TxtPos[1]["Y"], $TxtPos[2]["Y"], $TxtPos[3]["Y"]) + $BorderOffset - 3; 1264 1265 $X1 = $X1 - $TxtPos[$Align]["X"] + $X + $T[0]["X"]; 1266 $Y1 = $Y1 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"]; 1267 $X2 = $X2 - $TxtPos[$Align]["X"] + $X + $T[0]["X"]; 1268 $Y2 = $Y2 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"]; 1269 1270 $Settings = [ 1271 "R" => $BoxR, 1272 "G" => $BoxG, 1273 "B" => $BoxB, 1274 "Alpha" => $BoxAlpha, 1275 "BorderR" => $BoxBorderR, 1276 "BorderG" => $BoxBorderG, 1277 "BorderB" => $BoxBorderB, 1278 "BorderAlpha" => $BoxBorderAlpha 1279 ]; 1280 1281 if ($BoxRounded) { 1282 $this->drawRoundedFilledRectangle($X1, $Y1, $X2, $Y2, $RoundedRadius, $Settings); 1283 } else { 1284 $this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Settings); 1285 } 1286 } 1287 1288 $X = $X - $TxtPos[$Align]["X"] + $X; 1289 $Y = $Y - $TxtPos[$Align]["Y"] + $Y; 1290 1291 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 1292 $C_ShadowColor = $this->allocateColor( 1293 $this->Picture, 1294 $this->ShadowR, 1295 $this->ShadowG, 1296 $this->ShadowB, 1297 $this->Shadowa 1298 ); 1299 imagettftext( 1300 $this->Picture, 1301 $FontSize, 1302 $Angle, 1303 $X + $this->ShadowX, 1304 $Y + $this->ShadowY, 1305 $C_ShadowColor, 1306 $FontName, 1307 $Text 1308 ); 1309 } 1310 1311 $C_TextColor = $this->AllocateColor($this->Picture, $R, $G, $B, $Alpha); 1312 imagettftext($this->Picture, $FontSize, $Angle, $X, $Y, $C_TextColor, $FontName, $Text); 1313 1314 $this->Shadow = $Shadow; 1315 1316 return $TxtPos; 1317 } 1318 1319 /** 1320 * Draw a gradient within a defined area 1321 * @param int $X1 1322 * @param int $Y1 1323 * @param int $X2 1324 * @param int $Y2 1325 * @param int $Direction 1326 * @param array $Format 1327 * @return null|integer 1328 */ 1329 public function drawGradientArea($X1, $Y1, $X2, $Y2, $Direction, array $Format = []) 1330 { 1331 $StartR = isset($Format["StartR"]) ? $Format["StartR"] : 90; 1332 $StartG = isset($Format["StartG"]) ? $Format["StartG"] : 90; 1333 $StartB = isset($Format["StartB"]) ? $Format["StartB"] : 90; 1334 $EndR = isset($Format["EndR"]) ? $Format["EndR"] : 0; 1335 $EndG = isset($Format["EndG"]) ? $Format["EndG"] : 0; 1336 $EndB = isset($Format["EndB"]) ? $Format["EndB"] : 0; 1337 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 1338 $Levels = isset($Format["Levels"]) ? $Format["Levels"] : null; 1339 1340 $Shadow = $this->Shadow; 1341 $this->Shadow = false; 1342 1343 if ($StartR == $EndR && $StartG == $EndG && $StartB == $EndB) { 1344 $this->drawFilledRectangle( 1345 $X1, 1346 $Y1, 1347 $X2, 1348 $Y2, 1349 ["R" => $StartR, "G" => $StartG, "B" => $StartB, "Alpha" => $Alpha] 1350 ); 1351 return 0; 1352 } 1353 1354 if ($Levels != null) { 1355 $EndR = $StartR + $Levels; 1356 $EndG = $StartG + $Levels; 1357 $EndB = $StartB + $Levels; 1358 } 1359 1360 if ($X1 > $X2) { 1361 list($X1, $X2) = [$X2, $X1]; 1362 } 1363 if ($Y1 > $Y2) { 1364 list($Y1, $Y2) = [$Y2, $Y1]; 1365 } 1366 1367 if ($Direction == DIRECTION_VERTICAL) { 1368 $Width = abs($Y2 - $Y1); 1369 } 1370 if ($Direction == DIRECTION_HORIZONTAL) { 1371 $Width = abs($X2 - $X1); 1372 } 1373 1374 $Step = max(abs($EndR - $StartR), abs($EndG - $StartG), abs($EndB - $StartB)); 1375 $StepSize = $Width / $Step; 1376 $RStep = ($EndR - $StartR) / $Step; 1377 $GStep = ($EndG - $StartG) / $Step; 1378 $BStep = ($EndB - $StartB) / $Step; 1379 1380 $R = $StartR; 1381 $G = $StartG; 1382 $B = $StartB; 1383 switch ($Direction) { 1384 case DIRECTION_VERTICAL: 1385 $StartY = $Y1; 1386 $EndY = floor($Y2) + 1; 1387 $LastY2 = $StartY; 1388 for ($i = 0; $i <= $Step; $i++) { 1389 $Y2 = floor($StartY + ($i * $StepSize)); 1390 1391 if ($Y2 > $EndY) { 1392 $Y2 = $EndY; 1393 } 1394 if (($Y1 != $Y2 && $Y1 < $Y2) || $Y2 == $EndY) { 1395 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]; 1396 $this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color); 1397 $LastY2 = max($LastY2, $Y2); 1398 $Y1 = $Y2 + 1; 1399 } 1400 $R = $R + $RStep; 1401 $G = $G + $GStep; 1402 $B = $B + $BStep; 1403 } 1404 if ($LastY2 < $EndY && isset($Color)) { 1405 for ($i = $LastY2 + 1; $i <= $EndY; $i++) { 1406 $this->drawLine($X1, $i, $X2, $i, $Color); 1407 } 1408 } 1409 break; 1410 1411 case DIRECTION_HORIZONTAL: 1412 $StartX = $X1; 1413 $EndX = $X2; 1414 for ($i = 0; $i <= $Step; $i++) { 1415 $X2 = floor($StartX + ($i * $StepSize)); 1416 1417 if ($X2 > $EndX) { 1418 $X2 = $EndX; 1419 } 1420 if (($X1 != $X2 && $X1 < $X2) || $X2 == $EndX) { 1421 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]; 1422 $this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color); 1423 $X1 = $X2 + 1; 1424 } 1425 $R = $R + $RStep; 1426 $G = $G + $GStep; 1427 $B = $B + $BStep; 1428 } 1429 if ($X2 < $EndX && isset($Color)) { 1430 $this->drawFilledRectangle($X2, $Y1, $EndX, $Y2, $Color); 1431 } 1432 break; 1433 } 1434 1435 $this->Shadow = $Shadow; 1436 } 1437 1438 /** 1439 * Draw an aliased pixel 1440 * @param int $X 1441 * @param int $Y 1442 * @param array $Format 1443 * @return int|null 1444 */ 1445 public function drawAntialiasPixel($X, $Y, array $Format = []) 1446 { 1447 $R = isset($Format["R"]) ? $Format["R"] : 0; 1448 $G = isset($Format["G"]) ? $Format["G"] : 0; 1449 $B = isset($Format["B"]) ? $Format["B"] : 0; 1450 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 1451 1452 if ($X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize) { 1453 return -1; 1454 } 1455 1456 if ($R < 0) { 1457 $R = 0; 1458 } if ($R > 255) { 1459 $R = 255; 1460 } 1461 if ($G < 0) { 1462 $G = 0; 1463 } if ($G > 255) { 1464 $G = 255; 1465 } 1466 if ($B < 0) { 1467 $B = 0; 1468 } if ($B > 255) { 1469 $B = 255; 1470 } 1471 1472 if (!$this->Antialias) { 1473 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 1474 $ShadowColor = $this->allocateColor( 1475 $this->Picture, 1476 $this->ShadowR, 1477 $this->ShadowG, 1478 $this->ShadowB, 1479 $this->Shadowa 1480 ); 1481 imagesetpixel($this->Picture, $X + $this->ShadowX, $Y + $this->ShadowY, $ShadowColor); 1482 } 1483 1484 $PlotColor = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 1485 imagesetpixel($this->Picture, $X, $Y, $PlotColor); 1486 1487 return 0; 1488 } 1489 1490 $Xi = floor($X); 1491 $Yi = floor($Y); 1492 1493 if ($Xi == $X && $Yi == $Y) { 1494 if ($Alpha == 100) { 1495 $this->drawAlphaPixel($X, $Y, 100, $R, $G, $B); 1496 } else { 1497 $this->drawAlphaPixel($X, $Y, $Alpha, $R, $G, $B); 1498 } 1499 } else { 1500 $Alpha1 = (((1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; 1501 if ($Alpha1 > $this->AntialiasQuality) { 1502 $this->drawAlphaPixel($Xi, $Yi, $Alpha1, $R, $G, $B); 1503 } 1504 1505 $Alpha2 = ((($X - floor($X)) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; 1506 if ($Alpha2 > $this->AntialiasQuality) { 1507 $this->drawAlphaPixel($Xi + 1, $Yi, $Alpha2, $R, $G, $B); 1508 } 1509 1510 $Alpha3 = (((1 - ($X - floor($X))) * ($Y - floor($Y)) * 100) / 100) * $Alpha; 1511 if ($Alpha3 > $this->AntialiasQuality) { 1512 $this->drawAlphaPixel($Xi, $Yi + 1, $Alpha3, $R, $G, $B); 1513 } 1514 1515 $Alpha4 = ((($X - floor($X)) * ($Y - floor($Y)) * 100) / 100) * $Alpha; 1516 if ($Alpha4 > $this->AntialiasQuality) { 1517 $this->drawAlphaPixel($Xi + 1, $Yi + 1, $Alpha4, $R, $G, $B); 1518 } 1519 } 1520 } 1521 1522 /** 1523 * Draw a semi-transparent pixel 1524 * @param int $X 1525 * @param int $Y 1526 * @param int $Alpha 1527 * @param int $R 1528 * @param int $G 1529 * @param int $B 1530 * @return null|integer 1531 */ 1532 public function drawAlphaPixel($X, $Y, $Alpha, $R, $G, $B) 1533 { 1534 if (isset($this->Mask[$X]) && isset($this->Mask[$X][$Y])) { 1535 return 0; 1536 } 1537 1538 if ($X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize) { 1539 return -1; 1540 } 1541 if ($R < 0) { 1542 $R = 0; 1543 } if ($R > 255) { 1544 $R = 255; 1545 } 1546 if ($G < 0) { 1547 $G = 0; 1548 } if ($G > 255) { 1549 $G = 255; 1550 } 1551 if ($B < 0) { 1552 $B = 0; 1553 } if ($B > 255) { 1554 $B = 255; 1555 } 1556 1557 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 1558 $AlphaFactor = floor(($Alpha / 100) * $this->Shadowa); 1559 $ShadowColor = $this->allocateColor( 1560 $this->Picture, 1561 $this->ShadowR, 1562 $this->ShadowG, 1563 $this->ShadowB, 1564 $AlphaFactor 1565 ); 1566 imagesetpixel($this->Picture, $X + $this->ShadowX, $Y + $this->ShadowY, $ShadowColor); 1567 } 1568 1569 $C_Aliased = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 1570 imagesetpixel($this->Picture, $X, $Y, $C_Aliased); 1571 } 1572 1573 /** 1574 * Load a PNG file and draw it over the chart 1575 * @param int $X 1576 * @param int $Y 1577 * @param string $FileName 1578 */ 1579 public function drawFromPNG($X, $Y, $FileName) 1580 { 1581 $this->drawFromPicture(1, $FileName, $X, $Y); 1582 } 1583 1584 /** 1585 * Load a GIF file and draw it over the chart 1586 * @param int $X 1587 * @param int $Y 1588 * @param string $FileName 1589 */ 1590 public function drawFromGIF($X, $Y, $FileName) 1591 { 1592 $this->drawFromPicture(2, $FileName, $X, $Y); 1593 } 1594 1595 /** 1596 * Load a JPEG file and draw it over the chart 1597 * @param int $X 1598 * @param int $Y 1599 * @param string $FileName 1600 */ 1601 public function drawFromJPG($X, $Y, $FileName) 1602 { 1603 $this->drawFromPicture(3, $FileName, $X, $Y); 1604 } 1605 1606 /** 1607 * Generic loader public function for external pictures 1608 * @param int $PicType 1609 * @param string $FileName 1610 * @param int $X 1611 * @param int $Y 1612 * @return null|integer 1613 */ 1614 public function drawFromPicture($PicType, $FileName, $X, $Y) 1615 { 1616 if (file_exists($FileName)) { 1617 list($Width, $Height) = $this->getPicInfo($FileName); 1618 1619 if ($PicType == 1) { 1620 $Raster = imagecreatefrompng($FileName); 1621 } elseif ($PicType == 2) { 1622 $Raster = imagecreatefromgif($FileName); 1623 } elseif ($PicType == 3) { 1624 $Raster = imagecreatefromjpeg($FileName); 1625 } else { 1626 return 0; 1627 } 1628 1629 $RestoreShadow = $this->Shadow; 1630 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 1631 $this->Shadow = false; 1632 if ($PicType == 3) { 1633 $this->drawFilledRectangle( 1634 $X + $this->ShadowX, 1635 $Y + $this->ShadowY, 1636 $X + $Width + $this->ShadowX, 1637 $Y + $Height + $this->ShadowY, 1638 [ 1639 "R" => $this->ShadowR, 1640 "G" => $this->ShadowG, 1641 "B" => $this->ShadowB, 1642 "Alpha" => $this->Shadowa 1643 ] 1644 ); 1645 } else { 1646 $TranparentID = imagecolortransparent($Raster); 1647 for ($Xc = 0; $Xc <= $Width - 1; $Xc++) { 1648 for ($Yc = 0; $Yc <= $Height - 1; $Yc++) { 1649 $RGBa = imagecolorat($Raster, $Xc, $Yc); 1650 $Values = imagecolorsforindex($Raster, $RGBa); 1651 if ($Values["alpha"] < 120) { 1652 $AlphaFactor = floor( 1653 ($this->Shadowa / 100) * ((100 / 127) * (127 - $Values["alpha"])) 1654 ); 1655 $this->drawAlphaPixel( 1656 $X + $Xc + $this->ShadowX, 1657 $Y + $Yc + $this->ShadowY, 1658 $AlphaFactor, 1659 $this->ShadowR, 1660 $this->ShadowG, 1661 $this->ShadowB 1662 ); 1663 } 1664 } 1665 } 1666 } 1667 } 1668 $this->Shadow = $RestoreShadow; 1669 1670 imagecopy($this->Picture, $Raster, $X, $Y, 0, 0, $Width, $Height); 1671 imagedestroy($Raster); 1672 } 1673 } 1674 1675 /** 1676 * Draw an arrow 1677 * @param int $X1 1678 * @param int $Y1 1679 * @param int $X2 1680 * @param int $Y2 1681 * @param array $Format 1682 */ 1683 public function drawArrow($X1, $Y1, $X2, $Y2, array $Format = []) 1684 { 1685 $FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0; 1686 $FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0; 1687 $FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0; 1688 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $FillR; 1689 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $FillG; 1690 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $FillB; 1691 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 1692 $Size = isset($Format["Size"]) ? $Format["Size"] : 10; 1693 $Ratio = isset($Format["Ratio"]) ? $Format["Ratio"] : .5; 1694 $TwoHeads = isset($Format["TwoHeads"]) ? $Format["TwoHeads"] : false; 1695 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : false; 1696 1697 /* Calculate the line angle */ 1698 $Angle = $this->getAngle($X1, $Y1, $X2, $Y2); 1699 1700 /* Override Shadow support, this will be managed internally */ 1701 $RestoreShadow = $this->Shadow; 1702 if ($this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0) { 1703 $this->Shadow = false; 1704 $this->drawArrow( 1705 $X1 + $this->ShadowX, 1706 $Y1 + $this->ShadowY, 1707 $X2 + $this->ShadowX, 1708 $Y2 + $this->ShadowY, 1709 [ 1710 "FillR" => $this->ShadowR, 1711 "FillG" => $this->ShadowG, 1712 "FillB" => $this->ShadowB, 1713 "Alpha" => $this->Shadowa, 1714 "Size" => $Size, 1715 "Ratio" => $Ratio, 1716 "TwoHeads" => $TwoHeads, 1717 "Ticks" => $Ticks 1718 ] 1719 ); 1720 } 1721 1722 /* Draw the 1st Head */ 1723 $TailX = cos(($Angle - 180) * PI / 180) * $Size + $X2; 1724 $TailY = sin(($Angle - 180) * PI / 180) * $Size + $Y2; 1725 1726 $Points = []; 1727 $Points[] = $X2; 1728 $Points[] = $Y2; 1729 $Points[] = cos(($Angle - 90) * PI / 180) * $Size * $Ratio + $TailX; 1730 $Points[] = sin(($Angle - 90) * PI / 180) * $Size * $Ratio + $TailY; 1731 $Points[] = cos(($Angle - 270) * PI / 180) * $Size * $Ratio + $TailX; 1732 $Points[] = sin(($Angle - 270) * PI / 180) * $Size * $Ratio + $TailY; 1733 $Points[] = $X2; 1734 $Points[] = $Y2; 1735 1736 /* Visual correction */ 1737 if ($Angle == 180 || $Angle == 360) { 1738 $Points[4] = $Points[2]; 1739 } 1740 if ($Angle == 90 || $Angle == 270) { 1741 $Points[5] = $Points[3]; 1742 } 1743 1744 $ArrowColor = $this->allocateColor($this->Picture, $FillR, $FillG, $FillB, $Alpha); 1745 ImageFilledPolygon($this->Picture, $Points, 4, $ArrowColor); 1746 1747 $this->drawLine( 1748 $Points[0], 1749 $Points[1], 1750 $Points[2], 1751 $Points[3], 1752 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 1753 ); 1754 $this->drawLine( 1755 $Points[2], 1756 $Points[3], 1757 $Points[4], 1758 $Points[5], 1759 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 1760 ); 1761 $this->drawLine( 1762 $Points[0], 1763 $Points[1], 1764 $Points[4], 1765 $Points[5], 1766 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 1767 ); 1768 1769 /* Draw the second head */ 1770 if ($TwoHeads) { 1771 $Angle = $this->getAngle($X2, $Y2, $X1, $Y1); 1772 1773 $TailX2 = cos(($Angle - 180) * PI / 180) * $Size + $X1; 1774 $TailY2 = sin(($Angle - 180) * PI / 180) * $Size + $Y1; 1775 1776 $Points = []; 1777 $Points[] = $X1; 1778 $Points[] = $Y1; 1779 $Points[] = cos(($Angle - 90) * PI / 180) * $Size * $Ratio + $TailX2; 1780 $Points[] = sin(($Angle - 90) * PI / 180) * $Size * $Ratio + $TailY2; 1781 $Points[] = cos(($Angle - 270) * PI / 180) * $Size * $Ratio + $TailX2; 1782 $Points[] = sin(($Angle - 270) * PI / 180) * $Size * $Ratio + $TailY2; 1783 $Points[] = $X1; 1784 $Points[] = $Y1; 1785 1786 /* Visual correction */ 1787 if ($Angle == 180 || $Angle == 360) { 1788 $Points[4] = $Points[2]; 1789 } 1790 if ($Angle == 90 || $Angle == 270) { 1791 $Points[5] = $Points[3]; 1792 } 1793 1794 $ArrowColor = $this->allocateColor($this->Picture, $FillR, $FillG, $FillB, $Alpha); 1795 ImageFilledPolygon($this->Picture, $Points, 4, $ArrowColor); 1796 1797 $this->drawLine( 1798 $Points[0], 1799 $Points[1], 1800 $Points[2], 1801 $Points[3], 1802 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 1803 ); 1804 $this->drawLine( 1805 $Points[2], 1806 $Points[3], 1807 $Points[4], 1808 $Points[5], 1809 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 1810 ); 1811 $this->drawLine( 1812 $Points[0], 1813 $Points[1], 1814 $Points[4], 1815 $Points[5], 1816 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 1817 ); 1818 1819 $this->drawLine( 1820 $TailX, 1821 $TailY, 1822 $TailX2, 1823 $TailY2, 1824 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha, "Ticks" => $Ticks] 1825 ); 1826 } else { 1827 $this->drawLine( 1828 $X1, 1829 $Y1, 1830 $TailX, 1831 $TailY, 1832 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha, "Ticks" => $Ticks] 1833 ); 1834 } 1835 /* Re-enable shadows */ 1836 $this->Shadow = $RestoreShadow; 1837 } 1838 1839 /** 1840 * Draw a label with associated arrow 1841 * @param int $X1 1842 * @param int $Y1 1843 * @param string $Text 1844 * @param array $Format 1845 */ 1846 public function drawArrowLabel($X1, $Y1, $Text, array $Format = []) 1847 { 1848 $FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0; 1849 $FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0; 1850 $FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0; 1851 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $FillR; 1852 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $FillG; 1853 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $FillB; 1854 $FontName = isset($Format["FontName"]) ? $this->loadFont($Format["FontName"], 'fonts') : $this->FontName; 1855 $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; 1856 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 1857 $Length = isset($Format["Length"]) ? $Format["Length"] : 50; 1858 $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 315; 1859 $Size = isset($Format["Size"]) ? $Format["Size"] : 10; 1860 $Position = isset($Format["Position"]) ? $Format["Position"] : POSITION_TOP; 1861 $RoundPos = isset($Format["RoundPos"]) ? $Format["RoundPos"] : false; 1862 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 1863 1864 $Angle = $Angle % 360; 1865 1866 $X2 = sin(($Angle + 180) * PI / 180) * $Length + $X1; 1867 $Y2 = cos(($Angle + 180) * PI / 180) * $Length + $Y1; 1868 1869 if ($RoundPos && $Angle > 0 && $Angle < 180) { 1870 $Y2 = ceil($Y2); 1871 } 1872 if ($RoundPos && $Angle > 180) { 1873 $Y2 = floor($Y2); 1874 } 1875 1876 $this->drawArrow($X2, $Y2, $X1, $Y1, $Format); 1877 1878 $Size = imagettfbbox($FontSize, 0, $FontName, $Text); 1879 $TxtWidth = max(abs($Size[2] - $Size[0]), abs($Size[0] - $Size[6])); 1880 1881 if ($Angle > 0 && $Angle < 180) { 1882 $this->drawLine( 1883 $X2, 1884 $Y2, 1885 $X2 - $TxtWidth, 1886 $Y2, 1887 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha, "Ticks" => $Ticks] 1888 ); 1889 if ($Position == POSITION_TOP) { 1890 $this->drawText( 1891 $X2, 1892 $Y2 - 2, 1893 $Text, 1894 [ 1895 "R" => $BorderR, 1896 "G" => $BorderG, 1897 "B" => $BorderB, 1898 "Alpha" => $Alpha, 1899 "Align" => TEXT_ALIGN_BOTTOMRIGHT 1900 ] 1901 ); 1902 } else { 1903 $this->drawText( 1904 $X2, 1905 $Y2 + 4, 1906 $Text, 1907 [ 1908 "R" => $BorderR, 1909 "G" => $BorderG, 1910 "B" => $BorderB, 1911 "Alpha" => $Alpha, 1912 "Align" => TEXT_ALIGN_TOPRIGHT 1913 ] 1914 ); 1915 } 1916 } else { 1917 $this->drawLine( 1918 $X2, 1919 $Y2, 1920 $X2 + $TxtWidth, 1921 $Y2, 1922 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha, "Ticks" => $Ticks] 1923 ); 1924 if ($Position == POSITION_TOP) { 1925 $this->drawText( 1926 $X2, 1927 $Y2 - 2, 1928 $Text, 1929 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $Alpha] 1930 ); 1931 } else { 1932 $this->drawText( 1933 $X2, 1934 $Y2 + 4, 1935 $Text, 1936 [ 1937 "R" => $BorderR, 1938 "G" => $BorderG, 1939 "B" => $BorderB, 1940 "Alpha" => $Alpha, 1941 "Align" => TEXT_ALIGN_TOPLEFT 1942 ] 1943 ); 1944 } 1945 } 1946 } 1947 1948 /** 1949 * Draw a progress bar filled with specified % 1950 * @param int $X 1951 * @param int $Y 1952 * @param int|float $Percent 1953 * @param array $Format 1954 */ 1955 public function drawProgress($X, $Y, $Percent, array $Format = []) 1956 { 1957 if ($Percent > 100) { 1958 $Percent = 100; 1959 } 1960 if ($Percent < 0) { 1961 $Percent = 0; 1962 } 1963 1964 $Width = isset($Format["Width"]) ? $Format["Width"] : 200; 1965 $Height = isset($Format["Height"]) ? $Format["Height"] : 20; 1966 $Orientation = isset($Format["Orientation"]) ? $Format["Orientation"] : ORIENTATION_HORIZONTAL; 1967 $ShowLabel = isset($Format["ShowLabel"]) ? $Format["ShowLabel"] : false; 1968 $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : LABEL_POS_INSIDE; 1969 $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 10; 1970 $R = isset($Format["R"]) ? $Format["R"] : 130; 1971 $G = isset($Format["G"]) ? $Format["G"] : 130; 1972 $B = isset($Format["B"]) ? $Format["B"] : 130; 1973 $RFade = isset($Format["RFade"]) ? $Format["RFade"] : -1; 1974 $GFade = isset($Format["GFade"]) ? $Format["GFade"] : -1; 1975 $BFade = isset($Format["BFade"]) ? $Format["BFade"] : -1; 1976 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; 1977 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; 1978 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; 1979 $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 0; 1980 $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 0; 1981 $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 0; 1982 $BoxBackR = isset($Format["BoxBackR"]) ? $Format["BoxBackR"] : 255; 1983 $BoxBackG = isset($Format["BoxBackG"]) ? $Format["BoxBackG"] : 255; 1984 $BoxBackB = isset($Format["BoxBackB"]) ? $Format["BoxBackB"] : 255; 1985 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 1986 $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : null; 1987 $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : false; 1988 1989 if ($RFade != -1 && $GFade != -1 && $BFade != -1) { 1990 $RFade = (($RFade - $R) / 100) * $Percent + $R; 1991 $GFade = (($GFade - $G) / 100) * $Percent + $G; 1992 $BFade = (($BFade - $B) / 100) * $Percent + $B; 1993 } 1994 1995 if ($Surrounding != null) { 1996 $BorderR = $R + $Surrounding; 1997 $BorderG = $G + $Surrounding; 1998 $BorderB = $B + $Surrounding; 1999 } 2000 if ($BoxSurrounding != null) { 2001 $BoxBorderR = $BoxBackR + $Surrounding; 2002 $BoxBorderG = $BoxBackG + $Surrounding; 2003 $BoxBorderB = $BoxBackB + $Surrounding; 2004 } 2005 2006 if ($Orientation == ORIENTATION_VERTICAL) { 2007 $InnerHeight = (($Height - 2) / 100) * $Percent; 2008 $this->drawFilledRectangle( 2009 $X, 2010 $Y, 2011 $X + $Width, 2012 $Y - $Height, 2013 [ 2014 "R" => $BoxBackR, 2015 "G" => $BoxBackG, 2016 "B" => $BoxBackB, 2017 "BorderR" => $BoxBorderR, 2018 "BorderG" => $BoxBorderG, 2019 "BorderB" => $BoxBorderB, 2020 "NoAngle" => $NoAngle 2021 ] 2022 ); 2023 2024 $RestoreShadow = $this->Shadow; 2025 $this->Shadow = false; 2026 if ($RFade != -1 && $GFade != -1 && $BFade != -1) { 2027 $GradientOptions = [ 2028 "StartR" => $RFade, 2029 "StartG" => $GFade, 2030 "StartB" => $BFade, 2031 "EndR" => $R, 2032 "EndG" => $G, 2033 "EndB" => $B 2034 ]; 2035 $this->drawGradientArea( 2036 $X + 1, 2037 $Y - 1, 2038 $X + $Width - 1, 2039 $Y - $InnerHeight, 2040 DIRECTION_VERTICAL, 2041 $GradientOptions 2042 ); 2043 2044 if ($Surrounding) { 2045 $this->drawRectangle( 2046 $X + 1, 2047 $Y - 1, 2048 $X + $Width - 1, 2049 $Y - $InnerHeight, 2050 ["R" => 255, "G" => 255, "B" => 255, "Alpha" => $Surrounding] 2051 ); 2052 } 2053 } else { 2054 $this->drawFilledRectangle( 2055 $X + 1, 2056 $Y - 1, 2057 $X + $Width - 1, 2058 $Y - $InnerHeight, 2059 [ 2060 "R" => $R, 2061 "G" => $G, 2062 "B" => $B, 2063 "BorderR" => $BorderR, 2064 "BorderG" => $BorderG, 2065 "BorderB" => $BorderB 2066 ] 2067 ); 2068 } 2069 $this->Shadow = $RestoreShadow; 2070 2071 if ($ShowLabel && $LabelPos == LABEL_POS_BOTTOM) { 2072 $this->drawText( 2073 $X + ($Width / 2), 2074 $Y + $Margin, 2075 $Percent . "%", 2076 ["Align" => TEXT_ALIGN_TOPMIDDLE] 2077 ); 2078 } 2079 if ($ShowLabel && $LabelPos == LABEL_POS_TOP) { 2080 $this->drawText( 2081 $X + ($Width / 2), 2082 $Y - $Height - $Margin, 2083 $Percent . "%", 2084 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE] 2085 ); 2086 } 2087 if ($ShowLabel && $LabelPos == LABEL_POS_INSIDE) { 2088 $this->drawText( 2089 $X + ($Width / 2), 2090 $Y - $InnerHeight - $Margin, 2091 $Percent . "%", 2092 ["Align" => TEXT_ALIGN_MIDDLELEFT, "Angle" => 90] 2093 ); 2094 } 2095 if ($ShowLabel && $LabelPos == LABEL_POS_CENTER) { 2096 $this->drawText( 2097 $X + ($Width / 2), 2098 $Y - ($Height / 2), 2099 $Percent . "%", 2100 ["Align" => TEXT_ALIGN_MIDDLEMIDDLE, "Angle" => 90] 2101 ); 2102 } 2103 } else { 2104 if ($Percent == 100) { 2105 $InnerWidth = $Width - 1; 2106 } else { 2107 $InnerWidth = (($Width - 2) / 100) * $Percent; 2108 } 2109 $this->drawFilledRectangle( 2110 $X, 2111 $Y, 2112 $X + $Width, 2113 $Y + $Height, 2114 [ 2115 "R" => $BoxBackR, 2116 "G" => $BoxBackG, 2117 "B" => $BoxBackB, 2118 "BorderR" => $BoxBorderR, 2119 "BorderG" => $BoxBorderG, 2120 "BorderB" => $BoxBorderB, 2121 "NoAngle" => $NoAngle 2122 ] 2123 ); 2124 2125 $RestoreShadow = $this->Shadow; 2126 $this->Shadow = false; 2127 if ($RFade != -1 && $GFade != -1 && $BFade != -1) { 2128 $GradientOptions = [ 2129 "StartR" => $R, 2130 "StartG" => $G, 2131 "StartB" => $B, 2132 "EndR" => $RFade, 2133 "EndG" => $GFade, 2134 "EndB" => $BFade 2135 ]; 2136 $this->drawGradientArea( 2137 $X + 1, 2138 $Y + 1, 2139 $X + $InnerWidth, 2140 $Y + $Height - 1, 2141 DIRECTION_HORIZONTAL, 2142 $GradientOptions 2143 ); 2144 2145 if ($Surrounding) { 2146 $this->drawRectangle( 2147 $X + 1, 2148 $Y + 1, 2149 $X + $InnerWidth, 2150 $Y + $Height - 1, 2151 ["R" => 255, "G" => 255, "B" => 255, "Alpha" => $Surrounding] 2152 ); 2153 } 2154 } else { 2155 $this->drawFilledRectangle( 2156 $X + 1, 2157 $Y + 1, 2158 $X + $InnerWidth, 2159 $Y + $Height - 1, 2160 [ 2161 "R" => $R, 2162 "G" => $G, 2163 "B" => $B, 2164 "BorderR" => $BorderR, "BorderG" => $BorderG, "BorderB" => $BorderB 2165 ] 2166 ); 2167 } 2168 $this->Shadow = $RestoreShadow; 2169 2170 if ($ShowLabel && $LabelPos == LABEL_POS_LEFT) { 2171 $this->drawText( 2172 $X - $Margin, 2173 $Y + ($Height / 2), 2174 $Percent . "%", 2175 ["Align" => TEXT_ALIGN_MIDDLERIGHT] 2176 ); 2177 } 2178 if ($ShowLabel && $LabelPos == LABEL_POS_RIGHT) { 2179 $this->drawText( 2180 $X + $Width + $Margin, 2181 $Y + ($Height / 2), 2182 $Percent . "%", 2183 ["Align" => TEXT_ALIGN_MIDDLELEFT] 2184 ); 2185 } 2186 if ($ShowLabel && $LabelPos == LABEL_POS_CENTER) { 2187 $this->drawText( 2188 $X + ($Width / 2), 2189 $Y + ($Height / 2), 2190 $Percent . "%", 2191 ["Align" => TEXT_ALIGN_MIDDLEMIDDLE] 2192 ); 2193 } 2194 if ($ShowLabel && $LabelPos == LABEL_POS_INSIDE) { 2195 $this->drawText( 2196 $X + $InnerWidth + $Margin, 2197 $Y + ($Height / 2), 2198 $Percent . "%", 2199 ["Align" => TEXT_ALIGN_MIDDLELEFT] 2200 ); 2201 } 2202 } 2203 } 2204 2205 /** 2206 * Draw the legend of the active series 2207 * @param int $X 2208 * @param int $Y 2209 * @param array $Format 2210 */ 2211 public function drawLegend($X, $Y, array $Format = []) 2212 { 2213 $Family = isset($Format["Family"]) ? $Format["Family"] : LEGEND_FAMILY_BOX; 2214 $FontName = isset($Format["FontName"]) ? $this->loadFont($Format["FontName"], 'fonts') : $this->FontName; 2215 $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; 2216 $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->FontColorR; 2217 $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->FontColorG; 2218 $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->FontColorB; 2219 $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5; 2220 $BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5; 2221 $IconAreaWidth = isset($Format["IconAreaWidth"]) ? $Format["IconAreaWidth"] : $BoxWidth; 2222 $IconAreaHeight = isset($Format["IconAreaHeight"]) ? $Format["IconAreaHeight"] : $BoxHeight; 2223 $XSpacing = isset($Format["XSpacing"]) ? $Format["XSpacing"] : 5; 2224 $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; 2225 $R = isset($Format["R"]) ? $Format["R"] : 200; 2226 $G = isset($Format["G"]) ? $Format["G"] : 200; 2227 $B = isset($Format["B"]) ? $Format["B"] : 200; 2228 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 2229 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; 2230 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; 2231 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; 2232 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 2233 $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; 2234 $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; 2235 2236 if ($Surrounding != null) { 2237 $BorderR = $R + $Surrounding; 2238 $BorderG = $G + $Surrounding; 2239 $BorderB = $B + $Surrounding; 2240 } 2241 2242 $Data = $this->DataSet->getData(); 2243 2244 foreach ($Data["Series"] as $SerieName => $Serie) { 2245 if ($Serie["isDrawable"] == true 2246 && $SerieName != $Data["Abscissa"] 2247 && isset($Serie["Picture"]) 2248 ) { 2249 list($PicWidth, $PicHeight) = $this->getPicInfo($Serie["Picture"]); 2250 if ($IconAreaWidth < $PicWidth) { 2251 $IconAreaWidth = $PicWidth; 2252 } 2253 if ($IconAreaHeight < $PicHeight) { 2254 $IconAreaHeight = $PicHeight; 2255 } 2256 } 2257 } 2258 2259 $YStep = max($this->FontSize, $IconAreaHeight) + 5; 2260 $XStep = $IconAreaWidth + 5; 2261 $XStep = $XSpacing; 2262 2263 $Boundaries = []; 2264 $Boundaries["L"] = $X; 2265 $Boundaries["T"] = $Y; 2266 $Boundaries["R"] = 0; 2267 $Boundaries["B"] = 0; 2268 $vY = $Y; 2269 $vX = $X; 2270 foreach ($Data["Series"] as $SerieName => $Serie) { 2271 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 2272 if ($Mode == LEGEND_VERTICAL) { 2273 $BoxArray = $this->getTextBox( 2274 $vX + $IconAreaWidth + 4, 2275 $vY + $IconAreaHeight / 2, 2276 $FontName, 2277 $FontSize, 2278 0, 2279 $Serie["Description"] 2280 ); 2281 2282 if ($Boundaries["T"] > $BoxArray[2]["Y"] + $IconAreaHeight / 2) { 2283 $Boundaries["T"] = $BoxArray[2]["Y"] + $IconAreaHeight / 2; 2284 } 2285 if ($Boundaries["R"] < $BoxArray[1]["X"] + 2) { 2286 $Boundaries["R"] = $BoxArray[1]["X"] + 2; 2287 } 2288 if ($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2) { 2289 $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2; 2290 } 2291 2292 $Lines = preg_split("/\n/", $Serie["Description"]); 2293 $vY = $vY + max($this->FontSize * count($Lines), $IconAreaHeight) + 5; 2294 } elseif ($Mode == LEGEND_HORIZONTAL) { 2295 $Lines = preg_split("/\n/", $Serie["Description"]); 2296 $Width = []; 2297 foreach ($Lines as $Key => $Value) { 2298 $BoxArray = $this->getTextBox( 2299 $vX + $IconAreaWidth + 6, 2300 $Y + $IconAreaHeight / 2 + (($this->FontSize + 3) * $Key), 2301 $FontName, 2302 $FontSize, 2303 0, 2304 $Value 2305 ); 2306 2307 if ($Boundaries["T"] > $BoxArray[2]["Y"] + $IconAreaHeight / 2) { 2308 $Boundaries["T"] = $BoxArray[2]["Y"] + $IconAreaHeight / 2; 2309 } 2310 if ($Boundaries["R"] < $BoxArray[1]["X"] + 2) { 2311 $Boundaries["R"] = $BoxArray[1]["X"] + 2; 2312 } 2313 if ($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2) { 2314 $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2; 2315 } 2316 2317 $Width[] = $BoxArray[1]["X"]; 2318 } 2319 2320 $vX = max($Width) + $XStep; 2321 } 2322 } 2323 } 2324 $vY = $vY - $YStep; 2325 $vX = $vX - $XStep; 2326 2327 $TopOffset = $Y - $Boundaries["T"]; 2328 if ($Boundaries["B"] - ($vY + $IconAreaHeight) < $TopOffset) { 2329 $Boundaries["B"] = $vY + $IconAreaHeight + $TopOffset; 2330 } 2331 2332 if ($Style == LEGEND_ROUND) { 2333 $this->drawRoundedFilledRectangle( 2334 $Boundaries["L"] - $Margin, 2335 $Boundaries["T"] - $Margin, 2336 $Boundaries["R"] + $Margin, 2337 $Boundaries["B"] + $Margin, 2338 $Margin, 2339 [ 2340 "R" => $R, 2341 "G" => $G, 2342 "B" => $B, 2343 "Alpha" => $Alpha, 2344 "BorderR" => $BorderR, 2345 "BorderG" => $BorderG, 2346 "BorderB" => $BorderB 2347 ] 2348 ); 2349 } elseif ($Style == LEGEND_BOX) { 2350 $this->drawFilledRectangle( 2351 $Boundaries["L"] - $Margin, 2352 $Boundaries["T"] - $Margin, 2353 $Boundaries["R"] + $Margin, 2354 $Boundaries["B"] + $Margin, 2355 [ 2356 "R" => $R, 2357 "G" => $G, 2358 "B" => $B, 2359 "Alpha" => $Alpha, 2360 "BorderR" => $BorderR, 2361 "BorderG" => $BorderG, 2362 "BorderB" => $BorderB 2363 ] 2364 ); 2365 } 2366 2367 $RestoreShadow = $this->Shadow; 2368 $this->Shadow = false; 2369 foreach ($Data["Series"] as $SerieName => $Serie) { 2370 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 2371 $R = $Serie["Color"]["R"]; 2372 $G = $Serie["Color"]["G"]; 2373 $B = $Serie["Color"]["B"]; 2374 $Ticks = $Serie["Ticks"]; 2375 $Weight = $Serie["Weight"]; 2376 2377 if (isset($Serie["Picture"])) { 2378 $Picture = $Serie["Picture"]; 2379 list($PicWidth, $PicHeight) = $this->getPicInfo($Picture); 2380 $PicX = $X + $IconAreaWidth / 2; 2381 $PicY = $Y + $IconAreaHeight / 2; 2382 2383 $this->drawFromPNG($PicX - $PicWidth / 2, $PicY - $PicHeight / 2, $Picture); 2384 } else { 2385 if ($Family == LEGEND_FAMILY_BOX) { 2386 $XOffset = 0; 2387 if ($BoxWidth != $IconAreaWidth) { 2388 $XOffset = floor(($IconAreaWidth - $BoxWidth) / 2); 2389 } 2390 $YOffset = 0; 2391 if ($BoxHeight != $IconAreaHeight) { 2392 $YOffset = floor(($IconAreaHeight - $BoxHeight) / 2); 2393 } 2394 2395 $this->drawFilledRectangle( 2396 $X + 1 + $XOffset, 2397 $Y + 1 + $YOffset, 2398 $X + $BoxWidth + $XOffset + 1, 2399 $Y + $BoxHeight + 1 + $YOffset, 2400 ["R" => 0, "G" => 0, "B" => 0, "Alpha" => 20] 2401 ); 2402 $this->drawFilledRectangle( 2403 $X + $XOffset, 2404 $Y + $YOffset, 2405 $X + $BoxWidth + $XOffset, 2406 $Y + $BoxHeight + $YOffset, 2407 ["R" => $R, "G" => $G, "B" => $B, "Surrounding" => 20] 2408 ); 2409 } elseif ($Family == LEGEND_FAMILY_CIRCLE) { 2410 $this->drawFilledCircle( 2411 $X + 1 + $IconAreaWidth / 2, 2412 $Y + 1 + $IconAreaHeight / 2, 2413 min($IconAreaHeight / 2, $IconAreaWidth / 2), 2414 ["R" => 0, "G" => 0, "B" => 0, "Alpha" => 20] 2415 ); 2416 $this->drawFilledCircle( 2417 $X + $IconAreaWidth / 2, 2418 $Y + $IconAreaHeight / 2, 2419 min($IconAreaHeight / 2, $IconAreaWidth / 2), 2420 ["R" => $R, "G" => $G, "B" => $B, "Surrounding" => 20] 2421 ); 2422 } elseif ($Family == LEGEND_FAMILY_LINE) { 2423 $this->drawLine( 2424 $X + 1, 2425 $Y + 1 + $IconAreaHeight / 2, 2426 $X + 1 + $IconAreaWidth, 2427 $Y + 1 + $IconAreaHeight / 2, 2428 ["R" => 0, "G" => 0, "B" => 0, "Alpha" => 20, "Ticks" => $Ticks, "Weight" => $Weight] 2429 ); 2430 $this->drawLine( 2431 $X, 2432 $Y + $IconAreaHeight / 2, 2433 $X + $IconAreaWidth, 2434 $Y + $IconAreaHeight / 2, 2435 ["R" => $R, "G" => $G, "B" => $B, "Ticks" => $Ticks, "Weight" => $Weight] 2436 ); 2437 } 2438 } 2439 2440 if ($Mode == LEGEND_VERTICAL) { 2441 $Lines = preg_split("/\n/", $Serie["Description"]); 2442 foreach ($Lines as $Key => $Value) { 2443 $this->drawText( 2444 $X + $IconAreaWidth + 4, 2445 $Y + $IconAreaHeight / 2 + (($this->FontSize + 3) * $Key), 2446 $Value, 2447 [ 2448 "R" => $FontR, 2449 "G" => $FontG, 2450 "B" => $FontB, 2451 "Align" => TEXT_ALIGN_MIDDLELEFT, 2452 "FontSize" => $FontSize, 2453 "FontName" => $FontName 2454 ] 2455 ); 2456 } 2457 $Y = $Y + max($this->FontSize * count($Lines), $IconAreaHeight) + 5; 2458 } elseif ($Mode == LEGEND_HORIZONTAL) { 2459 $Lines = preg_split("/\n/", $Serie["Description"]); 2460 $Width = []; 2461 foreach ($Lines as $Key => $Value) { 2462 $BoxArray = $this->drawText( 2463 $X + $IconAreaWidth + 4, 2464 $Y + $IconAreaHeight / 2 + (($this->FontSize + 3) * $Key), 2465 $Value, 2466 [ 2467 "R" => $FontR, 2468 "G" => $FontG, 2469 "B" => $FontB, 2470 "Align" => TEXT_ALIGN_MIDDLELEFT, 2471 "FontSize" => $FontSize, 2472 "FontName" => $FontName 2473 ] 2474 ); 2475 $Width[] = $BoxArray[1]["X"]; 2476 } 2477 $X = max($Width) + 2 + $XStep; 2478 } 2479 } 2480 } 2481 2482 2483 $this->Shadow = $RestoreShadow; 2484 } 2485 2486 /** 2487 * @param array $Format 2488 * @throws Exception 2489 */ 2490 public function drawScale(array $Format = []) 2491 { 2492 $FloatingOffset = 0; 2493 $Pos = isset($Format["Pos"]) ? $Format["Pos"] : SCALE_POS_LEFTRIGHT; 2494 $Floating = isset($Format["Floating"]) ? $Format["Floating"] : false; 2495 $Mode = isset($Format["Mode"]) ? $Format["Mode"] : SCALE_MODE_FLOATING; 2496 $RemoveXAxis = isset($Format["RemoveXAxis"]) ? $Format["RemoveXAxis"] : false; 2497 $RemoveYAxis = isset($Format["RemoveYAxis"]) ? $Format["RemoveYAxis"] : false; 2498 $RemoveYAxiValues = isset($Format["RemoveYAxisValues"]) ? $Format["RemoveYAxisValues"] : false; 2499 $MinDivHeight = isset($Format["MinDivHeight"]) ? $Format["MinDivHeight"] : 20; 2500 $Factors = isset($Format["Factors"]) ? $Format["Factors"] : [1, 2, 5]; 2501 $ManualScale = isset($Format["ManualScale"]) 2502 ? $Format["ManualScale"] : ["0" => ["Min" => -100, "Max" => 100]] 2503 ; 2504 $XMargin = isset($Format["XMargin"]) ? $Format["XMargin"] : AUTO; 2505 $YMargin = isset($Format["YMargin"]) ? $Format["YMargin"] : 0; 2506 $ScaleSpacing = isset($Format["ScaleSpacing"]) ? $Format["ScaleSpacing"] : 15; 2507 $InnerTickWidth = isset($Format["InnerTickWidth"]) ? $Format["InnerTickWidth"] : 2; 2508 $OuterTickWidth = isset($Format["OuterTickWidth"]) ? $Format["OuterTickWidth"] : 2; 2509 $DrawXLines = isset($Format["DrawXLines"]) ? $Format["DrawXLines"] : true; 2510 $DrawYLines = isset($Format["DrawYLines"]) ? $Format["DrawYLines"] : ALL; 2511 $GridTicks = isset($Format["GridTicks"]) ? $Format["GridTicks"] : 4; 2512 $GridR = isset($Format["GridR"]) ? $Format["GridR"] : 255; 2513 $GridG = isset($Format["GridG"]) ? $Format["GridG"] : 255; 2514 $GridB = isset($Format["GridB"]) ? $Format["GridB"] : 255; 2515 $GridAlpha = isset($Format["GridAlpha"]) ? $Format["GridAlpha"] : 40; 2516 $AxisRo = isset($Format["AxisR"]) ? $Format["AxisR"] : 0; 2517 $AxisGo = isset($Format["AxisG"]) ? $Format["AxisG"] : 0; 2518 $AxisBo = isset($Format["AxisB"]) ? $Format["AxisB"] : 0; 2519 $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 100; 2520 $TickRo = isset($Format["TickR"]) ? $Format["TickR"] : 0; 2521 $TickGo = isset($Format["TickG"]) ? $Format["TickG"] : 0; 2522 $TickBo = isset($Format["TickB"]) ? $Format["TickB"] : 0; 2523 $TickAlpha = isset($Format["TickAlpha"]) ? $Format["TickAlpha"] : 100; 2524 $DrawSubTicks = isset($Format["DrawSubTicks"]) ? $Format["DrawSubTicks"] : false; 2525 $InnerSubTickWidth = isset($Format["InnerSubTickWidth"]) ? $Format["InnerSubTickWidth"] : 0; 2526 $OuterSubTickWidth = isset($Format["OuterSubTickWidth"]) ? $Format["OuterSubTickWidth"] : 2; 2527 $SubTickR = isset($Format["SubTickR"]) ? $Format["SubTickR"] : 255; 2528 $SubTickG = isset($Format["SubTickG"]) ? $Format["SubTickG"] : 0; 2529 $SubTickB = isset($Format["SubTickB"]) ? $Format["SubTickB"] : 0; 2530 $SubTickAlpha = isset($Format["SubTickAlpha"]) ? $Format["SubTickAlpha"] : 100; 2531 $AutoAxisLabels = isset($Format["AutoAxisLabels"]) ? $Format["AutoAxisLabels"] : true; 2532 $XReleasePercent = isset($Format["XReleasePercent"]) ? $Format["XReleasePercent"] : 1; 2533 $DrawArrows = isset($Format["DrawArrows"]) ? $Format["DrawArrows"] : false; 2534 $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 8; 2535 $CycleBackground = isset($Format["CycleBackground"]) ? $Format["CycleBackground"] : false; 2536 $BackgroundR1 = isset($Format["BackgroundR1"]) ? $Format["BackgroundR1"] : 255; 2537 $BackgroundG1 = isset($Format["BackgroundG1"]) ? $Format["BackgroundG1"] : 255; 2538 $BackgroundB1 = isset($Format["BackgroundB1"]) ? $Format["BackgroundB1"] : 255; 2539 $BackgroundAlpha1 = isset($Format["BackgroundAlpha1"]) ? $Format["BackgroundAlpha1"] : 20; 2540 $BackgroundR2 = isset($Format["BackgroundR2"]) ? $Format["BackgroundR2"] : 230; 2541 $BackgroundG2 = isset($Format["BackgroundG2"]) ? $Format["BackgroundG2"] : 230; 2542 $BackgroundB2 = isset($Format["BackgroundB2"]) ? $Format["BackgroundB2"] : 230; 2543 $BackgroundAlpha2 = isset($Format["BackgroundAlpha2"]) ? $Format["BackgroundAlpha2"] : 20; 2544 $LabelingMethod = isset($Format["LabelingMethod"]) ? $Format["LabelingMethod"] : LABELING_ALL; 2545 $LabelSkip = isset($Format["LabelSkip"]) ? $Format["LabelSkip"] : 0; 2546 $LabelRotation = isset($Format["LabelRotation"]) ? $Format["LabelRotation"] : 0; 2547 $RemoveSkippedAxis = isset($Format["RemoveSkippedAxis"]) ? $Format["RemoveSkippedAxis"] : false; 2548 $SkippedAxisTicks = isset($Format["SkippedAxisTicks"]) ? $Format["SkippedAxisTicks"] : $GridTicks + 2; 2549 $SkippedAxisR = isset($Format["SkippedAxisR"]) ? $Format["SkippedAxisR"] : $GridR; 2550 $SkippedAxisG = isset($Format["SkippedAxisG"]) ? $Format["SkippedAxisG"] : $GridG; 2551 $SkippedAxisB = isset($Format["SkippedAxisB"]) ? $Format["SkippedAxisB"] : $GridB; 2552 $SkippedAxisAlpha = isset($Format["SkippedAxisAlpha"]) ? $Format["SkippedAxisAlpha"] : $GridAlpha - 30; 2553 $SkippedTickR = isset($Format["SkippedTickR"]) ? $Format["SkippedTickR"] : $TickRo; 2554 $SkippedTickG = isset($Format["SkippedTickG"]) ? $Format["SkippedTickG"] : $TickGo; 2555 $SkippedTickB = isset($Format["SkippedTicksB"]) ? $Format["SkippedTickB"] : $TickBo; 2556 $SkippedTickAlpha = isset($Format["SkippedTickAlpha"]) ? $Format["SkippedTickAlpha"] : $TickAlpha - 80; 2557 $SkippedInnerTickWidth = isset($Format["SkippedInnerTickWidth"]) ? $Format["SkippedInnerTickWidth"] : 0; 2558 $SkippedOuterTickWidth = isset($Format["SkippedOuterTickWidth"]) ? $Format["SkippedOuterTickWidth"] : 2; 2559 2560 /* Floating scale require X & Y margins to be set manually */ 2561 if ($Floating && ($XMargin == AUTO || $YMargin == 0)) { 2562 $Floating = false; 2563 } 2564 2565 /* Skip a NOTICE event in case of an empty array */ 2566 if ($DrawYLines == NONE || $DrawYLines == false) { 2567 $DrawYLines = ["zarma" => "31"]; 2568 } 2569 2570 /* Define the color for the skipped elements */ 2571 $SkippedAxisColor = [ 2572 "R" => $SkippedAxisR, 2573 "G" => $SkippedAxisG, 2574 "B" => $SkippedAxisB, 2575 "Alpha" => $SkippedAxisAlpha, 2576 "Ticks" => $SkippedAxisTicks 2577 ]; 2578 $SkippedTickColor = [ 2579 "R" => $SkippedTickR, 2580 "G" => $SkippedTickG, 2581 "B" => $SkippedTickB, 2582 "Alpha" => $SkippedTickAlpha 2583 ]; 2584 2585 $Data = $this->DataSet->getData(); 2586 $Abscissa = null; 2587 if (isset($Data["Abscissa"])) { 2588 $Abscissa = $Data["Abscissa"]; 2589 } 2590 2591 /* Unset the abscissa axis, needed if we display multiple charts on the same picture */ 2592 if ($Abscissa != null) { 2593 foreach ($Data["Axis"] as $AxisID => $Parameters) { 2594 if ($Parameters["Identity"] == AXIS_X) { 2595 unset($Data["Axis"][$AxisID]); 2596 } 2597 } 2598 } 2599 2600 /* Build the scale settings */ 2601 $GotXAxis = false; 2602 foreach ($Data["Axis"] as $AxisID => $AxisParameter) { 2603 if ($AxisParameter["Identity"] == AXIS_X) { 2604 $GotXAxis = true; 2605 } 2606 2607 if ($Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_Y) { 2608 $Height = $this->GraphAreaY2 - $this->GraphAreaY1 - $YMargin * 2; 2609 } elseif ($Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_X) { 2610 $Height = $this->GraphAreaX2 - $this->GraphAreaX1; 2611 } elseif ($Pos == SCALE_POS_TOPBOTTOM && $AxisParameter["Identity"] == AXIS_Y) { 2612 $Height = $this->GraphAreaX2 - $this->GraphAreaX1 - $YMargin * 2; 2613 ; 2614 } else { 2615 $Height = $this->GraphAreaY2 - $this->GraphAreaY1; 2616 } 2617 2618 $AxisMin = ABSOLUTE_MAX; 2619 $AxisMax = OUT_OF_SIGHT; 2620 if ($Mode == SCALE_MODE_FLOATING || $Mode == SCALE_MODE_START0) { 2621 foreach ($Data["Series"] as $SerieID => $SerieParameter) { 2622 if ($SerieParameter["Axis"] == $AxisID 2623 && $Data["Series"][$SerieID]["isDrawable"] 2624 && $Data["Abscissa"] != $SerieID 2625 ) { 2626 $AxisMax = max($AxisMax, $Data["Series"][$SerieID]["Max"]); 2627 $AxisMin = min($AxisMin, $Data["Series"][$SerieID]["Min"]); 2628 } 2629 } 2630 $AutoMargin = (($AxisMax - $AxisMin) / 100) * $XReleasePercent; 2631 2632 $Data["Axis"][$AxisID]["Min"] = $AxisMin - $AutoMargin; 2633 $Data["Axis"][$AxisID]["Max"] = $AxisMax + $AutoMargin; 2634 if ($Mode == SCALE_MODE_START0) { 2635 $Data["Axis"][$AxisID]["Min"] = 0; 2636 } 2637 } elseif ($Mode == SCALE_MODE_MANUAL) { 2638 if (isset($ManualScale[$AxisID]["Min"]) && isset($ManualScale[$AxisID]["Max"])) { 2639 $Data["Axis"][$AxisID]["Min"] = $ManualScale[$AxisID]["Min"]; 2640 $Data["Axis"][$AxisID]["Max"] = $ManualScale[$AxisID]["Max"]; 2641 } else { 2642 throw new Exception("Manual scale boundaries not set."); 2643 } 2644 } elseif ($Mode == SCALE_MODE_ADDALL || $Mode == SCALE_MODE_ADDALL_START0) { 2645 $Series = []; 2646 foreach ($Data["Series"] as $SerieID => $SerieParameter) { 2647 if ($SerieParameter["Axis"] == $AxisID 2648 && $SerieParameter["isDrawable"] 2649 && $Data["Abscissa"] != $SerieID 2650 ) { 2651 $Series[$SerieID] = count($Data["Series"][$SerieID]["Data"]); 2652 } 2653 } 2654 2655 for ($ID = 0; $ID <= max($Series) - 1; $ID++) { 2656 $PointMin = 0; 2657 $PointMax = 0; 2658 foreach ($Series as $SerieID => $ValuesCount) { 2659 if (isset($Data["Series"][$SerieID]["Data"][$ID]) 2660 && $Data["Series"][$SerieID]["Data"][$ID] != null 2661 ) { 2662 $Value = $Data["Series"][$SerieID]["Data"][$ID]; 2663 if ($Value > 0) { 2664 $PointMax = $PointMax + $Value; 2665 } else { 2666 $PointMin = $PointMin + $Value; 2667 } 2668 } 2669 } 2670 $AxisMax = max($AxisMax, $PointMax); 2671 $AxisMin = min($AxisMin, $PointMin); 2672 } 2673 $AutoMargin = (($AxisMax - $AxisMin) / 100) * $XReleasePercent; 2674 $Data["Axis"][$AxisID]["Min"] = $AxisMin - $AutoMargin; 2675 $Data["Axis"][$AxisID]["Max"] = $AxisMax + $AutoMargin; 2676 } 2677 $MaxDivs = floor($Height / $MinDivHeight); 2678 2679 if ($Mode == SCALE_MODE_ADDALL_START0) { 2680 $Data["Axis"][$AxisID]["Min"] = 0; 2681 } 2682 2683 $Scale = $this->computeScale( 2684 $Data["Axis"][$AxisID]["Min"], 2685 $Data["Axis"][$AxisID]["Max"], 2686 $MaxDivs, 2687 $Factors, 2688 $AxisID 2689 ); 2690 2691 $Data["Axis"][$AxisID]["Margin"] = $AxisParameter["Identity"] == AXIS_X ? $XMargin : $YMargin; 2692 $Data["Axis"][$AxisID]["ScaleMin"] = $Scale["XMin"]; 2693 $Data["Axis"][$AxisID]["ScaleMax"] = $Scale["XMax"]; 2694 $Data["Axis"][$AxisID]["Rows"] = $Scale["Rows"]; 2695 $Data["Axis"][$AxisID]["RowHeight"] = $Scale["RowHeight"]; 2696 2697 if (isset($Scale["Format"])) { 2698 $Data["Axis"][$AxisID]["Format"] = $Scale["Format"]; 2699 } 2700 if (!isset($Data["Axis"][$AxisID]["Display"])) { 2701 $Data["Axis"][$AxisID]["Display"] = null; 2702 } 2703 if (!isset($Data["Axis"][$AxisID]["Format"])) { 2704 $Data["Axis"][$AxisID]["Format"] = null; 2705 } 2706 if (!isset($Data["Axis"][$AxisID]["Unit"])) { 2707 $Data["Axis"][$AxisID]["Unit"] = null; 2708 } 2709 } 2710 2711 /* Still no X axis */ 2712 if ($GotXAxis == false) { 2713 if ($Abscissa != null) { 2714 $Points = count($Data["Series"][$Abscissa]["Data"]); 2715 $AxisName = null; 2716 if ($AutoAxisLabels) { 2717 $AxisName = isset($Data["Series"][$Abscissa]["Description"]) 2718 ? $Data["Series"][$Abscissa]["Description"] : null 2719 ; 2720 } 2721 } else { 2722 $Points = 0; 2723 $AxisName = isset($Data["XAxisName"]) ? $Data["XAxisName"] : null; 2724 foreach ($Data["Series"] as $SerieID => $SerieParameter) { 2725 if ($SerieParameter["isDrawable"]) { 2726 $Points = max($Points, count($SerieParameter["Data"])); 2727 } 2728 } 2729 } 2730 2731 $AxisID = count($Data["Axis"]); 2732 $Data["Axis"][$AxisID]["Identity"] = AXIS_X; 2733 if ($Pos == SCALE_POS_LEFTRIGHT) { 2734 $Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_BOTTOM; 2735 } else { 2736 $Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_LEFT; 2737 } 2738 if (isset($Data["AbscissaName"])) { 2739 $Data["Axis"][$AxisID]["Name"] = $Data["AbscissaName"]; 2740 } 2741 if ($XMargin == AUTO) { 2742 if ($Pos == SCALE_POS_LEFTRIGHT) { 2743 $Height = $this->GraphAreaX2 - $this->GraphAreaX1; 2744 } else { 2745 $Height = $this->GraphAreaY2 - $this->GraphAreaY1; 2746 } 2747 2748 if ($Points == 0 || $Points == 1) { 2749 $Data["Axis"][$AxisID]["Margin"] = $Height / 2; 2750 } else { 2751 $Data["Axis"][$AxisID]["Margin"] = ($Height / $Points) / 2; 2752 } 2753 } else { 2754 $Data["Axis"][$AxisID]["Margin"] = $XMargin; 2755 } 2756 $Data["Axis"][$AxisID]["Rows"] = $Points - 1; 2757 if (!isset($Data["Axis"][$AxisID]["Display"])) { 2758 $Data["Axis"][$AxisID]["Display"] = null; 2759 } 2760 if (!isset($Data["Axis"][$AxisID]["Format"])) { 2761 $Data["Axis"][$AxisID]["Format"] = null; 2762 } 2763 if (!isset($Data["Axis"][$AxisID]["Unit"])) { 2764 $Data["Axis"][$AxisID]["Unit"] = null; 2765 } 2766 } 2767 2768 /* Do we need to reverse the abscissa position? */ 2769 if ($Pos != SCALE_POS_LEFTRIGHT) { 2770 $Data["AbsicssaPosition"] = AXIS_POSITION_RIGHT; 2771 if ($Data["AbsicssaPosition"] == AXIS_POSITION_BOTTOM) { 2772 $Data["AbsicssaPosition"] = AXIS_POSITION_LEFT; 2773 } 2774 } 2775 $Data["Axis"][$AxisID]["Position"] = $Data["AbsicssaPosition"]; 2776 2777 $this->DataSet->saveOrientation($Pos); 2778 $this->DataSet->saveAxisConfig($Data["Axis"]); 2779 $this->DataSet->saveYMargin($YMargin); 2780 2781 $FontColorRo = $this->FontColorR; 2782 $FontColorGo = $this->FontColorG; 2783 $FontColorBo = $this->FontColorB; 2784 2785 $AxisPos["L"] = $this->GraphAreaX1; 2786 $AxisPos["R"] = $this->GraphAreaX2; 2787 $AxisPos["T"] = $this->GraphAreaY1; 2788 $AxisPos["B"] = $this->GraphAreaY2; 2789 foreach ($Data["Axis"] as $AxisID => $Parameters) { 2790 if (isset($Parameters["Color"])) { 2791 $AxisR = $Parameters["Color"]["R"]; 2792 $AxisG = $Parameters["Color"]["G"]; 2793 $AxisB = $Parameters["Color"]["B"]; 2794 $TickR = $Parameters["Color"]["R"]; 2795 $TickG = $Parameters["Color"]["G"]; 2796 $TickB = $Parameters["Color"]["B"]; 2797 $this->setFontProperties( 2798 [ 2799 "R" => $Parameters["Color"]["R"], 2800 "G" => $Parameters["Color"]["G"], 2801 "B" => $Parameters["Color"]["B"] 2802 ] 2803 ); 2804 } else { 2805 $AxisR = $AxisRo; 2806 $AxisG = $AxisGo; 2807 $AxisB = $AxisBo; 2808 $TickR = $TickRo; 2809 $TickG = $TickGo; 2810 $TickB = $TickBo; 2811 $this->setFontProperties(["R" => $FontColorRo, "G" => $FontColorGo, "B" => $FontColorBo]); 2812 } 2813 2814 $LastValue = "w00t"; 2815 $ID = 1; 2816 if ($Parameters["Identity"] == AXIS_X) { 2817 if ($Pos == SCALE_POS_LEFTRIGHT) { 2818 if ($Parameters["Position"] == AXIS_POSITION_BOTTOM) { 2819 if ($LabelRotation == 0) { 2820 $LabelAlign = TEXT_ALIGN_TOPMIDDLE; 2821 $YLabelOffset = 2; 2822 } 2823 if ($LabelRotation > 0 && $LabelRotation < 190) { 2824 $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; 2825 $YLabelOffset = 5; 2826 } 2827 if ($LabelRotation == 180) { 2828 $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; 2829 $YLabelOffset = 5; 2830 } 2831 if ($LabelRotation > 180 && $LabelRotation < 360) { 2832 $LabelAlign = TEXT_ALIGN_MIDDLELEFT; 2833 $YLabelOffset = 2; 2834 } 2835 2836 if (!$RemoveXAxis) { 2837 if ($Floating) { 2838 $FloatingOffset = $YMargin; 2839 $this->drawLine( 2840 $this->GraphAreaX1 + $Parameters["Margin"], 2841 $AxisPos["B"], 2842 $this->GraphAreaX2 - $Parameters["Margin"], 2843 $AxisPos["B"], 2844 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 2845 ); 2846 } else { 2847 $FloatingOffset = 0; 2848 $this->drawLine( 2849 $this->GraphAreaX1, 2850 $AxisPos["B"], 2851 $this->GraphAreaX2, 2852 $AxisPos["B"], 2853 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 2854 ); 2855 } 2856 2857 if ($DrawArrows) { 2858 $this->drawArrow( 2859 $this->GraphAreaX2 - $Parameters["Margin"], 2860 $AxisPos["B"], 2861 $this->GraphAreaX2 + ($ArrowSize * 2), 2862 $AxisPos["B"], 2863 ["FillR" => $AxisR, "FillG" => $AxisG, "FillB" => $AxisB, "Size" => $ArrowSize] 2864 ); 2865 } 2866 } 2867 2868 $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2; 2869 2870 if ($Parameters["Rows"] == 0) { 2871 $Step = $Width; 2872 } else { 2873 $Step = $Width / ($Parameters["Rows"]); 2874 } 2875 2876 $MaxBottom = $AxisPos["B"]; 2877 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 2878 $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i; 2879 $YPos = $AxisPos["B"]; 2880 2881 if ($Abscissa != null) { 2882 $Value = ""; 2883 if (isset($Data["Series"][$Abscissa]["Data"][$i])) { 2884 $Value = $this->scaleFormat( 2885 $Data["Series"][$Abscissa]["Data"][$i], 2886 $Data["XAxisDisplay"], 2887 $Data["XAxisFormat"], 2888 $Data["XAxisUnit"] 2889 ); 2890 } 2891 } else { 2892 $Value = $i; 2893 if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) { 2894 $Value = $this->scaleFormat( 2895 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 2896 $Data["XAxisDisplay"], 2897 $Data["XAxisFormat"], 2898 $Data["XAxisUnit"] 2899 ); 2900 } 2901 } 2902 2903 $ID++; 2904 $Skipped = true; 2905 if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) 2906 && !$RemoveXAxis 2907 ) { 2908 $Bounds = $this->drawText( 2909 $XPos, 2910 $YPos + $OuterTickWidth + $YLabelOffset, 2911 $Value, 2912 ["Angle" => $LabelRotation, "Align" => $LabelAlign] 2913 ); 2914 $TxtBottom = $YPos + $OuterTickWidth + 2 + ($Bounds[0]["Y"] - $Bounds[2]["Y"]); 2915 $MaxBottom = max($MaxBottom, $TxtBottom); 2916 $LastValue = $Value; 2917 $Skipped = false; 2918 } 2919 2920 if ($RemoveXAxis) { 2921 $Skipped = false; 2922 } 2923 2924 if ($Skipped) { 2925 if ($DrawXLines && !$RemoveSkippedAxis) { 2926 $this->drawLine( 2927 $XPos, 2928 $this->GraphAreaY1 + $FloatingOffset, 2929 $XPos, 2930 $this->GraphAreaY2 - $FloatingOffset, 2931 $SkippedAxisColor 2932 ); 2933 } 2934 if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) 2935 && !$RemoveXAxis 2936 && !$RemoveSkippedAxis 2937 ) { 2938 $this->drawLine( 2939 $XPos, 2940 $YPos - $SkippedInnerTickWidth, 2941 $XPos, 2942 $YPos + $SkippedOuterTickWidth, 2943 $SkippedTickColor 2944 ); 2945 } 2946 } else { 2947 if ($DrawXLines 2948 && ($XPos != $this->GraphAreaX1 && $XPos != $this->GraphAreaX2) 2949 ) { 2950 $this->drawLine( 2951 $XPos, 2952 $this->GraphAreaY1 + $FloatingOffset, 2953 $XPos, 2954 $this->GraphAreaY2 - $FloatingOffset, 2955 [ 2956 "R" => $GridR, 2957 "G" => $GridG, 2958 "B" => $GridB, 2959 "Alpha" => $GridAlpha, 2960 "Ticks" => $GridTicks 2961 ] 2962 ); 2963 } 2964 if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) { 2965 $this->drawLine( 2966 $XPos, 2967 $YPos - $InnerTickWidth, 2968 $XPos, 2969 $YPos + $OuterTickWidth, 2970 ["R" => $TickR, "G" => $TickG, "B" => $TickB, "Alpha" => $TickAlpha] 2971 ); 2972 } 2973 } 2974 } 2975 2976 if (isset($Parameters["Name"]) && !$RemoveXAxis) { 2977 $YPos = $MaxBottom + 2; 2978 $XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2; 2979 $Bounds = $this->drawText( 2980 $XPos, 2981 $YPos, 2982 $Parameters["Name"], 2983 ["Align" => TEXT_ALIGN_TOPMIDDLE] 2984 ); 2985 $MaxBottom = $Bounds[0]["Y"]; 2986 2987 $this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize; 2988 } 2989 2990 $AxisPos["B"] = $MaxBottom + $ScaleSpacing; 2991 } elseif ($Parameters["Position"] == AXIS_POSITION_TOP) { 2992 if ($LabelRotation == 0) { 2993 $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; 2994 $YLabelOffset = 2; 2995 } 2996 if ($LabelRotation > 0 && $LabelRotation < 190) { 2997 $LabelAlign = TEXT_ALIGN_MIDDLELEFT; 2998 $YLabelOffset = 2; 2999 } 3000 if ($LabelRotation == 180) { 3001 $LabelAlign = TEXT_ALIGN_TOPMIDDLE; 3002 $YLabelOffset = 5; 3003 } 3004 if ($LabelRotation > 180 && $LabelRotation < 360) { 3005 $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; 3006 $YLabelOffset = 5; 3007 } 3008 3009 if (!$RemoveXAxis) { 3010 if ($Floating) { 3011 $FloatingOffset = $YMargin; 3012 $this->drawLine( 3013 $this->GraphAreaX1 + $Parameters["Margin"], 3014 $AxisPos["T"], 3015 $this->GraphAreaX2 - $Parameters["Margin"], 3016 $AxisPos["T"], 3017 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3018 ); 3019 } else { 3020 $FloatingOffset = 0; 3021 $this->drawLine( 3022 $this->GraphAreaX1, 3023 $AxisPos["T"], 3024 $this->GraphAreaX2, 3025 $AxisPos["T"], 3026 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3027 ); 3028 } 3029 3030 if ($DrawArrows) { 3031 $this->drawArrow( 3032 $this->GraphAreaX2 - $Parameters["Margin"], 3033 $AxisPos["T"], 3034 $this->GraphAreaX2 + ($ArrowSize * 2), 3035 $AxisPos["T"], 3036 ["FillR" => $AxisR, "FillG" => $AxisG, "FillB" => $AxisB, "Size" => $ArrowSize] 3037 ); 3038 } 3039 } 3040 3041 $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2; 3042 3043 if ($Parameters["Rows"] == 0) { 3044 $Step = $Width; 3045 } else { 3046 $Step = $Width / $Parameters["Rows"]; 3047 } 3048 3049 $MinTop = $AxisPos["T"]; 3050 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 3051 $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i; 3052 $YPos = $AxisPos["T"]; 3053 3054 if ($Abscissa != null) { 3055 $Value = ""; 3056 if (isset($Data["Series"][$Abscissa]["Data"][$i])) { 3057 $Value = $this->scaleFormat( 3058 $Data["Series"][$Abscissa]["Data"][$i], 3059 $Data["XAxisDisplay"], 3060 $Data["XAxisFormat"], 3061 $Data["XAxisUnit"] 3062 ); 3063 } 3064 } else { 3065 $Value = $i; 3066 if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) { 3067 $Value = $this->scaleFormat( 3068 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 3069 $Data["XAxisDisplay"], 3070 $Data["XAxisFormat"], 3071 $Data["XAxisUnit"] 3072 ); 3073 } 3074 } 3075 3076 $ID++; 3077 $Skipped = true; 3078 if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) 3079 && !$RemoveXAxis 3080 ) { 3081 $Bounds = $this->drawText( 3082 $XPos, 3083 $YPos - $OuterTickWidth - $YLabelOffset, 3084 $Value, 3085 ["Angle" => $LabelRotation, "Align" => $LabelAlign] 3086 ); 3087 $TxtBox = $YPos - $OuterTickWidth - 2 - ($Bounds[0]["Y"] - $Bounds[2]["Y"]); 3088 $MinTop = min($MinTop, $TxtBox); 3089 $LastValue = $Value; 3090 $Skipped = false; 3091 } 3092 3093 if ($RemoveXAxis) { 3094 $Skipped = false; 3095 } 3096 3097 if ($Skipped) { 3098 if ($DrawXLines && !$RemoveSkippedAxis) { 3099 $this->drawLine( 3100 $XPos, 3101 $this->GraphAreaY1 + $FloatingOffset, 3102 $XPos, 3103 $this->GraphAreaY2 - $FloatingOffset, 3104 $SkippedAxisColor 3105 ); 3106 } 3107 if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) 3108 && !$RemoveXAxis 3109 && !$RemoveSkippedAxis 3110 ) { 3111 $this->drawLine( 3112 $XPos, 3113 $YPos + $SkippedInnerTickWidth, 3114 $XPos, 3115 $YPos - $SkippedOuterTickWidth, 3116 $SkippedTickColor 3117 ); 3118 } 3119 } else { 3120 if ($DrawXLines) { 3121 $this->drawLine( 3122 $XPos, 3123 $this->GraphAreaY1 + $FloatingOffset, 3124 $XPos, 3125 $this->GraphAreaY2 - $FloatingOffset, 3126 [ 3127 "R" => $GridR, 3128 "G" => $GridG, 3129 "B" => $GridB, 3130 "Alpha" => $GridAlpha, 3131 "Ticks" => $GridTicks 3132 ] 3133 ); 3134 } 3135 if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) { 3136 $this->drawLine( 3137 $XPos, 3138 $YPos + $InnerTickWidth, 3139 $XPos, 3140 $YPos - $OuterTickWidth, 3141 [ 3142 "R" => $TickR, 3143 "G" => $TickG, 3144 "B" => $TickB, 3145 "Alpha" => $TickAlpha 3146 ] 3147 ); 3148 } 3149 } 3150 } 3151 3152 if (isset($Parameters["Name"]) && !$RemoveXAxis) { 3153 $YPos = $MinTop - 2; 3154 $XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2; 3155 $Bounds = $this->drawText( 3156 $XPos, 3157 $YPos, 3158 $Parameters["Name"], 3159 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE] 3160 ); 3161 $MinTop = $Bounds[2]["Y"]; 3162 3163 $this->DataSet->Data["GraphArea"]["Y1"] = $MinTop; 3164 } 3165 3166 $AxisPos["T"] = $MinTop - $ScaleSpacing; 3167 } 3168 } elseif ($Pos == SCALE_POS_TOPBOTTOM) { 3169 if ($Parameters["Position"] == AXIS_POSITION_LEFT) { 3170 if ($LabelRotation == 0) { 3171 $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; 3172 $XLabelOffset = -2; 3173 } 3174 if ($LabelRotation > 0 && $LabelRotation < 190) { 3175 $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; 3176 $XLabelOffset = -6; 3177 } 3178 if ($LabelRotation == 180) { 3179 $LabelAlign = TEXT_ALIGN_MIDDLELEFT; 3180 $XLabelOffset = -2; 3181 } 3182 if ($LabelRotation > 180 && $LabelRotation < 360) { 3183 $LabelAlign = TEXT_ALIGN_MIDDLELEFT; 3184 $XLabelOffset = -5; 3185 } 3186 3187 if (!$RemoveXAxis) { 3188 if ($Floating) { 3189 $FloatingOffset = $YMargin; 3190 $this->drawLine( 3191 $AxisPos["L"], 3192 $this->GraphAreaY1 + $Parameters["Margin"], 3193 $AxisPos["L"], 3194 $this->GraphAreaY2 - $Parameters["Margin"], 3195 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3196 ); 3197 } else { 3198 $FloatingOffset = 0; 3199 $this->drawLine( 3200 $AxisPos["L"], 3201 $this->GraphAreaY1, 3202 $AxisPos["L"], 3203 $this->GraphAreaY2, 3204 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3205 ); 3206 } 3207 3208 if ($DrawArrows) { 3209 $this->drawArrow( 3210 $AxisPos["L"], 3211 $this->GraphAreaY2 - $Parameters["Margin"], 3212 $AxisPos["L"], 3213 $this->GraphAreaY2 + ($ArrowSize * 2), 3214 [ 3215 "FillR" => $AxisR, 3216 "FillG" => $AxisG, 3217 "FillB" => $AxisB, 3218 "Size" => $ArrowSize 3219 ] 3220 ); 3221 } 3222 } 3223 3224 $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2; 3225 3226 if ($Parameters["Rows"] == 0) { 3227 $Step = $Height; 3228 } else { 3229 $Step = $Height / $Parameters["Rows"]; 3230 } 3231 3232 $MinLeft = $AxisPos["L"]; 3233 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 3234 $YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step * $i; 3235 $XPos = $AxisPos["L"]; 3236 3237 if ($Abscissa != null) { 3238 $Value = ""; 3239 if (isset($Data["Series"][$Abscissa]["Data"][$i])) { 3240 $Value = $this->scaleFormat( 3241 $Data["Series"][$Abscissa]["Data"][$i], 3242 $Data["XAxisDisplay"], 3243 $Data["XAxisFormat"], 3244 $Data["XAxisUnit"] 3245 ); 3246 } 3247 } else { 3248 $Value = $i; 3249 if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) { 3250 $Value = $this->scaleFormat( 3251 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 3252 $Data["XAxisDisplay"], 3253 $Data["XAxisFormat"], 3254 $Data["XAxisUnit"] 3255 ); 3256 } 3257 } 3258 3259 $ID++; 3260 $Skipped = true; 3261 if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) 3262 && !$RemoveXAxis 3263 ) { 3264 $Bounds = $this->drawText( 3265 $XPos - $OuterTickWidth + $XLabelOffset, 3266 $YPos, 3267 $Value, 3268 ["Angle" => $LabelRotation, "Align" => $LabelAlign] 3269 ); 3270 $TxtBox = $XPos - $OuterTickWidth - 2 - ($Bounds[1]["X"] - $Bounds[0]["X"]); 3271 $MinLeft = min($MinLeft, $TxtBox); 3272 $LastValue = $Value; 3273 $Skipped = false; 3274 } 3275 3276 if ($RemoveXAxis) { 3277 $Skipped = false; 3278 } 3279 3280 if ($Skipped) { 3281 if ($DrawXLines && !$RemoveSkippedAxis) { 3282 $this->drawLine( 3283 $this->GraphAreaX1 + $FloatingOffset, 3284 $YPos, 3285 $this->GraphAreaX2 - $FloatingOffset, 3286 $YPos, 3287 $SkippedAxisColor 3288 ); 3289 } 3290 if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) 3291 && !$RemoveXAxis 3292 && !$RemoveSkippedAxis 3293 ) { 3294 $this->drawLine( 3295 $XPos - $SkippedOuterTickWidth, 3296 $YPos, 3297 $XPos + $SkippedInnerTickWidth, 3298 $YPos, 3299 $SkippedTickColor 3300 ); 3301 } 3302 } else { 3303 if ($DrawXLines && 3304 ($YPos != $this->GraphAreaY1 && $YPos != $this->GraphAreaY2) 3305 ) { 3306 $this->drawLine( 3307 $this->GraphAreaX1 + $FloatingOffset, 3308 $YPos, 3309 $this->GraphAreaX2 - $FloatingOffset, 3310 $YPos, 3311 [ 3312 "R" => $GridR, 3313 "G" => $GridG, 3314 "B" => $GridB, 3315 "Alpha" => $GridAlpha, 3316 "Ticks" => $GridTicks 3317 ] 3318 ); 3319 } 3320 if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) { 3321 $this->drawLine( 3322 $XPos - $OuterTickWidth, 3323 $YPos, 3324 $XPos + $InnerTickWidth, 3325 $YPos, 3326 ["R" => $TickR, "G" => $TickG, "B" => $TickB, "Alpha" => $TickAlpha] 3327 ); 3328 } 3329 } 3330 } 3331 if (isset($Parameters["Name"]) && !$RemoveXAxis) { 3332 $XPos = $MinLeft - 2; 3333 $YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2; 3334 $Bounds = $this->drawText( 3335 $XPos, 3336 $YPos, 3337 $Parameters["Name"], 3338 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE, "Angle" => 90] 3339 ); 3340 $MinLeft = $Bounds[0]["X"]; 3341 3342 $this->DataSet->Data["GraphArea"]["X1"] = $MinLeft; 3343 } 3344 3345 $AxisPos["L"] = $MinLeft - $ScaleSpacing; 3346 } elseif ($Parameters["Position"] == AXIS_POSITION_RIGHT) { 3347 if ($LabelRotation == 0) { 3348 $LabelAlign = TEXT_ALIGN_MIDDLELEFT; 3349 $XLabelOffset = 2; 3350 } 3351 if ($LabelRotation > 0 && $LabelRotation < 190) { 3352 $LabelAlign = TEXT_ALIGN_MIDDLELEFT; 3353 $XLabelOffset = 6; 3354 } 3355 if ($LabelRotation == 180) { 3356 $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; 3357 $XLabelOffset = 5; 3358 } 3359 if ($LabelRotation > 180 && $LabelRotation < 360) { 3360 $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; 3361 $XLabelOffset = 7; 3362 } 3363 3364 if (!$RemoveXAxis) { 3365 if ($Floating) { 3366 $FloatingOffset = $YMargin; 3367 $this->drawLine( 3368 $AxisPos["R"], 3369 $this->GraphAreaY1 + $Parameters["Margin"], 3370 $AxisPos["R"], 3371 $this->GraphAreaY2 - $Parameters["Margin"], 3372 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3373 ); 3374 } else { 3375 $FloatingOffset = 0; 3376 $this->drawLine( 3377 $AxisPos["R"], 3378 $this->GraphAreaY1, 3379 $AxisPos["R"], 3380 $this->GraphAreaY2, 3381 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3382 ); 3383 } 3384 3385 if ($DrawArrows) { 3386 $this->drawArrow( 3387 $AxisPos["R"], 3388 $this->GraphAreaY2 - $Parameters["Margin"], 3389 $AxisPos["R"], 3390 $this->GraphAreaY2 + ($ArrowSize * 2), 3391 [ 3392 "FillR" => $AxisR, 3393 "FillG" => $AxisG, 3394 "FillB" => $AxisB, 3395 "Size" => $ArrowSize 3396 ] 3397 ); 3398 } 3399 } 3400 3401 $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2; 3402 3403 if ($Parameters["Rows"] == 0) { 3404 $Step = $Height; 3405 } else { 3406 $Step = $Height / $Parameters["Rows"]; 3407 } 3408 3409 $MaxRight = $AxisPos["R"]; 3410 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 3411 $YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step * $i; 3412 $XPos = $AxisPos["R"]; 3413 3414 if ($Abscissa != null) { 3415 $Value = ""; 3416 if (isset($Data["Series"][$Abscissa]["Data"][$i])) { 3417 $Value = $this->scaleFormat( 3418 $Data["Series"][$Abscissa]["Data"][$i], 3419 $Data["XAxisDisplay"], 3420 $Data["XAxisFormat"], 3421 $Data["XAxisUnit"] 3422 ); 3423 } 3424 } else { 3425 $Value = $i; 3426 if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) { 3427 $Value = $this->scaleFormat( 3428 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 3429 $Data["XAxisDisplay"], 3430 $Data["XAxisFormat"], 3431 $Data["XAxisUnit"] 3432 ); 3433 } 3434 } 3435 3436 $ID++; 3437 $Skipped = true; 3438 if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) 3439 && !$RemoveXAxis 3440 ) { 3441 $Bounds = $this->drawText( 3442 $XPos + $OuterTickWidth + $XLabelOffset, 3443 $YPos, 3444 $Value, 3445 ["Angle" => $LabelRotation, "Align" => $LabelAlign] 3446 ); 3447 $TxtBox = $XPos + $OuterTickWidth + 2 + ($Bounds[1]["X"] - $Bounds[0]["X"]); 3448 $MaxRight = max($MaxRight, $TxtBox); 3449 $LastValue = $Value; 3450 $Skipped = false; 3451 } 3452 3453 if ($RemoveXAxis) { 3454 $Skipped = false; 3455 } 3456 3457 if ($Skipped) { 3458 if ($DrawXLines && !$RemoveSkippedAxis) { 3459 $this->drawLine( 3460 $this->GraphAreaX1 + $FloatingOffset, 3461 $YPos, 3462 $this->GraphAreaX2 - $FloatingOffset, 3463 $YPos, 3464 $SkippedAxisColor 3465 ); 3466 } 3467 if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) 3468 && !$RemoveXAxis 3469 && !$RemoveSkippedAxis 3470 ) { 3471 $this->drawLine( 3472 $XPos + $SkippedOuterTickWidth, 3473 $YPos, 3474 $XPos - $SkippedInnerTickWidth, 3475 $YPos, 3476 $SkippedTickColor 3477 ); 3478 } 3479 } else { 3480 if ($DrawXLines) { 3481 $this->drawLine( 3482 $this->GraphAreaX1 + $FloatingOffset, 3483 $YPos, 3484 $this->GraphAreaX2 - $FloatingOffset, 3485 $YPos, 3486 [ 3487 "R" => $GridR, 3488 "G" => $GridG, 3489 "B" => $GridB, 3490 "Alpha" => $GridAlpha, 3491 "Ticks" => $GridTicks 3492 ] 3493 ); 3494 } 3495 if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) { 3496 $this->drawLine( 3497 $XPos + $OuterTickWidth, 3498 $YPos, 3499 $XPos - $InnerTickWidth, 3500 $YPos, 3501 [ 3502 "R" => $TickR, 3503 "G" => $TickG, 3504 "B" => $TickB, 3505 "Alpha" => $TickAlpha 3506 ] 3507 ); 3508 } 3509 } 3510 } 3511 3512 if (isset($Parameters["Name"]) && !$RemoveXAxis) { 3513 $XPos = $MaxRight + 4; 3514 $YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2; 3515 $Bounds = $this->drawText( 3516 $XPos, 3517 $YPos, 3518 $Parameters["Name"], 3519 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE, "Angle" => 270] 3520 ); 3521 $MaxRight = $Bounds[1]["X"]; 3522 3523 $this->DataSet->Data["GraphArea"]["X2"] = $MaxRight + $this->FontSize; 3524 } 3525 3526 $AxisPos["R"] = $MaxRight + $ScaleSpacing; 3527 } 3528 } 3529 } 3530 3531 if ($Parameters["Identity"] == AXIS_Y && !$RemoveYAxis) { 3532 if ($Pos == SCALE_POS_LEFTRIGHT) { 3533 if ($Parameters["Position"] == AXIS_POSITION_LEFT) { 3534 if ($Floating) { 3535 $FloatingOffset = $XMargin; 3536 $this->drawLine( 3537 $AxisPos["L"], 3538 $this->GraphAreaY1 + $Parameters["Margin"], 3539 $AxisPos["L"], 3540 $this->GraphAreaY2 - $Parameters["Margin"], 3541 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3542 ); 3543 } else { 3544 $FloatingOffset = 0; 3545 $this->drawLine( 3546 $AxisPos["L"], 3547 $this->GraphAreaY1, 3548 $AxisPos["L"], 3549 $this->GraphAreaY2, 3550 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3551 ); 3552 } 3553 3554 if ($DrawArrows) { 3555 $this->drawArrow( 3556 $AxisPos["L"], 3557 $this->GraphAreaY1 + $Parameters["Margin"], 3558 $AxisPos["L"], 3559 $this->GraphAreaY1 - ($ArrowSize * 2), 3560 [ 3561 "FillR" => $AxisR, 3562 "FillG" => $AxisG, 3563 "FillB" => $AxisB, 3564 "Size" => $ArrowSize 3565 ] 3566 ); 3567 } 3568 3569 $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2; 3570 $Step = $Height / $Parameters["Rows"]; 3571 $SubTicksSize = $Step / 2; 3572 $MinLeft = $AxisPos["L"]; 3573 $LastY = null; 3574 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 3575 $YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step * $i; 3576 $XPos = $AxisPos["L"]; 3577 $Value = $this->scaleFormat( 3578 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 3579 $Parameters["Display"], 3580 $Parameters["Format"], 3581 $Parameters["Unit"] 3582 ); 3583 3584 if ($i % 2 == 1) { 3585 $BGColor = [ 3586 "R" => $BackgroundR1, 3587 "G" => $BackgroundG1, 3588 "B" => $BackgroundB1, 3589 "Alpha" => $BackgroundAlpha1 3590 ]; 3591 } else { 3592 $BGColor = [ 3593 "R" => $BackgroundR2, 3594 "G" => $BackgroundG2, 3595 "B" => $BackgroundB2, 3596 "Alpha" => $BackgroundAlpha2 3597 ]; 3598 } 3599 if ($LastY != null 3600 && $CycleBackground 3601 && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) 3602 ) { 3603 $this->drawFilledRectangle( 3604 $this->GraphAreaX1 + $FloatingOffset, 3605 $LastY, 3606 $this->GraphAreaX2 - $FloatingOffset, 3607 $YPos, 3608 $BGColor 3609 ); 3610 } 3611 3612 if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) { 3613 $this->drawLine( 3614 $this->GraphAreaX1 + $FloatingOffset, 3615 $YPos, 3616 $this->GraphAreaX2 - $FloatingOffset, 3617 $YPos, 3618 [ 3619 "R" => $GridR, 3620 "G" => $GridG, 3621 "B" => $GridB, 3622 "Alpha" => $GridAlpha, 3623 "Ticks" => $GridTicks 3624 ] 3625 ); 3626 } 3627 3628 if ($DrawSubTicks && $i != $Parameters["Rows"]) { 3629 $this->drawLine( 3630 $XPos - $OuterSubTickWidth, 3631 $YPos - $SubTicksSize, 3632 $XPos + $InnerSubTickWidth, 3633 $YPos - $SubTicksSize, 3634 [ 3635 "R" => $SubTickR, 3636 "G" => $SubTickG, 3637 "B" => $SubTickB, 3638 "Alpha" => $SubTickAlpha 3639 ] 3640 ); 3641 } 3642 if (!$RemoveYAxiValues) { 3643 $this->drawLine( 3644 $XPos - $OuterTickWidth, 3645 $YPos, 3646 $XPos + $InnerTickWidth, 3647 $YPos, 3648 ["R" => $TickR, "G" => $TickG, "B" => $TickB, "Alpha" => $TickAlpha] 3649 ); 3650 $Bounds = $this->drawText( 3651 $XPos - $OuterTickWidth - 2, 3652 $YPos, 3653 $Value, 3654 ["Align" => TEXT_ALIGN_MIDDLERIGHT] 3655 ); 3656 $TxtLeft = $XPos - $OuterTickWidth - 2 - ($Bounds[1]["X"] - $Bounds[0]["X"]); 3657 $MinLeft = min($MinLeft, $TxtLeft); 3658 } 3659 3660 $LastY = $YPos; 3661 } 3662 3663 if (isset($Parameters["Name"])) { 3664 $XPos = $MinLeft - 2; 3665 $YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2; 3666 $Bounds = $this->drawText( 3667 $XPos, 3668 $YPos, 3669 $Parameters["Name"], 3670 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE, "Angle" => 90] 3671 ); 3672 $MinLeft = $Bounds[2]["X"]; 3673 3674 $this->DataSet->Data["GraphArea"]["X1"] = $MinLeft; 3675 } 3676 3677 $AxisPos["L"] = $MinLeft - $ScaleSpacing; 3678 } elseif ($Parameters["Position"] == AXIS_POSITION_RIGHT) { 3679 if ($Floating) { 3680 $FloatingOffset = $XMargin; 3681 $this->drawLine( 3682 $AxisPos["R"], 3683 $this->GraphAreaY1 + $Parameters["Margin"], 3684 $AxisPos["R"], 3685 $this->GraphAreaY2 - $Parameters["Margin"], 3686 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3687 ); 3688 } else { 3689 $FloatingOffset = 0; 3690 $this->drawLine( 3691 $AxisPos["R"], 3692 $this->GraphAreaY1, 3693 $AxisPos["R"], 3694 $this->GraphAreaY2, 3695 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3696 ); 3697 } 3698 3699 if ($DrawArrows) { 3700 $this->drawArrow( 3701 $AxisPos["R"], 3702 $this->GraphAreaY1 + $Parameters["Margin"], 3703 $AxisPos["R"], 3704 $this->GraphAreaY1 - ($ArrowSize * 2), 3705 [ 3706 "FillR" => $AxisR, 3707 "FillG" => $AxisG, 3708 "FillB" => $AxisB, 3709 "Size" => $ArrowSize 3710 ] 3711 ); 3712 } 3713 3714 $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2; 3715 $Step = $Height / $Parameters["Rows"]; 3716 $SubTicksSize = $Step / 2; 3717 $MaxLeft = $AxisPos["R"]; 3718 $LastY = null; 3719 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 3720 $YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step * $i; 3721 $XPos = $AxisPos["R"]; 3722 $Value = $this->scaleFormat( 3723 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 3724 $Parameters["Display"], 3725 $Parameters["Format"], 3726 $Parameters["Unit"] 3727 ); 3728 3729 if ($i % 2 == 1) { 3730 $BGColor = [ 3731 "R" => $BackgroundR1, 3732 "G" => $BackgroundG1, 3733 "B" => $BackgroundB1, 3734 "Alpha" => $BackgroundAlpha1 3735 ]; 3736 } else { 3737 $BGColor = [ 3738 "R" => $BackgroundR2, 3739 "G" => $BackgroundG2, 3740 "B" => $BackgroundB2, 3741 "Alpha" => $BackgroundAlpha2 3742 ]; 3743 } 3744 if ($LastY != null 3745 && $CycleBackground 3746 && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) 3747 ) { 3748 $this->drawFilledRectangle( 3749 $this->GraphAreaX1 + $FloatingOffset, 3750 $LastY, 3751 $this->GraphAreaX2 - $FloatingOffset, 3752 $YPos, 3753 $BGColor 3754 ); 3755 } 3756 3757 if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) { 3758 $this->drawLine( 3759 $this->GraphAreaX1 + $FloatingOffset, 3760 $YPos, 3761 $this->GraphAreaX2 - $FloatingOffset, 3762 $YPos, 3763 [ 3764 "R" => $GridR, 3765 "G" => $GridG, 3766 "B" => $GridB, 3767 "Alpha" => $GridAlpha, 3768 "Ticks" => $GridTicks 3769 ] 3770 ); 3771 } 3772 3773 if ($DrawSubTicks && $i != $Parameters["Rows"]) { 3774 $this->drawLine( 3775 $XPos - $OuterSubTickWidth, 3776 $YPos - $SubTicksSize, 3777 $XPos + $InnerSubTickWidth, 3778 $YPos - $SubTicksSize, 3779 [ 3780 "R" => $SubTickR, 3781 "G" => $SubTickG, 3782 "B" => $SubTickB, 3783 "Alpha" => $SubTickAlpha 3784 ] 3785 ); 3786 } 3787 $this->drawLine( 3788 $XPos - $InnerTickWidth, 3789 $YPos, 3790 $XPos + $OuterTickWidth, 3791 $YPos, 3792 ["R" => $TickR, "G" => $TickG, "B" => $TickB, "Alpha" => $TickAlpha] 3793 ); 3794 $Bounds = $this->drawText( 3795 $XPos + $OuterTickWidth + 2, 3796 $YPos, 3797 $Value, 3798 ["Align" => TEXT_ALIGN_MIDDLELEFT] 3799 ); 3800 $TxtLeft = $XPos + $OuterTickWidth + 2 + ($Bounds[1]["X"] - $Bounds[0]["X"]); 3801 $MaxLeft = max($MaxLeft, $TxtLeft); 3802 3803 $LastY = $YPos; 3804 } 3805 3806 if (isset($Parameters["Name"])) { 3807 $XPos = $MaxLeft + 6; 3808 $YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2; 3809 $Bounds = $this->drawText( 3810 $XPos, 3811 $YPos, 3812 $Parameters["Name"], 3813 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE, "Angle" => 270] 3814 ); 3815 $MaxLeft = $Bounds[2]["X"]; 3816 3817 $this->DataSet->Data["GraphArea"]["X2"] = $MaxLeft + $this->FontSize; 3818 } 3819 $AxisPos["R"] = $MaxLeft + $ScaleSpacing; 3820 } 3821 } elseif ($Pos == SCALE_POS_TOPBOTTOM) { 3822 if ($Parameters["Position"] == AXIS_POSITION_TOP) { 3823 if ($Floating) { 3824 $FloatingOffset = $XMargin; 3825 $this->drawLine( 3826 $this->GraphAreaX1 + $Parameters["Margin"], 3827 $AxisPos["T"], 3828 $this->GraphAreaX2 - $Parameters["Margin"], 3829 $AxisPos["T"], 3830 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3831 ); 3832 } else { 3833 $FloatingOffset = 0; 3834 $this->drawLine( 3835 $this->GraphAreaX1, 3836 $AxisPos["T"], 3837 $this->GraphAreaX2, 3838 $AxisPos["T"], 3839 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3840 ); 3841 } 3842 3843 if ($DrawArrows) { 3844 $this->drawArrow( 3845 $this->GraphAreaX2 - $Parameters["Margin"], 3846 $AxisPos["T"], 3847 $this->GraphAreaX2 + ($ArrowSize * 2), 3848 $AxisPos["T"], 3849 [ 3850 "FillR" => $AxisR, 3851 "FillG" => $AxisG, 3852 "FillB" => $AxisB, 3853 "Size" => $ArrowSize 3854 ] 3855 ); 3856 } 3857 3858 $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2; 3859 $Step = $Width / $Parameters["Rows"]; 3860 $SubTicksSize = $Step / 2; 3861 $MinTop = $AxisPos["T"]; 3862 $LastX = null; 3863 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 3864 $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i; 3865 $YPos = $AxisPos["T"]; 3866 $Value = $this->scaleFormat( 3867 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 3868 $Parameters["Display"], 3869 $Parameters["Format"], 3870 $Parameters["Unit"] 3871 ); 3872 3873 if ($i % 2 == 1) { 3874 $BGColor = [ 3875 "R" => $BackgroundR1, 3876 "G" => $BackgroundG1, 3877 "B" => $BackgroundB1, 3878 "Alpha" => $BackgroundAlpha1 3879 ]; 3880 } else { 3881 $BGColor = [ 3882 "R" => $BackgroundR2, 3883 "G" => $BackgroundG2, 3884 "B" => $BackgroundB2, 3885 "Alpha" => $BackgroundAlpha2 3886 ]; 3887 } 3888 if ($LastX != null 3889 && $CycleBackground 3890 && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) 3891 ) { 3892 $this->drawFilledRectangle( 3893 $LastX, 3894 $this->GraphAreaY1 + $FloatingOffset, 3895 $XPos, 3896 $this->GraphAreaY2 - $FloatingOffset, 3897 $BGColor 3898 ); 3899 } 3900 3901 if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) { 3902 $this->drawLine( 3903 $XPos, 3904 $this->GraphAreaY1 + $FloatingOffset, 3905 $XPos, 3906 $this->GraphAreaY2 - $FloatingOffset, 3907 [ 3908 "R" => $GridR, 3909 "G" => $GridG, 3910 "B" => $GridB, 3911 "Alpha" => $GridAlpha, 3912 "Ticks" => $GridTicks 3913 ] 3914 ); 3915 } 3916 3917 if ($DrawSubTicks && $i != $Parameters["Rows"]) { 3918 $this->drawLine( 3919 $XPos + $SubTicksSize, 3920 $YPos - $OuterSubTickWidth, 3921 $XPos + $SubTicksSize, 3922 $YPos + $InnerSubTickWidth, 3923 [ 3924 "R" => $SubTickR, 3925 "G" => $SubTickG, 3926 "B" => $SubTickB, 3927 "Alpha" => $SubTickAlpha 3928 ] 3929 ); 3930 } 3931 $this->drawLine( 3932 $XPos, 3933 $YPos - $OuterTickWidth, 3934 $XPos, 3935 $YPos + $InnerTickWidth, 3936 ["R" => $TickR, "G" => $TickG, "B" => $TickB, "Alpha" => $TickAlpha] 3937 ); 3938 $Bounds = $this->drawText( 3939 $XPos, 3940 $YPos - $OuterTickWidth - 2, 3941 $Value, 3942 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE] 3943 ); 3944 $TxtHeight = $YPos - $OuterTickWidth - 2 - ($Bounds[1]["Y"] - $Bounds[2]["Y"]); 3945 $MinTop = min($MinTop, $TxtHeight); 3946 3947 $LastX = $XPos; 3948 } 3949 3950 if (isset($Parameters["Name"])) { 3951 $YPos = $MinTop - 2; 3952 $XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2; 3953 $Bounds = $this->drawText( 3954 $XPos, 3955 $YPos, 3956 $Parameters["Name"], 3957 ["Align" => TEXT_ALIGN_BOTTOMMIDDLE] 3958 ); 3959 $MinTop = $Bounds[2]["Y"]; 3960 3961 $this->DataSet->Data["GraphArea"]["Y1"] = $MinTop; 3962 } 3963 3964 $AxisPos["T"] = $MinTop - $ScaleSpacing; 3965 } elseif ($Parameters["Position"] == AXIS_POSITION_BOTTOM) { 3966 if ($Floating) { 3967 $FloatingOffset = $XMargin; 3968 $this->drawLine( 3969 $this->GraphAreaX1 + $Parameters["Margin"], 3970 $AxisPos["B"], 3971 $this->GraphAreaX2 - $Parameters["Margin"], 3972 $AxisPos["B"], 3973 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3974 ); 3975 } else { 3976 $FloatingOffset = 0; 3977 $this->drawLine( 3978 $this->GraphAreaX1, 3979 $AxisPos["B"], 3980 $this->GraphAreaX2, 3981 $AxisPos["B"], 3982 ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha] 3983 ); 3984 } 3985 3986 if ($DrawArrows) { 3987 $this->drawArrow( 3988 $this->GraphAreaX2 - $Parameters["Margin"], 3989 $AxisPos["B"], 3990 $this->GraphAreaX2 + ($ArrowSize * 2), 3991 $AxisPos["B"], 3992 [ 3993 "FillR" => $AxisR, 3994 "FillG" => $AxisG, 3995 "FillB" => $AxisB, 3996 "Size" => $ArrowSize 3997 ] 3998 ); 3999 } 4000 4001 $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2; 4002 $Step = $Width / $Parameters["Rows"]; 4003 $SubTicksSize = $Step / 2; 4004 $MaxBottom = $AxisPos["B"]; 4005 $LastX = null; 4006 for ($i = 0; $i <= $Parameters["Rows"]; $i++) { 4007 $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i; 4008 $YPos = $AxisPos["B"]; 4009 $Value = $this->scaleFormat( 4010 $Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, 4011 $Parameters["Display"], 4012 $Parameters["Format"], 4013 $Parameters["Unit"] 4014 ); 4015 4016 if ($i % 2 == 1) { 4017 $BGColor = [ 4018 "R" => $BackgroundR1, 4019 "G" => $BackgroundG1, 4020 "B" => $BackgroundB1, 4021 "Alpha" => $BackgroundAlpha1 4022 ]; 4023 } else { 4024 $BGColor = [ 4025 "R" => $BackgroundR2, 4026 "G" => $BackgroundG2, 4027 "B" => $BackgroundB2, 4028 "Alpha" => $BackgroundAlpha2 4029 ]; 4030 } 4031 if ($LastX != null 4032 && $CycleBackground 4033 && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) 4034 ) { 4035 $this->drawFilledRectangle( 4036 $LastX, 4037 $this->GraphAreaY1 + $FloatingOffset, 4038 $XPos, 4039 $this->GraphAreaY2 - $FloatingOffset, 4040 $BGColor 4041 ); 4042 } 4043 4044 if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) { 4045 $this->drawLine( 4046 $XPos, 4047 $this->GraphAreaY1 + $FloatingOffset, 4048 $XPos, 4049 $this->GraphAreaY2 - $FloatingOffset, 4050 [ 4051 "R" => $GridR, 4052 "G" => $GridG, 4053 "B" => $GridB, 4054 "Alpha" => $GridAlpha, 4055 "Ticks" => $GridTicks 4056 ] 4057 ); 4058 } 4059 4060 if ($DrawSubTicks && $i != $Parameters["Rows"]) { 4061 $this->drawLine( 4062 $XPos + $SubTicksSize, 4063 $YPos - $OuterSubTickWidth, 4064 $XPos + $SubTicksSize, 4065 $YPos + $InnerSubTickWidth, 4066 [ 4067 "R" => $SubTickR, 4068 "G" => $SubTickG, 4069 "B" => $SubTickB, 4070 "Alpha" => $SubTickAlpha 4071 ] 4072 ); 4073 } 4074 $this->drawLine( 4075 $XPos, 4076 $YPos - $OuterTickWidth, 4077 $XPos, 4078 $YPos + $InnerTickWidth, 4079 ["R" => $TickR, "G" => $TickG, "B" => $TickB, "Alpha" => $TickAlpha] 4080 ); 4081 $Bounds = $this->drawText( 4082 $XPos, 4083 $YPos + $OuterTickWidth + 2, 4084 $Value, 4085 ["Align" => TEXT_ALIGN_TOPMIDDLE] 4086 ); 4087 $TxtHeight = $YPos + $OuterTickWidth + 2 + ($Bounds[1]["Y"] - $Bounds[2]["Y"]); 4088 $MaxBottom = max($MaxBottom, $TxtHeight); 4089 4090 $LastX = $XPos; 4091 } 4092 4093 if (isset($Parameters["Name"])) { 4094 $YPos = $MaxBottom + 2; 4095 $XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2; 4096 $Bounds = $this->drawText( 4097 $XPos, 4098 $YPos, 4099 $Parameters["Name"], 4100 ["Align" => TEXT_ALIGN_TOPMIDDLE] 4101 ); 4102 $MaxBottom = $Bounds[0]["Y"]; 4103 4104 $this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize; 4105 } 4106 4107 $AxisPos["B"] = $MaxBottom + $ScaleSpacing; 4108 } 4109 } 4110 } 4111 } 4112 } 4113 4114 /** 4115 * Draw an X threshold 4116 * @param mixed $Value 4117 * @param boolean $Format 4118 * @return array|null|integer 4119 */ 4120 public function drawXThreshold($Value, array $Format = []) 4121 { 4122 $R = isset($Format["R"]) ? $Format["R"] : 255; 4123 $G = isset($Format["G"]) ? $Format["G"] : 0; 4124 $B = isset($Format["B"]) ? $Format["B"] : 0; 4125 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; 4126 $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; 4127 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 6; 4128 $Wide = isset($Format["Wide"]) ? $Format["Wide"] : false; 4129 $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; 4130 $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : false; 4131 $Caption = isset($Format["Caption"]) ? $Format["Caption"] : null; 4132 $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; 4133 $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 5; 4134 $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; 4135 $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; 4136 $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; 4137 $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; 4138 $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : true; 4139 $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : false; 4140 $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 3; 4141 $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : true; 4142 $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; 4143 $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; 4144 $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; 4145 $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; 4146 $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 30; 4147 $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; 4148 $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; 4149 $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; 4150 $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; 4151 $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; 4152 $ValueIsLabel = isset($Format["ValueIsLabel"]) ? $Format["ValueIsLabel"] : false; 4153 4154 $Data = $this->DataSet->getData(); 4155 $AbscissaMargin = $this->getAbscissaMargin($Data); 4156 $XScale = $this->scaleGetXSettings(); 4157 4158 if (is_array($Value)) { 4159 foreach ($Value as $Key => $ID) { 4160 $this->drawXThreshold($ID, $Format); 4161 } 4162 return 0; 4163 } 4164 4165 if ($ValueIsLabel) { 4166 $Format["ValueIsLabel"] = false; 4167 foreach ($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $SerieValue) { 4168 if ($SerieValue == $Value) { 4169 $this->drawXThreshold($Key, $Format); 4170 } 4171 } 4172 return 0; 4173 } 4174 4175 $CaptionSettings = [ 4176 "DrawBox" => $DrawBox, 4177 "DrawBoxBorder" => $DrawBoxBorder, 4178 "BorderOffset" => $BorderOffset, 4179 "BoxRounded" => $BoxRounded, 4180 "RoundedRadius" => $RoundedRadius, 4181 "BoxR" => $BoxR, 4182 "BoxG" => $BoxG, 4183 "BoxB" => $BoxB, 4184 "BoxAlpha" => $BoxAlpha, 4185 "BoxSurrounding" => $BoxSurrounding, 4186 "BoxBorderR" => $BoxBorderR, 4187 "BoxBorderG" => $BoxBorderG, 4188 "BoxBorderB" => $BoxBorderB, 4189 "BoxBorderAlpha" => $BoxBorderAlpha, 4190 "R" => $CaptionR, 4191 "G" => $CaptionG, 4192 "B" => $CaptionB, 4193 "Alpha" => $CaptionAlpha 4194 ]; 4195 4196 if ($Caption == null) { 4197 $Caption = $Value; 4198 if (isset($Data["Abscissa"]) 4199 && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Value]) 4200 ) { 4201 $Caption = $Data["Series"][$Data["Abscissa"]]["Data"][$Value]; 4202 } 4203 } 4204 4205 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 4206 $XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] * 2) / $XScale[1]; 4207 $XPos = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value; 4208 $YPos1 = $this->GraphAreaY1 + $Data["YMargin"]; 4209 $YPos2 = $this->GraphAreaY2 - $Data["YMargin"]; 4210 4211 if ($XPos >= $this->GraphAreaX1 + $AbscissaMargin 4212 && $XPos <= $this->GraphAreaX2 - $AbscissaMargin 4213 ) { 4214 $this->drawLine( 4215 $XPos, 4216 $YPos1, 4217 $XPos, 4218 $YPos2, 4219 [ 4220 "R" => $R, 4221 "G" => $G, 4222 "B" => $B, 4223 "Alpha" => $Alpha, 4224 "Ticks" => $Ticks, 4225 "Weight" => $Weight 4226 ] 4227 ); 4228 4229 if ($Wide) { 4230 $this->drawLine( 4231 $XPos - 1, 4232 $YPos1, 4233 $XPos - 1, 4234 $YPos2, 4235 [ 4236 "R" => $R, 4237 "G" => $G, 4238 "B" => $B, 4239 "Alpha" => $Alpha / $WideFactor, 4240 "Ticks" => $Ticks 4241 ] 4242 ); 4243 $this->drawLine( 4244 $XPos + 1, 4245 $YPos1, 4246 $XPos + 1, 4247 $YPos2, 4248 [ 4249 "R" => $R, 4250 "G" => $G, 4251 "B" => $B, 4252 "Alpha" => $Alpha / $WideFactor, 4253 "Ticks" => $Ticks 4254 ] 4255 ); 4256 } 4257 4258 if ($WriteCaption) { 4259 if ($CaptionAlign == CAPTION_LEFT_TOP) { 4260 $Y = $YPos1 + $CaptionOffset; 4261 $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; 4262 } else { 4263 $Y = $YPos2 - $CaptionOffset; 4264 $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; 4265 } 4266 $this->drawText($XPos, $Y, $Caption, $CaptionSettings); 4267 } 4268 4269 return ["X" => $XPos]; 4270 } 4271 } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { 4272 $XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] * 2) / $XScale[1]; 4273 $XPos = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value; 4274 $YPos1 = $this->GraphAreaX1 + $Data["YMargin"]; 4275 $YPos2 = $this->GraphAreaX2 - $Data["YMargin"]; 4276 4277 if ($XPos >= $this->GraphAreaY1 + $AbscissaMargin 4278 && $XPos <= $this->GraphAreaY2 - $AbscissaMargin 4279 ) { 4280 $this->drawLine( 4281 $YPos1, 4282 $XPos, 4283 $YPos2, 4284 $XPos, 4285 [ 4286 "R" => $R, 4287 "G" => $G, 4288 "B" => $B, 4289 "Alpha" => $Alpha, 4290 "Ticks" => $Ticks, 4291 "Weight" => $Weight 4292 ] 4293 ); 4294 4295 if ($Wide) { 4296 $this->drawLine( 4297 $YPos1, 4298 $XPos - 1, 4299 $YPos2, 4300 $XPos - 1, 4301 [ 4302 "R" => $R, 4303 "G" => $G, 4304 "B" => $B, 4305 "Alpha" => $Alpha / $WideFactor, 4306 "Ticks" => $Ticks 4307 ] 4308 ); 4309 $this->drawLine( 4310 $YPos1, 4311 $XPos + 1, 4312 $YPos2, 4313 $XPos + 1, 4314 [ 4315 "R" => $R, 4316 "G" => $G, 4317 "B" => $B, 4318 "Alpha" => $Alpha / $WideFactor, 4319 "Ticks" => $Ticks 4320 ] 4321 ); 4322 } 4323 4324 if ($WriteCaption) { 4325 if ($CaptionAlign == CAPTION_LEFT_TOP) { 4326 $Y = $YPos1 + $CaptionOffset; 4327 $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; 4328 } else { 4329 $Y = $YPos2 - $CaptionOffset; 4330 $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; 4331 } 4332 4333 $this->drawText($Y, $XPos, $Caption, $CaptionSettings); 4334 } 4335 4336 return ["X" => $XPos]; 4337 } 4338 } 4339 } 4340 4341 /** 4342 * Draw an X threshold area 4343 * @param mixed $Value1 4344 * @param mixed $Value2 4345 * @param array $Format 4346 * @return array|null 4347 */ 4348 public function drawXThresholdArea($Value1, $Value2, array $Format = []) 4349 { 4350 $R = isset($Format["R"]) ? $Format["R"] : 255; 4351 $G = isset($Format["G"]) ? $Format["G"] : 0; 4352 $B = isset($Format["B"]) ? $Format["B"] : 0; 4353 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; 4354 $Border = isset($Format["Border"]) ? $Format["Border"] : true; 4355 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; 4356 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; 4357 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; 4358 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; 4359 $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; 4360 $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : null; 4361 $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; 4362 $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; 4363 $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; 4364 $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; 4365 $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; 4366 $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : true; 4367 4368 $RestoreShadow = $this->Shadow; 4369 if ($DisableShadowOnArea && $this->Shadow) { 4370 $this->Shadow = false; 4371 } 4372 4373 if ($BorderAlpha > 100) { 4374 $BorderAlpha = 100; 4375 } 4376 4377 $Data = $this->DataSet->getData(); 4378 $XScale = $this->scaleGetXSettings(); 4379 4380 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 4381 $XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] * 2) / $XScale[1]; 4382 $XPos1 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value1; 4383 $XPos2 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value2; 4384 $YPos1 = $this->GraphAreaY1 + $Data["YMargin"]; 4385 $YPos2 = $this->GraphAreaY2 - $Data["YMargin"]; 4386 4387 if ($XPos1 < $this->GraphAreaX1 + $XScale[0]) { 4388 $XPos1 = $this->GraphAreaX1 + $XScale[0]; 4389 } 4390 if ($XPos1 > $this->GraphAreaX2 - $XScale[0]) { 4391 $XPos1 = $this->GraphAreaX2 - $XScale[0]; 4392 } 4393 if ($XPos2 < $this->GraphAreaX1 + $XScale[0]) { 4394 $XPos2 = $this->GraphAreaX1 + $XScale[0]; 4395 } 4396 if ($XPos2 > $this->GraphAreaX2 - $XScale[0]) { 4397 $XPos2 = $this->GraphAreaX2 - $XScale[0]; 4398 } 4399 4400 $this->drawFilledRectangle( 4401 $XPos1, 4402 $YPos1, 4403 $XPos2, 4404 $YPos2, 4405 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 4406 ); 4407 4408 if ($Border) { 4409 $this->drawLine( 4410 $XPos1, 4411 $YPos1, 4412 $XPos1, 4413 $YPos2, 4414 [ 4415 "R" => $BorderR, 4416 "G" => $BorderG, 4417 "B" => $BorderB, 4418 "Alpha" => $BorderAlpha, 4419 "Ticks" => $BorderTicks 4420 ] 4421 ); 4422 $this->drawLine( 4423 $XPos2, 4424 $YPos1, 4425 $XPos2, 4426 $YPos2, 4427 [ 4428 "R" => $BorderR, 4429 "G" => $BorderG, 4430 "B" => $BorderB, 4431 "Alpha" => $BorderAlpha, 4432 "Ticks" => $BorderTicks 4433 ] 4434 ); 4435 } 4436 4437 if ($AreaName != null) { 4438 $XPos = ($XPos2 - $XPos1) / 2 + $XPos1; 4439 $YPos = ($YPos2 - $YPos1) / 2 + $YPos1; 4440 4441 if ($NameAngle == ZONE_NAME_ANGLE_AUTO) { 4442 $TxtPos = $this->getTextBox( 4443 $XPos, 4444 $YPos, 4445 $this->FontName, 4446 $this->FontSize, 4447 0, 4448 $AreaName 4449 ); 4450 $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; 4451 $NameAngle = 90; 4452 if (abs($XPos2 - $XPos1) > $TxtWidth) { 4453 $NameAngle = 0; 4454 } 4455 } 4456 $this->Shadow = $RestoreShadow; 4457 $this->drawText( 4458 $XPos, 4459 $YPos, 4460 $AreaName, 4461 [ 4462 "R" => $NameR, 4463 "G" => $NameG, 4464 "B" => $NameB, 4465 "Alpha" => $NameAlpha, 4466 "Angle" => $NameAngle, 4467 "Align" => TEXT_ALIGN_MIDDLEMIDDLE 4468 ] 4469 ); 4470 if ($DisableShadowOnArea) { 4471 $this->Shadow = false; 4472 } 4473 } 4474 4475 $this->Shadow = $RestoreShadow; 4476 return ["X1" => $XPos1, "X2" => $XPos2]; 4477 } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { 4478 $XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] * 2) / $XScale[1]; 4479 $XPos1 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value1; 4480 $XPos2 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value2; 4481 $YPos1 = $this->GraphAreaX1 + $Data["YMargin"]; 4482 $YPos2 = $this->GraphAreaX2 - $Data["YMargin"]; 4483 4484 if ($XPos1 < $this->GraphAreaY1 + $XScale[0]) { 4485 $XPos1 = $this->GraphAreaY1 + $XScale[0]; 4486 } 4487 if ($XPos1 > $this->GraphAreaY2 - $XScale[0]) { 4488 $XPos1 = $this->GraphAreaY2 - $XScale[0]; 4489 } 4490 if ($XPos2 < $this->GraphAreaY1 + $XScale[0]) { 4491 $XPos2 = $this->GraphAreaY1 + $XScale[0]; 4492 } 4493 if ($XPos2 > $this->GraphAreaY2 - $XScale[0]) { 4494 $XPos2 = $this->GraphAreaY2 - $XScale[0]; 4495 } 4496 4497 $this->drawFilledRectangle( 4498 $YPos1, 4499 $XPos1, 4500 $YPos2, 4501 $XPos2, 4502 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 4503 ); 4504 4505 if ($Border) { 4506 $this->drawLine( 4507 $YPos1, 4508 $XPos1, 4509 $YPos2, 4510 $XPos1, 4511 [ 4512 "R" => $BorderR, 4513 "G" => $BorderG, 4514 "B" => $BorderB, 4515 "Alpha" => $BorderAlpha, 4516 "Ticks" => $BorderTicks 4517 ] 4518 ); 4519 $this->drawLine( 4520 $YPos1, 4521 $XPos2, 4522 $YPos2, 4523 $XPos2, 4524 [ 4525 "R" => $BorderR, 4526 "G" => $BorderG, 4527 "B" => $BorderB, 4528 "Alpha" => $BorderAlpha, 4529 "Ticks" => $BorderTicks 4530 ] 4531 ); 4532 } 4533 4534 if ($AreaName != null) { 4535 $XPos = ($XPos2 - $XPos1) / 2 + $XPos1; 4536 $YPos = ($YPos2 - $YPos1) / 2 + $YPos1; 4537 4538 $this->Shadow = $RestoreShadow; 4539 $this->drawText( 4540 $YPos, 4541 $XPos, 4542 $AreaName, 4543 [ 4544 "R" => $NameR, 4545 "G" => $NameG, 4546 "B" => $NameB, 4547 "Alpha" => $NameAlpha, 4548 "Angle" => 0, 4549 "Align" => TEXT_ALIGN_MIDDLEMIDDLE 4550 ] 4551 ); 4552 if ($DisableShadowOnArea) { 4553 $this->Shadow = false; 4554 } 4555 } 4556 4557 $this->Shadow = $RestoreShadow; 4558 return ["X1" => $XPos1, "X2" => $XPos2]; 4559 } 4560 } 4561 4562 /** 4563 * Draw an Y threshold with the computed scale 4564 * @param mixed $Value 4565 * @param array $Format 4566 * @return array|int 4567 */ 4568 public function drawThreshold($Value, array $Format = []) 4569 { 4570 $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; 4571 $R = isset($Format["R"]) ? $Format["R"] : 255; 4572 $G = isset($Format["G"]) ? $Format["G"] : 0; 4573 $B = isset($Format["B"]) ? $Format["B"] : 0; 4574 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; 4575 $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; 4576 $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 6; 4577 $Wide = isset($Format["Wide"]) ? $Format["Wide"] : false; 4578 $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; 4579 $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : false; 4580 $Caption = isset($Format["Caption"]) ? $Format["Caption"] : null; 4581 $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; 4582 $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 10; 4583 $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; 4584 $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; 4585 $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; 4586 $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; 4587 $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : true; 4588 $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : false; 4589 $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 5; 4590 $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : true; 4591 $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; 4592 $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; 4593 $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; 4594 $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; 4595 $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 20; 4596 $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; 4597 $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; 4598 $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; 4599 $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; 4600 $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; 4601 $NoMargin = isset($Format["NoMargin"]) ? $Format["NoMargin"] : false; 4602 4603 if (is_array($Value)) { 4604 foreach ($Value as $Key => $ID) { 4605 $this->drawThreshold($ID, $Format); 4606 } 4607 return 0; 4608 } 4609 4610 $CaptionSettings = [ 4611 "DrawBox" => $DrawBox, 4612 "DrawBoxBorder" => $DrawBoxBorder, 4613 "BorderOffset" => $BorderOffset, 4614 "BoxRounded" => $BoxRounded, 4615 "RoundedRadius" => $RoundedRadius, 4616 "BoxR" => $BoxR, 4617 "BoxG" => $BoxG, 4618 "BoxB" => $BoxB, 4619 "BoxAlpha" => $BoxAlpha, 4620 "BoxSurrounding" => $BoxSurrounding, 4621 "BoxBorderR" => $BoxBorderR, 4622 "BoxBorderG" => $BoxBorderG, 4623 "BoxBorderB" => $BoxBorderB, 4624 "BoxBorderAlpha" => $BoxBorderAlpha, 4625 "R" => $CaptionR, 4626 "G" => $CaptionG, 4627 "B" => $CaptionB, 4628 "Alpha" => $CaptionAlpha 4629 ]; 4630 4631 $Data = $this->DataSet->getData(); 4632 $AbscissaMargin = $this->getAbscissaMargin($Data); 4633 4634 if ($NoMargin) { 4635 $AbscissaMargin = 0; 4636 } 4637 if (!isset($Data["Axis"][$AxisID])) { 4638 return -1; 4639 } 4640 if ($Caption == null) { 4641 $Caption = $Value; 4642 } 4643 4644 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 4645 $YPos = $this->scaleComputeY($Value, ["AxisID" => $AxisID]); 4646 if ($YPos >= $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"] 4647 && $YPos <= $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"] 4648 ) { 4649 $X1 = $this->GraphAreaX1 + $AbscissaMargin; 4650 $X2 = $this->GraphAreaX2 - $AbscissaMargin; 4651 4652 $this->drawLine( 4653 $X1, 4654 $YPos, 4655 $X2, 4656 $YPos, 4657 [ 4658 "R" => $R, 4659 "G" => $G, 4660 "B" => $B, 4661 "Alpha" => $Alpha, 4662 "Ticks" => $Ticks, 4663 "Weight" => $Weight 4664 ] 4665 ); 4666 4667 if ($Wide) { 4668 $this->drawLine( 4669 $X1, 4670 $YPos - 1, 4671 $X2, 4672 $YPos - 1, 4673 [ 4674 "R" => $R, 4675 "G" => $G, 4676 "B" => $B, 4677 "Alpha" => $Alpha / $WideFactor, 4678 "Ticks" => $Ticks 4679 ] 4680 ); 4681 $this->drawLine( 4682 $X1, 4683 $YPos + 1, 4684 $X2, 4685 $YPos + 1, 4686 [ 4687 "R" => $R, 4688 "G" => $G, 4689 "B" => $B, 4690 "Alpha" => $Alpha / $WideFactor, 4691 "Ticks" => $Ticks 4692 ] 4693 ); 4694 } 4695 4696 if ($WriteCaption) { 4697 if ($CaptionAlign == CAPTION_LEFT_TOP) { 4698 $X = $X1 + $CaptionOffset; 4699 $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; 4700 } else { 4701 $X = $X2 - $CaptionOffset; 4702 $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; 4703 } 4704 4705 $this->drawText($X, $YPos, $Caption, $CaptionSettings); 4706 } 4707 } 4708 4709 return ["Y" => $YPos]; 4710 } 4711 4712 if ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { 4713 $XPos = $this->scaleComputeY($Value, ["AxisID" => $AxisID]); 4714 if ($XPos >= $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] 4715 && $XPos <= $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"] 4716 ) { 4717 $Y1 = $this->GraphAreaY1 + $AbscissaMargin; 4718 $Y2 = $this->GraphAreaY2 - $AbscissaMargin; 4719 4720 $this->drawLine( 4721 $XPos, 4722 $Y1, 4723 $XPos, 4724 $Y2, 4725 [ 4726 "R" => $R, 4727 "G" => $G, 4728 "B" => $B, 4729 "Alpha" => $Alpha, 4730 "Ticks" => $Ticks, 4731 "Weight" => $Weight 4732 ] 4733 ); 4734 4735 if ($Wide) { 4736 $this->drawLine( 4737 $XPos - 1, 4738 $Y1, 4739 $XPos - 1, 4740 $Y2, 4741 [ 4742 "R" => $R, 4743 "G" => $G, 4744 "B" => $B, 4745 "Alpha" => $Alpha / $WideFactor, 4746 "Ticks" => $Ticks 4747 ] 4748 ); 4749 $this->drawLine( 4750 $XPos + 1, 4751 $Y1, 4752 $XPos + 1, 4753 $Y2, 4754 [ 4755 "R" => $R, 4756 "G" => $G, 4757 "B" => $B, 4758 "Alpha" => $Alpha / $WideFactor, 4759 "Ticks" => $Ticks 4760 ] 4761 ); 4762 } 4763 4764 if ($WriteCaption) { 4765 if ($CaptionAlign == CAPTION_LEFT_TOP) { 4766 $Y = $Y1 + $CaptionOffset; 4767 $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; 4768 } else { 4769 $Y = $Y2 - $CaptionOffset; 4770 $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; 4771 } 4772 4773 $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; 4774 $this->drawText($XPos, $Y, $Caption, $CaptionSettings); 4775 } 4776 } 4777 4778 return ["Y" => $XPos]; 4779 } 4780 } 4781 4782 /** 4783 * Draw a threshold with the computed scale 4784 * @param mixed $Value1 4785 * @param mixed $Value2 4786 * @param array $Format 4787 * @return array|int|null 4788 */ 4789 public function drawThresholdArea($Value1, $Value2, array $Format = []) 4790 { 4791 $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; 4792 $R = isset($Format["R"]) ? $Format["R"] : 255; 4793 $G = isset($Format["G"]) ? $Format["G"] : 0; 4794 $B = isset($Format["B"]) ? $Format["B"] : 0; 4795 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; 4796 $Border = isset($Format["Border"]) ? $Format["Border"] : true; 4797 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; 4798 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; 4799 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; 4800 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; 4801 $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; 4802 $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : null; 4803 $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; 4804 $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; 4805 $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; 4806 $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; 4807 $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; 4808 $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : true; 4809 $NoMargin = isset($Format["NoMargin"]) ? $Format["NoMargin"] : false; 4810 4811 if ($Value1 > $Value2) { 4812 list($Value1, $Value2) = [$Value2, $Value1]; 4813 } 4814 4815 $RestoreShadow = $this->Shadow; 4816 if ($DisableShadowOnArea && $this->Shadow) { 4817 $this->Shadow = false; 4818 } 4819 4820 if ($BorderAlpha > 100) { 4821 $BorderAlpha = 100; 4822 } 4823 4824 $Data = $this->DataSet->getData(); 4825 $AbscissaMargin = $this->getAbscissaMargin($Data); 4826 4827 if ($NoMargin) { 4828 $AbscissaMargin = 0; 4829 } 4830 if (!isset($Data["Axis"][$AxisID])) { 4831 return -1; 4832 } 4833 4834 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 4835 $XPos1 = $this->GraphAreaX1 + $AbscissaMargin; 4836 $XPos2 = $this->GraphAreaX2 - $AbscissaMargin; 4837 $YPos1 = $this->scaleComputeY($Value1, ["AxisID" => $AxisID]); 4838 $YPos2 = $this->scaleComputeY($Value2, ["AxisID" => $AxisID]); 4839 4840 if ($YPos1 < $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]) { 4841 $YPos1 = $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]; 4842 } 4843 if ($YPos1 > $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]) { 4844 $YPos1 = $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]; 4845 } 4846 if ($YPos2 < $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]) { 4847 $YPos2 = $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]; 4848 } 4849 if ($YPos2 > $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]) { 4850 $YPos2 = $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]; 4851 } 4852 4853 $this->drawFilledRectangle( 4854 $XPos1, 4855 $YPos1, 4856 $XPos2, 4857 $YPos2, 4858 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 4859 ); 4860 if ($Border) { 4861 $this->drawLine( 4862 $XPos1, 4863 $YPos1, 4864 $XPos2, 4865 $YPos1, 4866 [ 4867 "R" => $BorderR, 4868 "G" => $BorderG, 4869 "B" => $BorderB, 4870 "Alpha" => $BorderAlpha, 4871 "Ticks" => $BorderTicks 4872 ] 4873 ); 4874 $this->drawLine( 4875 $XPos1, 4876 $YPos2, 4877 $XPos2, 4878 $YPos2, 4879 [ 4880 "R" => $BorderR, 4881 "G" => $BorderG, 4882 "B" => $BorderB, 4883 "Alpha" => $BorderAlpha, 4884 "Ticks" => $BorderTicks 4885 ] 4886 ); 4887 } 4888 4889 if ($AreaName != null) { 4890 $XPos = ($XPos2 - $XPos1) / 2 + $XPos1; 4891 $YPos = ($YPos2 - $YPos1) / 2 + $YPos1; 4892 $this->Shadow = $RestoreShadow; 4893 $this->drawText( 4894 $XPos, 4895 $YPos, 4896 $AreaName, 4897 [ 4898 "R" => $NameR, 4899 "G" => $NameG, 4900 "B" => $NameB, 4901 "Alpha" => $NameAlpha, 4902 "Angle" => 0, 4903 "Align" => TEXT_ALIGN_MIDDLEMIDDLE 4904 ] 4905 ); 4906 if ($DisableShadowOnArea) { 4907 $this->Shadow = false; 4908 } 4909 } 4910 4911 $this->Shadow = $RestoreShadow; 4912 return ["Y1" => $YPos1, "Y2" => $YPos2]; 4913 } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { 4914 $YPos1 = $this->GraphAreaY1 + $AbscissaMargin; 4915 $YPos2 = $this->GraphAreaY2 - $AbscissaMargin; 4916 $XPos1 = $this->scaleComputeY($Value1, ["AxisID" => $AxisID]); 4917 $XPos2 = $this->scaleComputeY($Value2, ["AxisID" => $AxisID]); 4918 4919 if ($XPos1 < $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]) { 4920 $XPos1 = $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]; 4921 } 4922 if ($XPos1 > $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]) { 4923 $XPos1 = $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]; 4924 } 4925 if ($XPos2 < $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]) { 4926 $XPos2 = $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]; 4927 } 4928 if ($XPos2 > $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]) { 4929 $XPos2 = $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]; 4930 } 4931 4932 $this->drawFilledRectangle( 4933 $XPos1, 4934 $YPos1, 4935 $XPos2, 4936 $YPos2, 4937 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 4938 ); 4939 if ($Border) { 4940 $this->drawLine( 4941 $XPos1, 4942 $YPos1, 4943 $XPos1, 4944 $YPos2, 4945 [ 4946 "R" => $BorderR, 4947 "G" => $BorderG, 4948 "B" => $BorderB, 4949 "Alpha" => $BorderAlpha, 4950 "Ticks" => $BorderTicks 4951 ] 4952 ); 4953 $this->drawLine( 4954 $XPos2, 4955 $YPos1, 4956 $XPos2, 4957 $YPos2, 4958 [ 4959 "R" => $BorderR, 4960 "G" => $BorderG, 4961 "B" => $BorderB, 4962 "Alpha" => $BorderAlpha, 4963 "Ticks" => $BorderTicks 4964 ] 4965 ); 4966 } 4967 4968 if ($AreaName != null) { 4969 $XPos = ($YPos2 - $YPos1) / 2 + $YPos1; 4970 $YPos = ($XPos2 - $XPos1) / 2 + $XPos1; 4971 4972 if ($NameAngle == ZONE_NAME_ANGLE_AUTO) { 4973 $TxtPos = $this->getTextBox( 4974 $XPos, 4975 $YPos, 4976 $this->FontName, 4977 $this->FontSize, 4978 0, 4979 $AreaName 4980 ); 4981 $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; 4982 $NameAngle = 90; 4983 if (abs($XPos2 - $XPos1) > $TxtWidth) { 4984 $NameAngle = 0; 4985 } 4986 } 4987 $this->Shadow = $RestoreShadow; 4988 $this->drawText( 4989 $YPos, 4990 $XPos, 4991 $AreaName, 4992 [ 4993 "R" => $NameR, 4994 "G" => $NameG, 4995 "B" => $NameB, 4996 "Alpha" => $NameAlpha, 4997 "Angle" => $NameAngle, 4998 "Align" => TEXT_ALIGN_MIDDLEMIDDLE 4999 ] 5000 ); 5001 if ($DisableShadowOnArea) { 5002 $this->Shadow = false; 5003 } 5004 } 5005 5006 $this->Shadow = $RestoreShadow; 5007 return ["Y1" => $XPos1, "Y2" => $XPos2]; 5008 } 5009 } 5010 5011 /** 5012 * Draw a plot chart 5013 * @param array $Format 5014 */ 5015 public function drawPlotChart(array $Format = []) 5016 { 5017 $PlotSize = isset($Format["PlotSize"]) ? $Format["PlotSize"] : null; 5018 $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : false; 5019 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 50; 5020 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 50; 5021 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 50; 5022 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; 5023 $BorderSize = isset($Format["BorderSize"]) ? $Format["BorderSize"] : 2; 5024 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 5025 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 5026 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 4; 5027 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 5028 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 5029 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 5030 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 5031 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; 5032 5033 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 5034 5035 $Data = $this->DataSet->getData(); 5036 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 5037 5038 foreach ($Data["Series"] as $SerieName => $Serie) { 5039 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 5040 if (isset($Serie["Weight"])) { 5041 $SerieWeight = $Serie["Weight"] + 2; 5042 } else { 5043 $SerieWeight = 2; 5044 } 5045 if ($PlotSize != null) { 5046 $SerieWeight = $PlotSize; 5047 } 5048 5049 $R = $Serie["Color"]["R"]; 5050 $G = $Serie["Color"]["G"]; 5051 $B = $Serie["Color"]["B"]; 5052 $Alpha = (int) $Serie["Color"]["Alpha"]; 5053 $Ticks = $Serie["Ticks"]; 5054 if ($Surrounding != null) { 5055 $BorderR = $R + $Surrounding; 5056 $BorderG = $G + $Surrounding; 5057 $BorderB = $B + $Surrounding; 5058 } 5059 if (isset($Serie["Picture"])) { 5060 $Picture = $Serie["Picture"]; 5061 list($PicWidth, $PicHeight, $PicType) = $this->getPicInfo($Picture); 5062 } else { 5063 $Picture = null; 5064 $PicOffset = 0; 5065 } 5066 5067 if ($DisplayColor == DISPLAY_AUTO) { 5068 $DisplayR = $R; 5069 $DisplayG = $G; 5070 $DisplayB = $B; 5071 } 5072 5073 $AxisID = $Serie["Axis"]; 5074 $Shape = $Serie["Shape"]; 5075 $Mode = $Data["Axis"][$AxisID]["Display"]; 5076 $Format = $Data["Axis"][$AxisID]["Format"]; 5077 $Unit = $Data["Axis"][$AxisID]["Unit"]; 5078 5079 if (isset($Serie["Description"])) { 5080 $SerieDescription = $Serie["Description"]; 5081 } else { 5082 $SerieDescription = $SerieName; 5083 } 5084 5085 $PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]); 5086 5087 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 5088 5089 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 5090 if ($XDivs == 0) { 5091 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 5092 } else { 5093 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 5094 } 5095 if ($Picture != null) { 5096 $PicOffset = $PicHeight / 2; 5097 $SerieWeight = 0; 5098 } 5099 $X = $this->GraphAreaX1 + $XMargin; 5100 5101 if (!is_array($PosArray)) { 5102 $Value = $PosArray; 5103 $PosArray = []; 5104 $PosArray[0] = $Value; 5105 } 5106 foreach ($PosArray as $Key => $Y) { 5107 if ($DisplayValues) { 5108 $this->drawText( 5109 $X, 5110 $Y - $DisplayOffset - $SerieWeight - $BorderSize - $PicOffset, 5111 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 5112 [ 5113 "R" => $DisplayR, 5114 "G" => $DisplayG, 5115 "B" => $DisplayB, 5116 "Align" => TEXT_ALIGN_BOTTOMMIDDLE 5117 ] 5118 ); 5119 } 5120 if ($Y != VOID) { 5121 if ($RecordImageMap) { 5122 $this->addToImageMap( 5123 "CIRCLE", 5124 floor($X) . "," . floor($Y) . "," . $SerieWeight, 5125 $this->toHTMLColor($R, $G, $B), 5126 $SerieDescription, 5127 $this->scaleFormat( 5128 $Serie["Data"][$Key], 5129 $Mode, 5130 $Format, 5131 $Unit 5132 ) 5133 ); 5134 } 5135 5136 if ($Picture != null) { 5137 $this->drawFromPicture( 5138 $PicType, 5139 $Picture, 5140 $X - $PicWidth / 2, 5141 $Y - $PicHeight / 2 5142 ); 5143 } else { 5144 $this->drawShape( 5145 $X, 5146 $Y, 5147 $Shape, 5148 $SerieWeight, 5149 $PlotBorder, 5150 $BorderSize, 5151 $R, 5152 $G, 5153 $B, 5154 $Alpha, 5155 $BorderR, 5156 $BorderG, 5157 $BorderB, 5158 $BorderAlpha 5159 ); 5160 } 5161 } 5162 $X = $X + $XStep; 5163 } 5164 } else { 5165 if ($XDivs == 0) { 5166 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 5167 } else { 5168 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 5169 } 5170 if ($Picture != null) { 5171 $PicOffset = $PicWidth / 2; 5172 $SerieWeight = 0; 5173 } 5174 $Y = $this->GraphAreaY1 + $XMargin; 5175 5176 if (!is_array($PosArray)) { 5177 $Value = $PosArray; 5178 $PosArray = []; 5179 $PosArray[0] = $Value; 5180 } 5181 foreach ($PosArray as $Key => $X) { 5182 if ($DisplayValues) { 5183 $this->drawText( 5184 $X + $DisplayOffset + $SerieWeight + $BorderSize + $PicOffset, 5185 $Y, 5186 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 5187 [ 5188 "Angle" => 270, 5189 "R" => $DisplayR, 5190 "G" => $DisplayG, 5191 "B" => $DisplayB, 5192 "Align" => TEXT_ALIGN_BOTTOMMIDDLE 5193 ] 5194 ); 5195 } 5196 if ($X != VOID) { 5197 if ($RecordImageMap) { 5198 $this->addToImageMap( 5199 "CIRCLE", 5200 floor($X) . "," . floor($Y) . "," . $SerieWeight, 5201 $this->toHTMLColor($R, $G, $B), 5202 $SerieDescription, 5203 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 5204 ); 5205 } 5206 5207 if ($Picture != null) { 5208 $this->drawFromPicture( 5209 $PicType, 5210 $Picture, 5211 $X - $PicWidth / 2, 5212 $Y - $PicHeight / 2 5213 ); 5214 } else { 5215 $this->drawShape( 5216 $X, 5217 $Y, 5218 $Shape, 5219 $SerieWeight, 5220 $PlotBorder, 5221 $BorderSize, 5222 $R, 5223 $G, 5224 $B, 5225 $Alpha, 5226 $BorderR, 5227 $BorderG, 5228 $BorderB, 5229 $BorderAlpha 5230 ); 5231 } 5232 } 5233 $Y = $Y + $YStep; 5234 } 5235 } 5236 } 5237 } 5238 } 5239 5240 /** 5241 * Draw a spline chart 5242 * @param array $Format 5243 */ 5244 public function drawSplineChart(array $Format = []) 5245 { 5246 $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : true; 5247 $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; 5248 $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : null; // 234 5249 $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : null; // 55 5250 $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : null; // 26 5251 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 5252 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; 5253 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 5254 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 5255 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 5256 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 5257 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; 5258 $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; 5259 5260 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 5261 5262 $Data = $this->DataSet->getData(); 5263 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 5264 foreach ($Data["Series"] as $SerieName => $Serie) { 5265 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 5266 $R = $Serie["Color"]["R"]; 5267 $G = $Serie["Color"]["G"]; 5268 $B = $Serie["Color"]["B"]; 5269 $Alpha = $Serie["Color"]["Alpha"]; 5270 $Ticks = $Serie["Ticks"]; 5271 $Weight = $Serie["Weight"]; 5272 5273 if ($BreakR == null) { 5274 $BreakSettings = [ 5275 "R" => $R, 5276 "G" => $G, 5277 "B" => $B, 5278 "Alpha" => $Alpha, 5279 "Ticks" => $VoidTicks 5280 ]; 5281 } else { 5282 $BreakSettings = [ 5283 "R" => $BreakR, 5284 "G" => $BreakG, 5285 "B" => $BreakB, 5286 "Alpha" => $Alpha, 5287 "Ticks" => $VoidTicks, 5288 "Weight" => $Weight 5289 ]; 5290 } 5291 if ($DisplayColor == DISPLAY_AUTO) { 5292 $DisplayR = $R; 5293 $DisplayG = $G; 5294 $DisplayB = $B; 5295 } 5296 5297 $AxisID = $Serie["Axis"]; 5298 $Mode = $Data["Axis"][$AxisID]["Display"]; 5299 $Format = $Data["Axis"][$AxisID]["Format"]; 5300 $Unit = $Data["Axis"][$AxisID]["Unit"]; 5301 5302 if (isset($Serie["Description"])) { 5303 $SerieDescription = $Serie["Description"]; 5304 } else { 5305 $SerieDescription = $SerieName; 5306 } 5307 5308 $PosArray = $this->scaleComputeY( 5309 $Serie["Data"], 5310 ["AxisID" => $Serie["Axis"]] 5311 ); 5312 5313 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 5314 5315 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 5316 if ($XDivs == 0) { 5317 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 5318 } else { 5319 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 5320 } 5321 $X = $this->GraphAreaX1 + $XMargin; 5322 $WayPoints = []; 5323 $Force = $XStep / 5; 5324 5325 if (!is_array($PosArray)) { 5326 $Value = $PosArray; 5327 $PosArray = []; 5328 $PosArray[0] = $Value; 5329 } 5330 $LastGoodY = null; 5331 $LastGoodX = null; 5332 $LastX = 1; 5333 $LastY = 1; 5334 foreach ($PosArray as $Key => $Y) { 5335 if ($DisplayValues) { 5336 $this->drawText( 5337 $X, 5338 $Y - $DisplayOffset, 5339 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 5340 [ 5341 "R" => $DisplayR, 5342 "G" => $DisplayG, 5343 "B" => $DisplayB, 5344 "Align" => TEXT_ALIGN_BOTTOMMIDDLE 5345 ] 5346 ); 5347 } 5348 if ($RecordImageMap && $Y != VOID) { 5349 $this->addToImageMap( 5350 "CIRCLE", 5351 floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, 5352 $this->toHTMLColor($R, $G, $B), 5353 $SerieDescription, 5354 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 5355 ); 5356 } 5357 5358 if ($Y == VOID && $LastY != null) { 5359 $this->drawSpline( 5360 $WayPoints, 5361 [ 5362 "Force" => $Force, 5363 "R" => $R, 5364 "G" => $G, 5365 "B" => $B, 5366 "Alpha" => $Alpha, 5367 "Ticks" => $Ticks, 5368 "Weight" => $Weight 5369 ] 5370 ); 5371 $WayPoints = []; 5372 } 5373 5374 if ($Y != VOID && $LastY == null && $LastGoodY != null && !$BreakVoid) { 5375 $this->drawLine($LastGoodX, $LastGoodY, $X, $Y, $BreakSettings); 5376 } 5377 5378 if ($Y != VOID) { 5379 $WayPoints[] = [$X, $Y]; 5380 } 5381 if ($Y != VOID) { 5382 $LastGoodY = $Y; 5383 $LastGoodX = $X; 5384 } 5385 if ($Y == VOID) { 5386 $Y = null; 5387 } 5388 5389 $LastX = $X; 5390 $LastY = $Y; 5391 $X = $X + $XStep; 5392 } 5393 $this->drawSpline( 5394 $WayPoints, 5395 [ 5396 "Force" => $Force, 5397 "R" => $R, 5398 "G" => $G, 5399 "B" => $B, 5400 "Alpha" => $Alpha, 5401 "Ticks" => $Ticks, 5402 "Weight" => $Weight 5403 ] 5404 ); 5405 } else { 5406 if ($XDivs == 0) { 5407 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 5408 } else { 5409 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 5410 } 5411 $Y = $this->GraphAreaY1 + $XMargin; 5412 $WayPoints = []; 5413 $Force = $YStep / 5; 5414 5415 if (!is_array($PosArray)) { 5416 $Value = $PosArray; 5417 $PosArray = []; 5418 $PosArray[0] = $Value; 5419 } 5420 $LastGoodY = null; 5421 $LastGoodX = null; 5422 $LastX = 1; 5423 $LastY = 1; 5424 foreach ($PosArray as $Key => $X) { 5425 if ($DisplayValues) { 5426 $this->drawText( 5427 $X + $DisplayOffset, 5428 $Y, 5429 $this->scaleFormat( 5430 $Serie["Data"][$Key], 5431 $Mode, 5432 $Format, 5433 $Unit 5434 ), 5435 [ 5436 "Angle" => 270, 5437 "R" => $DisplayR, 5438 "G" => $DisplayG, 5439 "B" => $DisplayB, 5440 "Align" => TEXT_ALIGN_BOTTOMMIDDLE 5441 ] 5442 ); 5443 } 5444 if ($RecordImageMap && $X != VOID) { 5445 $this->addToImageMap( 5446 "CIRCLE", 5447 floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, 5448 $this->toHTMLColor($R, $G, $B), 5449 $SerieDescription, 5450 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 5451 ); 5452 } 5453 5454 if ($X == VOID && $LastX != null) { 5455 $this->drawSpline( 5456 $WayPoints, 5457 [ 5458 "Force" => $Force, 5459 "R" => $R, 5460 "G" => $G, 5461 "B" => $B, 5462 "Alpha" => $Alpha, 5463 "Ticks" => $Ticks, 5464 "Weight" => $Weight 5465 ] 5466 ); 5467 $WayPoints = []; 5468 } 5469 5470 if ($X != VOID && $LastX == null && $LastGoodX != null && !$BreakVoid) { 5471 $this->drawLine($LastGoodX, $LastGoodY, $X, $Y, $BreakSettings); 5472 } 5473 5474 if ($X != VOID) { 5475 $WayPoints[] = [$X, $Y]; 5476 } 5477 if ($X != VOID) { 5478 $LastGoodX = $X; 5479 $LastGoodY = $Y; 5480 } 5481 if ($X == VOID) { 5482 $X = null; 5483 } 5484 5485 $LastX = $X; 5486 $LastY = $Y; 5487 $Y = $Y + $YStep; 5488 } 5489 $this->drawSpline( 5490 $WayPoints, 5491 [ 5492 "Force" => $Force, 5493 "R" => $R, 5494 "G" => $G, 5495 "B" => $B, 5496 "Alpha" => $Alpha, 5497 "Ticks" => $Ticks, 5498 "Weight" => $Weight 5499 ] 5500 ); 5501 } 5502 } 5503 } 5504 } 5505 5506 /** 5507 * Draw a filled spline chart 5508 * @param array $Format 5509 */ 5510 public function drawFilledSplineChart(array $Format = []) 5511 { 5512 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 5513 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; 5514 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 5515 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 5516 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 5517 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 5518 $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; 5519 $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; 5520 5521 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 5522 5523 $Data = $this->DataSet->getData(); 5524 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 5525 foreach ($Data["Series"] as $SerieName => $Serie) { 5526 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 5527 $R = $Serie["Color"]["R"]; 5528 $G = $Serie["Color"]["G"]; 5529 $B = $Serie["Color"]["B"]; 5530 $Alpha = $Serie["Color"]["Alpha"]; 5531 $Ticks = $Serie["Ticks"]; 5532 if ($DisplayColor == DISPLAY_AUTO) { 5533 $DisplayR = $R; 5534 $DisplayG = $G; 5535 $DisplayB = $B; 5536 } 5537 5538 $AxisID = $Serie["Axis"]; 5539 $Mode = $Data["Axis"][$AxisID]["Display"]; 5540 $Format = $Data["Axis"][$AxisID]["Format"]; 5541 $Unit = $Data["Axis"][$AxisID]["Unit"]; 5542 5543 $PosArray = $this->scaleComputeY( 5544 $Serie["Data"], 5545 ["AxisID" => $Serie["Axis"]] 5546 ); 5547 if ($AroundZero) { 5548 $YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]); 5549 } 5550 5551 if ($Threshold != null) { 5552 foreach ($Threshold as $Key => $Params) { 5553 $Threshold[$Key]["MinX"] = $this->scaleComputeY( 5554 $Params["Min"], 5555 ["AxisID" => $Serie["Axis"]] 5556 ); 5557 $Threshold[$Key]["MaxX"] = $this->scaleComputeY( 5558 $Params["Max"], 5559 ["AxisID" => $Serie["Axis"]] 5560 ); 5561 } 5562 } 5563 5564 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 5565 5566 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 5567 if ($XDivs == 0) { 5568 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 5569 } else { 5570 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 5571 } 5572 $X = $this->GraphAreaX1 + $XMargin; 5573 $WayPoints = []; 5574 $Force = $XStep / 5; 5575 5576 if (!$AroundZero) { 5577 $YZero = $this->GraphAreaY2 - 1; 5578 } 5579 if ($YZero > $this->GraphAreaY2 - 1) { 5580 $YZero = $this->GraphAreaY2 - 1; 5581 } 5582 if ($YZero < $this->GraphAreaY1 + 1) { 5583 $YZero = $this->GraphAreaY1 + 1; 5584 } 5585 5586 if (!is_array($PosArray)) { 5587 $Value = $PosArray; 5588 $PosArray = []; 5589 $PosArray[0] = $Value; 5590 } 5591 foreach ($PosArray as $Key => $Y) { 5592 if ($DisplayValues) { 5593 $this->drawText( 5594 $X, 5595 $Y - $DisplayOffset, 5596 $this->scaleFormat( 5597 $Serie["Data"][$Key], 5598 $Mode, 5599 $Format, 5600 $Unit 5601 ), 5602 [ 5603 "R" => $DisplayR, 5604 "G" => $DisplayG, 5605 "B" => $DisplayB, 5606 "Align" => TEXT_ALIGN_BOTTOMMIDDLE 5607 ] 5608 ); 5609 } 5610 if ($Y == VOID) { 5611 $Area = $this->drawSpline( 5612 $WayPoints, 5613 ["Force" => $Force, "PathOnly" => true] 5614 ); 5615 5616 if (count($Area)) { 5617 foreach ($Area as $key => $Points) { 5618 $Corners = []; 5619 $Corners[] = $Area[$key][0]["X"]; 5620 $Corners[] = $YZero; 5621 foreach ($Points as $subKey => $Point) { 5622 if ($subKey == count($Points) - 1) { 5623 $Corners[] = $Point["X"] - 1; 5624 } else { 5625 $Corners[] = $Point["X"]; 5626 } 5627 $Corners[] = $Point["Y"] + 1; 5628 } 5629 $Corners[] = $Points[$subKey]["X"] - 1; 5630 $Corners[] = $YZero; 5631 5632 $this->drawPolygonChart( 5633 $Corners, 5634 [ 5635 "R" => $R, 5636 "G" => $G, 5637 "B" => $B, 5638 "Alpha" => $Alpha / 2, 5639 "NoBorder" => true, 5640 "Threshold" => $Threshold 5641 ] 5642 ); 5643 } 5644 $this->drawSpline( 5645 $WayPoints, 5646 [ 5647 "Force" => $Force, 5648 "R" => $R, 5649 "G" => $G, 5650 "B" => $B, 5651 "Alpha" => $Alpha, 5652 "Ticks" => $Ticks 5653 ] 5654 ); 5655 } 5656 5657 $WayPoints = []; 5658 } else { 5659 $WayPoints[] = [$X, $Y - .5]; /* -.5 for AA visual fix */ 5660 } 5661 $X = $X + $XStep; 5662 } 5663 $Area = $this->drawSpline($WayPoints, ["Force" => $Force, "PathOnly" => true]); 5664 5665 if (count($Area)) { 5666 foreach ($Area as $key => $Points) { 5667 $Corners = []; 5668 $Corners[] = $Area[$key][0]["X"]; 5669 $Corners[] = $YZero; 5670 foreach ($Points as $subKey => $Point) { 5671 if ($subKey == count($Points) - 1) { 5672 $Corners[] = $Point["X"] - 1; 5673 } else { 5674 $Corners[] = $Point["X"]; 5675 } 5676 $Corners[] = $Point["Y"] + 1; 5677 } 5678 $Corners[] = $Points[$subKey]["X"] - 1; 5679 $Corners[] = $YZero; 5680 5681 $this->drawPolygonChart( 5682 $Corners, 5683 [ 5684 "R" => $R, 5685 "G" => $G, 5686 "B" => $B, 5687 "Alpha" => $Alpha / 2, 5688 "NoBorder" => true, 5689 "Threshold" => $Threshold 5690 ] 5691 ); 5692 } 5693 $this->drawSpline( 5694 $WayPoints, 5695 [ 5696 "Force" => $Force, 5697 "R" => $R, 5698 "G" => $G, 5699 "B" => $B, 5700 "Alpha" => $Alpha, 5701 "Ticks" => $Ticks 5702 ] 5703 ); 5704 } 5705 } else { 5706 if ($XDivs == 0) { 5707 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 5708 } else { 5709 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 5710 } 5711 $Y = $this->GraphAreaY1 + $XMargin; 5712 $WayPoints = []; 5713 $Force = $YStep / 5; 5714 5715 if (!$AroundZero) { 5716 $YZero = $this->GraphAreaX1 + 1; 5717 } 5718 if ($YZero > $this->GraphAreaX2 - 1) { 5719 $YZero = $this->GraphAreaX2 - 1; 5720 } 5721 if ($YZero < $this->GraphAreaX1 + 1) { 5722 $YZero = $this->GraphAreaX1 + 1; 5723 } 5724 5725 if (!is_array($PosArray)) { 5726 $Value = $PosArray; 5727 $PosArray = []; 5728 $PosArray[0] = $Value; 5729 } 5730 foreach ($PosArray as $Key => $X) { 5731 if ($DisplayValues) { 5732 $this->drawText( 5733 $X + $DisplayOffset, 5734 $Y, 5735 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 5736 [ 5737 "Angle" => 270, 5738 "R" => $DisplayR, 5739 "G" => $DisplayG, 5740 "B" => $DisplayB, 5741 "Align" => TEXT_ALIGN_BOTTOMMIDDLE 5742 ] 5743 ); 5744 } 5745 if ($X == VOID) { 5746 $Area = $this->drawSpline( 5747 $WayPoints, 5748 ["Force" => $Force, "PathOnly" => true] 5749 ); 5750 5751 if (count($Area)) { 5752 foreach ($Area as $key => $Points) { 5753 $Corners = []; 5754 $Corners[] = $YZero; 5755 $Corners[] = $Area[$key][0]["Y"]; 5756 foreach ($Points as $subKey => $Point) { 5757 if ($subKey == count($Points) - 1) { 5758 $Corners[] = $Point["X"] - 1; 5759 } else { 5760 $Corners[] = $Point["X"]; 5761 } 5762 $Corners[] = $Point["Y"]; 5763 } 5764 $Corners[] = $YZero; 5765 $Corners[] = $Points[$subKey]["Y"] - 1; 5766 5767 $this->drawPolygonChart( 5768 $Corners, 5769 [ 5770 "R" => $R, 5771 "G" => $G, 5772 "B" => $B, 5773 "Alpha" => $Alpha / 2, 5774 "NoBorder" => true, 5775 "Threshold" => $Threshold 5776 ] 5777 ); 5778 } 5779 $this->drawSpline( 5780 $WayPoints, 5781 [ 5782 "Force" => $Force, 5783 "R" => $R, 5784 "G" => $G, 5785 "B" => $B, 5786 "Alpha" => $Alpha, 5787 "Ticks" => $Ticks 5788 ] 5789 ); 5790 } 5791 5792 $WayPoints = []; 5793 } else { 5794 $WayPoints[] = [$X, $Y]; 5795 } 5796 $Y = $Y + $YStep; 5797 } 5798 $Area = $this->drawSpline( 5799 $WayPoints, 5800 ["Force" => $Force, "PathOnly" => true] 5801 ); 5802 5803 if (count($Area)) { 5804 foreach ($Area as $key => $Points) { 5805 $Corners = []; 5806 $Corners[] = $YZero; 5807 $Corners[] = $Area[$key][0]["Y"]; 5808 foreach ($Points as $subKey => $Point) { 5809 if ($subKey == count($Points) - 1) { 5810 $Corners[] = $Point["X"] - 1; 5811 } else { 5812 $Corners[] = $Point["X"]; 5813 } 5814 $Corners[] = $Point["Y"]; 5815 } 5816 $Corners[] = $YZero; 5817 $Corners[] = $Points[$subKey]["Y"] - 1; 5818 5819 $this->drawPolygonChart( 5820 $Corners, 5821 [ 5822 "R" => $R, 5823 "G" => $G, 5824 "B" => $B, 5825 "Alpha" => $Alpha / 2, 5826 "NoBorder" => true, 5827 "Threshold" => $Threshold 5828 ] 5829 ); 5830 } 5831 $this->drawSpline( 5832 $WayPoints, 5833 [ 5834 "Force" => $Force, 5835 "R" => $R, 5836 "G" => $G, 5837 "B" => $B, 5838 "Alpha" => $Alpha, 5839 "Ticks" => $Ticks 5840 ] 5841 ); 5842 } 5843 } 5844 } 5845 } 5846 } 5847 5848 /** 5849 * Draw a line chart 5850 * @param array $Format 5851 */ 5852 public function drawLineChart(array $Format = []) 5853 { 5854 $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : true; 5855 $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; 5856 $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : null; 5857 $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : null; 5858 $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : null; 5859 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 5860 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; 5861 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 5862 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 5863 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 5864 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 5865 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; 5866 $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; 5867 $ForceColor = isset($Format["ForceColor"]) ? $Format["ForceColor"] : false; 5868 $ForceR = isset($Format["ForceR"]) ? $Format["ForceR"] : 0; 5869 $ForceG = isset($Format["ForceG"]) ? $Format["ForceG"] : 0; 5870 $ForceB = isset($Format["ForceB"]) ? $Format["ForceB"] : 0; 5871 $ForceAlpha = isset($Format["ForceAlpha"]) ? $Format["ForceAlpha"] : 100; 5872 5873 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 5874 5875 $Data = $this->DataSet->getData(); 5876 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 5877 foreach ($Data["Series"] as $SerieName => $Serie) { 5878 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 5879 $R = $Serie["Color"]["R"]; 5880 $G = $Serie["Color"]["G"]; 5881 $B = $Serie["Color"]["B"]; 5882 $Alpha = $Serie["Color"]["Alpha"]; 5883 $Ticks = $Serie["Ticks"]; 5884 $Weight = $Serie["Weight"]; 5885 5886 if ($ForceColor) { 5887 $R = $ForceR; 5888 $G = $ForceG; 5889 $B = $ForceB; 5890 $Alpha = $ForceAlpha; 5891 } 5892 5893 if ($BreakR == null) { 5894 $BreakSettings = [ 5895 "R" => $R, 5896 "G" => $G, 5897 "B" => $B, 5898 "Alpha" => $Alpha, 5899 "Ticks" => $VoidTicks, 5900 "Weight" => $Weight 5901 ]; 5902 } else { 5903 $BreakSettings = [ 5904 "R" => $BreakR, 5905 "G" => $BreakG, 5906 "B" => $BreakB, 5907 "Alpha" => $Alpha, 5908 "Ticks" => $VoidTicks, 5909 "Weight" => $Weight 5910 ]; 5911 } 5912 if ($DisplayColor == DISPLAY_AUTO) { 5913 $DisplayR = $R; 5914 $DisplayG = $G; 5915 $DisplayB = $B; 5916 } 5917 5918 $AxisID = $Serie["Axis"]; 5919 $Mode = $Data["Axis"][$AxisID]["Display"]; 5920 $Format = $Data["Axis"][$AxisID]["Format"]; 5921 $Unit = $Data["Axis"][$AxisID]["Unit"]; 5922 5923 if (isset($Serie["Description"])) { 5924 $SerieDescription = $Serie["Description"]; 5925 } else { 5926 $SerieDescription = $SerieName; 5927 } 5928 5929 $PosArray = $this->scaleComputeY( 5930 $Serie["Data"], 5931 ["AxisID" => $Serie["Axis"]] 5932 ); 5933 5934 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 5935 5936 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 5937 if ($XDivs == 0) { 5938 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 5939 } else { 5940 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 5941 } 5942 $X = $this->GraphAreaX1 + $XMargin; 5943 $LastX = null; 5944 $LastY = null; 5945 5946 if (!is_array($PosArray)) { 5947 $Value = $PosArray; 5948 $PosArray = []; 5949 $PosArray[0] = $Value; 5950 } 5951 $LastGoodY = null; 5952 $LastGoodX = null; 5953 foreach ($PosArray as $Key => $Y) { 5954 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 5955 if ($Serie["Data"][$Key] > 0) { 5956 $Align = TEXT_ALIGN_BOTTOMMIDDLE; 5957 $Offset = $DisplayOffset; 5958 } else { 5959 $Align = TEXT_ALIGN_TOPMIDDLE; 5960 $Offset = -$DisplayOffset; 5961 } 5962 $this->drawText( 5963 $X, 5964 $Y - $Offset - $Weight, 5965 $this->scaleFormat( 5966 $Serie["Data"][$Key], 5967 $Mode, 5968 $Format, 5969 $Unit 5970 ), 5971 [ 5972 "R" => $DisplayR, 5973 "G" => $DisplayG, 5974 "B" => $DisplayB, 5975 "Align" => $Align 5976 ] 5977 ); 5978 } 5979 5980 if ($RecordImageMap && $Y != VOID) { 5981 $this->addToImageMap( 5982 "CIRCLE", 5983 floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, 5984 $this->toHTMLColor($R, $G, $B), 5985 $SerieDescription, 5986 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 5987 ); 5988 } 5989 5990 if ($Y != VOID && $LastX != null && $LastY != null) { 5991 $this->drawLine( 5992 $LastX, 5993 $LastY, 5994 $X, 5995 $Y, 5996 [ 5997 "R" => $R, 5998 "G" => $G, 5999 "B" => $B, 6000 "Alpha" => $Alpha, 6001 "Ticks" => $Ticks, 6002 "Weight" => $Weight 6003 ] 6004 ); 6005 } 6006 if ($Y != VOID && $LastY == null && $LastGoodY != null && !$BreakVoid) { 6007 $this->drawLine( 6008 $LastGoodX, 6009 $LastGoodY, 6010 $X, 6011 $Y, 6012 $BreakSettings 6013 ); 6014 $LastGoodY = null; 6015 } 6016 6017 if ($Y != VOID) { 6018 $LastGoodY = $Y; 6019 $LastGoodX = $X; 6020 } 6021 if ($Y == VOID) { 6022 $Y = null; 6023 } 6024 6025 $LastX = $X; 6026 $LastY = $Y; 6027 $X = $X + $XStep; 6028 } 6029 } else { 6030 if ($XDivs == 0) { 6031 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 6032 } else { 6033 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 6034 } 6035 $Y = $this->GraphAreaY1 + $XMargin; 6036 $LastX = null; 6037 $LastY = null; 6038 6039 if (!is_array($PosArray)) { 6040 $Value = $PosArray; 6041 $PosArray = []; 6042 $PosArray[0] = $Value; 6043 } 6044 $LastGoodY = null; 6045 $LastGoodX = null; 6046 foreach ($PosArray as $Key => $X) { 6047 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 6048 $this->drawText( 6049 $X + $DisplayOffset + $Weight, 6050 $Y, 6051 $this->scaleFormat( 6052 $Serie["Data"][$Key], 6053 $Mode, 6054 $Format, 6055 $Unit 6056 ), 6057 [ 6058 "Angle" => 270, 6059 "R" => $DisplayR, 6060 "G" => $DisplayG, 6061 "B" => $DisplayB, 6062 "Align" => TEXT_ALIGN_BOTTOMMIDDLE 6063 ] 6064 ); 6065 } 6066 6067 if ($RecordImageMap && $X != VOID) { 6068 $this->addToImageMap( 6069 "CIRCLE", 6070 floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, 6071 $this->toHTMLColor($R, $G, $B), 6072 $SerieDescription, 6073 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6074 ); 6075 } 6076 6077 if ($X != VOID && $LastX != null && $LastY != null) { 6078 $this->drawLine( 6079 $LastX, 6080 $LastY, 6081 $X, 6082 $Y, 6083 [ 6084 "R" => $R, 6085 "G" => $G, 6086 "B" => $B, 6087 "Alpha" => $Alpha, 6088 "Ticks" => $Ticks, 6089 "Weight" => $Weight 6090 ] 6091 ); 6092 } 6093 if ($X != VOID && $LastX == null && $LastGoodY != null && !$BreakVoid) { 6094 $this->drawLine( 6095 $LastGoodX, 6096 $LastGoodY, 6097 $X, 6098 $Y, 6099 $BreakSettings 6100 ); 6101 $LastGoodY = null; 6102 } 6103 6104 if ($X != VOID) { 6105 $LastGoodY = $Y; 6106 $LastGoodX = $X; 6107 } 6108 if ($X == VOID) { 6109 $X = null; 6110 } 6111 6112 $LastX = $X; 6113 $LastY = $Y; 6114 $Y = $Y + $YStep; 6115 } 6116 } 6117 } 6118 } 6119 } 6120 6121 /** 6122 * Draw a zone chart 6123 * 6124 * @param string $SerieA 6125 * @param string $SerieB 6126 * @param array $Format 6127 * @return null|integer 6128 */ 6129 public function drawZoneChart($SerieA, $SerieB, array $Format = []) 6130 { 6131 $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; 6132 $LineR = isset($Format["LineR"]) ? $Format["LineR"] : 150; 6133 $LineG = isset($Format["LineG"]) ? $Format["LineG"] : 150; 6134 $LineB = isset($Format["LineB"]) ? $Format["LineB"] : 150; 6135 $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 50; 6136 $LineTicks = isset($Format["LineTicks"]) ? $Format["LineTicks"] : 1; 6137 $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 150; 6138 $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 150; 6139 $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 150; 6140 $AreaAlpha = isset($Format["AreaAlpha"]) ? $Format["AreaAlpha"] : 5; 6141 6142 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 6143 6144 $Data = $this->DataSet->getData(); 6145 if (!isset($Data["Series"][$SerieA]["Data"]) 6146 || !isset($Data["Series"][$SerieB]["Data"]) 6147 ) { 6148 return 0; 6149 } 6150 $SerieAData = $Data["Series"][$SerieA]["Data"]; 6151 $SerieBData = $Data["Series"][$SerieB]["Data"]; 6152 6153 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 6154 6155 $Mode = $Data["Axis"][$AxisID]["Display"]; 6156 $Format = $Data["Axis"][$AxisID]["Format"]; 6157 6158 $PosArrayA = $this->scaleComputeY($SerieAData, ["AxisID" => $AxisID]); 6159 $PosArrayB = $this->scaleComputeY($SerieBData, ["AxisID" => $AxisID]); 6160 if (count($PosArrayA) != count($PosArrayB)) { 6161 return 0; 6162 } 6163 6164 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 6165 if ($XDivs == 0) { 6166 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 6167 } else { 6168 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 6169 } 6170 $X = $this->GraphAreaX1 + $XMargin; 6171 $LastX = null; 6172 $LastY = null; 6173 6174 $LastY1 = null; 6175 $LastY2 = null; 6176 $BoundsA = []; 6177 $BoundsB = []; 6178 foreach ($PosArrayA as $Key => $Y1) { 6179 $Y2 = $PosArrayB[$Key]; 6180 6181 $BoundsA[] = $X; 6182 $BoundsA[] = $Y1; 6183 $BoundsB[] = $X; 6184 $BoundsB[] = $Y2; 6185 6186 $LastX = $X; 6187 $LastY1 = $Y1; 6188 $LastY2 = $Y2; 6189 6190 $X = $X + $XStep; 6191 } 6192 $Bounds = array_merge($BoundsA, $this->reversePlots($BoundsB)); 6193 $this->drawPolygonChart( 6194 $Bounds, 6195 [ 6196 "R" => $AreaR, 6197 "G" => $AreaG, 6198 "B" => $AreaB, 6199 "Alpha" => $AreaAlpha 6200 ] 6201 ); 6202 6203 for ($i = 0; $i <= count($BoundsA) - 4; $i = $i + 2) { 6204 $this->drawLine( 6205 $BoundsA[$i], 6206 $BoundsA[$i + 1], 6207 $BoundsA[$i + 2], 6208 $BoundsA[$i + 3], 6209 [ 6210 "R" => $LineR, 6211 "G" => $LineG, 6212 "B" => $LineB, 6213 "Alpha" => $LineAlpha, 6214 "Ticks" => $LineTicks 6215 ] 6216 ); 6217 $this->drawLine( 6218 $BoundsB[$i], 6219 $BoundsB[$i + 1], 6220 $BoundsB[$i + 2], 6221 $BoundsB[$i + 3], 6222 [ 6223 "R" => $LineR, 6224 "G" => $LineG, 6225 "B" => $LineB, 6226 "Alpha" => $LineAlpha, 6227 "Ticks" => $LineTicks 6228 ] 6229 ); 6230 } 6231 } else { 6232 if ($XDivs == 0) { 6233 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 6234 } else { 6235 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 6236 } 6237 $Y = $this->GraphAreaY1 + $XMargin; 6238 $LastX = null; 6239 $LastY = null; 6240 6241 $LastX1 = null; 6242 $LastX2 = null; 6243 $BoundsA = []; 6244 $BoundsB = []; 6245 foreach ($PosArrayA as $Key => $X1) { 6246 $X2 = $PosArrayB[$Key]; 6247 6248 $BoundsA[] = $X1; 6249 $BoundsA[] = $Y; 6250 $BoundsB[] = $X2; 6251 $BoundsB[] = $Y; 6252 6253 $LastY = $Y; 6254 $LastX1 = $X1; 6255 $LastX2 = $X2; 6256 6257 $Y = $Y + $YStep; 6258 } 6259 $Bounds = array_merge($BoundsA, $this->reversePlots($BoundsB)); 6260 $this->drawPolygonChart( 6261 $Bounds, 6262 ["R" => $AreaR, "G" => $AreaG, "B" => $AreaB, "Alpha" => $AreaAlpha] 6263 ); 6264 6265 for ($i = 0; $i <= count($BoundsA) - 4; $i = $i + 2) { 6266 $this->drawLine( 6267 $BoundsA[$i], 6268 $BoundsA[$i + 1], 6269 $BoundsA[$i + 2], 6270 $BoundsA[$i + 3], 6271 [ 6272 "R" => $LineR, 6273 "G" => $LineG, 6274 "B" => $LineB, 6275 "Alpha" => $LineAlpha, 6276 "Ticks" => $LineTicks 6277 ] 6278 ); 6279 $this->drawLine( 6280 $BoundsB[$i], 6281 $BoundsB[$i + 1], 6282 $BoundsB[$i + 2], 6283 $BoundsB[$i + 3], 6284 [ 6285 "R" => $LineR, 6286 "G" => $LineG, 6287 "B" => $LineB, 6288 "Alpha" => $LineAlpha, 6289 "Ticks" => $LineTicks 6290 ] 6291 ); 6292 } 6293 } 6294 } 6295 6296 /** 6297 * Draw a step chart 6298 * @param array $Format 6299 */ 6300 public function drawStepChart(array $Format = []) 6301 { 6302 $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : false; 6303 $ReCenter = isset($Format["ReCenter"]) ? $Format["ReCenter"] : true; 6304 $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; 6305 $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : null; 6306 $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : null; 6307 $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : null; 6308 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 6309 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; 6310 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 6311 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 6312 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 6313 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 6314 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; 6315 $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; 6316 6317 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 6318 6319 $Data = $this->DataSet->getData(); 6320 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 6321 foreach ($Data["Series"] as $SerieName => $Serie) { 6322 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 6323 $R = $Serie["Color"]["R"]; 6324 $G = $Serie["Color"]["G"]; 6325 $B = $Serie["Color"]["B"]; 6326 $Alpha = $Serie["Color"]["Alpha"]; 6327 $Ticks = $Serie["Ticks"]; 6328 $Weight = $Serie["Weight"]; 6329 6330 if (isset($Serie["Description"])) { 6331 $SerieDescription = $Serie["Description"]; 6332 } else { 6333 $SerieDescription = $SerieName; 6334 } 6335 6336 if ($BreakR == null) { 6337 $BreakSettings = [ 6338 "R" => $R, 6339 "G" => $G, 6340 "B" => $B, 6341 "Alpha" => $Alpha, 6342 "Ticks" => $VoidTicks, 6343 "Weight" => $Weight 6344 ]; 6345 } else { 6346 $BreakSettings = [ 6347 "R" => $BreakR, 6348 "G" => $BreakG, 6349 "B" => $BreakB, 6350 "Alpha" => $Alpha, 6351 "Ticks" => $VoidTicks, 6352 "Weight" => $Weight 6353 ]; 6354 } 6355 if ($DisplayColor == DISPLAY_AUTO) { 6356 $DisplayR = $R; 6357 $DisplayG = $G; 6358 $DisplayB = $B; 6359 } 6360 6361 $AxisID = $Serie["Axis"]; 6362 $Mode = $Data["Axis"][$AxisID]["Display"]; 6363 $Format = $Data["Axis"][$AxisID]["Format"]; 6364 $Unit = $Data["Axis"][$AxisID]["Unit"]; 6365 $Color = [ 6366 "R" => $R, 6367 "G" => $G, 6368 "B" => $B, 6369 "Alpha" => $Alpha, 6370 "Ticks" => $Ticks, 6371 "Weight" => $Weight 6372 ]; 6373 6374 $PosArray = $this->scaleComputeY( 6375 $Serie["Data"], 6376 ["AxisID" => $Serie["Axis"]] 6377 ); 6378 6379 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 6380 6381 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 6382 if ($XDivs == 0) { 6383 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 6384 } else { 6385 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 6386 } 6387 $X = $this->GraphAreaX1 + $XMargin; 6388 $LastX = null; 6389 $LastY = null; 6390 6391 if (!is_array($PosArray)) { 6392 $Value = $PosArray; 6393 $PosArray = []; 6394 $PosArray[0] = $Value; 6395 } 6396 $LastGoodY = null; 6397 $LastGoodX = null; 6398 $Init = false; 6399 foreach ($PosArray as $Key => $Y) { 6400 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 6401 if ($Y <= $LastY) { 6402 $Align = TEXT_ALIGN_BOTTOMMIDDLE; 6403 $Offset = $DisplayOffset; 6404 } else { 6405 $Align = TEXT_ALIGN_TOPMIDDLE; 6406 $Offset = -$DisplayOffset; 6407 } 6408 $this->drawText( 6409 $X, 6410 $Y - $Offset - $Weight, 6411 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 6412 ["R" => $DisplayR, "G" => $DisplayG, "B" => $DisplayB, "Align" => $Align] 6413 ); 6414 } 6415 6416 if ($Y != VOID && $LastX != null && $LastY != null) { 6417 $this->drawLine($LastX, $LastY, $X, $LastY, $Color); 6418 $this->drawLine($X, $LastY, $X, $Y, $Color); 6419 if ($ReCenter && $X + $XStep < $this->GraphAreaX2 - $XMargin) { 6420 $this->drawLine($X, $Y, $X + $XStep, $Y, $Color); 6421 if ($RecordImageMap) { 6422 $this->addToImageMap( 6423 "RECT", 6424 sprintf( 6425 '%s,%s,%s,%s', 6426 floor($X - $ImageMapPlotSize), 6427 floor($Y - $ImageMapPlotSize), 6428 floor($X + $XStep + $ImageMapPlotSize), 6429 floor($Y + $ImageMapPlotSize) 6430 ), 6431 $this->toHTMLColor($R, $G, $B), 6432 $SerieDescription, 6433 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6434 ); 6435 } 6436 } else { 6437 if ($RecordImageMap) { 6438 $this->addToImageMap( 6439 "RECT", 6440 sprintf( 6441 '%s,%s,%s,%s', 6442 floor($LastX - $ImageMapPlotSize), 6443 floor($LastY - $ImageMapPlotSize), 6444 floor($X + $ImageMapPlotSize), 6445 floor($LastY + $ImageMapPlotSize) 6446 ), 6447 $this->toHTMLColor($R, $G, $B), 6448 $SerieDescription, 6449 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6450 ); 6451 } 6452 } 6453 } 6454 6455 if ($Y != VOID && $LastY == null && $LastGoodY != null && !$BreakVoid) { 6456 if ($ReCenter) { 6457 $this->drawLine($LastGoodX + $XStep, $LastGoodY, $X, $LastGoodY, $BreakSettings); 6458 if ($RecordImageMap) { 6459 $this->addToImageMap( 6460 "RECT", 6461 sprintf( 6462 '%s,%s,%s,%s', 6463 floor($LastGoodX + $XStep - $ImageMapPlotSize), 6464 floor($LastGoodY - $ImageMapPlotSize), 6465 floor($X + $ImageMapPlotSize), 6466 floor($LastGoodY + $ImageMapPlotSize) 6467 ), 6468 $this->toHTMLColor($R, $G, $B), 6469 $SerieDescription, 6470 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6471 ); 6472 } 6473 } else { 6474 $this->drawLine($LastGoodX, $LastGoodY, $X, $LastGoodY, $BreakSettings); 6475 if ($RecordImageMap) { 6476 $this->addToImageMap( 6477 "RECT", 6478 sprintf( 6479 '%s,%s,%s,%s', 6480 floor($LastGoodX - $ImageMapPlotSize), 6481 floor($LastGoodY - $ImageMapPlotSize), 6482 floor($X + $ImageMapPlotSize), 6483 floor($LastGoodY + $ImageMapPlotSize) 6484 ), 6485 $SerieDescription, 6486 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6487 ); 6488 } 6489 } 6490 6491 $this->drawLine($X, $LastGoodY, $X, $Y, $BreakSettings); 6492 $LastGoodY = null; 6493 } elseif (!$BreakVoid && $LastGoodY == null && $Y != VOID) { 6494 $this->drawLine($this->GraphAreaX1 + $XMargin, $Y, $X, $Y, $BreakSettings); 6495 if ($RecordImageMap) { 6496 $this->addToImageMap( 6497 "RECT", 6498 sprintf( 6499 '%s,%s,%s,%s', 6500 floor($this->GraphAreaX1 + $XMargin - $ImageMapPlotSize), 6501 floor($Y - $ImageMapPlotSize), 6502 floor($X + $ImageMapPlotSize), 6503 floor($Y + $ImageMapPlotSize) 6504 ), 6505 $this->toHTMLColor($R, $G, $B), 6506 $SerieDescription, 6507 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6508 ); 6509 } 6510 } 6511 6512 if ($Y != VOID) { 6513 $LastGoodY = $Y; 6514 $LastGoodX = $X; 6515 } 6516 if ($Y == VOID) { 6517 $Y = null; 6518 } 6519 6520 if (!$Init && $ReCenter) { 6521 $X = $X - $XStep / 2; 6522 $Init = true; 6523 } 6524 $LastX = $X; 6525 $LastY = $Y; 6526 if ($LastX < $this->GraphAreaX1 + $XMargin) { 6527 $LastX = $this->GraphAreaX1 + $XMargin; 6528 } 6529 $X = $X + $XStep; 6530 } 6531 if ($ReCenter) { 6532 $this->drawLine($LastX, $LastY, $this->GraphAreaX2 - $XMargin, $LastY, $Color); 6533 if ($RecordImageMap) { 6534 $this->addToImageMap( 6535 "RECT", 6536 sprintf( 6537 '%s,%s,%s,%s', 6538 floor($LastX - $ImageMapPlotSize), 6539 floor($LastY - $ImageMapPlotSize), 6540 floor($this->GraphAreaX2 - $XMargin + $ImageMapPlotSize), 6541 floor($LastY + $ImageMapPlotSize) 6542 ), 6543 $this->toHTMLColor($R, $G, $B), 6544 $SerieDescription, 6545 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6546 ); 6547 } 6548 } 6549 } else { 6550 if ($XDivs == 0) { 6551 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 6552 } else { 6553 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 6554 } 6555 $Y = $this->GraphAreaY1 + $XMargin; 6556 $LastX = null; 6557 $LastY = null; 6558 6559 if (!is_array($PosArray)) { 6560 $Value = $PosArray; 6561 $PosArray = []; 6562 $PosArray[0] = $Value; 6563 } 6564 $LastGoodY = null; 6565 $LastGoodX = null; 6566 $Init = false; 6567 foreach ($PosArray as $Key => $X) { 6568 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 6569 if ($X >= $LastX) { 6570 $Align = TEXT_ALIGN_MIDDLELEFT; 6571 $Offset = $DisplayOffset; 6572 } else { 6573 $Align = TEXT_ALIGN_MIDDLERIGHT; 6574 $Offset = -$DisplayOffset; 6575 } 6576 $this->drawText( 6577 $X + $Offset + $Weight, 6578 $Y, 6579 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 6580 [ 6581 "R" => $DisplayR, 6582 "G" => $DisplayG, 6583 "B" => $DisplayB, 6584 "Align" => $Align 6585 ] 6586 ); 6587 } 6588 6589 if ($X != VOID && $LastX != null && $LastY != null) { 6590 $this->drawLine($LastX, $LastY, $LastX, $Y, $Color); 6591 $this->drawLine($LastX, $Y, $X, $Y, $Color); 6592 6593 if ($RecordImageMap) { 6594 $this->addToImageMap( 6595 "RECT", 6596 sprintf( 6597 '%s,%s,%s,%s', 6598 floor($LastX - $ImageMapPlotSize), 6599 floor($LastY - $ImageMapPlotSize), 6600 floor($LastX + $XStep + $ImageMapPlotSize), 6601 floor($Y + $ImageMapPlotSize) 6602 ), 6603 $this->toHTMLColor($R, $G, $B), 6604 $SerieDescription, 6605 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6606 ); 6607 } 6608 } 6609 6610 if ($X != VOID && $LastX == null && $LastGoodY != null && !$BreakVoid) { 6611 $this->drawLine( 6612 $LastGoodX, 6613 $LastGoodY, 6614 $LastGoodX, 6615 $LastGoodY + $YStep, 6616 $Color 6617 ); 6618 if ($RecordImageMap) { 6619 $this->addToImageMap( 6620 "RECT", 6621 sprintf( 6622 '%s,%s,%s,%s', 6623 floor($LastGoodX - $ImageMapPlotSize), 6624 floor($LastGoodY - $ImageMapPlotSize), 6625 floor($LastGoodX + $ImageMapPlotSize), 6626 floor($LastGoodY + $YStep + $ImageMapPlotSize) 6627 ), 6628 $this->toHTMLColor($R, $G, $B), 6629 $SerieDescription, 6630 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6631 ); 6632 } 6633 6634 $this->drawLine( 6635 $LastGoodX, 6636 $LastGoodY + $YStep, 6637 $LastGoodX, 6638 $Y, 6639 $BreakSettings 6640 ); 6641 if ($RecordImageMap) { 6642 $this->addToImageMap( 6643 "RECT", 6644 sprintf( 6645 '%s,%s,%s,%s', 6646 floor($LastGoodX - $ImageMapPlotSize), 6647 floor($LastGoodY + $YStep - $ImageMapPlotSize), 6648 floor($LastGoodX + $ImageMapPlotSize), 6649 floor($YStep + $ImageMapPlotSize) 6650 ), 6651 $this->toHTMLColor($R, $G, $B), 6652 $SerieDescription, 6653 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6654 ); 6655 } 6656 6657 $this->drawLine($LastGoodX, $Y, $X, $Y, $BreakSettings); 6658 $LastGoodY = null; 6659 } elseif ($X != VOID && $LastGoodY == null && !$BreakVoid) { 6660 $this->drawLine($X, $this->GraphAreaY1 + $XMargin, $X, $Y, $BreakSettings); 6661 if ($RecordImageMap) { 6662 $this->addToImageMap( 6663 "RECT", 6664 sprintf( 6665 '%s,%s,%s,%s', 6666 floor($X - $ImageMapPlotSize), 6667 floor($this->GraphAreaY1 + $XMargin - $ImageMapPlotSize), 6668 floor($X + $ImageMapPlotSize), 6669 floor($Y + $ImageMapPlotSize) 6670 ), 6671 $this->toHTMLColor($R, $G, $B), 6672 $SerieDescription, 6673 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6674 ); 6675 } 6676 } 6677 6678 if ($X != VOID) { 6679 $LastGoodY = $Y; 6680 $LastGoodX = $X; 6681 } 6682 if ($X == VOID) { 6683 $X = null; 6684 } 6685 6686 if (!$Init && $ReCenter) { 6687 $Y = $Y - $YStep / 2; 6688 $Init = true; 6689 } 6690 $LastX = $X; 6691 $LastY = $Y; 6692 if ($LastY < $this->GraphAreaY1 + $XMargin) { 6693 $LastY = $this->GraphAreaY1 + $XMargin; 6694 } 6695 $Y = $Y + $YStep; 6696 } 6697 if ($ReCenter) { 6698 $this->drawLine($LastX, $LastY, $LastX, $this->GraphAreaY2 - $XMargin, $Color); 6699 if ($RecordImageMap) { 6700 $this->addToImageMap( 6701 "RECT", 6702 sprintf( 6703 '%s,%s,%s,%s', 6704 floor($LastX - $ImageMapPlotSize), 6705 floor($LastY - $ImageMapPlotSize), 6706 floor($LastX + $ImageMapPlotSize), 6707 floor($this->GraphAreaY2 - $XMargin + $ImageMapPlotSize) 6708 ), 6709 $this->toHTMLColor($R, $G, $B), 6710 $SerieDescription, 6711 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 6712 ); 6713 } 6714 } 6715 } 6716 } 6717 } 6718 } 6719 6720 /** 6721 * Draw a step chart 6722 * @param array $Format 6723 */ 6724 public function drawFilledStepChart(array $Format = []) 6725 { 6726 $ReCenter = isset($Format["ReCenter"]) ? $Format["ReCenter"] : true; 6727 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 6728 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; 6729 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 6730 $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : null; 6731 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 6732 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 6733 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 6734 $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; 6735 6736 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 6737 6738 $Data = $this->DataSet->getData(); 6739 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 6740 foreach ($Data["Series"] as $SerieName => $Serie) { 6741 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 6742 $R = $Serie["Color"]["R"]; 6743 $G = $Serie["Color"]["G"]; 6744 $B = $Serie["Color"]["B"]; 6745 $Alpha = $Serie["Color"]["Alpha"]; 6746 6747 if ($DisplayColor == DISPLAY_AUTO) { 6748 $DisplayR = $R; 6749 $DisplayG = $G; 6750 $DisplayB = $B; 6751 } 6752 6753 $AxisID = $Serie["Axis"]; 6754 $Format = $Data["Axis"][$AxisID]["Format"]; 6755 6756 $Color = ["R" => $R, "G" => $G, "B" => $B]; 6757 if ($ForceTransparency != null) { 6758 $Color["Alpha"] = $ForceTransparency; 6759 } else { 6760 $Color["Alpha"] = $Alpha; 6761 } 6762 6763 $PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]); 6764 $YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]); 6765 6766 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 6767 6768 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 6769 if ($YZero > $this->GraphAreaY2 - 1) { 6770 $YZero = $this->GraphAreaY2 - 1; 6771 } 6772 if ($YZero < $this->GraphAreaY1 + 1) { 6773 $YZero = $this->GraphAreaY1 + 1; 6774 } 6775 6776 if ($XDivs == 0) { 6777 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 6778 } else { 6779 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 6780 } 6781 $X = $this->GraphAreaX1 + $XMargin; 6782 $LastX = null; 6783 $LastY = null; 6784 6785 if (!$AroundZero) { 6786 $YZero = $this->GraphAreaY2 - 1; 6787 } 6788 6789 if (!is_array($PosArray)) { 6790 $Value = $PosArray; 6791 $PosArray = []; 6792 $PosArray[0] = $Value; 6793 } 6794 $LastGoodY = null; 6795 $LastGoodX = null; 6796 $Points = []; 6797 $Init = false; 6798 foreach ($PosArray as $Key => $Y) { 6799 if ($Y == VOID && $LastX != null && $LastY != null && count($Points)) { 6800 $Points[] = $LastX; 6801 $Points[] = $LastY; 6802 $Points[] = $X; 6803 $Points[] = $LastY; 6804 $Points[] = $X; 6805 $Points[] = $YZero; 6806 $this->drawPolygon($Points, $Color); 6807 $Points = []; 6808 } 6809 6810 if ($Y != VOID && $LastX != null && $LastY != null) { 6811 if (count($Points)) { 6812 $Points[] = $LastX; 6813 $Points[] = $YZero; 6814 } 6815 $Points[] = $LastX; 6816 $Points[] = $LastY; 6817 $Points[] = $X; 6818 $Points[] = $LastY; 6819 $Points[] = $X; 6820 $Points[] = $Y; 6821 } 6822 6823 if ($Y != VOID) { 6824 $LastGoodY = $Y; 6825 $LastGoodX = $X; 6826 } 6827 if ($Y == VOID) { 6828 $Y = null; 6829 } 6830 6831 if (!$Init && $ReCenter) { 6832 $X = $X - $XStep / 2; 6833 $Init = true; 6834 } 6835 $LastX = $X; 6836 $LastY = $Y; 6837 if ($LastX < $this->GraphAreaX1 + $XMargin) { 6838 $LastX = $this->GraphAreaX1 + $XMargin; 6839 } 6840 $X = $X + $XStep; 6841 } 6842 6843 if ($ReCenter) { 6844 $Points[] = $LastX + $XStep / 2; 6845 $Points[] = $LastY; 6846 $Points[] = $LastX + $XStep / 2; 6847 $Points[] = $YZero; 6848 } else { 6849 $Points[] = $LastX; 6850 $Points[] = $YZero; 6851 } 6852 6853 $this->drawPolygon($Points, $Color); 6854 } else { 6855 if ($YZero < $this->GraphAreaX1 + 1) { 6856 $YZero = $this->GraphAreaX1 + 1; 6857 } 6858 if ($YZero > $this->GraphAreaX2 - 1) { 6859 $YZero = $this->GraphAreaX2 - 1; 6860 } 6861 6862 if ($XDivs == 0) { 6863 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 6864 } else { 6865 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 6866 } 6867 $Y = $this->GraphAreaY1 + $XMargin; 6868 $LastX = null; 6869 $LastY = null; 6870 6871 if (!is_array($PosArray)) { 6872 $Value = $PosArray; 6873 $PosArray = []; 6874 $PosArray[0] = $Value; 6875 } 6876 $LastGoodY = null; 6877 $LastGoodX = null; 6878 $Points = []; 6879 foreach ($PosArray as $Key => $X) { 6880 if ($X == VOID && $LastX != null && $LastY != null && count($Points)) { 6881 $Points[] = $LastX; 6882 $Points[] = $LastY; 6883 $Points[] = $LastX; 6884 $Points[] = $Y; 6885 $Points[] = $YZero; 6886 $Points[] = $Y; 6887 $this->drawPolygon($Points, $Color); 6888 $Points = []; 6889 } 6890 6891 if ($X != VOID && $LastX != null && $LastY != null) { 6892 if (count($Points)) { 6893 $Points[] = $YZero; 6894 $Points[] = $LastY; 6895 } 6896 $Points[] = $LastX; 6897 $Points[] = $LastY; 6898 $Points[] = $LastX; 6899 $Points[] = $Y; 6900 $Points[] = $X; 6901 $Points[] = $Y; 6902 } 6903 6904 if ($X != VOID) { 6905 $LastGoodY = $Y; 6906 $LastGoodX = $X; 6907 } 6908 if ($X == VOID) { 6909 $X = null; 6910 } 6911 6912 if ($LastX == null && $ReCenter) { 6913 $Y = $Y - $YStep / 2; 6914 } 6915 $LastX = $X; 6916 $LastY = $Y; 6917 if ($LastY < $this->GraphAreaY1 + $XMargin) { 6918 $LastY = $this->GraphAreaY1 + $XMargin; 6919 } 6920 $Y = $Y + $YStep; 6921 } 6922 6923 if ($ReCenter) { 6924 $Points[] = $LastX; 6925 $Points[] = $LastY + $YStep / 2; 6926 $Points[] = $YZero; 6927 $Points[] = $LastY + $YStep / 2; 6928 } else { 6929 $Points[] = $YZero; 6930 $Points[] = $LastY; 6931 } 6932 6933 $this->drawPolygon($Points, $Color); 6934 } 6935 } 6936 } 6937 } 6938 6939 /** 6940 * Draw an area chart 6941 * @param array $Format 6942 */ 6943 public function drawAreaChart(array $Format = []) 6944 { 6945 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 6946 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; 6947 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 6948 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 6949 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 6950 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 6951 $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : 25; 6952 $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; 6953 $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; 6954 6955 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 6956 6957 $Data = $this->DataSet->getData(); 6958 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 6959 6960 foreach ($Data["Series"] as $SerieName => $Serie) { 6961 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 6962 $R = $Serie["Color"]["R"]; 6963 $G = $Serie["Color"]["G"]; 6964 $B = $Serie["Color"]["B"]; 6965 $Alpha = $Serie["Color"]["Alpha"]; 6966 $Ticks = $Serie["Ticks"]; 6967 if ($DisplayColor == DISPLAY_AUTO) { 6968 $DisplayR = $R; 6969 $DisplayG = $G; 6970 $DisplayB = $B; 6971 } 6972 6973 $AxisID = $Serie["Axis"]; 6974 $Mode = $Data["Axis"][$AxisID]["Display"]; 6975 $Format = $Data["Axis"][$AxisID]["Format"]; 6976 $Unit = $Data["Axis"][$AxisID]["Unit"]; 6977 6978 $PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]); 6979 $YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]); 6980 6981 if ($Threshold != null) { 6982 foreach ($Threshold as $Key => $Params) { 6983 $Threshold[$Key]["MinX"] = $this->scaleComputeY( 6984 $Params["Min"], 6985 ["AxisID" => $Serie["Axis"]] 6986 ); 6987 $Threshold[$Key]["MaxX"] = $this->scaleComputeY( 6988 $Params["Max"], 6989 ["AxisID" => $Serie["Axis"]] 6990 ); 6991 } 6992 } 6993 6994 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 6995 6996 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 6997 if ($YZero > $this->GraphAreaY2 - 1) { 6998 $YZero = $this->GraphAreaY2 - 1; 6999 } 7000 7001 $Areas = []; 7002 $AreaID = 0; 7003 $Areas[$AreaID][] = $this->GraphAreaX1 + $XMargin; 7004 if ($AroundZero) { 7005 $Areas[$AreaID][] = $YZero; 7006 } else { 7007 $Areas[$AreaID][] = $this->GraphAreaY2 - 1; 7008 } 7009 7010 if ($XDivs == 0) { 7011 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 7012 } else { 7013 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 7014 } 7015 $X = $this->GraphAreaX1 + $XMargin; 7016 $LastX = null; 7017 $LastY = null; 7018 7019 if (!is_array($PosArray)) { 7020 $Value = $PosArray; 7021 $PosArray = []; 7022 $PosArray[0] = $Value; 7023 } 7024 foreach ($PosArray as $Key => $Y) { 7025 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 7026 if ($Serie["Data"][$Key] > 0) { 7027 $Align = TEXT_ALIGN_BOTTOMMIDDLE; 7028 $Offset = $DisplayOffset; 7029 } else { 7030 $Align = TEXT_ALIGN_TOPMIDDLE; 7031 $Offset = -$DisplayOffset; 7032 } 7033 $this->drawText( 7034 $X, 7035 $Y - $Offset, 7036 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 7037 ["R" => $DisplayR, "G" => $DisplayG, "B" => $DisplayB, "Align" => $Align] 7038 ); 7039 } 7040 7041 if ($Y == VOID && isset($Areas[$AreaID])) { 7042 if ($LastX == null) { 7043 $Areas[$AreaID][] = $X; 7044 } else { 7045 $Areas[$AreaID][] = $LastX; 7046 } 7047 7048 if ($AroundZero) { 7049 $Areas[$AreaID][] = $YZero; 7050 } else { 7051 $Areas[$AreaID][] = $this->GraphAreaY2 - 1; 7052 } 7053 $AreaID++; 7054 } elseif ($Y != VOID) { 7055 if (!isset($Areas[$AreaID])) { 7056 $Areas[$AreaID][] = $X; 7057 if ($AroundZero) { 7058 $Areas[$AreaID][] = $YZero; 7059 } else { 7060 $Areas[$AreaID][] = $this->GraphAreaY2 - 1; 7061 } 7062 } 7063 7064 $Areas[$AreaID][] = $X; 7065 $Areas[$AreaID][] = $Y; 7066 } 7067 7068 $LastX = $X; 7069 $X = $X + $XStep; 7070 } 7071 $Areas[$AreaID][] = $LastX; 7072 if ($AroundZero) { 7073 $Areas[$AreaID][] = $YZero; 7074 } else { 7075 $Areas[$AreaID][] = $this->GraphAreaY2 - 1; 7076 } 7077 7078 /* Handle shadows in the areas */ 7079 if ($this->Shadow) { 7080 $ShadowArea = []; 7081 foreach ($Areas as $Key => $Points) { 7082 $ShadowArea[$Key] = []; 7083 foreach ($Points as $Key2 => $Value) { 7084 if ($Key2 % 2 == 0) { 7085 $ShadowArea[$Key][] = $Value + $this->ShadowX; 7086 } else { 7087 $ShadowArea[$Key][] = $Value + $this->ShadowY; 7088 } 7089 } 7090 } 7091 7092 foreach ($ShadowArea as $Key => $Points) { 7093 $this->drawPolygonChart( 7094 $Points, 7095 [ 7096 "R" => $this->ShadowR, 7097 "G" => $this->ShadowG, 7098 "B" => $this->ShadowB, 7099 "Alpha" => $this->Shadowa 7100 ] 7101 ); 7102 } 7103 } 7104 7105 $Alpha = $ForceTransparency != null ? $ForceTransparency : $Alpha; 7106 $Color = [ 7107 "R" => $R, 7108 "G" => $G, 7109 "B" => $B, 7110 "Alpha" => $Alpha, 7111 "Threshold" => $Threshold 7112 ]; 7113 7114 foreach ($Areas as $Key => $Points) { 7115 $this->drawPolygonChart($Points, $Color); 7116 } 7117 } else { 7118 if ($YZero < $this->GraphAreaX1 + 1) { 7119 $YZero = $this->GraphAreaX1 + 1; 7120 } 7121 if ($YZero > $this->GraphAreaX2 - 1) { 7122 $YZero = $this->GraphAreaX2 - 1; 7123 } 7124 7125 $Areas = []; 7126 $AreaID = 0; 7127 if ($AroundZero) { 7128 $Areas[$AreaID][] = $YZero; 7129 } else { 7130 $Areas[$AreaID][] = $this->GraphAreaX1 + 1; 7131 } 7132 $Areas[$AreaID][] = $this->GraphAreaY1 + $XMargin; 7133 7134 if ($XDivs == 0) { 7135 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 7136 } else { 7137 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 7138 } 7139 $Y = $this->GraphAreaY1 + $XMargin; 7140 $LastX = null; 7141 $LastY = null; 7142 7143 if (!is_array($PosArray)) { 7144 $Value = $PosArray; 7145 $PosArray = []; 7146 $PosArray[0] = $Value; 7147 } 7148 foreach ($PosArray as $Key => $X) { 7149 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 7150 if ($Serie["Data"][$Key] > 0) { 7151 $Align = TEXT_ALIGN_BOTTOMMIDDLE; 7152 $Offset = $DisplayOffset; 7153 } else { 7154 $Align = TEXT_ALIGN_TOPMIDDLE; 7155 $Offset = -$DisplayOffset; 7156 } 7157 $this->drawText( 7158 $X + $Offset, 7159 $Y, 7160 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 7161 [ 7162 "Angle" => 270, 7163 "R" => $DisplayR, 7164 "G" => $DisplayG, 7165 "B" => $DisplayB, 7166 "Align" => $Align 7167 ] 7168 ); 7169 } 7170 7171 if ($X == VOID && isset($Areas[$AreaID])) { 7172 if ($AroundZero) { 7173 $Areas[$AreaID][] = $YZero; 7174 } else { 7175 $Areas[$AreaID][] = $this->GraphAreaX1 + 1; 7176 } 7177 7178 if ($LastY == null) { 7179 $Areas[$AreaID][] = $Y; 7180 } else { 7181 $Areas[$AreaID][] = $LastY; 7182 } 7183 7184 $AreaID++; 7185 } elseif ($X != VOID) { 7186 if (!isset($Areas[$AreaID])) { 7187 if ($AroundZero) { 7188 $Areas[$AreaID][] = $YZero; 7189 } else { 7190 $Areas[$AreaID][] = $this->GraphAreaX1 + 1; 7191 } 7192 $Areas[$AreaID][] = $Y; 7193 } 7194 7195 $Areas[$AreaID][] = $X; 7196 $Areas[$AreaID][] = $Y; 7197 } 7198 7199 $LastX = $X; 7200 $LastY = $Y; 7201 $Y = $Y + $YStep; 7202 } 7203 if ($AroundZero) { 7204 $Areas[$AreaID][] = $YZero; 7205 } else { 7206 $Areas[$AreaID][] = $this->GraphAreaX1 + 1; 7207 } 7208 $Areas[$AreaID][] = $LastY; 7209 7210 /* Handle shadows in the areas */ 7211 if ($this->Shadow) { 7212 $ShadowArea = []; 7213 foreach ($Areas as $Key => $Points) { 7214 $ShadowArea[$Key] = []; 7215 foreach ($Points as $Key2 => $Value) { 7216 if ($Key2 % 2 == 0) { 7217 $ShadowArea[$Key][] = $Value + $this->ShadowX; 7218 } else { 7219 $ShadowArea[$Key][] = $Value + $this->ShadowY; 7220 } 7221 } 7222 } 7223 7224 foreach ($ShadowArea as $Key => $Points) { 7225 $this->drawPolygonChart( 7226 $Points, 7227 [ 7228 "R" => $this->ShadowR, 7229 "G" => $this->ShadowG, 7230 "B" => $this->ShadowB, 7231 "Alpha" => $this->Shadowa 7232 ] 7233 ); 7234 } 7235 } 7236 7237 $Alpha = $ForceTransparency != null ? $ForceTransparency : $Alpha; 7238 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Threshold" => $Threshold]; 7239 7240 foreach ($Areas as $Key => $Points) { 7241 $this->drawPolygonChart($Points, $Color); 7242 } 7243 } 7244 } 7245 } 7246 } 7247 7248 /** 7249 * Draw a bar chart 7250 * @param array $Format 7251 */ 7252 public function drawBarChart(array $Format = []) 7253 { 7254 $Floating0Serie = isset($Format["Floating0Serie"]) ? $Format["Floating0Serie"] : null; 7255 $Floating0Value = isset($Format["Floating0Value"]) ? $Format["Floating0Value"] : null; 7256 $Draw0Line = isset($Format["Draw0Line"]) ? $Format["Draw0Line"] : false; 7257 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 7258 $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; 7259 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 7260 $DisplayFont = isset($Format["DisplayFont"]) ? $Format["DisplayFont"] : $this->FontName; 7261 $DisplaySize = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontSize; 7262 $DisplayPos = isset($Format["DisplayPos"]) ? $Format["DisplayPos"] : LABEL_POS_OUTSIDE; 7263 $DisplayShadow = isset($Format["DisplayShadow"]) ? $Format["DisplayShadow"] : true; 7264 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 7265 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 7266 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 7267 $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; 7268 $Interleave = isset($Format["Interleave"]) ? $Format["Interleave"] : .5; 7269 $Rounded = isset($Format["Rounded"]) ? $Format["Rounded"] : false; 7270 $RoundRadius = isset($Format["RoundRadius"]) ? $Format["RoundRadius"] : 4; 7271 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 7272 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; 7273 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; 7274 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; 7275 $Gradient = isset($Format["Gradient"]) ? $Format["Gradient"] : false; 7276 $GradientMode = isset($Format["GradientMode"]) ? $Format["GradientMode"] : GRADIENT_SIMPLE; 7277 $GradientAlpha = isset($Format["GradientAlpha"]) ? $Format["GradientAlpha"] : 20; 7278 $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; 7279 $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; 7280 $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; 7281 $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 0; 7282 $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 0; 7283 $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 0; 7284 $TxtMargin = isset($Format["TxtMargin"]) ? $Format["TxtMargin"] : 6; 7285 $OverrideColors = isset($Format["OverrideColors"]) ? $Format["OverrideColors"] : null; 7286 $OverrideSurrounding = isset($Format["OverrideSurrounding"]) ? $Format["OverrideSurrounding"] : 30; 7287 $InnerSurrounding = isset($Format["InnerSurrounding"]) ? $Format["InnerSurrounding"] : null; 7288 $InnerBorderR = isset($Format["InnerBorderR"]) ? $Format["InnerBorderR"] : -1; 7289 $InnerBorderG = isset($Format["InnerBorderG"]) ? $Format["InnerBorderG"] : -1; 7290 $InnerBorderB = isset($Format["InnerBorderB"]) ? $Format["InnerBorderB"] : -1; 7291 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; 7292 7293 $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; 7294 7295 $Data = $this->DataSet->getData(); 7296 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 7297 7298 if ($OverrideColors != null) { 7299 $OverrideColors = $this->validatePalette($OverrideColors, $OverrideSurrounding); 7300 $this->DataSet->saveExtendedData("Palette", $OverrideColors); 7301 } 7302 7303 $RestoreShadow = $this->Shadow; 7304 7305 $SeriesCount = $this->countDrawableSeries(); 7306 $CurrentSerie = 0; 7307 foreach ($Data["Series"] as $SerieName => $Serie) { 7308 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 7309 $R = $Serie["Color"]["R"]; 7310 $G = $Serie["Color"]["G"]; 7311 $B = $Serie["Color"]["B"]; 7312 $Alpha = $Serie["Color"]["Alpha"]; 7313 $Ticks = $Serie["Ticks"]; 7314 if ($DisplayColor == DISPLAY_AUTO) { 7315 $DisplayR = $R; 7316 $DisplayG = $G; 7317 $DisplayB = $B; 7318 } 7319 if ($Surrounding != null) { 7320 $BorderR = $R + $Surrounding; 7321 $BorderG = $G + $Surrounding; 7322 $BorderB = $B + $Surrounding; 7323 } 7324 if ($InnerSurrounding != null) { 7325 $InnerBorderR = $R + $InnerSurrounding; 7326 $InnerBorderG = $G + $InnerSurrounding; 7327 $InnerBorderB = $B + $InnerSurrounding; 7328 } 7329 if ($InnerBorderR == -1) { 7330 $InnerColor = null; 7331 } else { 7332 $InnerColor = [ 7333 "R" => $InnerBorderR, 7334 "G" => $InnerBorderG, 7335 "B" => $InnerBorderB 7336 ]; 7337 } 7338 $Color = [ 7339 "R" => $R, 7340 "G" => $G, 7341 "B" => $B, 7342 "Alpha" => $Alpha, 7343 "BorderR" => $BorderR, 7344 "BorderG" => $BorderG, 7345 "BorderB" => $BorderB 7346 ]; 7347 7348 $AxisID = $Serie["Axis"]; 7349 $Mode = $Data["Axis"][$AxisID]["Display"]; 7350 $Format = $Data["Axis"][$AxisID]["Format"]; 7351 $Unit = $Data["Axis"][$AxisID]["Unit"]; 7352 7353 if (isset($Serie["Description"])) { 7354 $SerieDescription = $Serie["Description"]; 7355 } else { 7356 $SerieDescription = $SerieName; 7357 } 7358 7359 $PosArray = $this->scaleComputeY( 7360 $Serie["Data"], 7361 ["AxisID" => $Serie["Axis"]] 7362 ); 7363 7364 if ($Floating0Value != null) { 7365 $YZero = $this->scaleComputeY( 7366 $Floating0Value, 7367 ["AxisID" => $Serie["Axis"]] 7368 ); 7369 } else { 7370 $YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]); 7371 } 7372 7373 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 7374 if ($YZero > $this->GraphAreaY2 - 1) { 7375 $YZero = $this->GraphAreaY2 - 1; 7376 } 7377 if ($YZero < $this->GraphAreaY1 + 1) { 7378 $YZero = $this->GraphAreaY1 + 1; 7379 } 7380 7381 if ($XDivs == 0) { 7382 $XStep = 0; 7383 } else { 7384 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 7385 } 7386 $X = $this->GraphAreaX1 + $XMargin; 7387 7388 if ($AroundZero) { 7389 $Y1 = $YZero; 7390 } else { 7391 $Y1 = $this->GraphAreaY2 - 1; 7392 } 7393 if ($XDivs == 0) { 7394 $XSize = ($this->GraphAreaX2 - $this->GraphAreaX1) / ($SeriesCount + $Interleave); 7395 } else { 7396 $XSize = ($XStep / ($SeriesCount + $Interleave)); 7397 } 7398 7399 $XOffset = -($XSize * $SeriesCount) / 2 + $CurrentSerie * $XSize; 7400 if ($X + $XOffset <= $this->GraphAreaX1) { 7401 $XOffset = $this->GraphAreaX1 - $X + 1; 7402 } 7403 7404 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = $XOffset + $XSize / 2; 7405 7406 if ($Rounded || $BorderR != -1) { 7407 $XSpace = 1; 7408 } else { 7409 $XSpace = 0; 7410 } 7411 7412 if (!is_array($PosArray)) { 7413 $Value = $PosArray; 7414 $PosArray = []; 7415 $PosArray[0] = $Value; 7416 } 7417 7418 $ID = 0; 7419 foreach ($PosArray as $Key => $Y2) { 7420 if ($Floating0Serie != null) { 7421 if (isset($Data["Series"][$Floating0Serie]["Data"][$Key])) { 7422 $Value = $Data["Series"][$Floating0Serie]["Data"][$Key]; 7423 } else { 7424 $Value = 0; 7425 } 7426 7427 $YZero = $this->scaleComputeY($Value, ["AxisID" => $Serie["Axis"]]); 7428 if ($YZero > $this->GraphAreaY2 - 1) { 7429 $YZero = $this->GraphAreaY2 - 1; 7430 } 7431 if ($YZero < $this->GraphAreaY1 + 1) { 7432 $YZero = $this->GraphAreaY1 + 1; 7433 } 7434 7435 if ($AroundZero) { 7436 $Y1 = $YZero; 7437 } else { 7438 $Y1 = $this->GraphAreaY2 - 1; 7439 } 7440 } 7441 7442 if ($OverrideColors != null) { 7443 if (isset($OverrideColors[$ID])) { 7444 $Color = [ 7445 "R" => $OverrideColors[$ID]["R"], 7446 "G" => $OverrideColors[$ID]["G"], 7447 "B" => $OverrideColors[$ID]["B"], 7448 "Alpha" => $OverrideColors[$ID]["Alpha"], 7449 "BorderR" => $OverrideColors[$ID]["BorderR"], 7450 "BorderG" => $OverrideColors[$ID]["BorderG"], 7451 "BorderB" => $OverrideColors[$ID]["BorderB"] 7452 ]; 7453 } else { 7454 $Color = $this->getRandomColor(); 7455 } 7456 } 7457 7458 if ($Y2 != VOID) { 7459 $BarHeight = $Y1 - $Y2; 7460 7461 if ($Serie["Data"][$Key] == 0) { 7462 $this->drawLine( 7463 $X + $XOffset + $XSpace, 7464 $Y1, 7465 $X + $XOffset + $XSize - $XSpace, 7466 $Y1, 7467 $Color 7468 ); 7469 if ($RecordImageMap) { 7470 $this->addToImageMap( 7471 "RECT", 7472 sprintf( 7473 "%s,%s,%s,%s", 7474 floor($X + $XOffset + $XSpace), 7475 floor($Y1 - 1), 7476 floor($X + $XOffset + $XSize - $XSpace), 7477 floor($Y1 + 1) 7478 ), 7479 $this->toHTMLColor($R, $G, $B), 7480 $SerieDescription, 7481 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 7482 ); 7483 } 7484 } else { 7485 if ($RecordImageMap) { 7486 $this->addToImageMap( 7487 "RECT", 7488 sprintf( 7489 "%s,%s,%s,%s", 7490 floor($X + $XOffset + $XSpace), 7491 floor($Y1), 7492 floor($X + $XOffset + $XSize - $XSpace), 7493 floor($Y2) 7494 ), 7495 $this->toHTMLColor($R, $G, $B), 7496 $SerieDescription, 7497 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 7498 ); 7499 } 7500 7501 if ($Rounded) { 7502 $this->drawRoundedFilledRectangle( 7503 $X + $XOffset + $XSpace, 7504 $Y1, 7505 $X + $XOffset + $XSize - $XSpace, 7506 $Y2, 7507 $RoundRadius, 7508 $Color 7509 ); 7510 } else { 7511 $this->drawFilledRectangle( 7512 $X + $XOffset + $XSpace, 7513 $Y1, 7514 $X + $XOffset + $XSize - $XSpace, 7515 $Y2, 7516 $Color 7517 ); 7518 7519 if ($InnerColor != null) { 7520 $this->drawRectangle( 7521 $X + $XOffset + $XSpace + 1, 7522 min($Y1, $Y2) + 1, 7523 $X + $XOffset + $XSize - $XSpace - 1, 7524 max($Y1, $Y2) - 1, 7525 $InnerColor 7526 ); 7527 } 7528 7529 if ($Gradient) { 7530 $this->Shadow = false; 7531 7532 if ($GradientMode == GRADIENT_SIMPLE) { 7533 if ($Serie["Data"][$Key] >= 0) { 7534 $GradienColor = [ 7535 "StartR" => $GradientStartR, 7536 "StartG" => $GradientStartG, 7537 "StartB" => $GradientStartB, 7538 "EndR" => $GradientEndR, 7539 "EndG" => $GradientEndG, 7540 "EndB" => $GradientEndB, 7541 "Alpha" => $GradientAlpha 7542 ]; 7543 } else { 7544 $GradienColor = [ 7545 "StartR" => $GradientEndR, 7546 "StartG" => $GradientEndG, 7547 "StartB" => $GradientEndB, 7548 "EndR" => $GradientStartR, 7549 "EndG" => $GradientStartG, 7550 "EndB" => $GradientStartB, 7551 "Alpha" => $GradientAlpha 7552 ]; 7553 } 7554 $this->drawGradientArea( 7555 $X + $XOffset + $XSpace, 7556 $Y1, 7557 $X + $XOffset + $XSize - $XSpace, 7558 $Y2, 7559 DIRECTION_VERTICAL, 7560 $GradienColor 7561 ); 7562 } elseif ($GradientMode == GRADIENT_EFFECT_CAN) { 7563 $GradienColor1 = [ 7564 "StartR" => $GradientEndR, 7565 "StartG" => $GradientEndG, 7566 "StartB" => $GradientEndB, 7567 "EndR" => $GradientStartR, 7568 "EndG" => $GradientStartG, 7569 "EndB" => $GradientStartB, 7570 "Alpha" => $GradientAlpha 7571 ]; 7572 $GradienColor2 = [ 7573 "StartR" => $GradientStartR, 7574 "StartG" => $GradientStartG, 7575 "StartB" => $GradientStartB, 7576 "EndR" => $GradientEndR, 7577 "EndG" => $GradientEndG, 7578 "EndB" => $GradientEndB, 7579 "Alpha" => $GradientAlpha 7580 ]; 7581 $XSpan = floor($XSize / 3); 7582 7583 $this->drawGradientArea( 7584 $X + $XOffset + $XSpace, 7585 $Y1, 7586 $X + $XOffset + $XSpan - $XSpace, 7587 $Y2, 7588 DIRECTION_HORIZONTAL, 7589 $GradienColor1 7590 ); 7591 $this->drawGradientArea( 7592 $X + $XOffset + $XSpan + $XSpace, 7593 $Y1, 7594 $X + $XOffset + $XSize - $XSpace, 7595 $Y2, 7596 DIRECTION_HORIZONTAL, 7597 $GradienColor2 7598 ); 7599 } 7600 $this->Shadow = $RestoreShadow; 7601 } 7602 } 7603 7604 if ($Draw0Line) { 7605 $Line0Color = ["R" => 0, "G" => 0, "B" => 0, "Alpha" => 20]; 7606 7607 if (abs($Y1 - $Y2) > 3) { 7608 $Line0Width = 3; 7609 } else { 7610 $Line0Width = 1; 7611 } 7612 if ($Y1 - $Y2 < 0) { 7613 $Line0Width = -$Line0Width; 7614 } 7615 7616 $this->drawFilledRectangle( 7617 $X + $XOffset + $XSpace, 7618 floor($Y1), 7619 $X + $XOffset + $XSize - $XSpace, 7620 floor($Y1) - $Line0Width, 7621 $Line0Color 7622 ); 7623 $this->drawLine( 7624 $X + $XOffset + $XSpace, 7625 floor($Y1), 7626 $X + $XOffset + $XSize - $XSpace, 7627 floor($Y1), 7628 $Line0Color 7629 ); 7630 } 7631 } 7632 7633 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 7634 if ($DisplayShadow) { 7635 $this->Shadow = true; 7636 } 7637 7638 $Caption = $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit); 7639 $TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 90, $Caption); 7640 $TxtHeight = $TxtPos[0]["Y"] - $TxtPos[1]["Y"] + $TxtMargin; 7641 7642 if ($DisplayPos == LABEL_POS_INSIDE && abs($TxtHeight) < abs($BarHeight)) { 7643 $CenterX = (($X + $XOffset + $XSize - $XSpace) - ($X + $XOffset + $XSpace)) 7644 / 2 + $X + $XOffset + $XSpace 7645 ; 7646 $CenterY = ($Y2 - $Y1) / 2 + $Y1; 7647 7648 $this->drawText( 7649 $CenterX, 7650 $CenterY, 7651 $Caption, 7652 [ 7653 "R" => $DisplayR, 7654 "G" => $DisplayG, 7655 "B" => $DisplayB, 7656 "Align" => TEXT_ALIGN_MIDDLEMIDDLE, 7657 "FontSize" => $DisplaySize, 7658 "Angle" => 90 7659 ] 7660 ); 7661 } else { 7662 if ($Serie["Data"][$Key] >= 0) { 7663 $Align = TEXT_ALIGN_BOTTOMMIDDLE; 7664 $Offset = $DisplayOffset; 7665 } else { 7666 $Align = TEXT_ALIGN_TOPMIDDLE; 7667 $Offset = -$DisplayOffset; 7668 } 7669 $this->drawText( 7670 $X + $XOffset + $XSize / 2, 7671 $Y2 - $Offset, 7672 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), 7673 [ 7674 "R" => $DisplayR, 7675 "G" => $DisplayG, 7676 "B" => $DisplayB, 7677 "Align" => $Align, 7678 "FontSize" => $DisplaySize 7679 ] 7680 ); 7681 } 7682 7683 $this->Shadow = $RestoreShadow; 7684 } 7685 } 7686 7687 $X = $X + $XStep; 7688 $ID++; 7689 } 7690 } else { 7691 if ($YZero < $this->GraphAreaX1 + 1) { 7692 $YZero = $this->GraphAreaX1 + 1; 7693 } 7694 if ($YZero > $this->GraphAreaX2 - 1) { 7695 $YZero = $this->GraphAreaX2 - 1; 7696 } 7697 7698 if ($XDivs == 0) { 7699 $YStep = 0; 7700 } else { 7701 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 7702 } 7703 7704 $Y = $this->GraphAreaY1 + $XMargin; 7705 7706 if ($AroundZero) { 7707 $X1 = $YZero; 7708 } else { 7709 $X1 = $this->GraphAreaX1 + 1; 7710 } 7711 if ($XDivs == 0) { 7712 $YSize = ($this->GraphAreaY2 - $this->GraphAreaY1) / ($SeriesCount + $Interleave); 7713 } else { 7714 $YSize = ($YStep / ($SeriesCount + $Interleave)); 7715 } 7716 7717 $YOffset = -($YSize * $SeriesCount) / 2 + $CurrentSerie * $YSize; 7718 if ($Y + $YOffset <= $this->GraphAreaY1) { 7719 $YOffset = $this->GraphAreaY1 - $Y + 1; 7720 } 7721 7722 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = $YOffset + $YSize / 2; 7723 7724 if ($Rounded || $BorderR != -1) { 7725 $YSpace = 1; 7726 } else { 7727 $YSpace = 0; 7728 } 7729 7730 if (!is_array($PosArray)) { 7731 $Value = $PosArray; 7732 $PosArray = []; 7733 $PosArray[0] = $Value; 7734 } 7735 7736 $ID = 0; 7737 foreach ($PosArray as $Key => $X2) { 7738 if ($Floating0Serie != null) { 7739 if (isset($Data["Series"][$Floating0Serie]["Data"][$Key])) { 7740 $Value = $Data["Series"][$Floating0Serie]["Data"][$Key]; 7741 } else { 7742 $Value = 0; 7743 } 7744 7745 $YZero = $this->scaleComputeY($Value, ["AxisID" => $Serie["Axis"]]); 7746 if ($YZero < $this->GraphAreaX1 + 1) { 7747 $YZero = $this->GraphAreaX1 + 1; 7748 } 7749 if ($YZero > $this->GraphAreaX2 - 1) { 7750 $YZero = $this->GraphAreaX2 - 1; 7751 } 7752 if ($AroundZero) { 7753 $X1 = $YZero; 7754 } else { 7755 $X1 = $this->GraphAreaX1 + 1; 7756 } 7757 } 7758 7759 if ($OverrideColors != null) { 7760 if (isset($OverrideColors[$ID])) { 7761 $Color = [ 7762 "R" => $OverrideColors[$ID]["R"], 7763 "G" => $OverrideColors[$ID]["G"], 7764 "B" => $OverrideColors[$ID]["B"], 7765 "Alpha" => $OverrideColors[$ID]["Alpha"], 7766 "BorderR" => $OverrideColors[$ID]["BorderR"], 7767 "BorderG" => $OverrideColors[$ID]["BorderG"], 7768 "BorderB" => $OverrideColors[$ID]["BorderB"] 7769 ]; 7770 } else { 7771 $Color = $this->getRandomColor(); 7772 } 7773 } 7774 7775 if ($X2 != VOID) { 7776 $BarWidth = $X2 - $X1; 7777 if ($Serie["Data"][$Key] == 0) { 7778 $this->drawLine( 7779 $X1, 7780 $Y + $YOffset + $YSpace, 7781 $X1, 7782 $Y + $YOffset + $YSize - $YSpace, 7783 $Color 7784 ); 7785 if ($RecordImageMap) { 7786 $this->addToImageMap( 7787 "RECT", 7788 sprintf( 7789 "%s,%s,%s,%s", 7790 floor($X1 - 1), 7791 floor($Y + $YOffset + $YSpace), 7792 floor($X1 + 1), 7793 floor($Y + $YOffset + $YSize - $YSpace) 7794 ), 7795 $this->toHTMLColor($R, $G, $B), 7796 $SerieDescription, 7797 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 7798 ); 7799 } 7800 } else { 7801 if ($RecordImageMap) { 7802 $this->addToImageMap( 7803 "RECT", 7804 sprintf( 7805 "%s,%s,%s,%s", 7806 floor($X1), 7807 floor($Y + $YOffset + $YSpace), 7808 floor($X2), 7809 floor($Y + $YOffset + $YSize - $YSpace) 7810 ), 7811 $this->toHTMLColor($R, $G, $B), 7812 $SerieDescription, 7813 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 7814 ); 7815 } 7816 7817 if ($Rounded) { 7818 $this->drawRoundedFilledRectangle( 7819 $X1 + 1, 7820 $Y + $YOffset + $YSpace, 7821 $X2, 7822 $Y + $YOffset + $YSize - $YSpace, 7823 $RoundRadius, 7824 $Color 7825 ); 7826 } else { 7827 $this->drawFilledRectangle( 7828 $X1, 7829 $Y + $YOffset + $YSpace, 7830 $X2, 7831 $Y + $YOffset + $YSize - $YSpace, 7832 $Color 7833 ); 7834 7835 if ($InnerColor != null) { 7836 $this->drawRectangle( 7837 min($X1, $X2) + 1, 7838 $Y + $YOffset + $YSpace + 1, 7839 max($X1, $X2) - 1, 7840 $Y + $YOffset + $YSize - $YSpace - 1, 7841 $InnerColor 7842 ); 7843 } 7844 7845 if ($Gradient) { 7846 $this->Shadow = false; 7847 7848 if ($GradientMode == GRADIENT_SIMPLE) { 7849 if ($Serie["Data"][$Key] >= 0) { 7850 $GradienColor = [ 7851 "StartR" => $GradientStartR, 7852 "StartG" => $GradientStartG, 7853 "StartB" => $GradientStartB, 7854 "EndR" => $GradientEndR, 7855 "EndG" => $GradientEndG, 7856 "EndB" => $GradientEndB, 7857 "Alpha" => $GradientAlpha 7858 ]; 7859 } else { 7860 $GradienColor = [ 7861 "StartR" => $GradientEndR, 7862 "StartG" => $GradientEndG, 7863 "StartB" => $GradientEndB, 7864 "EndR" => $GradientStartR, 7865 "EndG" => $GradientStartG, 7866 "EndB" => $GradientStartB, 7867 "Alpha" => $GradientAlpha 7868 ]; 7869 } 7870 $this->drawGradientArea( 7871 $X1, 7872 $Y + $YOffset + $YSpace, 7873 $X2, 7874 $Y + $YOffset + $YSize - $YSpace, 7875 DIRECTION_HORIZONTAL, 7876 $GradienColor 7877 ); 7878 } elseif ($GradientMode == GRADIENT_EFFECT_CAN) { 7879 $GradienColor1 = [ 7880 "StartR" => $GradientEndR, 7881 "StartG" => $GradientEndG, 7882 "StartB" => $GradientEndB, 7883 "EndR" => $GradientStartR, 7884 "EndG" => $GradientStartG, 7885 "EndB" => $GradientStartB, 7886 "Alpha" => $GradientAlpha 7887 ]; 7888 $GradienColor2 = [ 7889 "StartR" => $GradientStartR, 7890 "StartG" => $GradientStartG, 7891 "StartB" => $GradientStartB, 7892 "EndR" => $GradientEndR, 7893 "EndG" => $GradientEndG, 7894 "EndB" => $GradientEndB, 7895 "Alpha" => $GradientAlpha 7896 ]; 7897 $YSpan = floor($YSize / 3); 7898 7899 $this->drawGradientArea( 7900 $X1, 7901 $Y + $YOffset + $YSpace, 7902 $X2, 7903 $Y + $YOffset + $YSpan - $YSpace, 7904 DIRECTION_VERTICAL, 7905 $GradienColor1 7906 ); 7907 $this->drawGradientArea( 7908 $X1, 7909 $Y + $YOffset + $YSpan, 7910 $X2, 7911 $Y + $YOffset + $YSize - $YSpace, 7912 DIRECTION_VERTICAL, 7913 $GradienColor2 7914 ); 7915 } 7916 $this->Shadow = $RestoreShadow; 7917 } 7918 } 7919 7920 if ($Draw0Line) { 7921 $Line0Color = ["R" => 0, "G" => 0, "B" => 0, "Alpha" => 20]; 7922 7923 if (abs($X1 - $X2) > 3) { 7924 $Line0Width = 3; 7925 } else { 7926 $Line0Width = 1; 7927 } 7928 if ($X2 - $X1 < 0) { 7929 $Line0Width = -$Line0Width; 7930 } 7931 7932 $this->drawFilledRectangle( 7933 floor($X1), 7934 $Y + $YOffset + $YSpace, 7935 floor($X1) + $Line0Width, 7936 $Y + $YOffset + $YSize - $YSpace, 7937 $Line0Color 7938 ); 7939 $this->drawLine( 7940 floor($X1), 7941 $Y + $YOffset + $YSpace, 7942 floor($X1), 7943 $Y + $YOffset + $YSize - $YSpace, 7944 $Line0Color 7945 ); 7946 } 7947 } 7948 7949 if ($DisplayValues && $Serie["Data"][$Key] != VOID) { 7950 if ($DisplayShadow) { 7951 $this->Shadow = true; 7952 } 7953 7954 $Caption = $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit); 7955 $TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 0, $Caption); 7956 $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"] + $TxtMargin; 7957 7958 if ($DisplayPos == LABEL_POS_INSIDE && abs($TxtWidth) < abs($BarWidth)) { 7959 $CenterX = ($X2 - $X1) / 2 + $X1; 7960 $CenterY = (($Y + $YOffset + $YSize - $YSpace) 7961 - ($Y + $YOffset + $YSpace)) / 2 7962 + ($Y + $YOffset + $YSpace) 7963 ; 7964 7965 $this->drawText( 7966 $CenterX, 7967 $CenterY, 7968 $Caption, 7969 [ 7970 "R" => $DisplayR, 7971 "G" => $DisplayG, 7972 "B" => $DisplayB, 7973 "Align" => TEXT_ALIGN_MIDDLEMIDDLE, 7974 "FontSize" => $DisplaySize 7975 ] 7976 ); 7977 } else { 7978 if ($Serie["Data"][$Key] >= 0) { 7979 $Align = TEXT_ALIGN_MIDDLELEFT; 7980 $Offset = $DisplayOffset; 7981 } else { 7982 $Align = TEXT_ALIGN_MIDDLERIGHT; 7983 $Offset = -$DisplayOffset; 7984 } 7985 $this->drawText( 7986 $X2 + $Offset, 7987 $Y + $YOffset + $YSize / 2, 7988 $Caption, 7989 [ 7990 "R" => $DisplayR, 7991 "G" => $DisplayG, 7992 "B" => $DisplayB, 7993 "Align" => $Align, 7994 "FontSize" => $DisplaySize 7995 ] 7996 ); 7997 } 7998 7999 $this->Shadow = $RestoreShadow; 8000 } 8001 } 8002 $Y = $Y + $YStep; 8003 $ID++; 8004 } 8005 } 8006 $CurrentSerie++; 8007 } 8008 } 8009 } 8010 8011 /** 8012 * Draw a bar chart 8013 * @param array $Format 8014 */ 8015 public function drawStackedBarChart(array $Format = []) 8016 { 8017 $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; 8018 $DisplayOrientation = isset($Format["DisplayOrientation"]) ? $Format["DisplayOrientation"] : ORIENTATION_AUTO; 8019 $DisplayRound = isset($Format["DisplayRound"]) ? $Format["DisplayRound"] : 0; 8020 $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; 8021 $DisplayFont = isset($Format["DisplayFont"]) ? $Format["DisplayFont"] : $this->FontName; 8022 $DisplaySize = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontSize; 8023 $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; 8024 $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; 8025 $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; 8026 $Interleave = isset($Format["Interleave"]) ? $Format["Interleave"] : .5; 8027 $Rounded = isset($Format["Rounded"]) ? $Format["Rounded"] : false; 8028 $RoundRadius = isset($Format["RoundRadius"]) ? $Format["RoundRadius"] : 4; 8029 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 8030 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; 8031 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; 8032 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; 8033 $Gradient = isset($Format["Gradient"]) ? $Format["Gradient"] : false; 8034 $GradientMode = isset($Format["GradientMode"]) ? $Format["GradientMode"] : GRADIENT_SIMPLE; 8035 $GradientAlpha = isset($Format["GradientAlpha"]) ? $Format["GradientAlpha"] : 20; 8036 $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; 8037 $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; 8038 $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; 8039 $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 0; 8040 $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 0; 8041 $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 0; 8042 $InnerSurrounding = isset($Format["InnerSurrounding"]) ? $Format["InnerSurrounding"] : null; 8043 $InnerBorderR = isset($Format["InnerBorderR"]) ? $Format["InnerBorderR"] : -1; 8044 $InnerBorderG = isset($Format["InnerBorderG"]) ? $Format["InnerBorderG"] : -1; 8045 $InnerBorderB = isset($Format["InnerBorderB"]) ? $Format["InnerBorderB"] : -1; 8046 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; 8047 $FontFactor = isset($Format["FontFactor"]) ? $Format["FontFactor"] : 8; 8048 8049 $this->LastChartLayout = CHART_LAST_LAYOUT_STACKED; 8050 8051 $Data = $this->DataSet->getData(); 8052 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 8053 8054 $RestoreShadow = $this->Shadow; 8055 8056 $LastX = []; 8057 $LastY = []; 8058 foreach ($Data["Series"] as $SerieName => $Serie) { 8059 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 8060 $R = $Serie["Color"]["R"]; 8061 $G = $Serie["Color"]["G"]; 8062 $B = $Serie["Color"]["B"]; 8063 $Alpha = $Serie["Color"]["Alpha"]; 8064 $Ticks = $Serie["Ticks"]; 8065 if ($DisplayColor == DISPLAY_AUTO) { 8066 $DisplayR = 255; 8067 $DisplayG = 255; 8068 $DisplayB = 255; 8069 } 8070 if ($Surrounding != null) { 8071 $BorderR = $R + $Surrounding; 8072 $BorderG = $G + $Surrounding; 8073 $BorderB = $B + $Surrounding; 8074 } 8075 if ($InnerSurrounding != null) { 8076 $InnerBorderR = $R + $InnerSurrounding; 8077 $InnerBorderG = $G + $InnerSurrounding; 8078 $InnerBorderB = $B + $InnerSurrounding; 8079 } 8080 if ($InnerBorderR == -1) { 8081 $InnerColor = null; 8082 } else { 8083 $InnerColor = [ 8084 "R" => $InnerBorderR, 8085 "G" => $InnerBorderG, 8086 "B" => $InnerBorderB 8087 ]; 8088 } 8089 8090 $AxisID = $Serie["Axis"]; 8091 $Mode = $Data["Axis"][$AxisID]["Display"]; 8092 $Format = $Data["Axis"][$AxisID]["Format"]; 8093 $Unit = $Data["Axis"][$AxisID]["Unit"]; 8094 8095 if (isset($Serie["Description"])) { 8096 $SerieDescription = $Serie["Description"]; 8097 } else { 8098 $SerieDescription = $SerieName; 8099 } 8100 8101 $PosArray = $this->scaleComputeY( 8102 $Serie["Data"], 8103 ["AxisID" => $Serie["Axis"]], 8104 true 8105 ); 8106 $YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]); 8107 8108 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 8109 8110 $Color = [ 8111 "TransCorner" => true, 8112 "R" => $R, 8113 "G" => $G, 8114 "B" => $B, 8115 "Alpha" => $Alpha, 8116 "BorderR" => $BorderR, 8117 "BorderG" => $BorderG, 8118 "BorderB" => $BorderB 8119 ]; 8120 8121 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 8122 if ($YZero > $this->GraphAreaY2 - 1) { 8123 $YZero = $this->GraphAreaY2 - 1; 8124 } 8125 if ($YZero > $this->GraphAreaY2 - 1) { 8126 $YZero = $this->GraphAreaY2 - 1; 8127 } 8128 8129 if ($XDivs == 0) { 8130 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 8131 } else { 8132 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 8133 } 8134 $X = $this->GraphAreaX1 + $XMargin; 8135 8136 $XSize = ($XStep / (1 + $Interleave)); 8137 $XOffset = -($XSize / 2); 8138 8139 if (!is_array($PosArray)) { 8140 $Value = $PosArray; 8141 $PosArray = []; 8142 $PosArray[0] = $Value; 8143 } 8144 foreach ($PosArray as $Key => $Height) { 8145 if ($Height != VOID && $Serie["Data"][$Key] != 0) { 8146 if ($Serie["Data"][$Key] > 0) { 8147 $Pos = "+"; 8148 } else { 8149 $Pos = "-"; 8150 } 8151 8152 if (!isset($LastY[$Key])) { 8153 $LastY[$Key] = []; 8154 } 8155 if (!isset($LastY[$Key][$Pos])) { 8156 $LastY[$Key][$Pos] = $YZero; 8157 } 8158 8159 $Y1 = $LastY[$Key][$Pos]; 8160 $Y2 = $Y1 - $Height; 8161 8162 if (($Rounded || $BorderR != -1) && ($Pos == "+" && $Y1 != $YZero)) { 8163 $YSpaceUp = 1; 8164 } else { 8165 $YSpaceUp = 0; 8166 } 8167 if (($Rounded || $BorderR != -1) && ($Pos == "-" && $Y1 != $YZero)) { 8168 $YSpaceDown = 1; 8169 } else { 8170 $YSpaceDown = 0; 8171 } 8172 8173 if ($RecordImageMap) { 8174 $this->addToImageMap( 8175 "RECT", 8176 sprintf( 8177 "%s,%s,%s,%s", 8178 floor($X + $XOffset), 8179 floor($Y1 - $YSpaceUp + $YSpaceDown), 8180 floor($X + $XOffset + $XSize), 8181 floor($Y2) 8182 ), 8183 $this->toHTMLColor($R, $G, $B), 8184 $SerieDescription, 8185 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 8186 ); 8187 } 8188 8189 if ($Rounded) { 8190 $this->drawRoundedFilledRectangle( 8191 $X + $XOffset, 8192 $Y1 - $YSpaceUp + $YSpaceDown, 8193 $X + $XOffset + $XSize, 8194 $Y2, 8195 $RoundRadius, 8196 $Color 8197 ); 8198 } else { 8199 $this->drawFilledRectangle( 8200 $X + $XOffset, 8201 $Y1 - $YSpaceUp + $YSpaceDown, 8202 $X + $XOffset + $XSize, 8203 $Y2, 8204 $Color 8205 ); 8206 8207 if ($InnerColor != null) { 8208 $RestoreShadow = $this->Shadow; 8209 $this->Shadow = false; 8210 $this->drawRectangle( 8211 min($X + $XOffset + 1, $X + $XOffset + $XSize), 8212 min($Y1 - $YSpaceUp + $YSpaceDown, $Y2) + 1, 8213 max($X + $XOffset + 1, $X + $XOffset + $XSize) - 1, 8214 max($Y1 - $YSpaceUp + $YSpaceDown, $Y2) - 1, 8215 $InnerColor 8216 ); 8217 $this->Shadow = $RestoreShadow; 8218 } 8219 8220 if ($Gradient) { 8221 $this->Shadow = false; 8222 8223 if ($GradientMode == GRADIENT_SIMPLE) { 8224 $GradientColor = [ 8225 "StartR" => $GradientStartR, 8226 "StartG" => $GradientStartG, 8227 "StartB" => $GradientStartB, 8228 "EndR" => $GradientEndR, 8229 "EndG" => $GradientEndG, 8230 "EndB" => $GradientEndB, 8231 "Alpha" => $GradientAlpha 8232 ]; 8233 $this->drawGradientArea( 8234 $X + $XOffset, 8235 $Y1 - 1 - $YSpaceUp + $YSpaceDown, 8236 $X + $XOffset + $XSize, 8237 $Y2 + 1, 8238 DIRECTION_VERTICAL, 8239 $GradientColor 8240 ); 8241 } elseif ($GradientMode == GRADIENT_EFFECT_CAN) { 8242 $GradientColor1 = [ 8243 "StartR" => $GradientEndR, 8244 "StartG" => $GradientEndG, 8245 "StartB" => $GradientEndB, 8246 "EndR" => $GradientStartR, 8247 "EndG" => $GradientStartG, 8248 "EndB" => $GradientStartB, 8249 "Alpha" => $GradientAlpha 8250 ]; 8251 $GradientColor2 = [ 8252 "StartR" => $GradientStartR, 8253 "StartG" => $GradientStartG, 8254 "StartB" => $GradientStartB, 8255 "EndR" => $GradientEndR, 8256 "EndG" => $GradientEndG, 8257 "EndB" => $GradientEndB, 8258 "Alpha" => $GradientAlpha 8259 ]; 8260 $XSpan = floor($XSize / 3); 8261 8262 $this->drawGradientArea( 8263 $X + $XOffset - .5, 8264 $Y1 - .5 - $YSpaceUp + $YSpaceDown, 8265 $X + $XOffset + $XSpan, 8266 $Y2 + .5, 8267 DIRECTION_HORIZONTAL, 8268 $GradientColor1 8269 ); 8270 $this->drawGradientArea( 8271 $X + $XSpan + $XOffset - .5, 8272 $Y1 - .5 - $YSpaceUp + $YSpaceDown, 8273 $X + $XOffset + $XSize, 8274 $Y2 + .5, 8275 DIRECTION_HORIZONTAL, 8276 $GradientColor2 8277 ); 8278 } 8279 $this->Shadow = $RestoreShadow; 8280 } 8281 } 8282 8283 if ($DisplayValues) { 8284 $BarHeight = abs($Y2 - $Y1) - 2; 8285 $BarWidth = $XSize + ($XOffset / 2) - $FontFactor; 8286 8287 $Caption = $this->scaleFormat( 8288 round($Serie["Data"][$Key], $DisplayRound), 8289 $Mode, 8290 $Format, 8291 $Unit 8292 ); 8293 $TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 0, $Caption); 8294 $TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]); 8295 $TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]); 8296 8297 $XCenter = (($X + $XOffset + $XSize) - ($X + $XOffset)) / 2 + $X + $XOffset; 8298 $YCenter = (($Y2) - ($Y1 - $YSpaceUp + $YSpaceDown)) / 2 8299 + $Y1 - $YSpaceUp + $YSpaceDown 8300 ; 8301 8302 $Done = false; 8303 if ($DisplayOrientation == ORIENTATION_HORIZONTAL 8304 || $DisplayOrientation == ORIENTATION_AUTO 8305 ) { 8306 if ($TxtHeight < $BarHeight && $TxtWidth < $BarWidth) { 8307 $this->drawText( 8308 $XCenter, 8309 $YCenter, 8310 $this->scaleFormat( 8311 $Serie["Data"][$Key], 8312 $Mode, 8313 $Format, 8314 $Unit 8315 ), 8316 [ 8317 "R" => $DisplayR, 8318 "G" => $DisplayG, 8319 "B" => $DisplayB, 8320 "Align" => TEXT_ALIGN_MIDDLEMIDDLE, 8321 "FontSize" => $DisplaySize, 8322 "FontName" => $DisplayFont 8323 ] 8324 ); 8325 $Done = true; 8326 } 8327 } 8328 8329 if ($DisplayOrientation == ORIENTATION_VERTICAL 8330 || ($DisplayOrientation == ORIENTATION_AUTO && !$Done) 8331 ) { 8332 if ($TxtHeight < $BarWidth && $TxtWidth < $BarHeight) { 8333 $this->drawText( 8334 $XCenter, 8335 $YCenter, 8336 $this->scaleFormat( 8337 $Serie["Data"][$Key], 8338 $Mode, 8339 $Format, 8340 $Unit 8341 ), 8342 [ 8343 "R" => $DisplayR, 8344 "G" => $DisplayG, 8345 "B" => $DisplayB, 8346 "Angle" => 90, 8347 "Align" => TEXT_ALIGN_MIDDLEMIDDLE, 8348 "FontSize" => $DisplaySize, 8349 "FontName" => $DisplayFont 8350 ] 8351 ); 8352 } 8353 } 8354 } 8355 $LastY[$Key][$Pos] = $Y2; 8356 } 8357 $X = $X + $XStep; 8358 } 8359 } else { 8360 if ($YZero < $this->GraphAreaX1 + 1) { 8361 $YZero = $this->GraphAreaX1 + 1; 8362 } 8363 if ($YZero > $this->GraphAreaX2 - 1) { 8364 $YZero = $this->GraphAreaX2 - 1; 8365 } 8366 8367 if ($XDivs == 0) { 8368 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 8369 } else { 8370 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 8371 } 8372 $Y = $this->GraphAreaY1 + $XMargin; 8373 8374 $YSize = $YStep / (1 + $Interleave); 8375 $YOffset = -($YSize / 2); 8376 8377 if (!is_array($PosArray)) { 8378 $Value = $PosArray; 8379 $PosArray = []; 8380 $PosArray[0] = $Value; 8381 } 8382 foreach ($PosArray as $Key => $Width) { 8383 if ($Width != VOID && $Serie["Data"][$Key] != 0) { 8384 if ($Serie["Data"][$Key] > 0) { 8385 $Pos = "+"; 8386 } else { 8387 $Pos = "-"; 8388 } 8389 8390 if (!isset($LastX[$Key])) { 8391 $LastX[$Key] = []; 8392 } 8393 if (!isset($LastX[$Key][$Pos])) { 8394 $LastX[$Key][$Pos] = $YZero; 8395 } 8396 8397 $X1 = $LastX[$Key][$Pos]; 8398 $X2 = $X1 + $Width; 8399 8400 if (($Rounded || $BorderR != -1) && ($Pos == "+" && $X1 != $YZero)) { 8401 $XSpaceLeft = 2; 8402 } else { 8403 $XSpaceLeft = 0; 8404 } 8405 if (($Rounded || $BorderR != -1) && ($Pos == "-" && $X1 != $YZero)) { 8406 $XSpaceRight = 2; 8407 } else { 8408 $XSpaceRight = 0; 8409 } 8410 8411 if ($RecordImageMap) { 8412 $this->addToImageMap( 8413 "RECT", 8414 sprintf( 8415 "%s,%s,%s,%s", 8416 floor($X1 + $XSpaceLeft), 8417 floor($Y + $YOffset), 8418 floor($X2 - $XSpaceRight), 8419 floor($Y + $YOffset + $YSize) 8420 ), 8421 $this->toHTMLColor($R, $G, $B), 8422 $SerieDescription, 8423 $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit) 8424 ); 8425 } 8426 8427 if ($Rounded) { 8428 $this->drawRoundedFilledRectangle( 8429 $X1 + $XSpaceLeft, 8430 $Y + $YOffset, 8431 $X2 - $XSpaceRight, 8432 $Y + $YOffset + $YSize, 8433 $RoundRadius, 8434 $Color 8435 ); 8436 } else { 8437 $this->drawFilledRectangle( 8438 $X1 + $XSpaceLeft, 8439 $Y + $YOffset, 8440 $X2 - $XSpaceRight, 8441 $Y + $YOffset + $YSize, 8442 $Color 8443 ); 8444 8445 if ($InnerColor != null) { 8446 $RestoreShadow = $this->Shadow; 8447 $this->Shadow = false; 8448 $this->drawRectangle( 8449 min($X1 + $XSpaceLeft, $X2 - $XSpaceRight) + 1, 8450 min($Y + $YOffset, $Y + $YOffset + $YSize) + 1, 8451 max($X1 + $XSpaceLeft, $X2 - $XSpaceRight) - 1, 8452 max($Y + $YOffset, $Y + $YOffset + $YSize) - 1, 8453 $InnerColor 8454 ); 8455 $this->Shadow = $RestoreShadow; 8456 } 8457 8458 if ($Gradient) { 8459 $this->Shadow = false; 8460 8461 if ($GradientMode == GRADIENT_SIMPLE) { 8462 $GradientColor = [ 8463 "StartR" => $GradientStartR, 8464 "StartG" => $GradientStartG, 8465 "StartB" => $GradientStartB, 8466 "EndR" => $GradientEndR, 8467 "EndG" => $GradientEndG, 8468 "EndB" => $GradientEndB, 8469 "Alpha" => $GradientAlpha 8470 ]; 8471 $this->drawGradientArea( 8472 $X1 + $XSpaceLeft, 8473 $Y + $YOffset, 8474 $X2 - $XSpaceRight, 8475 $Y + $YOffset + $YSize, 8476 DIRECTION_HORIZONTAL, 8477 $GradientColor 8478 ); 8479 } elseif ($GradientMode == GRADIENT_EFFECT_CAN) { 8480 $GradientColor1 = [ 8481 "StartR" => $GradientEndR, 8482 "StartG" => $GradientEndG, 8483 "StartB" => $GradientEndB, 8484 "EndR" => $GradientStartR, 8485 "EndG" => $GradientStartG, 8486 "EndB" => $GradientStartB, 8487 "Alpha" => $GradientAlpha 8488 ]; 8489 $GradientColor2 = [ 8490 "StartR" => $GradientStartR, 8491 "StartG" => $GradientStartG, 8492 "StartB" => $GradientStartB, 8493 "EndR" => $GradientEndR, 8494 "EndG" => $GradientEndG, 8495 "EndB" => $GradientEndB, 8496 "Alpha" => $GradientAlpha 8497 ]; 8498 $YSpan = floor($YSize / 3); 8499 8500 $this->drawGradientArea( 8501 $X1 + $XSpaceLeft, 8502 $Y + $YOffset, 8503 $X2 - $XSpaceRight, 8504 $Y + $YOffset + $YSpan, 8505 DIRECTION_VERTICAL, 8506 $GradientColor1 8507 ); 8508 $this->drawGradientArea( 8509 $X1 + $XSpaceLeft, 8510 $Y + $YOffset + $YSpan, 8511 $X2 - $XSpaceRight, 8512 $Y + $YOffset + $YSize, 8513 DIRECTION_VERTICAL, 8514 $GradientColor2 8515 ); 8516 } 8517 $this->Shadow = $RestoreShadow; 8518 } 8519 } 8520 8521 if ($DisplayValues) { 8522 $BarWidth = abs($X2 - $X1) - $FontFactor; 8523 $BarHeight = $YSize + ($YOffset / 2) - $FontFactor / 2; 8524 $Caption = $this->scaleFormat( 8525 round($Serie["Data"][$Key], $DisplayRound), 8526 $Mode, 8527 $Format, 8528 $Unit 8529 ); 8530 $TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 0, $Caption); 8531 $TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]); 8532 $TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]); 8533 8534 $XCenter = ($X2 - $X1) / 2 + $X1; 8535 $YCenter = (($Y + $YOffset + $YSize) - ($Y + $YOffset)) / 2 + $Y + $YOffset; 8536 8537 $Done = false; 8538 if ($DisplayOrientation == ORIENTATION_HORIZONTAL 8539 || $DisplayOrientation == ORIENTATION_AUTO 8540 ) { 8541 if ($TxtHeight < $BarHeight && $TxtWidth < $BarWidth) { 8542 $this->drawText( 8543 $XCenter, 8544 $YCenter, 8545 $this->scaleFormat( 8546 $Serie["Data"][$Key], 8547 $Mode, 8548 $Format, 8549 $Unit 8550 ), 8551 [ 8552 "R" => $DisplayR, 8553 "G" => $DisplayG, 8554 "B" => $DisplayB, 8555 "Align" => TEXT_ALIGN_MIDDLEMIDDLE, 8556 "FontSize" => $DisplaySize, 8557 "FontName" => $DisplayFont 8558 ] 8559 ); 8560 $Done = true; 8561 } 8562 } 8563 8564 if ($DisplayOrientation == ORIENTATION_VERTICAL 8565 || ($DisplayOrientation == ORIENTATION_AUTO && !$Done) 8566 ) { 8567 if ($TxtHeight < $BarWidth && $TxtWidth < $BarHeight) { 8568 $this->drawText( 8569 $XCenter, 8570 $YCenter, 8571 $this->scaleFormat( 8572 $Serie["Data"][$Key], 8573 $Mode, 8574 $Format, 8575 $Unit 8576 ), 8577 [ 8578 "R" => $DisplayR, 8579 "G" => $DisplayG, 8580 "B" => $DisplayB, 8581 "Angle" => 90, 8582 "Align" => TEXT_ALIGN_MIDDLEMIDDLE, 8583 "FontSize" => $DisplaySize, 8584 "FontName" => $DisplayFont 8585 ] 8586 ); 8587 } 8588 } 8589 } 8590 8591 $LastX[$Key][$Pos] = $X2; 8592 } 8593 8594 $Y = $Y + $YStep; 8595 } 8596 } 8597 } 8598 } 8599 } 8600 8601 /** 8602 * Draw a stacked area chart 8603 * @param array $Format 8604 */ 8605 public function drawStackedAreaChart(array $Format = []) 8606 { 8607 $DrawLine = isset($Format["DrawLine"]) ? $Format["DrawLine"] : false; 8608 $LineSurrounding = isset($Format["LineSurrounding"]) ? $Format["LineSurrounding"] : null; 8609 $LineR = isset($Format["LineR"]) ? $Format["LineR"] : VOID; 8610 $LineG = isset($Format["LineG"]) ? $Format["LineG"] : VOID; 8611 $LineB = isset($Format["LineB"]) ? $Format["LineB"] : VOID; 8612 $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 100; 8613 $DrawPlot = isset($Format["DrawPlot"]) ? $Format["DrawPlot"] : false; 8614 $PlotRadius = isset($Format["PlotRadius"]) ? $Format["PlotRadius"] : 2; 8615 $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : 1; 8616 $PlotBorderSurrounding = isset($Format["PlotBorderSurrounding"]) ? $Format["PlotBorderSurrounding"] : null; 8617 $PlotBorderR = isset($Format["PlotBorderR"]) ? $Format["PlotBorderR"] : 0; 8618 $PlotBorderG = isset($Format["PlotBorderG"]) ? $Format["PlotBorderG"] : 0; 8619 $PlotBorderB = isset($Format["PlotBorderB"]) ? $Format["PlotBorderB"] : 0; 8620 $PlotBorderAlpha = isset($Format["PlotBorderAlpha"]) ? $Format["PlotBorderAlpha"] : 50; 8621 $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : null; 8622 8623 $this->LastChartLayout = CHART_LAST_LAYOUT_STACKED; 8624 8625 $Data = $this->DataSet->getData(); 8626 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 8627 8628 $RestoreShadow = $this->Shadow; 8629 $this->Shadow = false; 8630 8631 /* Build the offset data series */ 8632 $OverallOffset = []; 8633 $SerieOrder = []; 8634 foreach ($Data["Series"] as $SerieName => $Serie) { 8635 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 8636 $SerieOrder[] = $SerieName; 8637 8638 foreach ($Serie["Data"] as $Key => $Value) { 8639 if ($Value == VOID) { 8640 $Value = 0; 8641 } 8642 if ($Value >= 0) { 8643 $Sign = "+"; 8644 } else { 8645 $Sign = "-"; 8646 } 8647 if (!isset($OverallOffset[$Key]) || !isset($OverallOffset[$Key][$Sign])) { 8648 $OverallOffset[$Key][$Sign] = 0; 8649 } 8650 8651 if ($Sign == "+") { 8652 $Data["Series"][$SerieName]["Data"][$Key] = $Value + $OverallOffset[$Key][$Sign]; 8653 } else { 8654 $Data["Series"][$SerieName]["Data"][$Key] = $Value - $OverallOffset[$Key][$Sign]; 8655 } 8656 8657 $OverallOffset[$Key][$Sign] = $OverallOffset[$Key][$Sign] + abs($Value); 8658 } 8659 } 8660 } 8661 $SerieOrder = array_reverse($SerieOrder); 8662 8663 foreach ($SerieOrder as $Key => $SerieName) { 8664 $Serie = $Data["Series"][$SerieName]; 8665 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 8666 $R = $Serie["Color"]["R"]; 8667 $G = $Serie["Color"]["G"]; 8668 $B = $Serie["Color"]["B"]; 8669 $Alpha = $Serie["Color"]["Alpha"]; 8670 $Ticks = $Serie["Ticks"]; 8671 if ($ForceTransparency != null) { 8672 $Alpha = $ForceTransparency; 8673 } 8674 8675 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]; 8676 if ($LineSurrounding != null) { 8677 $LineColor = [ 8678 "R" => $R + $LineSurrounding, 8679 "G" => $G + $LineSurrounding, 8680 "B" => $B + $LineSurrounding, 8681 "Alpha" => $Alpha 8682 ]; 8683 } elseif ($LineR != VOID) { 8684 $LineColor = [ 8685 "R" => $LineR, 8686 "G" => $LineG, 8687 "B" => $LineB, 8688 "Alpha" => $LineAlpha 8689 ]; 8690 } else { 8691 $LineColor = $Color; 8692 } 8693 if ($PlotBorderSurrounding != null) { 8694 $PlotBorderColor = [ 8695 "R" => $R + $PlotBorderSurrounding, 8696 "G" => $G + $PlotBorderSurrounding, 8697 "B" => $B + $PlotBorderSurrounding, 8698 "Alpha" => $PlotBorderAlpha 8699 ]; 8700 } else { 8701 $PlotBorderColor = [ 8702 "R" => $PlotBorderR, 8703 "G" => $PlotBorderG, 8704 "B" => $PlotBorderB, 8705 "Alpha" => $PlotBorderAlpha 8706 ]; 8707 } 8708 $AxisID = $Serie["Axis"]; 8709 $Format = $Data["Axis"][$AxisID]["Format"]; 8710 8711 $PosArray = $this->scaleComputeY( 8712 $Serie["Data"], 8713 ["AxisID" => $Serie["Axis"]], 8714 true 8715 ); 8716 $YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]); 8717 8718 $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; 8719 8720 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 8721 if ($YZero < $this->GraphAreaY1 + 1) { 8722 $YZero = $this->GraphAreaY1 + 1; 8723 } 8724 if ($YZero > $this->GraphAreaY2 - 1) { 8725 $YZero = $this->GraphAreaY2 - 1; 8726 } 8727 8728 if ($XDivs == 0) { 8729 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 8730 } else { 8731 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 8732 } 8733 $X = $this->GraphAreaX1 + $XMargin; 8734 8735 if (!is_array($PosArray)) { 8736 $Value = $PosArray; 8737 $PosArray = []; 8738 $PosArray[0] = $Value; 8739 } 8740 8741 $Plots = []; 8742 $Plots[] = $X; 8743 $Plots[] = $YZero; 8744 foreach ($PosArray as $Key => $Height) { 8745 if ($Height != VOID) { 8746 $Plots[] = $X; 8747 $Plots[] = $YZero - $Height; 8748 } 8749 $X = $X + $XStep; 8750 } 8751 $Plots[] = $X - $XStep; 8752 $Plots[] = $YZero; 8753 8754 $this->drawPolygon($Plots, $Color); 8755 8756 $this->Shadow = $RestoreShadow; 8757 if ($DrawLine) { 8758 for ($i = 2; $i <= count($Plots) - 6; $i = $i + 2) { 8759 $this->drawLine( 8760 $Plots[$i], 8761 $Plots[$i + 1], 8762 $Plots[$i + 2], 8763 $Plots[$i + 3], 8764 $LineColor 8765 ); 8766 } 8767 } 8768 if ($DrawPlot) { 8769 for ($i = 2; $i <= count($Plots) - 4; $i = $i + 2) { 8770 if ($PlotBorder != 0) { 8771 $this->drawFilledCircle( 8772 $Plots[$i], 8773 $Plots[$i + 1], 8774 $PlotRadius + $PlotBorder, 8775 $PlotBorderColor 8776 ); 8777 } 8778 $this->drawFilledCircle($Plots[$i], $Plots[$i + 1], $PlotRadius, $Color); 8779 } 8780 } 8781 $this->Shadow = false; 8782 } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { 8783 if ($YZero < $this->GraphAreaX1 + 1) { 8784 $YZero = $this->GraphAreaX1 + 1; 8785 } 8786 if ($YZero > $this->GraphAreaX2 - 1) { 8787 $YZero = $this->GraphAreaX2 - 1; 8788 } 8789 8790 if ($XDivs == 0) { 8791 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 8792 } else { 8793 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 8794 } 8795 $Y = $this->GraphAreaY1 + $XMargin; 8796 8797 if (!is_array($PosArray)) { 8798 $Value = $PosArray; 8799 $PosArray = []; 8800 $PosArray[0] = $Value; 8801 } 8802 8803 $Plots = []; 8804 $Plots[] = $YZero; 8805 $Plots[] = $Y; 8806 foreach ($PosArray as $Key => $Height) { 8807 if ($Height != VOID) { 8808 $Plots[] = $YZero + $Height; 8809 $Plots[] = $Y; 8810 } 8811 $Y = $Y + $YStep; 8812 } 8813 $Plots[] = $YZero; 8814 $Plots[] = $Y - $YStep; 8815 8816 $this->drawPolygon($Plots, $Color); 8817 8818 $this->Shadow = $RestoreShadow; 8819 if ($DrawLine) { 8820 for ($i = 2; $i <= count($Plots) - 6; $i = $i + 2) { 8821 $this->drawLine( 8822 $Plots[$i], 8823 $Plots[$i + 1], 8824 $Plots[$i + 2], 8825 $Plots[$i + 3], 8826 $LineColor 8827 ); 8828 } 8829 } 8830 if ($DrawPlot) { 8831 for ($i = 2; $i <= count($Plots) - 4; $i = $i + 2) { 8832 if ($PlotBorder != 0) { 8833 $this->drawFilledCircle( 8834 $Plots[$i], 8835 $Plots[$i + 1], 8836 $PlotRadius + $PlotBorder, 8837 $PlotBorderColor 8838 ); 8839 } 8840 8841 $this->drawFilledCircle($Plots[$i], $Plots[$i + 1], $PlotRadius, $Color); 8842 } 8843 } 8844 $this->Shadow = false; 8845 } 8846 } 8847 } 8848 $this->Shadow = $RestoreShadow; 8849 } 8850 8851 /** 8852 * Draw the derivative chart associated to the data series 8853 * @param array $Format 8854 */ 8855 public function drawDerivative(array $Format = []) 8856 { 8857 $Offset = isset($Format["Offset"]) ? $Format["Offset"] : 10; 8858 $SerieSpacing = isset($Format["SerieSpacing"]) ? $Format["SerieSpacing"] : 3; 8859 $DerivativeHeight = isset($Format["DerivativeHeight"]) ? $Format["DerivativeHeight"] : 4; 8860 $ShadedSlopeBox = isset($Format["ShadedSlopeBox"]) ? $Format["ShadedSlopeBox"] : false; 8861 $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : true; 8862 $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255; 8863 $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255; 8864 $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255; 8865 $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 20; 8866 $DrawBorder = isset($Format["DrawBorder"]) ? $Format["DrawBorder"] : true; 8867 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; 8868 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; 8869 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; 8870 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100; 8871 $Caption = isset($Format["Caption"]) ? $Format["Caption"] : true; 8872 $CaptionHeight = isset($Format["CaptionHeight"]) ? $Format["CaptionHeight"] : 10; 8873 $CaptionWidth = isset($Format["CaptionWidth"]) ? $Format["CaptionWidth"] : 20; 8874 $CaptionMargin = isset($Format["CaptionMargin"]) ? $Format["CaptionMargin"] : 4; 8875 $CaptionLine = isset($Format["CaptionLine"]) ? $Format["CaptionLine"] : false; 8876 $CaptionBox = isset($Format["CaptionBox"]) ? $Format["CaptionBox"] : false; 8877 $CaptionBorderR = isset($Format["CaptionBorderR"]) ? $Format["CaptionBorderR"] : 0; 8878 $CaptionBorderG = isset($Format["CaptionBorderG"]) ? $Format["CaptionBorderG"] : 0; 8879 $CaptionBorderB = isset($Format["CaptionBorderB"]) ? $Format["CaptionBorderB"] : 0; 8880 $CaptionFillR = isset($Format["CaptionFillR"]) ? $Format["CaptionFillR"] : 255; 8881 $CaptionFillG = isset($Format["CaptionFillG"]) ? $Format["CaptionFillG"] : 255; 8882 $CaptionFillB = isset($Format["CaptionFillB"]) ? $Format["CaptionFillB"] : 255; 8883 $CaptionFillAlpha = isset($Format["CaptionFillAlpha"]) ? $Format["CaptionFillAlpha"] : 80; 8884 $PositiveSlopeStartR = isset($Format["PositiveSlopeStartR"]) ? $Format["PositiveSlopeStartR"] : 184; 8885 $PositiveSlopeStartG = isset($Format["PositiveSlopeStartG"]) ? $Format["PositiveSlopeStartG"] : 234; 8886 $PositiveSlopeStartB = isset($Format["PositiveSlopeStartB"]) ? $Format["PositiveSlopeStartB"] : 88; 8887 $PositiveSlopeEndR = isset($Format["PositiveSlopeStartR"]) ? $Format["PositiveSlopeStartR"] : 239; 8888 $PositiveSlopeEndG = isset($Format["PositiveSlopeStartG"]) ? $Format["PositiveSlopeStartG"] : 31; 8889 $PositiveSlopeEndB = isset($Format["PositiveSlopeStartB"]) ? $Format["PositiveSlopeStartB"] : 36; 8890 $NegativeSlopeStartR = isset($Format["NegativeSlopeStartR"]) ? $Format["NegativeSlopeStartR"] : 184; 8891 $NegativeSlopeStartG = isset($Format["NegativeSlopeStartG"]) ? $Format["NegativeSlopeStartG"] : 234; 8892 $NegativeSlopeStartB = isset($Format["NegativeSlopeStartB"]) ? $Format["NegativeSlopeStartB"] : 88; 8893 $NegativeSlopeEndR = isset($Format["NegativeSlopeStartR"]) ? $Format["NegativeSlopeStartR"] : 67; 8894 $NegativeSlopeEndG = isset($Format["NegativeSlopeStartG"]) ? $Format["NegativeSlopeStartG"] : 124; 8895 $NegativeSlopeEndB = isset($Format["NegativeSlopeStartB"]) ? $Format["NegativeSlopeStartB"] : 227; 8896 8897 $Data = $this->DataSet->getData(); 8898 8899 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 8900 8901 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 8902 $YPos = $this->DataSet->Data["GraphArea"]["Y2"] + $Offset; 8903 } else { 8904 $XPos = $this->DataSet->Data["GraphArea"]["X2"] + $Offset; 8905 } 8906 foreach ($Data["Series"] as $SerieName => $Serie) { 8907 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 8908 $R = $Serie["Color"]["R"]; 8909 $G = $Serie["Color"]["G"]; 8910 $B = $Serie["Color"]["B"]; 8911 $Alpha = $Serie["Color"]["Alpha"]; 8912 $Ticks = $Serie["Ticks"]; 8913 $Weight = $Serie["Weight"]; 8914 8915 $AxisID = $Serie["Axis"]; 8916 $PosArray = $this->scaleComputeY( 8917 $Serie["Data"], 8918 ["AxisID" => $Serie["Axis"]] 8919 ); 8920 8921 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 8922 if ($Caption) { 8923 if ($CaptionLine) { 8924 $StartX = floor($this->GraphAreaX1 - $CaptionWidth + $XMargin - $CaptionMargin); 8925 $EndX = floor($this->GraphAreaX1 - $CaptionMargin + $XMargin); 8926 8927 $CaptionSettings = [ 8928 "R" => $R, 8929 "G" => $G, 8930 "B" => $B, 8931 "Alpha" => $Alpha, 8932 "Ticks" => $Ticks, 8933 "Weight" => $Weight 8934 ]; 8935 if ($CaptionBox) { 8936 $this->drawFilledRectangle( 8937 $StartX, 8938 $YPos, 8939 $EndX, 8940 $YPos + $CaptionHeight, 8941 [ 8942 "R" => $CaptionFillR, 8943 "G" => $CaptionFillG, 8944 "B" => $CaptionFillB, 8945 "BorderR" => $CaptionBorderR, 8946 "BorderG" => $CaptionBorderG, 8947 "BorderB" => $CaptionBorderB, 8948 "Alpha" => $CaptionFillAlpha 8949 ] 8950 ); 8951 } 8952 $this->drawLine( 8953 $StartX + 2, 8954 $YPos + ($CaptionHeight / 2), 8955 $EndX - 2, 8956 $YPos + ($CaptionHeight / 2), 8957 $CaptionSettings 8958 ); 8959 } else { 8960 $this->drawFilledRectangle( 8961 $this->GraphAreaX1 - $CaptionWidth + $XMargin - $CaptionMargin, 8962 $YPos, 8963 $this->GraphAreaX1 - $CaptionMargin + $XMargin, 8964 $YPos + $CaptionHeight, 8965 [ 8966 "R" => $R, 8967 "G" => $G, 8968 "B" => $B, 8969 "BorderR" => $CaptionBorderR, 8970 "BorderG" => $CaptionBorderG, 8971 "BorderB" => $CaptionBorderB 8972 ] 8973 ); 8974 } 8975 } 8976 8977 if ($XDivs == 0) { 8978 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 8979 } else { 8980 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 8981 } 8982 $X = $this->GraphAreaX1 + $XMargin; 8983 8984 $TopY = $YPos + ($CaptionHeight / 2) - ($DerivativeHeight / 2); 8985 $BottomY = $YPos + ($CaptionHeight / 2) + ($DerivativeHeight / 2); 8986 8987 $StartX = floor($this->GraphAreaX1 + $XMargin); 8988 $EndX = floor($this->GraphAreaX2 - $XMargin); 8989 8990 if ($DrawBackground) { 8991 $this->drawFilledRectangle( 8992 $StartX - 1, 8993 $TopY - 1, 8994 $EndX + 1, 8995 $BottomY + 1, 8996 [ 8997 "R" => $BackgroundR, 8998 "G" => $BackgroundG, 8999 "B" => $BackgroundB, 9000 "Alpha" => $BackgroundAlpha 9001 ] 9002 ); 9003 } 9004 if ($DrawBorder) { 9005 $this->drawRectangle( 9006 $StartX - 1, 9007 $TopY - 1, 9008 $EndX + 1, 9009 $BottomY + 1, 9010 [ 9011 "R" => $BorderR, 9012 "G" => $BorderG, 9013 "B" => $BorderB, 9014 "Alpha" => $BorderAlpha 9015 ] 9016 ); 9017 } 9018 9019 if (!is_array($PosArray)) { 9020 $Value = $PosArray; 9021 $PosArray = []; 9022 $PosArray[0] = $Value; 9023 } 9024 9025 $RestoreShadow = $this->Shadow; 9026 $this->Shadow = false; 9027 9028 /* Determine the Max slope index */ 9029 $LastX = null; 9030 $LastY = null; 9031 $MinSlope = 0; 9032 $MaxSlope = 1; 9033 foreach ($PosArray as $Key => $Y) { 9034 if ($Y != VOID && $LastX != null) { 9035 $Slope = ($LastY - $Y); 9036 if ($Slope > $MaxSlope) { 9037 $MaxSlope = $Slope; 9038 } if ($Slope < $MinSlope) { 9039 $MinSlope = $Slope; 9040 } 9041 } 9042 9043 if ($Y == VOID) { 9044 $LastX = null; 9045 $LastY = null; 9046 } else { 9047 $LastX = $X; 9048 $LastY = $Y; 9049 } 9050 } 9051 9052 $LastX = null; 9053 $LastY = null; 9054 $LastColor = null; 9055 foreach ($PosArray as $Key => $Y) { 9056 if ($Y != VOID && $LastY != null) { 9057 $Slope = ($LastY - $Y); 9058 9059 if ($Slope >= 0) { 9060 $SlopeIndex = (100 / $MaxSlope) * $Slope; 9061 $R = (($PositiveSlopeEndR - $PositiveSlopeStartR) / 100) 9062 * $SlopeIndex + $PositiveSlopeStartR 9063 ; 9064 $G = (($PositiveSlopeEndG - $PositiveSlopeStartG) / 100) 9065 * $SlopeIndex + $PositiveSlopeStartG 9066 ; 9067 $B = (($PositiveSlopeEndB - $PositiveSlopeStartB) / 100) 9068 * $SlopeIndex + $PositiveSlopeStartB 9069 ; 9070 } elseif ($Slope < 0) { 9071 $SlopeIndex = (100 / abs($MinSlope)) * abs($Slope); 9072 $R = (($NegativeSlopeEndR - $NegativeSlopeStartR) / 100) 9073 * $SlopeIndex + $NegativeSlopeStartR 9074 ; 9075 $G = (($NegativeSlopeEndG - $NegativeSlopeStartG) / 100) 9076 * $SlopeIndex + $NegativeSlopeStartG 9077 ; 9078 $B = (($NegativeSlopeEndB - $NegativeSlopeStartB) / 100) 9079 * $SlopeIndex + $NegativeSlopeStartB 9080 ; 9081 } 9082 9083 $Color = ["R" => $R, "G" => $G, "B" => $B]; 9084 9085 if ($ShadedSlopeBox && $LastColor != null) {// && $Slope != 0 9086 $GradientSettings = [ 9087 "StartR" => $LastColor["R"], 9088 "StartG" => $LastColor["G"], 9089 "StartB" => $LastColor["B"], 9090 "EndR" => $R, 9091 "EndG" => $G, 9092 "EndB" => $B 9093 ]; 9094 $this->drawGradientArea( 9095 $LastX, 9096 $TopY, 9097 $X, 9098 $BottomY, 9099 DIRECTION_HORIZONTAL, 9100 $GradientSettings 9101 ); 9102 } elseif (!$ShadedSlopeBox || $LastColor == null) { // || $Slope == 0 9103 $this->drawFilledRectangle( 9104 floor($LastX), 9105 $TopY, 9106 floor($X), 9107 $BottomY, 9108 $Color 9109 ); 9110 } 9111 $LastColor = $Color; 9112 } 9113 9114 if ($Y == VOID) { 9115 $LastY = null; 9116 } else { 9117 $LastX = $X; 9118 $LastY = $Y; 9119 } 9120 9121 $X = $X + $XStep; 9122 } 9123 9124 $YPos = $YPos + $CaptionHeight + $SerieSpacing; 9125 } else { 9126 if ($Caption) { 9127 $StartY = floor($this->GraphAreaY1 - $CaptionWidth + $XMargin - $CaptionMargin); 9128 $EndY = floor($this->GraphAreaY1 - $CaptionMargin + $XMargin); 9129 if ($CaptionLine) { 9130 $CaptionSettings = [ 9131 "R" => $R, 9132 "G" => $G, 9133 "B" => $B, 9134 "Alpha" => $Alpha, 9135 "Ticks" => $Ticks, 9136 "Weight" => $Weight 9137 ]; 9138 if ($CaptionBox) { 9139 $this->drawFilledRectangle( 9140 $XPos, 9141 $StartY, 9142 $XPos + $CaptionHeight, 9143 $EndY, 9144 [ 9145 "R" => $CaptionFillR, 9146 "G" => $CaptionFillG, 9147 "B" => $CaptionFillB, 9148 "BorderR" => $CaptionBorderR, 9149 "BorderG" => $CaptionBorderG, 9150 "BorderB" => $CaptionBorderB, 9151 "Alpha" => $CaptionFillAlpha 9152 ] 9153 ); 9154 } 9155 $this->drawLine( 9156 $XPos + ($CaptionHeight / 2), 9157 $StartY + 2, 9158 $XPos + ($CaptionHeight / 2), 9159 $EndY - 2, 9160 $CaptionSettings 9161 ); 9162 } else { 9163 $this->drawFilledRectangle( 9164 $XPos, 9165 $StartY, 9166 $XPos + $CaptionHeight, 9167 $EndY, 9168 [ 9169 "R" => $R, 9170 "G" => $G, 9171 "B" => $B, 9172 "BorderR" => $CaptionBorderR, 9173 "BorderG" => $CaptionBorderG, 9174 "BorderB" => $CaptionBorderB 9175 ] 9176 ); 9177 } 9178 } 9179 9180 9181 if ($XDivs == 0) { 9182 $XStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 9183 } else { 9184 $XStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 9185 } 9186 $Y = $this->GraphAreaY1 + $XMargin; 9187 9188 $TopX = $XPos + ($CaptionHeight / 2) - ($DerivativeHeight / 2); 9189 $BottomX = $XPos + ($CaptionHeight / 2) + ($DerivativeHeight / 2); 9190 9191 $StartY = floor($this->GraphAreaY1 + $XMargin); 9192 $EndY = floor($this->GraphAreaY2 - $XMargin); 9193 9194 if ($DrawBackground) { 9195 $this->drawFilledRectangle( 9196 $TopX - 1, 9197 $StartY - 1, 9198 $BottomX + 1, 9199 $EndY + 1, 9200 [ 9201 "R" => $BackgroundR, 9202 "G" => $BackgroundG, 9203 "B" => $BackgroundB, 9204 "Alpha" => $BackgroundAlpha 9205 ] 9206 ); 9207 } 9208 if ($DrawBorder) { 9209 $this->drawRectangle( 9210 $TopX - 1, 9211 $StartY - 1, 9212 $BottomX + 1, 9213 $EndY + 1, 9214 [ 9215 "R" => $BorderR, 9216 "G" => $BorderG, 9217 "B" => $BorderB, 9218 "Alpha" => $BorderAlpha 9219 ] 9220 ); 9221 } 9222 9223 if (!is_array($PosArray)) { 9224 $Value = $PosArray; 9225 $PosArray = []; 9226 $PosArray[0] = $Value; 9227 } 9228 9229 $RestoreShadow = $this->Shadow; 9230 $this->Shadow = false; 9231 9232 /* Determine the Max slope index */ 9233 $LastX = null; 9234 $LastY = null; 9235 $MinSlope = 0; 9236 $MaxSlope = 1; 9237 foreach ($PosArray as $Key => $X) { 9238 if ($X != VOID && $LastX != null) { 9239 $Slope = ($X - $LastX); 9240 if ($Slope > $MaxSlope) { 9241 $MaxSlope = $Slope; 9242 } 9243 if ($Slope < $MinSlope) { 9244 $MinSlope = $Slope; 9245 } 9246 } 9247 9248 if ($X == VOID) { 9249 $LastX = null; 9250 } else { 9251 $LastX = $X; 9252 } 9253 } 9254 9255 $LastX = null; 9256 $LastY = null; 9257 $LastColor = null; 9258 foreach ($PosArray as $Key => $X) { 9259 if ($X != VOID && $LastX != null) { 9260 $Slope = ($X - $LastX); 9261 9262 if ($Slope >= 0) { 9263 $SlopeIndex = (100 / $MaxSlope) * $Slope; 9264 $R = (($PositiveSlopeEndR - $PositiveSlopeStartR) / 100) 9265 * $SlopeIndex + $PositiveSlopeStartR 9266 ; 9267 $G = (($PositiveSlopeEndG - $PositiveSlopeStartG) / 100) 9268 * $SlopeIndex + $PositiveSlopeStartG 9269 ; 9270 $B = (($PositiveSlopeEndB - $PositiveSlopeStartB) / 100) 9271 * $SlopeIndex + $PositiveSlopeStartB 9272 ; 9273 } elseif ($Slope < 0) { 9274 $SlopeIndex = (100 / abs($MinSlope)) * abs($Slope); 9275 $R = (($NegativeSlopeEndR - $NegativeSlopeStartR) / 100) 9276 * $SlopeIndex + $NegativeSlopeStartR 9277 ; 9278 $G = (($NegativeSlopeEndG - $NegativeSlopeStartG) / 100) 9279 * $SlopeIndex + $NegativeSlopeStartG 9280 ; 9281 $B = (($NegativeSlopeEndB - $NegativeSlopeStartB) / 100) 9282 * $SlopeIndex + $NegativeSlopeStartB 9283 ; 9284 } 9285 9286 $Color = ["R" => $R, "G" => $G, "B" => $B]; 9287 9288 if ($ShadedSlopeBox && $LastColor != null) { 9289 $GradientSettings = [ 9290 "StartR" => $LastColor["R"], 9291 "StartG" => $LastColor["G"], 9292 "StartB" => $LastColor["B"], 9293 "EndR" => $R, 9294 "EndG" => $G, 9295 "EndB" => $B 9296 ]; 9297 9298 $this->drawGradientArea( 9299 $TopX, 9300 $LastY, 9301 $BottomX, 9302 $Y, 9303 DIRECTION_VERTICAL, 9304 $GradientSettings 9305 ); 9306 } elseif (!$ShadedSlopeBox || $LastColor == null) { 9307 $this->drawFilledRectangle( 9308 $TopX, 9309 floor($LastY), 9310 $BottomX, 9311 floor($Y), 9312 $Color 9313 ); 9314 } 9315 $LastColor = $Color; 9316 } 9317 9318 if ($X == VOID) { 9319 $LastX = null; 9320 } else { 9321 $LastX = $X; 9322 $LastY = $Y; 9323 } 9324 9325 $Y = $Y + $XStep; 9326 } 9327 9328 $XPos = $XPos + $CaptionHeight + $SerieSpacing; 9329 } 9330 $this->Shadow = $RestoreShadow; 9331 } 9332 } 9333 } 9334 9335 /** 9336 * Draw the line of best fit 9337 * @param array $Format 9338 */ 9339 public function drawBestFit(array $Format = []) 9340 { 9341 $OverrideTicks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; 9342 $OverrideR = isset($Format["R"]) ? $Format["R"] : VOID; 9343 $OverrideG = isset($Format["G"]) ? $Format["G"] : VOID; 9344 $OverrideB = isset($Format["B"]) ? $Format["B"] : VOID; 9345 $OverrideAlpha = isset($Format["Alpha"]) ? $Format["Alpha"] : VOID; 9346 9347 $Data = $this->DataSet->getData(); 9348 list($XMargin, $XDivs) = $this->scaleGetXSettings(); 9349 9350 foreach ($Data["Series"] as $SerieName => $Serie) { 9351 if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { 9352 if ($OverrideR != VOID && $OverrideG != VOID && $OverrideB != VOID) { 9353 $R = $OverrideR; 9354 $G = $OverrideG; 9355 $B = $OverrideB; 9356 } else { 9357 $R = $Serie["Color"]["R"]; 9358 $G = $Serie["Color"]["G"]; 9359 $B = $Serie["Color"]["B"]; 9360 } 9361 if ($OverrideTicks == null) { 9362 $Ticks = $Serie["Ticks"]; 9363 } else { 9364 $Ticks = $OverrideTicks; 9365 } 9366 if ($OverrideAlpha == VOID) { 9367 $Alpha = $Serie["Color"]["Alpha"]; 9368 } else { 9369 $Alpha = $OverrideAlpha; 9370 } 9371 9372 $Color = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks]; 9373 9374 $PosArray = $this->scaleComputeY( 9375 $Serie["Data"], 9376 ["AxisID" => $Serie["Axis"]] 9377 ); 9378 9379 if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { 9380 if ($XDivs == 0) { 9381 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4; 9382 } else { 9383 $XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs; 9384 } 9385 $X = $this->GraphAreaX1 + $XMargin; 9386 9387 if (!is_array($PosArray)) { 9388 $Value = $PosArray; 9389 $PosArray = []; 9390 $PosArray[0] = $Value; 9391 } 9392 $Sxy = 0; 9393 $Sx = 0; 9394 $Sy = 0; 9395 $Sxx = 0; 9396 foreach ($PosArray as $Key => $Y) { 9397 if ($Y != VOID) { 9398 $Sxy = $Sxy + $X * $Y; 9399 $Sx = $Sx + $X; 9400 $Sy = $Sy + $Y; 9401 $Sxx = $Sxx + $X * $X; 9402 } 9403 9404 $X = $X + $XStep; 9405 } 9406 $n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray); 9407 $M = (($n * $Sxy) - ($Sx * $Sy)) / (($n * $Sxx) - ($Sx * $Sx)); 9408 $B = (($Sy) - ($M * $Sx)) / ($n); 9409 9410 $X1 = $this->GraphAreaX1 + $XMargin; 9411 $Y1 = $M * $X1 + $B; 9412 $X2 = $this->GraphAreaX2 - $XMargin; 9413 $Y2 = $M * $X2 + $B; 9414 9415 if ($Y1 < $this->GraphAreaY1) { 9416 $X1 = $X1 + ($this->GraphAreaY1 - $Y1); 9417 $Y1 = $this->GraphAreaY1; 9418 } 9419 if ($Y1 > $this->GraphAreaY2) { 9420 $X1 = $X1 + ($Y1 - $this->GraphAreaY2); 9421 $Y1 = $this->GraphAreaY2; 9422 } 9423 if ($Y2 < $this->GraphAreaY1) { 9424 $X2 = $X2 - ($this->GraphAreaY1 - $Y2); 9425 $Y2 = $this->GraphAreaY1; 9426 } 9427 if ($Y2 > $this->GraphAreaY2) { 9428 $X2 = $X2 - ($Y2 - $this->GraphAreaY2); 9429 $Y2 = $this->GraphAreaY2; 9430 } 9431 9432 $this->drawLine($X1, $Y1, $X2, $Y2, $Color); 9433 } else { 9434 if ($XDivs == 0) { 9435 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4; 9436 } else { 9437 $YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs; 9438 } 9439 $Y = $this->GraphAreaY1 + $XMargin; 9440 9441 if (!is_array($PosArray)) { 9442 $Value = $PosArray; 9443 $PosArray = []; 9444 $PosArray[0] = $Value; 9445 } 9446 $Sxy = 0; 9447 $Sx = 0; 9448 $Sy = 0; 9449 $Sxx = 0; 9450 foreach ($PosArray as $Key => $X) { 9451 if ($X != VOID) { 9452 $Sxy = $Sxy + $X * $Y; 9453 $Sx = $Sx + $Y; 9454 $Sy = $Sy + $X; 9455 $Sxx = $Sxx + $Y * $Y; 9456 } 9457 9458 $Y = $Y + $YStep; 9459 } 9460 $n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray); 9461 $M = (($n * $Sxy) - ($Sx * $Sy)) / (($n * $Sxx) - ($Sx * $Sx)); 9462 $B = (($Sy) - ($M * $Sx)) / ($n); 9463 9464 $Y1 = $this->GraphAreaY1 + $XMargin; 9465 $X1 = $M * $Y1 + $B; 9466 $Y2 = $this->GraphAreaY2 - $XMargin; 9467 $X2 = $M * $Y2 + $B; 9468 9469 if ($X1 < $this->GraphAreaX1) { 9470 $Y1 = $Y1 + ($this->GraphAreaX1 - $X1); 9471 $X1 = $this->GraphAreaX1; 9472 } 9473 if ($X1 > $this->GraphAreaX2) { 9474 $Y1 = $Y1 + ($X1 - $this->GraphAreaX2); 9475 $X1 = $this->GraphAreaX2; 9476 } 9477 if ($X2 < $this->GraphAreaX1) { 9478 $Y2 = $Y2 - ($this->GraphAreaY1 - $X2); 9479 $X2 = $this->GraphAreaX1; 9480 } 9481 if ($X2 > $this->GraphAreaX2) { 9482 $Y2 = $Y2 - ($X2 - $this->GraphAreaX2); 9483 $X2 = $this->GraphAreaX2; 9484 } 9485 9486 $this->drawLine($X1, $Y1, $X2, $Y2, $Color); 9487 } 9488 } 9489 } 9490 } 9491 9492 /** 9493 * Draw a label box 9494 * @param int $X 9495 * @param int $Y 9496 * @param string $Title 9497 * @param array $Captions 9498 * @param array $Format 9499 */ 9500 public function drawLabelBox($X, $Y, $Title, array $Captions, array $Format = []) 9501 { 9502 $NoTitle = isset($Format["NoTitle"]) ? $Format["NoTitle"] : null; 9503 $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 50; 9504 $DrawSerieColor = isset($Format["DrawSerieColor"]) ? $Format["DrawSerieColor"] : true; 9505 $SerieBoxSize = isset($Format["SerieBoxSize"]) ? $Format["SerieBoxSize"] : 6; 9506 $SerieBoxSpacing = isset($Format["SerieBoxSpacing"]) ? $Format["SerieBoxSpacing"] : 4; 9507 $VerticalMargin = isset($Format["VerticalMargin"]) ? $Format["VerticalMargin"] : 10; 9508 $HorizontalMargin = isset($Format["HorizontalMargin"]) ? $Format["HorizontalMargin"] : 8; 9509 $R = isset($Format["R"]) ? $Format["R"] : $this->FontColorR; 9510 $G = isset($Format["G"]) ? $Format["G"] : $this->FontColorG; 9511 $B = isset($Format["B"]) ? $Format["B"] : $this->FontColorB; 9512 $FontName = isset($Format["FontName"]) ? $this->loadFont($Format["FontName"], 'fonts') : $this->FontName; 9513 $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; 9514 $TitleMode = isset($Format["TitleMode"]) ? $Format["TitleMode"] : LABEL_TITLE_NOBACKGROUND; 9515 $TitleR = isset($Format["TitleR"]) ? $Format["TitleR"] : $R; 9516 $TitleG = isset($Format["TitleG"]) ? $Format["TitleG"] : $G; 9517 $TitleB = isset($Format["TitleB"]) ? $Format["TitleB"] : $B; 9518 $TitleBackgroundR = isset($Format["TitleBackgroundR"]) ? $Format["TitleBackgroundR"] : 0; 9519 $TitleBackgroundG = isset($Format["TitleBackgroundG"]) ? $Format["TitleBackgroundG"] : 0; 9520 $TitleBackgroundB = isset($Format["TitleBackgroundB"]) ? $Format["TitleBackgroundB"] : 0; 9521 $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; 9522 $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; 9523 $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; 9524 $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 220; 9525 $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 220; 9526 $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 220; 9527 $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 100; 9528 9529 if (!$DrawSerieColor) { 9530 $SerieBoxSize = 0; 9531 $SerieBoxSpacing = 0; 9532 } 9533 9534 $TxtPos = $this->getTextBox($X, $Y, $FontName, $FontSize, 0, $Title); 9535 $TitleWidth = ($TxtPos[1]["X"] - $TxtPos[0]["X"]) + $VerticalMargin * 2; 9536 $TitleHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]); 9537 9538 if ($NoTitle) { 9539 $TitleWidth = 0; 9540 $TitleHeight = 0; 9541 } 9542 9543 $CaptionWidth = 0; 9544 $CaptionHeight = -$HorizontalMargin; 9545 foreach ($Captions as $Key => $Caption) { 9546 $TxtPos = $this->getTextBox( 9547 $X, 9548 $Y, 9549 $FontName, 9550 $FontSize, 9551 0, 9552 $Caption["Caption"] 9553 ); 9554 $CaptionWidth = max( 9555 $CaptionWidth, 9556 ($TxtPos[1]["X"] - $TxtPos[0]["X"]) + $VerticalMargin * 2 9557 ); 9558 $CaptionHeight = $CaptionHeight 9559 + max(($TxtPos[0]["Y"] - $TxtPos[2]["Y"]), ($SerieBoxSize + 2)) 9560 + $HorizontalMargin 9561 ; 9562 } 9563 9564 if ($CaptionHeight <= 5) { 9565 $CaptionHeight = $CaptionHeight + $HorizontalMargin / 2; 9566 } 9567 9568 if ($DrawSerieColor) { 9569 $CaptionWidth = $CaptionWidth + $SerieBoxSize + $SerieBoxSpacing; 9570 } 9571 9572 $BoxWidth = max($BoxWidth, $TitleWidth, $CaptionWidth); 9573 9574 $XMin = $X - 5 - floor(($BoxWidth - 10) / 2); 9575 $XMax = $X + 5 + floor(($BoxWidth - 10) / 2); 9576 9577 $RestoreShadow = $this->Shadow; 9578 if ($this->Shadow == true) { 9579 $this->Shadow = false; 9580 9581 $Poly = []; 9582 $Poly[] = $X + $this->ShadowX; 9583 $Poly[] = $Y + $this->ShadowX; 9584 $Poly[] = $X + 5 + $this->ShadowX; 9585 $Poly[] = $Y - 5 + $this->ShadowX; 9586 $Poly[] = $XMax + $this->ShadowX; 9587 $Poly[] = $Y - 5 + $this->ShadowX; 9588 9589 if ($NoTitle) { 9590 $Poly[] = $XMax + $this->ShadowX; 9591 $Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2 + $this->ShadowX; 9592 $Poly[] = $XMin + $this->ShadowX; 9593 $Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2 + $this->ShadowX; 9594 } else { 9595 $Poly[] = $XMax + $this->ShadowX; 9596 $Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3 + $this->ShadowX; 9597 $Poly[] = $XMin + $this->ShadowX; 9598 $Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3 + $this->ShadowX; 9599 } 9600 9601 $Poly[] = $XMin + $this->ShadowX; 9602 $Poly[] = $Y - 5 + $this->ShadowX; 9603 $Poly[] = $X - 5 + $this->ShadowX; 9604 $Poly[] = $Y - 5 + $this->ShadowX; 9605 $this->drawPolygon( 9606 $Poly, 9607 [ 9608 "R" => $this->ShadowR, 9609 "G" => $this->ShadowG, 9610 "B" => $this->ShadowB, 9611 "Alpha" => $this->Shadowa 9612 ] 9613 ); 9614 } 9615 9616 /* Draw the background */ 9617 $GradientSettings = [ 9618 "StartR" => $GradientStartR, 9619 "StartG" => $GradientStartG, 9620 "StartB" => $GradientStartB, 9621 "EndR" => $GradientEndR, 9622 "EndG" => $GradientEndG, 9623 "EndB" => $GradientEndB, 9624 "Alpha" => $BoxAlpha 9625 ]; 9626 if ($NoTitle) { 9627 $this->drawGradientArea( 9628 $XMin, 9629 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9630 $XMax, 9631 $Y - 6, 9632 DIRECTION_VERTICAL, 9633 $GradientSettings 9634 ); 9635 } else { 9636 $this->drawGradientArea( 9637 $XMin, 9638 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9639 $XMax, 9640 $Y - 6, 9641 DIRECTION_VERTICAL, 9642 $GradientSettings 9643 ); 9644 } 9645 $Poly = []; 9646 $Poly[] = $X; 9647 $Poly[] = $Y; 9648 $Poly[] = $X - 5; 9649 $Poly[] = $Y - 5; 9650 $Poly[] = $X + 5; 9651 $Poly[] = $Y - 5; 9652 $this->drawPolygon( 9653 $Poly, 9654 [ 9655 "R" => $GradientEndR, 9656 "G" => $GradientEndG, 9657 "B" => $GradientEndB, 9658 "Alpha" => $BoxAlpha, 9659 "NoBorder" => true 9660 ] 9661 ); 9662 9663 /* Outer border */ 9664 $OuterBorderColor = $this->allocateColor($this->Picture, 100, 100, 100, $BoxAlpha); 9665 imageline($this->Picture, $XMin, $Y - 5, $X - 5, $Y - 5, $OuterBorderColor); 9666 imageline($this->Picture, $X, $Y, $X - 5, $Y - 5, $OuterBorderColor); 9667 imageline($this->Picture, $X, $Y, $X + 5, $Y - 5, $OuterBorderColor); 9668 imageline($this->Picture, $X + 5, $Y - 5, $XMax, $Y - 5, $OuterBorderColor); 9669 if ($NoTitle) { 9670 imageline( 9671 $this->Picture, 9672 $XMin, 9673 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9674 $XMin, 9675 $Y - 5, 9676 $OuterBorderColor 9677 ); 9678 imageline( 9679 $this->Picture, 9680 $XMax, 9681 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9682 $XMax, 9683 $Y - 5, 9684 $OuterBorderColor 9685 ); 9686 imageline( 9687 $this->Picture, 9688 $XMin, 9689 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9690 $XMax, 9691 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9692 $OuterBorderColor 9693 ); 9694 } else { 9695 imageline( 9696 $this->Picture, 9697 $XMin, 9698 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9699 $XMin, 9700 $Y - 5, 9701 $OuterBorderColor 9702 ); 9703 imageline( 9704 $this->Picture, 9705 $XMax, 9706 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9707 $XMax, 9708 $Y - 5, 9709 $OuterBorderColor 9710 ); 9711 imageline( 9712 $this->Picture, 9713 $XMin, 9714 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9715 $XMax, 9716 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9717 $OuterBorderColor 9718 ); 9719 } 9720 9721 /* Inner border */ 9722 $InnerBorderColor = $this->allocateColor($this->Picture, 255, 255, 255, $BoxAlpha); 9723 imageline($this->Picture, $XMin + 1, $Y - 6, $X - 5, $Y - 6, $InnerBorderColor); 9724 imageline($this->Picture, $X, $Y - 1, $X - 5, $Y - 6, $InnerBorderColor); 9725 imageline($this->Picture, $X, $Y - 1, $X + 5, $Y - 6, $InnerBorderColor); 9726 imageline($this->Picture, $X + 5, $Y - 6, $XMax - 1, $Y - 6, $InnerBorderColor); 9727 if ($NoTitle) { 9728 imageline( 9729 $this->Picture, 9730 $XMin + 1, 9731 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9732 $XMin + 1, 9733 $Y - 6, 9734 $InnerBorderColor 9735 ); 9736 imageline( 9737 $this->Picture, 9738 $XMax - 1, 9739 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9740 $XMax - 1, 9741 $Y - 6, 9742 $InnerBorderColor 9743 ); 9744 imageline( 9745 $this->Picture, 9746 $XMin + 1, 9747 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9748 $XMax - 1, 9749 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, 9750 $InnerBorderColor 9751 ); 9752 } else { 9753 imageline( 9754 $this->Picture, 9755 $XMin + 1, 9756 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9757 $XMin + 1, 9758 $Y - 6, 9759 $InnerBorderColor 9760 ); 9761 imageline( 9762 $this->Picture, 9763 $XMax - 1, 9764 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9765 $XMax - 1, 9766 $Y - 6, 9767 $InnerBorderColor 9768 ); 9769 imageline( 9770 $this->Picture, 9771 $XMin + 1, 9772 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9773 $XMax - 1, 9774 $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9775 $InnerBorderColor 9776 ); 9777 } 9778 9779 /* Draw the separator line */ 9780 if ($TitleMode == LABEL_TITLE_NOBACKGROUND && !$NoTitle) { 9781 $YPos = $Y - 7 - $CaptionHeight - $HorizontalMargin - $HorizontalMargin / 2; 9782 $XMargin = $VerticalMargin / 2; 9783 $this->drawLine( 9784 $XMin + $XMargin, 9785 $YPos + 1, 9786 $XMax - $XMargin, 9787 $YPos + 1, 9788 [ 9789 "R" => $GradientEndR, 9790 "G" => $GradientEndG, 9791 "B" => $GradientEndB, 9792 "Alpha" => $BoxAlpha 9793 ] 9794 ); 9795 $this->drawLine( 9796 $XMin + $XMargin, 9797 $YPos, 9798 $XMax - $XMargin, 9799 $YPos, 9800 [ 9801 "R" => $GradientStartR, 9802 "G" => $GradientStartG, 9803 "B" => $GradientStartB, 9804 "Alpha" => $BoxAlpha 9805 ] 9806 ); 9807 } elseif ($TitleMode == LABEL_TITLE_BACKGROUND) { 9808 $this->drawFilledRectangle( 9809 $XMin, 9810 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, 9811 $XMax, 9812 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin + $HorizontalMargin / 2, 9813 [ 9814 "R" => $TitleBackgroundR, 9815 "G" => $TitleBackgroundG, 9816 "B" => $TitleBackgroundB, 9817 "Alpha" => $BoxAlpha 9818 ] 9819 ); 9820 imageline( 9821 $this->Picture, 9822 $XMin + 1, 9823 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin + $HorizontalMargin / 2 + 1, 9824 $XMax - 1, 9825 $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin + $HorizontalMargin / 2 + 1, 9826 $InnerBorderColor 9827 ); 9828 } 9829 9830 /* Write the description */ 9831 if (!$NoTitle) { 9832 $this->drawText( 9833 $XMin + $VerticalMargin, 9834 $Y - 7 - $CaptionHeight - $HorizontalMargin * 2, 9835 $Title, 9836 [ 9837 "Align" => TEXT_ALIGN_BOTTOMLEFT, 9838 "R" => $TitleR, 9839 "G" => $TitleG, 9840 "B" => $TitleB 9841 ] 9842 ); 9843 } 9844 9845 /* Write the value */ 9846 $YPos = $Y - 5 - $HorizontalMargin; 9847 $XPos = $XMin + $VerticalMargin + $SerieBoxSize + $SerieBoxSpacing; 9848 foreach ($Captions as $Key => $Caption) { 9849 $CaptionTxt = $Caption["Caption"]; 9850 $TxtPos = $this->getTextBox($XPos, $YPos, $FontName, $FontSize, 0, $CaptionTxt); 9851 $CaptionHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]); 9852 9853 /* Write the serie color if needed */ 9854 if ($DrawSerieColor) { 9855 $BoxSettings = [ 9856 "R" => $Caption["Format"]["R"], 9857 "G" => $Caption["Format"]["G"], 9858 "B" => $Caption["Format"]["B"], 9859 "Alpha" => $Caption["Format"]["Alpha"], 9860 "BorderR" => 0, 9861 "BorderG" => 0, 9862 "BorderB" => 0 9863 ]; 9864 $this->drawFilledRectangle( 9865 $XMin + $VerticalMargin, 9866 $YPos - $SerieBoxSize, 9867 $XMin + $VerticalMargin + $SerieBoxSize, 9868 $YPos, 9869 $BoxSettings 9870 ); 9871 } 9872 9873 $this->drawText($XPos, $YPos, $CaptionTxt, ["Align" => TEXT_ALIGN_BOTTOMLEFT]); 9874 9875 $YPos = $YPos - $CaptionHeight - $HorizontalMargin; 9876 } 9877 9878 $this->Shadow = $RestoreShadow; 9879 } 9880 9881 /** 9882 * Draw a basic shape 9883 * @param int $X 9884 * @param int $Y 9885 * @param int $Shape 9886 * @param int $PlotSize 9887 * @param int $PlotBorder 9888 * @param int $BorderSize 9889 * @param int $R 9890 * @param int $G 9891 * @param int $B 9892 * @param int|float $Alpha 9893 * @param int $BorderR 9894 * @param int $BorderG 9895 * @param int $BorderB 9896 * @param int|float $BorderAlpha 9897 */ 9898 public function drawShape( 9899 $X, 9900 $Y, 9901 $Shape, 9902 $PlotSize, 9903 $PlotBorder, 9904 $BorderSize, 9905 $R, 9906 $G, 9907 $B, 9908 $Alpha, 9909 $BorderR, 9910 $BorderG, 9911 $BorderB, 9912 $BorderAlpha 9913 ) { 9914 if ($Shape == SERIE_SHAPE_FILLEDCIRCLE) { 9915 if ($PlotBorder) { 9916 $this->drawFilledCircle( 9917 $X, 9918 $Y, 9919 $PlotSize + $BorderSize, 9920 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $BorderAlpha] 9921 ); 9922 } 9923 $this->drawFilledCircle( 9924 $X, 9925 $Y, 9926 $PlotSize, 9927 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 9928 ); 9929 } elseif ($Shape == SERIE_SHAPE_FILLEDSQUARE) { 9930 if ($PlotBorder) { 9931 $this->drawFilledRectangle( 9932 $X - $PlotSize - $BorderSize, 9933 $Y - $PlotSize - $BorderSize, 9934 $X + $PlotSize + $BorderSize, 9935 $Y + $PlotSize + $BorderSize, 9936 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $BorderAlpha] 9937 ); 9938 } 9939 $this->drawFilledRectangle( 9940 $X - $PlotSize, 9941 $Y - $PlotSize, 9942 $X + $PlotSize, 9943 $Y + $PlotSize, 9944 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 9945 ); 9946 } elseif ($Shape == SERIE_SHAPE_FILLEDTRIANGLE) { 9947 if ($PlotBorder) { 9948 $Pos = []; 9949 $Pos[] = $X; 9950 $Pos[] = $Y - $PlotSize - $BorderSize; 9951 $Pos[] = $X - $PlotSize - $BorderSize; 9952 $Pos[] = $Y + $PlotSize + $BorderSize; 9953 $Pos[] = $X + $PlotSize + $BorderSize; 9954 $Pos[] = $Y + $PlotSize + $BorderSize; 9955 $this->drawPolygon( 9956 $Pos, 9957 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $BorderAlpha] 9958 ); 9959 } 9960 9961 $Pos = []; 9962 $Pos[] = $X; 9963 $Pos[] = $Y - $PlotSize; 9964 $Pos[] = $X - $PlotSize; 9965 $Pos[] = $Y + $PlotSize; 9966 $Pos[] = $X + $PlotSize; 9967 $Pos[] = $Y + $PlotSize; 9968 $this->drawPolygon($Pos, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 9969 } elseif ($Shape == SERIE_SHAPE_TRIANGLE) { 9970 $this->drawLine( 9971 $X, 9972 $Y - $PlotSize, 9973 $X - $PlotSize, 9974 $Y + $PlotSize, 9975 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 9976 ); 9977 $this->drawLine( 9978 $X - $PlotSize, 9979 $Y + $PlotSize, 9980 $X + $PlotSize, 9981 $Y + $PlotSize, 9982 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 9983 ); 9984 $this->drawLine( 9985 $X + $PlotSize, 9986 $Y + $PlotSize, 9987 $X, 9988 $Y - $PlotSize, 9989 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 9990 ); 9991 } elseif ($Shape == SERIE_SHAPE_SQUARE) { 9992 $this->drawRectangle( 9993 $X - $PlotSize, 9994 $Y - $PlotSize, 9995 $X + $PlotSize, 9996 $Y + $PlotSize, 9997 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 9998 ); 9999 } elseif ($Shape == SERIE_SHAPE_CIRCLE) { 10000 $this->drawCircle( 10001 $X, 10002 $Y, 10003 $PlotSize, 10004 $PlotSize, 10005 ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha] 10006 ); 10007 } elseif ($Shape == SERIE_SHAPE_DIAMOND) { 10008 $Pos = []; 10009 $Pos[] = $X - $PlotSize; 10010 $Pos[] = $Y; 10011 $Pos[] = $X; 10012 $Pos[] = $Y - $PlotSize; 10013 $Pos[] = $X + $PlotSize; 10014 $Pos[] = $Y; 10015 $Pos[] = $X; 10016 $Pos[] = $Y + $PlotSize; 10017 $this->drawPolygon( 10018 $Pos, 10019 [ 10020 "NoFill" => true, 10021 "BorderR" => $R, 10022 "BorderG" => $G, 10023 "BorderB" => $B, 10024 "BorderAlpha" => $Alpha 10025 ] 10026 ); 10027 } elseif ($Shape == SERIE_SHAPE_FILLEDDIAMOND) { 10028 if ($PlotBorder) { 10029 $Pos = []; 10030 $Pos[] = $X - $PlotSize - $BorderSize; 10031 $Pos[] = $Y; 10032 $Pos[] = $X; 10033 $Pos[] = $Y - $PlotSize - $BorderSize; 10034 $Pos[] = $X + $PlotSize + $BorderSize; 10035 $Pos[] = $Y; 10036 $Pos[] = $X; 10037 $Pos[] = $Y + $PlotSize + $BorderSize; 10038 $this->drawPolygon( 10039 $Pos, 10040 ["R" => $BorderR, "G" => $BorderG, "B" => $BorderB, "Alpha" => $BorderAlpha] 10041 ); 10042 } 10043 10044 $Pos = []; 10045 $Pos[] = $X - $PlotSize; 10046 $Pos[] = $Y; 10047 $Pos[] = $X; 10048 $Pos[] = $Y - $PlotSize; 10049 $Pos[] = $X + $PlotSize; 10050 $Pos[] = $Y; 10051 $Pos[] = $X; 10052 $Pos[] = $Y + $PlotSize; 10053 $this->drawPolygon($Pos, ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha]); 10054 } 10055 } 10056 10057 /** 10058 * 10059 * @param array $Points 10060 * @param array $Format 10061 * @return null|integer 10062 */ 10063 public function drawPolygonChart(array $Points, array $Format = []) 10064 { 10065 $R = isset($Format["R"]) ? $Format["R"] : 0; 10066 $G = isset($Format["G"]) ? $Format["G"] : 0; 10067 $B = isset($Format["B"]) ? $Format["B"] : 0; 10068 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 10069 $NoFill = isset($Format["NoFill"]) ? $Format["NoFill"] : false; 10070 $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : false; 10071 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; 10072 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; 10073 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; 10074 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha / 2; 10075 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; 10076 $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; 10077 10078 if ($Surrounding != null) { 10079 $BorderR = $R + $Surrounding; 10080 $BorderG = $G + $Surrounding; 10081 $BorderB = $B + $Surrounding; 10082 } 10083 10084 $RestoreShadow = $this->Shadow; 10085 $this->Shadow = false; 10086 10087 $AllIntegers = true; 10088 for ($i = 0; $i <= count($Points) - 2; $i = $i + 2) { 10089 if ($this->getFirstDecimal($Points[$i + 1]) != 0) { 10090 $AllIntegers = false; 10091 } 10092 } 10093 10094 /* Convert polygon to segments */ 10095 $Segments = []; 10096 for ($i = 2; $i <= count($Points) - 2; $i = $i + 2) { 10097 $Segments[] = [ 10098 "X1" => $Points[$i - 2], 10099 "Y1" => $Points[$i - 1], 10100 "X2" => $Points[$i], 10101 "Y2" => $Points[$i + 1] 10102 ]; 10103 } 10104 $Segments[] = [ 10105 "X1" => $Points[$i - 2], 10106 "Y1" => $Points[$i - 1], 10107 "X2" => $Points[0], 10108 "Y2" => $Points[1] 10109 ]; 10110 10111 /* Simplify straight lines */ 10112 $Result = []; 10113 $inHorizon = false; 10114 $LastX = VOID; 10115 foreach ($Segments as $Key => $Pos) { 10116 if ($Pos["Y1"] != $Pos["Y2"]) { 10117 if ($inHorizon) { 10118 $inHorizon = false; 10119 $Result[] = [ 10120 "X1" => $LastX, 10121 "Y1" => $Pos["Y1"], 10122 "X2" => $Pos["X1"], 10123 "Y2" => $Pos["Y1"] 10124 ]; 10125 } 10126 10127 $Result[] = [ 10128 "X1" => $Pos["X1"], 10129 "Y1" => $Pos["Y1"], 10130 "X2" => $Pos["X2"], 10131 "Y2" => $Pos["Y2"] 10132 ]; 10133 } else { 10134 if (!$inHorizon) { 10135 $inHorizon = true; 10136 $LastX = $Pos["X1"]; 10137 } 10138 } 10139 } 10140 $Segments = $Result; 10141 10142 /* Do we have something to draw */ 10143 if (!count($Segments)) { 10144 return 0; 10145 } 10146 10147 /* For segments debugging purpose */ 10148 //foreach($Segments as $Key => $Pos) 10149 // echo $Pos["X1"].",".$Pos["Y1"].",".$Pos["X2"].",".$Pos["Y2"]."\r\n"; 10150 10151 /* Find out the min & max Y boundaries */ 10152 $MinY = OUT_OF_SIGHT; 10153 $MaxY = OUT_OF_SIGHT; 10154 foreach ($Segments as $Key => $Coords) { 10155 if ($MinY == OUT_OF_SIGHT || $MinY > min($Coords["Y1"], $Coords["Y2"])) { 10156 $MinY = min($Coords["Y1"], $Coords["Y2"]); 10157 } 10158 if ($MaxY == OUT_OF_SIGHT || $MaxY < max($Coords["Y1"], $Coords["Y2"])) { 10159 $MaxY = max($Coords["Y1"], $Coords["Y2"]); 10160 } 10161 } 10162 10163 if ($AllIntegers) { 10164 $YStep = 1; 10165 } else { 10166 $YStep = .5; 10167 } 10168 10169 $MinY = floor($MinY); 10170 $MaxY = floor($MaxY); 10171 10172 /* Scan each Y lines */ 10173 $DefaultColor = $this->allocateColor($this->Picture, $R, $G, $B, $Alpha); 10174 $DebugLine = 0; 10175 $DebugColor = $this->allocateColor($this->Picture, 255, 0, 0, 100); 10176 10177 $MinY = floor($MinY); 10178 $MaxY = floor($MaxY); 10179 $YStep = 1; 10180 10181 if (!$NoFill) { 10182 //if ($DebugLine ) { $MinY = $DebugLine; $MaxY = $DebugLine; } 10183 for ($Y = $MinY; $Y <= $MaxY; $Y = $Y + $YStep) { 10184 $Intersections = []; 10185 $LastSlope = null; 10186 $RestoreLast = "-"; 10187 foreach ($Segments as $Key => $Coords) { 10188 $X1 = $Coords["X1"]; 10189 $X2 = $Coords["X2"]; 10190 $Y1 = $Coords["Y1"]; 10191 $Y2 = $Coords["Y2"]; 10192 10193 if (min($Y1, $Y2) <= $Y && max($Y1, $Y2) >= $Y) { 10194 if ($Y1 == $Y2) { 10195 $X = $X1; 10196 } else { 10197 $X = $X1 + (($Y - $Y1) * $X2 - ($Y - $Y1) * $X1) / ($Y2 - $Y1); 10198 } 10199 10200 $X = floor($X); 10201 10202 if ($X2 == $X1) { 10203 $Slope = "!"; 10204 } else { 10205 $SlopeC = ($Y2 - $Y1) / ($X2 - $X1); 10206 if ($SlopeC == 0) { 10207 $Slope = "="; 10208 } elseif ($SlopeC > 0) { 10209 $Slope = "+"; 10210 } elseif ($SlopeC < 0) { 10211 $Slope = "-"; 10212 } 10213 } 10214 10215 if (!is_array($Intersections)) { 10216 $Intersections[] = $X; 10217 } elseif (!in_array($X, $Intersections)) { 10218 $Intersections[] = $X; 10219 } elseif (in_array($X, $Intersections)) { 10220 if ($Y == $DebugLine) { 10221 echo $Slope . "/" . $LastSlope . "(" . $X . ") "; 10222 } 10223 10224 if ($Slope == "=" && $LastSlope == "-") { 10225 $Intersections[] = $X; 10226 } 10227 if ($Slope != $LastSlope && $LastSlope != "!" && $LastSlope != "=") { 10228 $Intersections[] = $X; 10229 } 10230 if ($Slope != $LastSlope && $LastSlope == "!" && $Slope == "+") { 10231 $Intersections[] = $X; 10232 } 10233 } 10234 10235 if (is_array($Intersections) 10236 && in_array($X, $Intersections) 10237 && $LastSlope == "=" 10238 && ($Slope == "-") 10239 ) { 10240 $Intersections[] = $X; 10241 } 10242 10243 $LastSlope = $Slope; 10244 } 10245 } 10246 if ($RestoreLast != "-") { 10247 $Intersections[] = $RestoreLast; 10248 echo "@" . $Y . "\r\n"; 10249 } 10250 10251 if (is_array($Intersections)) { 10252 sort($Intersections); 10253 10254 if ($Y == $DebugLine) { 10255 print_r($Intersections); 10256 } 10257 10258 /* Remove null plots */ 10259 $Result = []; 10260 for ($i = 0; $i <= count($Intersections) - 1; $i = $i + 2) { 10261 if (isset($Intersections[$i + 1])) { 10262 if ($Intersections[$i] != $Intersections[$i + 1]) { 10263 $Result[] = $Intersections[$i]; 10264 $Result[] = $Intersections[$i + 1]; 10265 } 10266 } 10267 } 10268 10269 if (is_array($Result)) { 10270 $Intersections = $Result; 10271 10272 $LastX = OUT_OF_SIGHT; 10273 foreach ($Intersections as $Key => $X) { 10274 if ($LastX == OUT_OF_SIGHT) { 10275 $LastX = $X; 10276 } elseif ($LastX != OUT_OF_SIGHT) { 10277 if ($this->getFirstDecimal($LastX) > 1) { 10278 $LastX++; 10279 } 10280 10281 $Color = $DefaultColor; 10282 if ($Threshold != null) { 10283 foreach ($Threshold as $Key => $Parameters) { 10284 if ($Y <= $Parameters["MinX"] 10285 && $Y >= $Parameters["MaxX"] 10286 ) { 10287 if (isset($Parameters["R"])) { 10288 $R = $Parameters["R"]; 10289 } else { 10290 $R = 0; 10291 } 10292 if (isset($Parameters["G"])) { 10293 $G = $Parameters["G"]; 10294 } else { 10295 $G = 0; 10296 } 10297 if (isset($Parameters["B"])) { 10298 $B = $Parameters["B"]; 10299 } else { 10300 $B = 0; 10301 } 10302 if (isset($Parameters["Alpha"])) { 10303 $Alpha = $Parameters["Alpha"]; 10304 } else { 10305 $Alpha = 100; 10306 } 10307 $Color = $this->allocateColor( 10308 $this->Picture, 10309 $R, 10310 $G, 10311 $B, 10312 $Alpha 10313 ); 10314 } 10315 } 10316 } 10317 10318 imageline($this->Picture, $LastX, $Y, $X, $Y, $Color); 10319 10320 if ($Y == $DebugLine) { 10321 imageline($this->Picture, $LastX, $Y, $X, $Y, $DebugColor); 10322 } 10323 10324 $LastX = OUT_OF_SIGHT; 10325 } 10326 } 10327 } 10328 } 10329 } 10330 } 10331 10332 /* Draw the polygon border, if required */ 10333 if (!$NoBorder) { 10334 foreach ($Segments as $Key => $Coords) { 10335 $this->drawLine( 10336 $Coords["X1"], 10337 $Coords["Y1"], 10338 $Coords["X2"], 10339 $Coords["Y2"], 10340 [ 10341 "R" => $BorderR, 10342 "G" => $BorderG, 10343 "B" => $BorderB, 10344 "Alpha" => $BorderAlpha, 10345 "Threshold" => $Threshold 10346 ] 10347 ); 10348 } 10349 } 10350 10351 $this->Shadow = $RestoreShadow; 10352 } 10353} 10354