AutorÃa | Ultima modificación | Ver Log |
<?php/*pDraw - class extension with drawing methodsVersion : 2.1.4Made by : Jean-Damien POGOLOTTILast Update : 19/01/2014This file can be distributed under the license you can find at :http://www.pchart.net/licenseYou can find the whole class documentation on the pChart web site.*/define("DIRECTION_VERTICAL", 690001);define("DIRECTION_HORIZONTAL", 690002);define("SCALE_POS_LEFTRIGHT", 690101);define("SCALE_POS_TOPBOTTOM", 690102);define("SCALE_MODE_FLOATING", 690201);define("SCALE_MODE_START0", 690202);define("SCALE_MODE_ADDALL", 690203);define("SCALE_MODE_ADDALL_START0", 690204);define("SCALE_MODE_MANUAL", 690205);define("SCALE_SKIP_NONE", 690301);define("SCALE_SKIP_SAME", 690302);define("SCALE_SKIP_NUMBERS", 690303);define("TEXT_ALIGN_TOPLEFT", 690401);define("TEXT_ALIGN_TOPMIDDLE", 690402);define("TEXT_ALIGN_TOPRIGHT", 690403);define("TEXT_ALIGN_MIDDLELEFT", 690404);define("TEXT_ALIGN_MIDDLEMIDDLE", 690405);define("TEXT_ALIGN_MIDDLERIGHT", 690406);define("TEXT_ALIGN_BOTTOMLEFT", 690407);define("TEXT_ALIGN_BOTTOMMIDDLE", 690408);define("TEXT_ALIGN_BOTTOMRIGHT", 690409);define("POSITION_TOP", 690501);define("POSITION_BOTTOM", 690502);define("LABEL_POS_LEFT", 690601);define("LABEL_POS_CENTER", 690602);define("LABEL_POS_RIGHT", 690603);define("LABEL_POS_TOP", 690604);define("LABEL_POS_BOTTOM", 690605);define("LABEL_POS_INSIDE", 690606);define("LABEL_POS_OUTSIDE", 690607);define("ORIENTATION_HORIZONTAL", 690701);define("ORIENTATION_VERTICAL", 690702);define("ORIENTATION_AUTO", 690703);define("LEGEND_NOBORDER", 690800);define("LEGEND_BOX", 690801);define("LEGEND_ROUND", 690802);define("LEGEND_VERTICAL", 690901);define("LEGEND_HORIZONTAL", 690902);define("LEGEND_FAMILY_BOX", 691051);define("LEGEND_FAMILY_CIRCLE", 691052);define("LEGEND_FAMILY_LINE", 691053);define("DISPLAY_AUTO", 691001);define("DISPLAY_MANUAL", 691002);define("LABELING_ALL", 691011);define("LABELING_DIFFERENT", 691012);define("BOUND_MIN", 691021);define("BOUND_MAX", 691022);define("BOUND_BOTH", 691023);define("BOUND_LABEL_POS_TOP", 691031);define("BOUND_LABEL_POS_BOTTOM", 691032);define("BOUND_LABEL_POS_AUTO", 691033);define("CAPTION_LEFT_TOP", 691041);define("CAPTION_RIGHT_BOTTOM", 691042);define("GRADIENT_SIMPLE", 691051);define("GRADIENT_EFFECT_CAN", 691052);define("LABEL_TITLE_NOBACKGROUND", 691061);define("LABEL_TITLE_BACKGROUND", 691062);define("LABEL_POINT_NONE", 691071);define("LABEL_POINT_CIRCLE", 691072);define("LABEL_POINT_BOX", 691073);define("ZONE_NAME_ANGLE_AUTO", 691081);define("PI", 3.14159265);define("ALL", 69);define("NONE", 31);define("AUTO", 690000);define("OUT_OF_SIGHT", -10000000000000);class pDraw{var $aColorCache = [];/* Returns the number of drawable series */function countDrawableSeries(){$Results = 0;$Data = $this->DataSet->getData();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$Results++;}}return $Results;}/* Fix box coordinates */function fixBoxCoordinates($Xa, $Ya, $Xb, $Yb){return [min($Xa, $Xb),min($Ya, $Yb),max($Xa, $Xb),max($Ya, $Yb)];}/* Draw a polygon */function drawPolygon($Points, array $Format = []){$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;$NoFill = isset($Format["NoFill"]) ? $Format["NoFill"] : FALSE;$NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : FALSE;$Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;$BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R;$BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G;$BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B;$BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha / 2;$SkipX = isset($Format["SkipX"]) ? $Format["SkipX"] : OUT_OF_SIGHT;$SkipY = isset($Format["SkipY"]) ? $Format["SkipY"] : OUT_OF_SIGHT;#extract($Format); # Don't use is for frequently used functions/* Calling the ImageFilledPolygon() function over the $Points array will round it */$Backup = $Points;if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}($SkipX != OUT_OF_SIGHT) AND $SkipX = floor($SkipX);($SkipY != OUT_OF_SIGHT) AND $SkipY = floor($SkipY);$RestoreShadow = $this->Shadow;if (!$NoFill) {if ($this->Shadow) {$this->Shadow = FALSE;$Shadow = []; // MOMCHIL: local var missingfor ($i = 0; $i <= count($Points) - 1; $i = $i + 2) {$Shadow[] = $Points[$i] + $this->ShadowX;$Shadow[] = $Points[$i + 1] + $this->ShadowY;}$this->drawPolygon($Shadow, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa,"NoBorder" => TRUE]);}$FillColor = $this->allocateColor($R, $G, $B, $Alpha);if (count($Points) >= 6) {ImageFilledPolygon($this->Picture, $Points, count($Points) / 2, $FillColor);}}if (!$NoBorder) {$Points = $Backup;if ($NoFill) {$BorderSettings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];} else {$BorderSettings = ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha];}for ($i = 0; $i <= count($Points) - 1; $i = $i + 2) {if (isset($Points[$i + 2])) {if (!($Points[$i] == $Points[$i + 2] && $Points[$i] == $SkipX) && !($Points[$i + 1] == $Points[$i + 3] && $Points[$i + 1] == $SkipY)){$this->drawLine($Points[$i], $Points[$i + 1], $Points[$i + 2], $Points[$i + 3], $BorderSettings);}} else {if (!($Points[$i] == $Points[0] && $Points[$i] == $SkipX) && !($Points[$i + 1] == $Points[1] && $Points[$i + 1] == $SkipY)) {$this->drawLine($Points[$i], $Points[$i + 1], $Points[0], $Points[1], $BorderSettings);}}}}$this->Shadow = $RestoreShadow;}/* Apply AALias correction to the rounded box boundaries */function offsetCorrection($Value, $Mode) # UNUSED{$Value = round($Value, 1);if ($Value == 0 && $Mode == 1) {$ret = .9;} elseif ($Value == 0) {$ret = 0;} else {$matrix = [1 => [1 => .9,.1 => .9,.2 => .8,.3 => .8,.4 => .7,.5 => .5,.6 => .8,.7 => .7,.8 => .6,.9 => .9],2 => [1 => .9,.1 => .1,.2 => .2,.3 => .3,.4 => .4,.5 => .5,.6 => .8,.7 => .7,.8 => .8,.9 => .9],3 => [1 => .9,.1 => .1,.2 => .2,.3 => .3,.4 => .4,.5 => .9,.6 => .6,.7 => .7,.8 => .4,.9 => .5],4 => [1 => -1,.1 => .1,.2 => .2,.3 => .3,.4 => .1,.5 => -.1,.6 => .8,.7 => .1,.8 => .1,.9 => .1]];$ret = $matrix[$Mode][$Value];}return $ret;}/* Draw a rectangle with rounded corners */function drawRoundedRectangle($X1, $Y1, $X2, $Y2, $Radius, array $Format = []){$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;list($X1, $Y1, $X2, $Y2) = $this->fixBoxCoordinates($X1, $Y1, $X2, $Y2);($X2 - $X1 < $Radius) AND $Radius = floor(($X2 - $X1) / 2);($Y2 - $Y1 < $Radius) AND $Radius = floor(($Y2 - $Y1) / 2);$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"NoBorder" => TRUE];if ($Radius <= 0) {$this->drawRectangle($X1, $Y1, $X2, $Y2, $Color);return 0;}if ($this->Antialias) {$this->drawLine($X1 + $Radius, $Y1, $X2 - $Radius, $Y1, $Color);$this->drawLine($X2, $Y1 + $Radius, $X2, $Y2 - $Radius, $Color);$this->drawLine($X2 - $Radius, $Y2, $X1 + $Radius, $Y2, $Color);$this->drawLine($X1, $Y1 + $Radius, $X1, $Y2 - $Radius, $Color);} else {$ColorA = $this->allocateColor($R, $G, $B, $Alpha);imageline($this->Picture, $X1 + $Radius, $Y1, $X2 - $Radius, $Y1, $ColorA);imageline($this->Picture, $X2, $Y1 + $Radius, $X2, $Y2 - $Radius, $ColorA);imageline($this->Picture, $X2 - $Radius, $Y2, $X1 + $Radius, $Y2, $ColorA);imageline($this->Picture, $X1, $Y1 + $Radius, $X1, $Y2 - $Radius, $ColorA);}$Step = 360 / (2 * PI * $Radius);unset($Color["NoBorder"]);for ($i = 0; $i <= 90; $i = $i + $Step) {$X = cos(($i + 180) * PI / 180) * $Radius + $X1 + $Radius;$Y = sin(($i + 180) * PI / 180) * $Radius + $Y1 + $Radius;$this->drawAntialiasPixel($X, $Y, $Color);$X = cos(($i + 90) * PI / 180) * $Radius + $X1 + $Radius;$Y = sin(($i + 90) * PI / 180) * $Radius + $Y2 - $Radius;$this->drawAntialiasPixel($X, $Y, $Color);$X = cos($i * PI / 180) * $Radius + $X2 - $Radius;$Y = sin($i * PI / 180) * $Radius + $Y2 - $Radius;$this->drawAntialiasPixel($X, $Y, $Color);$X = cos(($i + 270) * PI / 180) * $Radius + $X2 - $Radius;$Y = sin(($i + 270) * PI / 180) * $Radius + $Y1 + $Radius;$this->drawAntialiasPixel($X, $Y, $Color);}}/* Draw a rectangle with rounded corners */function drawRoundedFilledRectangle($X1, $Y1, $X2, $Y2, $Radius, array $Format = []){$R = 0;$G = 0;$B = 0;$Alpha = 100;$Surrounding = NULL;$BorderR = -1;$BorderG = -1;$BorderB = -1;extract($Format);/* Temporary fix for AA issue */$Y1 = floor($Y1);$Y2 = floor($Y2);$X1 = floor($X1);$X2 = floor($X2);if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}if ($BorderR == - 1) {$BorderR = $R;$BorderG = $G;$BorderB = $B;}list($X1, $Y1, $X2, $Y2) = $this->fixBoxCoordinates($X1, $Y1, $X2, $Y2);if ($X2 - $X1 < $Radius * 2) {$Radius = floor((($X2 - $X1)) / 4);}if ($Y2 - $Y1 < $Radius * 2) {$Radius = floor((($Y2 - $Y1)) / 4);}$RestoreShadow = $this->Shadow;if ($this->Shadow) {$this->Shadow = FALSE;$this->drawRoundedFilledRectangle($X1 + $this->ShadowX, $Y1 + $this->ShadowY, $X2 + $this->ShadowX, $Y2 + $this->ShadowY, $Radius, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa]);}$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"NoBorder" => TRUE];if ($Radius <= 0) {$this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color);return 0;}$YTop = $Y1 + $Radius;$YBottom = $Y2 - $Radius;$Step = 360 / (2 * PI * $Radius);$Positions = [];$Radius--;$MinY = "";$MaxY = "";for ($i = 0; $i <= 90; $i = $i + $Step) {$Xp1 = cos(($i + 180) * PI / 180) * $Radius + $X1 + $Radius;$Xp2 = cos(((90 - $i) + 270) * PI / 180) * $Radius + $X2 - $Radius;$Yp = floor(sin(($i + 180) * PI / 180) * $Radius + $YTop);($MinY == "" || $Yp > $MinY) AND $MinY = $Yp;($Xp1 <= floor($X1)) AND $Xp1++;($Xp2 >= floor($X2)) AND $Xp2--;$Xp1++;if (!isset($Positions[$Yp])) {$Positions[$Yp]["X1"] = $Xp1;$Positions[$Yp]["X2"] = $Xp2;} else {$Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"] + $Xp1) / 2;$Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"] + $Xp2) / 2;}$Xp1 = cos(($i + 90) * PI / 180) * $Radius + $X1 + $Radius;$Xp2 = cos((90 - $i) * PI / 180) * $Radius + $X2 - $Radius;$Yp = floor(sin(($i + 90) * PI / 180) * $Radius + $YBottom);($MaxY == "" || $Yp < $MaxY) AND $MaxY = $Yp;($Xp1 <= floor($X1)) AND $Xp1++;($Xp2 >= floor($X2)) AND $Xp2--;$Xp1++;if (!isset($Positions[$Yp])) {$Positions[$Yp]["X1"] = $Xp1;$Positions[$Yp]["X2"] = $Xp2;} else {$Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"] + $Xp1) / 2;$Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"] + $Xp2) / 2;}}$ManualColor = $this->allocateColor($R, $G, $B, $Alpha);foreach($Positions as $Yp => $Bounds) {$X1 = $Bounds["X1"];$X1Dec = $this->getFirstDecimal($X1);if ($X1Dec != 0) {$X1 = floor($X1) + 1;}$X2 = $Bounds["X2"];$X2Dec = $this->getFirstDecimal($X2);if ($X2Dec != 0) {$X2 = floor($X2) - 1;}imageline($this->Picture, $X1, $Yp, $X2, $Yp, $ManualColor);}$this->drawFilledRectangle($X1, $MinY + 1, floor($X2), $MaxY - 1, $Color);$Radius++;$this->drawRoundedRectangle($X1, $Y1, $X2 + 1, $Y2 - 1, $Radius, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $Alpha]);$this->Shadow = $RestoreShadow;}/* Draw a rectangle with rounded corners */function drawRoundedFilledRectangle_deprecated($X1, $Y1, $X2, $Y2, $Radius, array $Format = []) # UNUSED{$R = 0;$G = 0;$B = 0;$Alpha = 100;$Surrounding = NULL;$BorderR = -1;$BorderG = -1;$BorderB = -1;extract($Format);if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}if ($BorderR == - 1) {$BorderR = $R;$BorderG = $G;$BorderB = $B;}list($X1, $Y1, $X2, $Y2) = $this->fixBoxCoordinates($X1, $Y1, $X2, $Y2);if ($X2 - $X1 < $Radius) {$Radius = floor((($X2 - $X1) + 2) / 2);}if ($Y2 - $Y1 < $Radius) {$Radius = floor((($Y2 - $Y1) + 2) / 2);}$RestoreShadow = $this->Shadow;if ($this->Shadow) {$this->Shadow = FALSE;$this->drawRoundedFilledRectangle($X1 + $this->ShadowX, $Y1 + $this->ShadowY, $X2 + $this->ShadowX, $Y2 + $this->ShadowY, $Radius, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa]);}$XOffset2 = ($this->getFirstDecimal($X2) >= 5) ? 1 : 0;$XOffset1 = ($this->getFirstDecimal($X1) <= 5) ? 1 : 0;if (!$this->Antialias) {$XOffset1 = 1;$XOffset2 = 1;}$YTop = floor($Y1 + $Radius);$YBottom = floor($Y2 - $Radius);$this->drawFilledRectangle($X1 - $XOffset1, $YTop, $X2 + $XOffset2, $YBottom, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"NoBorder" => TRUE]);$Step = 360 / (2 * PI * $Radius);$Color = $this->allocateColor($R, $G, $B, $Alpha);$Color2 = $this->allocateColor(255, 0, 0, $Alpha);$Drawn = [];($Alpha < 100) AND $Drawn[$YTop] = FALSE;($Alpha < 100) AND $Drawn[$YBottom] = TRUE;for ($i = 0; $i <= 90; $i = $i + $Step) {$Xp1 = cos(($i + 180) * PI / 180) * $Radius + $X1 + $Radius;$Xp2 = cos(((90 - $i) + 270) * PI / 180) * $Radius + $X2 - $Radius;$Yp = sin(($i + 180) * PI / 180) * $Radius + $YTop;$XOffset1 = ($this->getFirstDecimal($Xp1) > 5) ? 1 : 0;$XOffset2 = ($this->getFirstDecimal($Xp2) > 5) ? 1 : 0;$YOffset = ($this->getFirstDecimal($Yp) > 5) ? 1 : 0;if (!isset($Drawn[$Yp + $YOffset]) || $Alpha == 100) {imageline($this->Picture, $Xp1 + $XOffset1, $Yp + $YOffset, $Xp2 + $XOffset2, $Yp + $YOffset, $Color);}$Drawn[$Yp + $YOffset] = $Xp2;$Xp1 = cos(($i + 90) * PI / 180) * $Radius + $X1 + $Radius;$Xp2 = cos((90 - $i) * PI / 180) * $Radius + $X2 - $Radius;$Yp = sin(($i + 90) * PI / 180) * $Radius + $YBottom;$XOffset1 = ($this->getFirstDecimal($Xp1) > 7) ? 1 : 0;$XOffset2 = ($this->getFirstDecimal($Xp2) > 7) ? 1 : 0;$YOffset = ($this->getFirstDecimal($Yp) > 5) ? 1 : 0;if (!isset($Drawn[$Yp + $YOffset]) || $Alpha == 100) {imageline($this->Picture, $Xp1 + $XOffset1, $Yp + $YOffset, $Xp2 + $XOffset2, $Yp + $YOffset, $Color);}$Drawn[$Yp + $YOffset] = $Xp2;}$this->drawRoundedRectangle($X1, $Y1, $X2, $Y2, $Radius, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $Alpha]);$this->Shadow = $RestoreShadow;}/* Draw a rectangle */function drawRectangle($X1, $Y1, $X2, $Y2, array $Format = []){$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;$Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;$NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : FALSE;($X1 > $X2) AND list($X1, $X2) = [$X2,$X1];($Y1 > $Y2) AND list($Y1, $Y2) = [$Y2,$Y1];$RGB = ["R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha, "Ticks" => $Ticks];if ($this->Antialias) {if ($NoAngle) {$this->drawLine($X1 + 1, $Y1, $X2 - 1, $Y1, $RGB);$this->drawLine($X2, $Y1 + 1, $X2, $Y2 - 1, $RGB);$this->drawLine($X2 - 1, $Y2, $X1 + 1, $Y2, $RGB);$this->drawLine($X1, $Y1 + 1, $X1, $Y2 - 1, $RGB);} else {$this->drawLine($X1 + 1, $Y1, $X2 - 1, $Y1, $RGB);$this->drawLine($X2, $Y1, $X2, $Y2, $RGB);$this->drawLine($X2 - 1, $Y2, $X1 + 1, $Y2, $RGB);$this->drawLine($X1, $Y1, $X1, $Y2, $RGB);}} else {imagerectangle($this->Picture, $X1, $Y1, $X2, $Y2, $this->allocateColor($R, $G, $B, $Alpha));}}/* Draw a filled rectangle */function drawFilledRectangle($X1, $Y1, $X2, $Y2, array $Format = []){$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;$NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : FALSE;$Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;$Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;$BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1;$BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1;$BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1;$BorderAlpha = $Alpha;$NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : NULL;$Dash = isset($Format["Dash"]) ? $Format["Dash"] : FALSE;$DashStep = isset($Format["DashStep"]) ? $Format["DashStep"] : 4;$DashR = isset($Format["DashR"]) ? $Format["DashR"] : 0;$DashG = isset($Format["DashG"]) ? $Format["DashG"] : 0;$DashB = isset($Format["DashB"]) ? $Format["DashB"] : 0;if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}($X1 > $X2) AND list($X1, $X2) = [$X2,$X1];($Y1 > $Y2) AND list($Y1, $Y2) = [$Y2,$Y1];$X1c = ceil($X1);$Y1c = ceil($Y1);$X2f = floor($X2);$Y2f = floor($Y2);$RestoreShadow = $this->Shadow;if ($this->Shadow) {$this->Shadow = FALSE;$this->drawFilledRectangle($X1 + $this->ShadowX, $Y1 + $this->ShadowY, $X2 + $this->ShadowX, $Y2 + $this->ShadowY, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa,"Ticks" => $Ticks,"NoAngle" => $NoAngle]);}$Color = $this->allocateColor($R, $G, $B, $Alpha);if ($NoAngle) {imagefilledrectangle($this->Picture, $X1c + 1, $Y1c, $X2f - 1, $Y2f, $Color);imageline($this->Picture, $X1c, $Y1c + 1, $X1c, $Y2f - 1, $Color);imageline($this->Picture, $X2f, $Y1c + 1, $X2f, $Y2f - 1, $Color);} else {imagefilledrectangle($this->Picture, $X1c, $Y1c, $X2f, $Y2f, $Color);}if ($Dash) {if ($BorderR != - 1) {$iX1 = $X1 + 1;$iY1 = $Y1 + 1;$iX2 = $X2 - 1;$iY2 = $Y2 - 1;} else {$iX1 = $X1;$iY1 = $Y1;$iX2 = $X2;$iY2 = $Y2;}$Color = $this->allocateColor($DashR, $DashG, $DashB, $Alpha);$Y = $iY1 - $DashStep;for ($X = $iX1; $X <= $iX2 + ($iY2 - $iY1); $X = $X + $DashStep) {$Y = $Y + $DashStep;if ($X > $iX2) {$Xa = $X - ($X - $iX2);$Ya = $iY1 + ($X - $iX2);} else {$Xa = $X;$Ya = $iY1;}if ($Y > $iY2) {$Xb = $iX1 + ($Y - $iY2);$Yb = $Y - ($Y - $iY2);} else {$Xb = $iX1;$Yb = $Y;}imageline($this->Picture, $Xa, $Ya, $Xb, $Yb, $Color);}}if ($this->Antialias && !$NoBorder) {if ($X1 < $X1c) {$AlphaA = $Alpha * ($X1c - $X1);$Color = $this->allocateColor($R, $G, $B, $AlphaA);imageline($this->Picture, $X1c - 1, $Y1c, $X1c - 1, $Y2f, $Color);}if ($Y1 < $Y1c) {$AlphaA = $Alpha * ($Y1c - $Y1);$Color = $this->allocateColor($R, $G, $B, $AlphaA);imageline($this->Picture, $X1c, $Y1c - 1, $X2f, $Y1c - 1, $Color);}if ($X2 > $X2f) {$AlphaA = $Alpha * (.5 - ($X2 - $X2f));$Color = $this->allocateColor($R, $G, $B, $AlphaA);imageline($this->Picture, $X2f + 1, $Y1c, $X2f + 1, $Y2f, $Color);}if ($Y2 > $Y2f) {$AlphaA = $Alpha * (.5 - ($Y2 - $Y2f));$Color = $this->allocateColor($R, $G, $B, $AlphaA);imageline($this->Picture, $X1c, $Y2f + 1, $X2f, $Y2f + 1, $Color);}}if ($BorderR != - 1) {$this->drawRectangle($X1, $Y1, $X2, $Y2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $Ticks,"NoAngle" => $NoAngle]);}$this->Shadow = $RestoreShadow;}/* Draw a rectangular marker of the specified size */function drawRectangleMarker($X, $Y, array $Format = []){$Size = isset($Format["Size"]) ? $Format["Size"] : 4;$HalfSize = floor($Size / 2);$this->drawFilledRectangle($X - $HalfSize, $Y - $HalfSize, $X + $HalfSize, $Y + $HalfSize, $Format);}/* Drawn a spline based on the bezier function */function drawSpline(array $Coordinates, array $Format = []){#$R = 0; # UNUSED#$G = 0;#$B = 0;#$Alpha = 100;#$Ticks = NULL;$PathOnly = FALSE;#$Weight = NULL;#$ShowC = FALSE;$Force = 30;$Forces = NULL;extract($Format);#$Cpt = NULL; # UNUSED#$Mode = NULL;$Result = [];for ($i = 1; $i <= count($Coordinates) - 1; $i++) {$X1 = $Coordinates[$i - 1][0];$Y1 = $Coordinates[$i - 1][1];$X2 = $Coordinates[$i][0];$Y2 = $Coordinates[$i][1];if ($Forces != NULL) {$Force = $Forces[$i];}/* First segment */if ($i == 1) {$Xv1 = $X1;$Yv1 = $Y1;} else {$Angle1 = $this->getAngle($XLast, $YLast, $X1, $Y1);$Angle2 = $this->getAngle($X1, $Y1, $X2, $Y2);$XOff = cos($Angle2 * PI / 180) * $Force + $X1;$YOff = sin($Angle2 * PI / 180) * $Force + $Y1;$Xv1 = cos($Angle1 * PI / 180) * $Force + $XOff;$Yv1 = sin($Angle1 * PI / 180) * $Force + $YOff;}/* Last segment */if ($i == count($Coordinates) - 1) {$Xv2 = $X2;$Yv2 = $Y2;} else {$Angle1 = $this->getAngle($X2, $Y2, $Coordinates[$i + 1][0], $Coordinates[$i + 1][1]);$Angle2 = $this->getAngle($X1, $Y1, $X2, $Y2);$XOff = cos(($Angle2 + 180) * PI / 180) * $Force + $X2;$YOff = sin(($Angle2 + 180) * PI / 180) * $Force + $Y2;$Xv2 = cos(($Angle1 + 180) * PI / 180) * $Force + $XOff;$Yv2 = sin(($Angle1 + 180) * PI / 180) * $Force + $YOff;}$Path = $this->drawBezier($X1, $Y1, $X2, $Y2, $Xv1, $Yv1, $Xv2, $Yv2, $Format);if ($PathOnly) {$Result[] = $Path;}$XLast = $X1;$YLast = $Y1;}return $Result;}/* Draw a bezier curve with two controls points */function drawBezier($X1, $Y1, $X2, $Y2, $Xv1, $Yv1, $Xv2, $Yv2, array $Format = []){$R = 0;$G = 0;$B = 0;$Alpha = 100;$Segments = NULL;$Ticks = NULL;$NoDraw = FALSE;$PathOnly = FALSE;$Weight = NULL;$ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : FALSE;$DrawArrow = FALSE;$ArrowSize = 10;$ArrowRatio = .5;$ArrowTwoHeads = FALSE;extract($Format);if ($Segments == NULL) {$Length = $this->getLength($X1, $Y1, $X2, $Y2);$Precision = ($Length * 125) / 1000;} else {$Precision = $Segments;}$P = [0 => ["X" => $X1, "Y" => $Y1],1 => ["X" => $Xv1, "Y" => $Yv1],2 => ["X" => $Xv2, "Y" => $Yv2],3 => ["X" => $X2, "Y" => $Y2]];/* Compute the bezier points */$Q = [];$ID = 0; //$Path = ""; # UNUSEDfor ($i = 0; $i <= $Precision; $i = $i + 1) {$u = $i / $Precision;$C = [0 => (1 - $u) * (1 - $u) * (1 - $u),1 => ($u * 3) * (1 - $u) * (1 - $u),2 => 3 * $u * $u * (1 - $u),3 => $u * $u * $u];for ($j = 0; $j <= 3; $j++) {(!isset($Q[$ID])) AND $Q[$ID] = [];(!isset($Q[$ID]["X"])) AND $Q[$ID]["X"] = 0;(!isset($Q[$ID]["Y"])) AND $Q[$ID]["Y"] = 0;$Q[$ID]["X"] = $Q[$ID]["X"] + $P[$j]["X"] * $C[$j];$Q[$ID]["Y"] = $Q[$ID]["Y"] + $P[$j]["Y"] * $C[$j];}$ID++;}$Q[$ID]["X"] = $X2;$Q[$ID]["Y"] = $Y2;if (!$NoDraw) {/* Display the control points */if ($ShowC && !$PathOnly) {$Xv1 = floor($Xv1);$Yv1 = floor($Yv1);$Xv2 = floor($Xv2);$Yv2 = floor($Yv2);$this->drawLine($X1, $Y1, $X2, $Y2, ["R" => 0,"G" => 0,"B" => 0,"Alpha" => 30]);$MyMarkerSettings = ["R" => 255,"G" => 0,"B" => 0,"BorderR" => 255,"BorderB" => 255,"BorderG" => 255,"Size" => 4];$this->drawRectangleMarker($Xv1, $Yv1, $MyMarkerSettings);$this->drawText($Xv1 + 4, $Yv1, "v1");$MyMarkerSettings = ["R" => 0,"G" => 0,"B" => 255,"BorderR" => 255,"BorderB" => 255,"BorderG" => 255,"Size" => 4];$this->drawRectangleMarker($Xv2, $Yv2, $MyMarkerSettings);$this->drawText($Xv2 + 4, $Yv2, "v2");}/* Draw the bezier */$LastX = NULL;$LastY = NULL;$Cpt = NULL;$Mode = NULL;$ArrowS = [];$ArrowE = [];foreach($Q as $Key => $Point) {$X = $Point["X"];$Y = $Point["Y"];/* Get the first segment */if (count($ArrowS) == 0 && $LastX != NULL && $LastY != NULL) {$ArrowS["X2"] = $LastX;$ArrowS["Y2"] = $LastY;$ArrowS["X1"] = $X;$ArrowS["Y1"] = $Y;}if ($LastX != NULL && $LastY != NULL && !$PathOnly) {list($Cpt, $Mode) = $this->drawLine($LastX, $LastY, $X, $Y, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Cpt" => $Cpt,"Mode" => $Mode,"Weight" => $Weight]);}/* Get the last segment */$ArrowE["X1"] = $LastX;$ArrowE["Y1"] = $LastY;$ArrowE["X2"] = $X;$ArrowE["Y2"] = $Y;$LastX = $X;$LastY = $Y;}if ($DrawArrow && !$PathOnly) {$ArrowSettings = ["FillR" => $R,"FillG" => $G,"FillB" => $B,"Alpha" => $Alpha,"Size" => $ArrowSize,"Ratio" => $ArrowRatio];if ($ArrowTwoHeads) {$this->drawArrow($ArrowS["X1"], $ArrowS["Y1"], $ArrowS["X2"], $ArrowS["Y2"], $ArrowSettings);}$this->drawArrow($ArrowE["X1"], $ArrowE["Y1"], $ArrowE["X2"], $ArrowE["Y2"], $ArrowSettings);}}return $Q;}/* Draw a line between two points */function drawLine($X1, $Y1, $X2, $Y2, array $Format = []) # FAST{$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;$Cpt = isset($Format["Cpt"]) ? $Format["Cpt"] : 1;$Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : NULL;$Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;$Weight = isset($Format["Weight"]) ? $Format["Weight"] : NULL;$Mode = isset($Format["Mode"]) ? $Format["Mode"] : 1;if ($this->Antialias == FALSE && $Ticks == NULL) {if ($this->Shadow) {$ShadowColor = $this->allocateColor($this->ShadowR, $this->ShadowG, $this->ShadowB, $this->Shadowa);imageline($this->Picture, $X1 + $this->ShadowX, $Y1 + $this->ShadowY, $X2 + $this->ShadowX, $Y2 + $this->ShadowY, $ShadowColor);}$Color = $this->allocateColor($R, $G, $B, $Alpha);imageline($this->Picture, $X1, $Y1, $X2, $Y2, $Color);return 0;}$Distance = sqrt(($X2 - $X1) * ($X2 - $X1) + ($Y2 - $Y1) * ($Y2 - $Y1));if ($Distance == 0) {return -1;}/* Derivative algorithm for overweighted lines, re-route to polygons primitives */if ($Weight != NULL) {$Angle = $this->getAngle($X1, $Y1, $X2, $Y2);$PolySettings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"BorderAlpha" => $Alpha];$AngleCosPlus90 = cos(deg2rad($Angle + 90)) * $Weight; // Momchil$AngleCosMinus90 = cos(deg2rad($Angle - 90)) * $Weight;$AngleSinPlus90 = sin(deg2rad($Angle + 90)) * $Weight; // Momchil$AngleSinMinus90 = sin(deg2rad($Angle - 90)) * $Weight;if ($Ticks == NULL) {$Points = [$AngleCosMinus90 + $X1, $AngleSinMinus90 + $Y1, $AngleCosPlus90 + $X1, $AngleSinPlus90 + $Y1, $AngleCosPlus90 + $X2, $AngleSinPlus90 + $Y2, $AngleCosMinus90 + $X2, $AngleSinMinus90 + $Y2];$this->drawPolygon($Points, $PolySettings);} else {for ($i = 0; $i <= $Distance; $i = $i + $Ticks * 2) {$Xa = (($X2 - $X1) / $Distance) * $i + $X1;$Ya = (($Y2 - $Y1) / $Distance) * $i + $Y1;$Xb = (($X2 - $X1) / $Distance) * ($i + $Ticks) + $X1;$Yb = (($Y2 - $Y1) / $Distance) * ($i + $Ticks) + $Y1;$Points = [$AngleCosMinus90 + $Xa, $AngleSinMinus90 + $Ya, $AngleCosPlus90 + $Xa, $AngleSinPlus90 + $Ya, $AngleCosPlus90 + $Xb, $AngleSinPlus90 + $Yb, $AngleCosMinus90 + $Xb, $AngleSinMinus90 + $Yb];$this->drawPolygon($Points, $PolySettings);}}return 1;}$XStep = ($X2 - $X1) / $Distance;$YStep = ($Y2 - $Y1) / $Distance;$defaultColor = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];if ($Threshold == NULL && $Ticks == NULL){ # Momchil: Fast path based on my test casesfor ($i = 0; $i <= $Distance; $i++) {$this->drawAntialiasPixel($i * $XStep + $X1, $i * $YStep + $Y1, $defaultColor);}} else {for ($i = 0; $i <= $Distance; $i++) {$X = $i * $XStep + $X1;$Y = $i * $YStep + $Y1;$Color = $defaultColor;if ($Threshold != NULL) {foreach($Threshold as $Key => $Parameters) {if ($Y <= $Parameters["MinX"] && $Y >= $Parameters["MaxX"]) {$RT = (isset($Parameters["R"])) ? $Parameters["R"] : 0;$GT = (isset($Parameters["G"])) ? $Parameters["G"] : 0;$BT = (isset($Parameters["B"])) ? $Parameters["B"] : 0;$AlphaT = (isset($Parameters["Alpha"])) ? $Parameters["Alpha"] : 0;$Color = ["R" => $RT,"G" => $GT,"B" => $BT,"Alpha" => $AlphaT];}}}if ($Ticks != NULL) {if ($Cpt % $Ticks == 0) {$Cpt = 0;$Mode = ($Mode == 1) ? 0 : 1;}($Mode == 1) AND $this->drawAntialiasPixel($X, $Y, $Color);$Cpt++;} else {$this->drawAntialiasPixel($X, $Y, $Color);}}}return [$Cpt,$Mode];}/* Draw a circle */function drawCircle($Xc, $Yc, $Height, $Width, array $Format = []){$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;$Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;$Height = abs($Height);$Width = abs($Width);($Height == 0) AND $Height = 1;($Width == 0) AND $Width = 1;$Xc = floor($Xc);$Yc = floor($Yc);$RestoreShadow = $this->Shadow;if ($this->Shadow) {$this->Shadow = FALSE;$this->drawCircle($Xc + $this->ShadowX, $Yc + $this->ShadowY, $Height, $Width, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa,"Ticks" => $Ticks]);}($Width == 0) AND $Width = $Height;#($R < 0) AND $R = 0; # # Will be done in drawAntialiasPixel anyway#($R > 255) AND $R = 255;#($G < 0) AND $G = 0;#($G > 255) AND $G = 255;#($B < 0) AND $B = 0;#($B > 255) AND $B = 255;$Step = 360 / (2 * PI * max($Width, $Height));$Mode = 1;$Cpt = 1;for ($i = 0; $i <= 360; $i = $i + $Step) {$X = cos($i * PI / 180) * $Height + $Xc;$Y = sin($i * PI / 180) * $Width + $Yc;if ($Ticks != NULL) {if ($Cpt % $Ticks == 0) {$Cpt = 0;$Mode = ($Mode == 1) ? 0 : 1;}if ($Mode == 1) { # Mode seems to always be 1$this->drawAntialiasPixel($X, $Y, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha]);}$Cpt++;} else {$this->drawAntialiasPixel($X, $Y, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha]);}}$this->Shadow = $RestoreShadow;}/* Draw a filled circle */function drawFilledCircle($X, $Y, $Radius, array $Format = []){$R = 0;$G = 0;$B = 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;$Surrounding = NULL;$Ticks = NULL;$BorderR = -1;$BorderG = -1;$BorderB = -1;$BorderAlpha = $Alpha;extract($Format);($Radius == 0) AND $Radius = 1;if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}$X = floor($X);$Y = floor($Y);$Radius = abs($Radius);$RestoreShadow = $this->Shadow;if ($this->Shadow) {$this->Shadow = FALSE;$this->drawFilledCircle($X + $this->ShadowX, $Y + $this->ShadowY, $Radius, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa,"Ticks" => $Ticks]);}$this->Mask = [];$Color = $this->allocateColor($R, $G, $B, $Alpha);for ($i = 0; $i <= $Radius * 2; $i++) {$Slice = sqrt($Radius * $Radius - ($Radius - $i) * ($Radius - $i));$XPos = floor($Slice);$YPos = $Y + $i - $Radius;$AAlias = $Slice - floor($Slice);$this->Mask[$X - $XPos][$YPos] = TRUE;$this->Mask[$X + $XPos][$YPos] = TRUE;imageline($this->Picture, $X - $XPos, $YPos, $X + $XPos, $YPos, $Color);}if ($this->Antialias) {$this->drawCircle($X, $Y, $Radius, $Radius, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks]);}$this->Mask = [];if ($BorderR != - 1) {$this->drawCircle($X, $Y, $Radius, $Radius, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $Ticks]);}$this->Shadow = $RestoreShadow;}/* Write text */function drawText($X, $Y, $Text, array $Format = []){$R = $this->FontColorR;$G = $this->FontColorG;$B = $this->FontColorB;$Angle = 0;$Align = TEXT_ALIGN_BOTTOMLEFT;$Alpha = $this->FontColorA;$FontName = $this->FontName;$FontSize = $this->FontSize;$ShowOrigine = FALSE;$TOffset = 2;$DrawBox = FALSE;$DrawBoxBorder = TRUE;$BorderOffset = 6;$BoxRounded = FALSE;$RoundedRadius = 6;$BoxR = 255;$BoxG = 255;$BoxB = 255;$BoxAlpha = 50;$BoxSurrounding = "";$BoxBorderR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0;$BoxBorderG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0;$BoxBorderB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0;$BoxBorderAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 50;$NoShadow = FALSE;/* Override defaults */extract($Format);$Shadow = $this->Shadow;($NoShadow) AND $this->Shadow = FALSE;if ($BoxSurrounding != "") {$BoxBorderR = $BoxR - $BoxSurrounding;$BoxBorderG = $BoxG - $BoxSurrounding;$BoxBorderB = $BoxB - $BoxSurrounding;$BoxBorderAlpha = $BoxAlpha;}if ($ShowOrigine) {$MyMarkerSettings = ["R" => 255,"G" => 0,"B" => 0,"BorderR" => 255,"BorderB" => 255,"BorderG" => 255,"Size" => 4];$this->drawRectangleMarker($X, $Y, $MyMarkerSettings);}$TxtPos = $this->getTextBox($X, $Y, $FontName, $FontSize, $Angle, $Text);if ($DrawBox && ($Angle == 0 || $Angle == 90 || $Angle == 180 || $Angle == 270)) {$T = [0 => ["X" => 0, "Y" => 0]];#$T[0]["X"] = 0;#$T[0]["Y"] = 0;#$T[1]["X"] = 0; # Momchil: Only $T[0] is in use#$T[1]["Y"] = 0;#$T[2]["X"] = 0;#$T[2]["Y"] = 0;#$T[3]["X"] = 0;#$T[3]["Y"] = 0;if ($Angle == 0) {$T = [0 => ["X" => - $TOffset, "Y" => $TOffset]];#$T[0]["X"] = - $TOffset;#$T[0]["Y"] = $TOffset;#$T[1]["X"] = $TOffset;#$T[1]["Y"] = $TOffset;#$T[2]["X"] = $TOffset;#$T[2]["Y"] = - $TOffset;#$T[3]["X"] = - $TOffset;#$T[3]["Y"] = - $TOffset;}$X1 = min($TxtPos[0]["X"], $TxtPos[1]["X"], $TxtPos[2]["X"], $TxtPos[3]["X"]) - $BorderOffset + 3;$Y1 = min($TxtPos[0]["Y"], $TxtPos[1]["Y"], $TxtPos[2]["Y"], $TxtPos[3]["Y"]) - $BorderOffset;$X2 = max($TxtPos[0]["X"], $TxtPos[1]["X"], $TxtPos[2]["X"], $TxtPos[3]["X"]) + $BorderOffset + 3;$Y2 = max($TxtPos[0]["Y"], $TxtPos[1]["Y"], $TxtPos[2]["Y"], $TxtPos[3]["Y"]) + $BorderOffset - 3;$X1 = $X1 - $TxtPos[$Align]["X"] + $X + $T[0]["X"];$Y1 = $Y1 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"];$X2 = $X2 - $TxtPos[$Align]["X"] + $X + $T[0]["X"];$Y2 = $Y2 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"];$Settings = ["R" => $BoxR,"G" => $BoxG,"B" => $BoxB,"Alpha" => $BoxAlpha,"BorderR" => $BoxBorderR,"BorderG" => $BoxBorderG,"BorderB" => $BoxBorderB,"BorderAlpha" => $BoxBorderAlpha];if ($BoxRounded) {$this->drawRoundedFilledRectangle($X1, $Y1, $X2, $Y2, $RoundedRadius, $Settings);} else {$this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Settings);}}$X = $X - $TxtPos[$Align]["X"] + $X;$Y = $Y - $TxtPos[$Align]["Y"] + $Y;if ($this->Shadow) {$C_ShadowColor = $this->allocateColor($this->ShadowR, $this->ShadowG, $this->ShadowB, $this->Shadowa);imagettftext($this->Picture, $FontSize, $Angle, $X + $this->ShadowX, $Y + $this->ShadowY, $C_ShadowColor, realpath($FontName), $Text);}$C_TextColor = $this->AllocateColor($R, $G, $B, $Alpha);imagettftext($this->Picture, $FontSize, $Angle, $X, $Y, $C_TextColor, realpath($FontName), $Text);$this->Shadow = $Shadow;return $TxtPos;}/* Draw a gradient within a defined area */function drawGradientArea($X1, $Y1, $X2, $Y2, $Direction, array $Format = []){$StartR = 90;$StartG = 90;$StartB = 90;$EndR = 0;$EndG = 0;$EndB = 0;$Alpha = 100;$Levels = NULL;/* Draw a gradient within a defined area */extract($Format);$Shadow = $this->Shadow;$this->Shadow = FALSE;if ($StartR == $EndR && $StartG == $EndG && $StartB == $EndB) {$this->drawFilledRectangle($X1, $Y1, $X2, $Y2, ["R" => $StartR,"G" => $StartG,"B" => $StartB,"Alpha" => $Alpha]);return 0;}if ($Levels != NULL) {$EndR = $StartR + $Levels;$EndG = $StartG + $Levels;$EndB = $StartB + $Levels;}($X1 > $X2) AND list($X1, $X2) = [$X2,$X1];($Y1 > $Y2) AND list($Y1, $Y2) = [$Y2,$Y1];($Direction == DIRECTION_VERTICAL) AND $Width = abs($Y2 - $Y1);($Direction == DIRECTION_HORIZONTAL) AND $Width = abs($X2 - $X1);$Step = max(abs($EndR - $StartR), abs($EndG - $StartG), abs($EndB - $StartB));$StepSize = $Width / $Step;$RStep = ($EndR - $StartR) / $Step;$GStep = ($EndG - $StartG) / $Step;$BStep = ($EndB - $StartB) / $Step;$R = $StartR;$G = $StartG;$B = $StartB;switch ($Direction) {case DIRECTION_VERTICAL:$StartY = $Y1;$EndY = floor($Y2) + 1;$LastY2 = $StartY;for ($i = 0; $i <= $Step; $i++) {$Y2 = floor($StartY + ($i * $StepSize));($Y2 > $EndY) AND $Y2 = $EndY;if (($Y1 != $Y2 && $Y1 < $Y2) || $Y2 == $EndY) {$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];$this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color);$LastY2 = max($LastY2, $Y2);$Y1 = $Y2 + 1;}$R = $R + $RStep;$G = $G + $GStep;$B = $B + $BStep;}if ($LastY2 < $EndY && isset($Color)) {for ($i = $LastY2 + 1; $i <= $EndY; $i++) {$this->drawLine($X1, $i, $X2, $i, $Color);}}break;case DIRECTION_HORIZONTAL:$StartX = $X1;$EndX = $X2;for ($i = 0; $i <= $Step; $i++) {$X2 = floor($StartX + ($i * $StepSize));if ($X2 > $EndX) {$X2 = $EndX;}if (($X1 != $X2 && $X1 < $X2) || $X2 == $EndX) {$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];$this->drawFilledRectangle($X1, $Y1, $X2, $Y2, $Color);$X1 = $X2 + 1;}$R = $R + $RStep;$G = $G + $GStep;$B = $B + $BStep;}if ($X2 < $EndX && isset($Color)) {$this->drawFilledRectangle($X2, $Y1, $EndX, $Y2, $Color);}break;}$this->Shadow = $Shadow;}/* Draw an aliased pixel */function drawAntialiasPixel($X, $Y, array $Format = []){if ($X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize){return -1;}# Momchil: This one is actually faster than extract$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;($R < 0) AND $R = 0;($R > 255) AND $R = 255;($G < 0) AND $G = 0;($G > 255) AND $G = 255;($B < 0) AND $B = 0;($B > 255) AND $B = 255;if (!$this->Antialias) {if ($this->Shadow) {imagesetpixel($this->Picture, $X + $this->ShadowX, $Y + $this->ShadowY, $this->allocateColor($this->ShadowR, $this->ShadowG, $this->ShadowB, $this->Shadowa));}imagesetpixel($this->Picture, $X, $Y, $this->allocateColor($R, $G, $B, $Alpha));return 0;}// $Plot = ""; # UNUSED$Xi = floor($X);$Yi = floor($Y);if ($Xi == $X && $Yi == $Y) {$this->drawAlphaPixel($X, $Y, $Alpha, $R, $G, $B, true);} else {$Yleaf = $Y - $Yi;$Xleaf = $X - $Xi;# Momchil: That allows to skip the check in drawAlphaPixel and reuse the safe paramif (($Xi + 1) >= $this->XSize || ($Yi + 1) >= $this->YSize){return -1;}# Momchil: well worth the local var$AntialiasQuality = $this->AntialiasQuality;# Momchil: Fast path: mostly zeroes in my test cases# AntialiasQuality does not seem to be in use and is always 0# $Xleaf is always > 0 && $Yleaf > 0 => $AlphaX > 0if ($AntialiasQuality == 0) {switch(TRUE){case ($Yleaf == 0):$this->drawAlphaPixel($Xi, $Yi, (1 - $Xleaf) * $Alpha, $R, $G, $B, true);$this->drawAlphaPixel($Xi + 1, $Yi, $Xleaf * $Alpha, $R, $G, $B, true);break;case ($Xleaf == 0):$this->drawAlphaPixel($Xi, $Yi, (1 - $Yleaf) * $Alpha, $R, $G, $B, true);$this->drawAlphaPixel($Xi, $Yi + 1, $Yleaf * $Alpha, $R, $G, $B, true);break;default:$this->drawAlphaPixel($Xi, $Yi, ((1 - $Xleaf) * (1 - $Yleaf) * $Alpha), $R, $G, $B, true);$this->drawAlphaPixel($Xi + 1, $Yi, ($Xleaf * (1 - $Yleaf) * $Alpha), $R, $G, $B, true);$this->drawAlphaPixel($Xi, $Yi + 1, (1 - $Xleaf) * $Yleaf * $Alpha, $R, $G, $B, true);$this->drawAlphaPixel($Xi + 1, $Yi + 1, ($Xleaf * $Yleaf * $Alpha), $R, $G, $B, true);}} else { # Momchil: no changes here# Momchil: *100/100 seems redundand#$Alpha1 = (((1 - $Xleaf) * (1 - $Yleaf) * 100) / 100) * $Alpha;$Alpha1 = (1 - $Xleaf) * (1 - $Yleaf) * $Alpha;if ($Alpha1 > $AntialiasQuality) {$this->drawAlphaPixel($Xi, $Yi, $Alpha1, $R, $G, $B, true);}#$Alpha2 = (($Xleaf * (1 - $Yleaf) * 100) / 100) * $Alpha;$Alpha2 = $Xleaf * (1 - $Yleaf) * $Alpha;if ($Alpha2 > $AntialiasQuality) {$this->drawAlphaPixel($Xi + 1, $Yi, $Alpha2, $R, $G, $B, true);}#$Alpha3 = (((1 - $Xleaf) * $Yleaf * 100) / 100) * $Alpha;$Alpha3 = (1 - $Xleaf) * $Yleaf * $Alpha;if ($Alpha3 > $AntialiasQuality) {$this->drawAlphaPixel($Xi, $Yi + 1, $Alpha3, $R, $G, $B, true);}#$Alpha4 = (($Xleaf * $Yleaf * 100) / 100) * $Alpha;$Alpha4 = $Xleaf * $Yleaf * $Alpha;if ($Alpha4 > $AntialiasQuality) {$this->drawAlphaPixel($Xi + 1, $Yi + 1, $Alpha4, $R, $G, $B, true);}}}}/* Draw a semi-transparent pixel */function drawAlphaPixel($X, $Y, $Alpha, $R, $G, $B, $safe = FALSE){if (isset($this->Mask[$X])) {if (isset($this->Mask[$X][$Y])) {return 0;}}if ($this->Shadow) {imagesetpixel($this->Picture, $X + $this->ShadowX, $Y + $this->ShadowY, $this->allocateColor($this->ShadowR, $this->ShadowG, $this->ShadowB, floor(($Alpha / 100) * $this->Shadowa)));}if (!$safe){ # Momchil: Seems to be worth the micro optimizationif ($X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize) {return -1;}($R < 0) AND $R = 0;($R > 255) AND $R = 255;($G < 0) AND $G = 0;($G > 255) AND $G = 255;($B < 0) AND $B = 0;($B > 255) AND $B = 255;}imagesetpixel($this->Picture, $X, $Y, $this->allocateColor($R, $G, $B, $Alpha));}/* Allocate a color with transparency */function allocateColor($R, $G, $B, $Alpha = 100){if (!isset($this->aColorCache["$R.$G.$B.$Alpha"])){($R < 0) AND $R = 0;($R > 255) AND $R = 255;($G < 0) AND $G = 0;($G > 255) AND $G = 255;($B < 0) AND $B = 0;($B > 255) AND $B = 255;($Alpha < 0) AND $Alpha = 0;($Alpha > 100) AND $Alpha = 100;$this->aColorCache["$R.$G.$B.$Alpha"] = imagecolorallocatealpha($this->Picture, $R, $G, $B, (1.27 * (100 - $Alpha)));}return $this->aColorCache["$R.$G.$B.$Alpha"];}/* Load a PNG file and draw it over the chart */function drawFromPNG($X, $Y, $FileName){$this->drawFromPicture(1, $FileName, $X, $Y);}/* Load a GIF file and draw it over the chart */function drawFromGIF($X, $Y, $FileName){$this->drawFromPicture(2, $FileName, $X, $Y);}/* Load a JPEG file and draw it over the chart */function drawFromJPG($X, $Y, $FileName){$this->drawFromPicture(3, $FileName, $X, $Y);}function getPicInfo($FileName){$Infos = getimagesize($FileName);$Width = $Infos[0];$Height = $Infos[1];$Type = $Infos["mime"];($Type == "image/png") AND $Type = 1;($Type == "image/gif") AND $Type = 2;($Type == "image/jpeg") AND $Type = 3;return [$Width,$Height,$Type];}/* Generic loader function for external pictures */function drawFromPicture($PicType, $FileName, $X, $Y){if (file_exists($FileName)) {# getPicInfo returns and array of 3 elements, but the "Type" is not usedlist($Width, $Height) = $this->getPicInfo($FileName);if ($PicType == 1) {$Raster = imagecreatefrompng($FileName);} elseif ($PicType == 2) {$Raster = imagecreatefromgif($FileName);} elseif ($PicType == 3) {$Raster = imagecreatefromjpeg($FileName);} else {return 0;}$RestoreShadow = $this->Shadow;if ($this->Shadow) {$this->Shadow = FALSE;if ($PicType == 3) {$this->drawFilledRectangle($X + $this->ShadowX, $Y + $this->ShadowY, $X + $Width + $this->ShadowX, $Y + $Height + $this->ShadowY, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa]);} else {$TranparentID = imagecolortransparent($Raster);for ($Xc = 0; $Xc <= $Width - 1; $Xc++) {for ($Yc = 0; $Yc <= $Height - 1; $Yc++) {$RGBa = imagecolorat($Raster, $Xc, $Yc);$Values = imagecolorsforindex($Raster, $RGBa);if ($Values["alpha"] < 120) {$AlphaFactor = floor(($this->Shadowa / 100) * ((100 / 127) * (127 - $Values["alpha"])));$this->drawAlphaPixel($X + $Xc + $this->ShadowX, $Y + $Yc + $this->ShadowY, $AlphaFactor, $this->ShadowR, $this->ShadowG, $this->ShadowB);}}}}}$this->Shadow = $RestoreShadow;imagecopy($this->Picture, $Raster, $X, $Y, 0, 0, $Width, $Height);imagedestroy($Raster);}}/* Draw an arrow */function drawArrow($X1, $Y1, $X2, $Y2, array $Format = []){$FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0;$FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0;$FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0;$BorderR = $FillR;$BorderG = $FillG;$BorderB = $FillB;$Alpha = 100;$Size =10;$Ratio = .5;$TwoHeads = FALSE;$Ticks = FALSE;extract($Format);/* Calculate the line angle */$Angle = $this->getAngle($X1, $Y1, $X2, $Y2);$RGB = ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $Alpha];/* Override Shadow support, this will be managed internally */$RestoreShadow = $this->Shadow;if ($this->Shadow) {$this->Shadow = FALSE;$this->drawArrow($X1 + $this->ShadowX, $Y1 + $this->ShadowY, $X2 + $this->ShadowX, $Y2 + $this->ShadowY, ["FillR" => $this->ShadowR,"FillG" => $this->ShadowG,"FillB" => $this->ShadowB,"Alpha" => $this->Shadowa,"Size" => $Size,"Ratio" => $Ratio,"TwoHeads" => $TwoHeads,"Ticks" => $Ticks]);}/* Draw the 1st Head */$TailX = cos(($Angle - 180) * PI / 180) * $Size + $X2;$TailY = sin(($Angle - 180) * PI / 180) * $Size + $Y2;$Scale = $Size * $Ratio;$Points = [$X2, $Y2, cos(($Angle - 90) * PI / 180) * $Scale + $TailX, sin(($Angle - 90) * PI / 180) * $Scale + $TailY, cos(($Angle - 270) * PI / 180) * $Scale + $TailX, sin(($Angle - 270) * PI / 180) * $Scale + $TailY, $X2, $Y2];/* Visual correction */($Angle == 180 || $Angle == 360) AND $Points[4] = $Points[2];($Angle == 90 || $Angle == 270) AND $Points[5] = $Points[3];ImageFilledPolygon($this->Picture, $Points, 4, $this->allocateColor($FillR, $FillG, $FillB, $Alpha));$this->drawLine($Points[0], $Points[1], $Points[2], $Points[3], $RGB);$this->drawLine($Points[2], $Points[3], $Points[4], $Points[5], $RGB);$this->drawLine($Points[0], $Points[1], $Points[4], $Points[5], $RGB);/* Draw the second head */if ($TwoHeads) {$Angle = $this->getAngle($X2, $Y2, $X1, $Y1);$TailX2 = cos(($Angle - 180) * PI / 180) * $Size + $X1;$TailY2 = sin(($Angle - 180) * PI / 180) * $Size + $Y1;$Points = [$X1, $Y1, cos(($Angle - 90) * PI / 180) * $Scale + $TailX2, sin(($Angle - 90) * PI / 180) * $Scale + $TailY2, cos(($Angle - 270) * PI / 180) * $Scale + $TailX2, sin(($Angle - 270) * PI / 180) * $Scale + $TailY2, $X1, $Y1];/* Visual correction */($Angle == 180 || $Angle == 360) AND $Points[4] = $Points[2];($Angle == 90 || $Angle == 270) AND $Points[5] = $Points[3];ImageFilledPolygon($this->Picture, $Points, 4, $this->allocateColor($FillR, $FillG, $FillB, $Alpha));$this->drawLine($Points[0], $Points[1], $Points[2], $Points[3], $RGB);$this->drawLine($Points[2], $Points[3], $Points[4], $Points[5], $RGB);$this->drawLine($Points[0], $Points[1], $Points[4], $Points[5], $RGB);$this->drawLine($TailX, $TailY, $TailX2, $TailY2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $Alpha,"Ticks" => $Ticks]);} else {$this->drawLine($X1, $Y1, $TailX, $TailY, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $Alpha,"Ticks" => $Ticks]);}/* Re-enable shadows */$this->Shadow = $RestoreShadow;}/* Draw a label with associated arrow */function drawArrowLabel($X1, $Y1, $Text, array $Format = []){$FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0;$FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0;$FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0;$BorderR = $FillR;$BorderG = $FillG;$BorderB = $FillB;$FontName = $this->FontName;$FontSize = $this->FontSize;$Alpha = 100;$Length = 50;$Angle = 315;$Size = 10;$Position = POSITION_TOP;$RoundPos = FALSE;$Ticks = NULL;extract($Format);$Angle = $Angle % 360;$X2 = sin(($Angle + 180) * PI / 180) * $Length + $X1;$Y2 = cos(($Angle + 180) * PI / 180) * $Length + $Y1;($RoundPos && $Angle > 0 && $Angle < 180) AND $Y2 = ceil($Y2);($RoundPos && $Angle > 180) AND $Y2 = floor($Y2);$this->drawArrow($X2, $Y2, $X1, $Y1, $Format);$Size = imagettfbbox($FontSize, 0, realpath($FontName), $Text);$TxtWidth = max(abs($Size[2] - $Size[0]), abs($Size[0] - $Size[6]));#$TxtHeight = max(abs($Size[1] - $Size[7]), abs($Size[3] - $Size[1])); # UNUSED$RGB = ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $Alpha];if ($Angle > 0 && $Angle < 180) {$TxtWidth = $X2 - $TxtWidth;if ($Position == POSITION_TOP) {$RGB["Align"] = TEXT_ALIGN_BOTTOMRIGHT;$Y3 = $Y2 - 2;} else {$RGB["Align"] = TEXT_ALIGN_TOPRIGHT;$Y3 = $Y2 + 2;}} else {$TxtWidth = $X2 + $TxtWidth;if ($Position == POSITION_TOP) {$Y3 = $Y2 - 2;} else {$RGB["Align"] = TEXT_ALIGN_TOPLEFT;$Y3 = $Y2 + 2;}}$this->drawLine($X2, $Y2, $TxtWidth, $Y2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $Alpha,"Ticks" => $Ticks]);$this->drawText($X2, $Y3, $Text, $RGB);}/* Draw a progress bar filled with specified % */function drawProgress($X, $Y, $Percent, array $Format = []){($Percent > 100) AND $Percent = 100;($Percent < 0) AND $Percent = 0;$Width = 200;$Height = 20;$Orientation = ORIENTATION_HORIZONTAL;$ShowLabel = FALSE;$LabelPos = LABEL_POS_INSIDE;$Margin = 10;$R = isset($Format["R"]) ? $Format["R"] : 130;$G = isset($Format["G"]) ? $Format["G"] : 130;$B = isset($Format["B"]) ? $Format["B"] : 130;$RFade = -1;$GFade = -1;$BFade = -1;$BorderR = $R;$BorderG = $G;$BorderB = $B;$BoxBorderR = 0;$BoxBorderG = 0;$BoxBorderB = 0;$BoxBackR = 255;$BoxBackG = 255;$BoxBackB = 255;$Alpha = 100;$Surrounding = NULL;$BoxSurrounding = NULL;$NoAngle = FALSE;/* Override defaults */extract($Format);if ($RFade != - 1 && $GFade != - 1 && $BFade != - 1) {$RFade = (($RFade - $R) / 100) * $Percent + $R;$GFade = (($GFade - $G) / 100) * $Percent + $G;$BFade = (($BFade - $B) / 100) * $Percent + $B;}if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}if ($BoxSurrounding != NULL) {$BoxBorderR = $BoxBackR + $Surrounding;$BoxBorderG = $BoxBackG + $Surrounding;$BoxBorderB = $BoxBackB + $Surrounding;}if ($Orientation == ORIENTATION_VERTICAL) {$InnerHeight = (($Height - 2) / 100) * $Percent;$this->drawFilledRectangle($X, $Y, $X + $Width, $Y - $Height, ["R" => $BoxBackR,"G" => $BoxBackG,"B" => $BoxBackB,"BorderR" => $BoxBorderR,"BorderG" => $BoxBorderG,"BorderB" => $BoxBorderB,"NoAngle" => $NoAngle]);$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;if ($RFade != - 1 && $GFade != - 1 && $BFade != - 1) {$this->drawGradientArea($X + 1, $Y - 1, $X + $Width - 1, $Y - $InnerHeight, DIRECTION_VERTICAL, ["StartR" => $RFade,"StartG" => $GFade,"StartB" => $BFade,"EndR" => $R,"EndG" => $G,"EndB" => $B]);if ($Surrounding) { # != NULL, [] && ""$this->drawRectangle($X + 1, $Y - 1, $X + $Width - 1, $Y - $InnerHeight, ["R" => 255,"G" => 255,"B" => 255,"Alpha" => $Surrounding]);}} else {$this->drawFilledRectangle($X + 1, $Y - 1, $X + $Width - 1, $Y - $InnerHeight, ["R" => $R,"G" => $G,"B" => $B,"BorderR" => $BorderR,"BorderG" => $BorderG,"BorderB" => $BorderB]);}$this->Shadow = $RestoreShadow;switch (TRUE) {case ($ShowLabel && $LabelPos == LABEL_POS_BOTTOM):$this->drawText($X + ($Width / 2), $Y + $Margin, $Percent . "%", ["Align" => TEXT_ALIGN_TOPMIDDLE]);break;case ($ShowLabel && $LabelPos == LABEL_POS_TOP):$this->drawText($X + ($Width / 2), $Y - $Height - $Margin, $Percent . "%", ["Align" => TEXT_ALIGN_BOTTOMMIDDLE]);break;case ($ShowLabel && $LabelPos == LABEL_POS_INSIDE):$this->drawText($X + ($Width / 2), $Y - $InnerHeight - $Margin, $Percent . "%", ["Align" => TEXT_ALIGN_MIDDLELEFT,"Angle" => 90]);break;case ($ShowLabel && $LabelPos == LABEL_POS_CENTER):$this->drawText($X + ($Width / 2), $Y - ($Height / 2), $Percent . "%", ["Align" => TEXT_ALIGN_MIDDLEMIDDLE,"Angle" => 90]);break;}} else {$InnerWidth = ($Percent == 100) ? $Width - 1 : (($Width - 2) / 100) * $Percent;$this->drawFilledRectangle($X, $Y, $X + $Width, $Y + $Height, ["R" => $BoxBackR,"G" => $BoxBackG,"B" => $BoxBackB,"BorderR" => $BoxBorderR,"BorderG" => $BoxBorderG,"BorderB" => $BoxBorderB,"NoAngle" => $NoAngle]);$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;if ($RFade != - 1 && $GFade != - 1 && $BFade != - 1) {$this->drawGradientArea($X + 1, $Y + 1, $X + $InnerWidth, $Y + $Height - 1, DIRECTION_HORIZONTAL, ["StartR" => $R,"StartG" => $G,"StartB" => $B,"EndR" => $RFade,"EndG" => $GFade,"EndB" => $BFade]);if ($Surrounding) { # != NULL, [] && ""$this->drawRectangle($X + 1, $Y + 1, $X + $InnerWidth, $Y + $Height - 1, ["R" => 255,"G" => 255,"B" => 255,"Alpha" => $Surrounding]);}} else {$this->drawFilledRectangle($X + 1, $Y + 1, $X + $InnerWidth, $Y + $Height - 1, ["R" => $R,"G" => $G,"B" => $B,"BorderR" => $BorderR,"BorderG" => $BorderG,"BorderB" => $BorderB]);}$this->Shadow = $RestoreShadow;switch (TRUE) {case ($ShowLabel && $LabelPos == LABEL_POS_LEFT):$this->drawText($X - $Margin, $Y + ($Height / 2), $Percent . "%", ["Align" => TEXT_ALIGN_MIDDLERIGHT]);break;case ($ShowLabel && $LabelPos == LABEL_POS_RIGHT):$this->drawText($X + $Width + $Margin, $Y + ($Height / 2), $Percent . "%", ["Align" => TEXT_ALIGN_MIDDLELEFT]);break;case ($ShowLabel && $LabelPos == LABEL_POS_CENTER):$this->drawText($X + ($Width / 2), $Y + ($Height / 2), $Percent . "%", ["Align" => TEXT_ALIGN_MIDDLEMIDDLE]);break;case ($ShowLabel && $LabelPos == LABEL_POS_INSIDE):$this->drawText($X + $InnerWidth + $Margin, $Y + ($Height / 2), $Percent . "%", ["Align" => TEXT_ALIGN_MIDDLELEFT]);break;}}}/* Get the legend box size */function getLegendSize(array $Format = []){$FontName = $this->FontName;$FontSize = $this->FontSize;$BoxSize = 5;$Margin = 5;$Style = LEGEND_ROUND;$Mode = LEGEND_VERTICAL;$BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5;$BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5;$IconAreaWidth = $BoxWidth;$IconAreaHeight = $BoxHeight;$XSpacing = 5;extract($Format);$Data = $this->DataSet->getData();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] && isset($Serie["Picture"])) {list($PicWidth, $PicHeight) = $this->getPicInfo($Serie["Picture"]);($IconAreaWidth < $PicWidth) AND $IconAreaWidth = $PicWidth;($IconAreaHeight < $PicHeight) AND $IconAreaHeight = $PicHeight;}}$YStep = max($this->FontSize, $IconAreaHeight) + 5;$XStep = $IconAreaWidth + 5;$XStep = $XSpacing;$X = 100;$Y = 100;$Boundaries = ["L" => $X, "T" => $Y, "R" => 0, "B" => 0];$vY = $Y;$vX = $X;foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {if ($Mode == LEGEND_VERTICAL) {$BoxArray = $this->getTextBox($vX + $IconAreaWidth + 4, $vY + $IconAreaHeight / 2, $FontName, $FontSize, 0, $Serie["Description"]);($Boundaries["T"] > $BoxArray[2]["Y"] + $IconAreaHeight / 2) AND $Boundaries["T"] = $BoxArray[2]["Y"] + $IconAreaHeight / 2;($Boundaries["R"] < $BoxArray[1]["X"] + 2) AND $Boundaries["R"] = $BoxArray[1]["X"] + 2;($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2) AND $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2;$Lines = preg_split("/\n/", $Serie["Description"]);$vY = $vY + max($this->FontSize * count($Lines), $IconAreaHeight) + 5;} elseif ($Mode == LEGEND_HORIZONTAL) {$Lines = preg_split("/\n/", $Serie["Description"]);$Width = [];foreach($Lines as $Key => $Value) {$BoxArray = $this->getTextBox($vX + $IconAreaWidth + 6, $Y + $IconAreaHeight / 2 + (($this->FontSize + 3) * $Key), $FontName, $FontSize, 0, $Value);($Boundaries["T"] > $BoxArray[2]["Y"] + $IconAreaHeight / 2) AND $Boundaries["T"] = $BoxArray[2]["Y"] + $IconAreaHeight / 2;($Boundaries["R"] < $BoxArray[1]["X"] + 2) AND $Boundaries["R"] = $BoxArray[1]["X"] + 2;($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2) AND $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2;$Width[] = $BoxArray[1]["X"];}$vX = max($Width) + $XStep;}}}$vY = $vY - $YStep;$vX = $vX - $XStep;$TopOffset = $Y - $Boundaries["T"];($Boundaries["B"] - ($vY + $IconAreaHeight) < $TopOffset) AND $Boundaries["B"] = $vY + $IconAreaHeight + $TopOffset;$Width = ($Boundaries["R"] + $Margin) - ($Boundaries["L"] - $Margin);$Height = ($Boundaries["B"] + $Margin) - ($Boundaries["T"] - $Margin);return ["Width" => $Width,"Height" => $Height];}/* Draw the legend of the active series */function drawLegend($X, $Y, array $Format = []){$Family = LEGEND_FAMILY_BOX;$FontName = $this->FontName;$FontSize = $this->FontSize;$FontR = $this->FontColorR;$FontG = $this->FontColorG;$FontB = $this->FontColorB;$BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5;$BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5;$IconAreaWidth = $BoxWidth;$IconAreaHeight = $BoxHeight;$XSpacing = 5;$Margin = 5;$R = 200;$G = 200;$B = 200;$Alpha = 100;$BorderR = 255;$BorderG = 255;$BorderB = 255;$Surrounding = NULL;$Style = LEGEND_ROUND;$Mode = LEGEND_VERTICAL;/* Override defaults */extract($Format);if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}$Data = $this->DataSet->getData();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] && isset($Serie["Picture"])) {list($PicWidth, $PicHeight) = $this->getPicInfo($Serie["Picture"]);($IconAreaWidth < $PicWidth) AND $IconAreaWidth = $PicWidth;($IconAreaHeight < $PicHeight) AND $IconAreaHeight = $PicHeight;}}$YStep = max($this->FontSize, $IconAreaHeight) + 5;$XStep = $IconAreaWidth + 5;$XStep = $XSpacing;$Boundaries = ["L" => $X, "T" => $Y, "R" => 0, "B" => 0];$vY = $Y;$vX = $X;foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {if ($Mode == LEGEND_VERTICAL) {$BoxArray = $this->getTextBox($vX + $IconAreaWidth + 4, $vY + $IconAreaHeight / 2, $FontName, $FontSize, 0, $Serie["Description"]);($Boundaries["T"] > $BoxArray[2]["Y"] + $IconAreaHeight / 2) AND $Boundaries["T"] = $BoxArray[2]["Y"] + $IconAreaHeight / 2;($Boundaries["R"] < $BoxArray[1]["X"] + 2) AND $Boundaries["R"] = $BoxArray[1]["X"] + 2;($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2) AND $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2;$Lines = preg_split("/\n/", $Serie["Description"]);$vY = $vY + max($this->FontSize * count($Lines), $IconAreaHeight) + 5;} elseif ($Mode == LEGEND_HORIZONTAL) {$Lines = preg_split("/\n/", $Serie["Description"]);$Width = [];foreach($Lines as $Key => $Value) {$BoxArray = $this->getTextBox($vX + $IconAreaWidth + 6, $Y + $IconAreaHeight / 2 + (($this->FontSize + 3) * $Key), $FontName, $FontSize, 0, $Value);($Boundaries["T"] > $BoxArray[2]["Y"] + $IconAreaHeight / 2) AND $Boundaries["T"] = $BoxArray[2]["Y"] + $IconAreaHeight / 2;($Boundaries["R"] < $BoxArray[1]["X"] + 2) AND $Boundaries["R"] = $BoxArray[1]["X"] + 2;($Boundaries["B"] < $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2) AND $Boundaries["B"] = $BoxArray[1]["Y"] + 2 + $IconAreaHeight / 2;$Width[] = $BoxArray[1]["X"];}$vX = max($Width) + $XStep;}}}$vY = $vY - $YStep;$vX = $vX - $XStep;$TopOffset = $Y - $Boundaries["T"];($Boundaries["B"] - ($vY + $IconAreaHeight) < $TopOffset) AND $Boundaries["B"] = $vY + $IconAreaHeight + $TopOffset;if ($Style == LEGEND_ROUND) {$this->drawRoundedFilledRectangle($Boundaries["L"] - $Margin, $Boundaries["T"] - $Margin, $Boundaries["R"] + $Margin, $Boundaries["B"] + $Margin, $Margin, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"BorderR" => $BorderR,"BorderG" => $BorderG,"BorderB" => $BorderB]);} elseif ($Style == LEGEND_BOX) {$this->drawFilledRectangle($Boundaries["L"] - $Margin, $Boundaries["T"] - $Margin, $Boundaries["R"] + $Margin, $Boundaries["B"] + $Margin, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"BorderR" => $BorderR,"BorderG" => $BorderG,"BorderB" => $BorderB]);}$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Ticks = $Serie["Ticks"];$Weight = $Serie["Weight"];if (isset($Serie["Picture"])) {$Picture = $Serie["Picture"];list($PicWidth, $PicHeight) = $this->getPicInfo($Picture);$PicX = $X + $IconAreaWidth / 2;$PicY = $Y + $IconAreaHeight / 2;$this->drawFromPNG($PicX - $PicWidth / 2, $PicY - $PicHeight / 2, $Picture);} else {if ($Family == LEGEND_FAMILY_BOX) {$XOffset = ($BoxWidth != $IconAreaWidth) ? floor(($IconAreaWidth - $BoxWidth) / 2) : 0;$YOffset = ($BoxHeight != $IconAreaHeight) ? floor(($IconAreaHeight - $BoxHeight) / 2) : 0;$this->drawFilledRectangle($X + 1 + $XOffset, $Y + 1 + $YOffset, $X + $BoxWidth + $XOffset + 1, $Y + $BoxHeight + 1 + $YOffset, ["R" => 0,"G" => 0,"B" => 0,"Alpha" => 20]);$this->drawFilledRectangle($X + $XOffset, $Y + $YOffset, $X + $BoxWidth + $XOffset, $Y + $BoxHeight + $YOffset, ["R" => $R,"G" => $G,"B" => $B,"Surrounding" => 20]);} elseif ($Family == LEGEND_FAMILY_CIRCLE) {$this->drawFilledCircle($X + 1 + $IconAreaWidth / 2, $Y + 1 + $IconAreaHeight / 2, min($IconAreaHeight / 2, $IconAreaWidth / 2), ["R" => 0,"G" => 0,"B" => 0,"Alpha" => 20]);$this->drawFilledCircle($X + $IconAreaWidth / 2, $Y + $IconAreaHeight / 2, min($IconAreaHeight / 2, $IconAreaWidth / 2), ["R" => $R,"G" => $G,"B" => $B,"Surrounding" => 20]);} elseif ($Family == LEGEND_FAMILY_LINE) {$this->drawLine($X + 1, $Y + 1 + $IconAreaHeight / 2, $X + 1 + $IconAreaWidth, $Y + 1 + $IconAreaHeight / 2, ["R" => 0,"G" => 0,"B" => 0,"Alpha" => 20,"Ticks" => $Ticks,"Weight" => $Weight]);$this->drawLine($X, $Y + $IconAreaHeight / 2, $X + $IconAreaWidth, $Y + $IconAreaHeight / 2, ["R" => $R,"G" => $G,"B" => $B,"Ticks" => $Ticks,"Weight" => $Weight]);}}if ($Mode == LEGEND_VERTICAL) {$Lines = preg_split("/\n/", $Serie["Description"]);foreach($Lines as $Key => $Value) {$this->drawText($X + $IconAreaWidth + 4, $Y + $IconAreaHeight / 2 + (($this->FontSize + 3) * $Key), $Value, ["R" => $FontR,"G" => $FontG,"B" => $FontB,"Align" => TEXT_ALIGN_MIDDLELEFT,"FontSize" => $FontSize,"FontName" => $FontName]);}$Y = $Y + max($this->FontSize * count($Lines), $IconAreaHeight) + 5;} elseif ($Mode == LEGEND_HORIZONTAL) {$Lines = preg_split("/\n/", $Serie["Description"]);$Width = [];foreach($Lines as $Key => $Value) {$BoxArray = $this->drawText($X + $IconAreaWidth + 4, $Y + $IconAreaHeight / 2 + (($this->FontSize + 3) * $Key), $Value, ["R" => $FontR,"G" => $FontG,"B" => $FontB,"Align" => TEXT_ALIGN_MIDDLELEFT,"FontSize" => $FontSize,"FontName" => $FontName]);$Width[] = $BoxArray[1]["X"];}$X = max($Width) + 2 + $XStep;}}}$this->Shadow = $RestoreShadow;}function drawScale(array $Format = []){$Pos = SCALE_POS_LEFTRIGHT;$Floating = FALSE;$Mode = SCALE_MODE_FLOATING;$RemoveXAxis = FALSE;$MinDivHeight = 20;$Factors = [1,2,5];$ManualScale = array("0" => ["Min" => - 100,"Max" => 100]);$XMargin = AUTO;$YMargin = 0;$ScaleSpacing = 15;$InnerTickWidth = 2;$OuterTickWidth = 2;$DrawXLines = TRUE;$DrawYLines = isset($Format["DrawYLines"]) ? $Format["DrawYLines"] : ALL;$GridTicks = isset($Format["GridTicks"]) ? $Format["GridTicks"] : 4;$GridR = isset($Format["GridR"]) ? $Format["GridR"] : 255;$GridG = isset($Format["GridG"]) ? $Format["GridG"] : 255;$GridB = isset($Format["GridB"]) ? $Format["GridB"] : 255;$GridAlpha = isset($Format["GridAlpha"]) ? $Format["GridAlpha"] : 40;$AxisRo = isset($Format["AxisR"]) ? $Format["AxisR"] : 0;$AxisGo = isset($Format["AxisG"]) ? $Format["AxisG"] : 0;$AxisBo = isset($Format["AxisB"]) ? $Format["AxisB"] : 0;$AxisAlpha = 100;$TickRo = isset($Format["TickR"]) ? $Format["TickR"] : 0;$TickGo = isset($Format["TickG"]) ? $Format["TickG"] : 0;$TickBo = isset($Format["TickB"]) ? $Format["TickB"] : 0;$TickAlpha = isset($Format["TickAlpha"]) ? $Format["TickAlpha"] : 100;$DrawSubTicks = FALSE;$InnerSubTickWidth = 0;$OuterSubTickWidth = 2;$SubTickR = 255;$SubTickG = 0;$SubTickB = 0;$SubTickAlpha = 100;$AutoAxisLabels = TRUE;$XReleasePercent = 1;$DrawArrows = FALSE;$ArrowSize = 8;$CycleBackground = FALSE;$BackgroundR1 = 255;$BackgroundG1 = 255;$BackgroundB1 = 255;$BackgroundAlpha1 = 20;$BackgroundR2 = 230;$BackgroundG2 = 230;$BackgroundB2 = 230;$BackgroundAlpha2 = 20;$LabelingMethod = LABELING_ALL;$LabelSkip = 0;$LabelRotation = 0;$RemoveSkippedAxis = FALSE;$SkippedAxisTicks = $GridTicks + 2;$SkippedAxisR = $GridR;$SkippedAxisG = $GridG;$SkippedAxisB = $GridB;$SkippedAxisAlpha = $GridAlpha - 30;$SkippedTickR = $TickRo;$SkippedTickG = $TickGo;$SkippedTickB = $TickBo;$SkippedTickAlpha = $TickAlpha - 80;$SkippedInnerTickWidth = 0;$SkippedOuterTickWidth = 2;/* Override defaults */extract($Format);/* Floating scale require X & Y margins to be set manually */($Floating && ($XMargin == AUTO || $YMargin == 0)) AND $Floating = FALSE;/* Skip a NOTICE event in case of an empty array */($DrawYLines == NONE || $DrawYLines == FALSE) AND $DrawYLines = ["zarma" => "31"];/* Define the color for the skipped elements */$SkippedAxisColor = ["R" => $SkippedAxisR,"G" => $SkippedAxisG,"B" => $SkippedAxisB,"Alpha" => $SkippedAxisAlpha,"Ticks" => $SkippedAxisTicks];$SkippedTickColor = ["R" => $SkippedTickR,"G" => $SkippedTickG,"B" => $SkippedTickB,"Alpha" => $SkippedTickAlpha];$Data = $this->DataSet->getData();$Abscissa = (isset($Data["Abscissa"])) ? $Data["Abscissa"] : null;/* Unset the abscissa axis, needed if we display multiple charts on the same picture */if ($Abscissa != NULL) {foreach($Data["Axis"] as $AxisID => $Parameters) {if ($Parameters["Identity"] == AXIS_X) {unset($Data["Axis"][$AxisID]);}}}/* Build the scale settings */$GotXAxis = FALSE;foreach($Data["Axis"] as $AxisID => $AxisParameter) {if ($AxisParameter["Identity"] == AXIS_X) {$GotXAxis = TRUE;}if ($Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_Y) {$Height = $this->GraphAreaY2 - $this->GraphAreaY1 - $YMargin * 2;} elseif ($Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_X) {$Height = $this->GraphAreaX2 - $this->GraphAreaX1;} elseif ($Pos == SCALE_POS_TOPBOTTOM && $AxisParameter["Identity"] == AXIS_Y) {$Height = $this->GraphAreaX2 - $this->GraphAreaX1 - $YMargin * 2;;} else {$Height = $this->GraphAreaY2 - $this->GraphAreaY1;}$AxisMin = ABSOLUTE_MAX;$AxisMax = OUT_OF_SIGHT;if ($Mode == SCALE_MODE_FLOATING || $Mode == SCALE_MODE_START0) {foreach($Data["Series"] as $SerieID => $SerieParameter) {if ($SerieParameter["Axis"] == $AxisID && $Data["Series"][$SerieID]["isDrawable"] && $Data["Abscissa"] != $SerieID) {if (!is_numeric($Data["Series"][$SerieID]["Max"]) || !is_numeric($Data["Series"][$SerieID]["Min"])){die("Series ".$SerieID.": non-numeric input");}$AxisMax = max($AxisMax, $Data["Series"][$SerieID]["Max"]);$AxisMin = min($AxisMin, $Data["Series"][$SerieID]["Min"]);}}(!is_numeric($AxisMin)) AND $AxisMin = 1; // $Data["Series"][$SerieID]["Min"] = Bulgium # MOMCHIL$AutoMargin = (($AxisMax - $AxisMin) / 100) * $XReleasePercent;$Data["Axis"][$AxisID]["Min"] = $AxisMin - $AutoMargin;$Data["Axis"][$AxisID]["Max"] = $AxisMax + $AutoMargin;if ($Mode == SCALE_MODE_START0) {$Data["Axis"][$AxisID]["Min"] = 0;}} elseif ($Mode == SCALE_MODE_MANUAL) {if (isset($ManualScale[$AxisID]["Min"]) && isset($ManualScale[$AxisID]["Max"])) {$Data["Axis"][$AxisID]["Min"] = $ManualScale[$AxisID]["Min"];$Data["Axis"][$AxisID]["Max"] = $ManualScale[$AxisID]["Max"];} else {echo "Manual scale boundaries not set.";exit();}} elseif ($Mode == SCALE_MODE_ADDALL || $Mode == SCALE_MODE_ADDALL_START0) {$Series = [];foreach($Data["Series"] as $SerieID => $SerieParameter) {if ($SerieParameter["Axis"] == $AxisID && $SerieParameter["isDrawable"] && $Data["Abscissa"] != $SerieID) {$Series[$SerieID] = count($Data["Series"][$SerieID]["Data"]);}}for ($ID = 0; $ID <= max($Series) - 1; $ID++) {$PointMin = 0;$PointMax = 0;foreach($Series as $SerieID => $ValuesCount) {if (isset($Data["Series"][$SerieID]["Data"][$ID]) && $Data["Series"][$SerieID]["Data"][$ID] != NULL) {$Value = $Data["Series"][$SerieID]["Data"][$ID];if ($Value > 0) {$PointMax = $PointMax + $Value;} else {$PointMin = $PointMin + $Value;}}}$AxisMax = max($AxisMax, $PointMax);$AxisMin = min($AxisMin, $PointMin);}$AutoMargin = (($AxisMax - $AxisMin) / 100) * $XReleasePercent;$Data["Axis"][$AxisID]["Min"] = $AxisMin - $AutoMargin;$Data["Axis"][$AxisID]["Max"] = $AxisMax + $AutoMargin;}$MaxDivs = floor($Height / $MinDivHeight);if ($Mode == SCALE_MODE_ADDALL_START0) {$Data["Axis"][$AxisID]["Min"] = 0;}$Scale = $this->computeScale($Data["Axis"][$AxisID]["Min"], $Data["Axis"][$AxisID]["Max"], $MaxDivs, $Factors, $AxisID);$Data["Axis"][$AxisID]["Margin"] = $AxisParameter["Identity"] == AXIS_X ? $XMargin : $YMargin;$Data["Axis"][$AxisID]["ScaleMin"] = $Scale["XMin"];$Data["Axis"][$AxisID]["ScaleMax"] = $Scale["XMax"];$Data["Axis"][$AxisID]["Rows"] = $Scale["Rows"];$Data["Axis"][$AxisID]["RowHeight"] = $Scale["RowHeight"];(isset($Scale["Format"])) AND $Data["Axis"][$AxisID]["Format"] = $Scale["Format"];(!isset($Data["Axis"][$AxisID]["Display"])) AND $Data["Axis"][$AxisID]["Display"] = NULL;(!isset($Data["Axis"][$AxisID]["Format"])) AND $Data["Axis"][$AxisID]["Format"] = NULL;(!isset($Data["Axis"][$AxisID]["Unit"])) AND $Data["Axis"][$AxisID]["Unit"] = NULL;}/* Still no X axis */if ($GotXAxis == FALSE) {if ($Abscissa != NULL) {$Points = count($Data["Series"][$Abscissa]["Data"]);if ($AutoAxisLabels) {$AxisName = isset($Data["Series"][$Abscissa]["Description"]) ? $Data["Series"][$Abscissa]["Description"] : NULL;} else {$AxisName = NULL;}} else {$Points = 0;$AxisName = isset($Data["XAxisName"]) ? $Data["XAxisName"] : NULL;foreach($Data["Series"] as $SerieID => $SerieParameter) {if ($SerieParameter["isDrawable"]) {$Points = max($Points, count($SerieParameter["Data"]));}}}$AxisID = count($Data["Axis"]);$Data["Axis"][$AxisID]["Identity"] = AXIS_X;$Data["Axis"][$AxisID]["Position"] = ($Pos == SCALE_POS_LEFTRIGHT) ? AXIS_POSITION_BOTTOM : AXIS_POSITION_LEFT;(isset($Data["AbscissaName"])) AND $Data["Axis"][$AxisID]["Name"] = $Data["AbscissaName"];if ($XMargin == AUTO) {$Height = ($Pos == SCALE_POS_LEFTRIGHT) ? $this->GraphAreaX2 - $this->GraphAreaX1 : $this->GraphAreaY2 - $this->GraphAreaY1;$Data["Axis"][$AxisID]["Margin"] = ($Points == 1) ? ($Height / 2) : (($Height / $Points) / 2);} else {$Data["Axis"][$AxisID]["Margin"] = $XMargin;}$Data["Axis"][$AxisID]["Rows"] = $Points - 1;(!isset($Data["Axis"][$AxisID]["Display"])) AND $Data["Axis"][$AxisID]["Display"] = NULL;(!isset($Data["Axis"][$AxisID]["Format"])) AND $Data["Axis"][$AxisID]["Format"] = NULL;(!isset($Data["Axis"][$AxisID]["Unit"])) AND $Data["Axis"][$AxisID]["Unit"] = NULL;}/* Do we need to reverse the abscissa position? */if ($Pos != SCALE_POS_LEFTRIGHT) {$Data["AbsicssaPosition"] = ($Data["AbsicssaPosition"] == AXIS_POSITION_BOTTOM) ? AXIS_POSITION_LEFT : AXIS_POSITION_RIGHT;}$Data["Axis"][$AxisID]["Position"] = $Data["AbsicssaPosition"];$this->DataSet->saveOrientation($Pos);$this->DataSet->saveAxisConfig($Data["Axis"]);$this->DataSet->saveYMargin($YMargin);$FontColorRo = $this->FontColorR;$FontColorGo = $this->FontColorG;$FontColorBo = $this->FontColorB;$AxisPos["L"] = $this->GraphAreaX1;$AxisPos["R"] = $this->GraphAreaX2;$AxisPos["T"] = $this->GraphAreaY1;$AxisPos["B"] = $this->GraphAreaY2;foreach($Data["Axis"] as $AxisID => $Parameters) {if (isset($Parameters["Color"])) {$AxisR = $Parameters["Color"]["R"];$AxisG = $Parameters["Color"]["G"];$AxisB = $Parameters["Color"]["B"];$TickR = $Parameters["Color"]["R"];$TickG = $Parameters["Color"]["G"];$TickB = $Parameters["Color"]["B"];$this->setFontProperties(["R" => $Parameters["Color"]["R"],"G" => $Parameters["Color"]["G"],"B" => $Parameters["Color"]["B"]]);} else {$AxisR = $AxisRo;$AxisG = $AxisGo;$AxisB = $AxisBo;$TickR = $TickRo;$TickG = $TickGo;$TickB = $TickBo;$this->setFontProperties(["R" => $FontColorRo,"G" => $FontColorGo,"B" => $FontColorBo]);}$LastValue = "w00t";$ID = 1;if ($Parameters["Identity"] == AXIS_X) {if ($Pos == SCALE_POS_LEFTRIGHT) {if ($Parameters["Position"] == AXIS_POSITION_BOTTOM) {switch(TRUE){case ($LabelRotation == 0):$LabelAlign = TEXT_ALIGN_TOPMIDDLE;$YLabelOffset = 2;break;case ($LabelRotation > 0 && $LabelRotation < 190):$LabelAlign = TEXT_ALIGN_MIDDLERIGHT;$YLabelOffset = 5;break;case ($LabelRotation == 180):$LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE;$YLabelOffset = 5;break;case ($LabelRotation > 180 && $LabelRotation < 360):$LabelAlign = TEXT_ALIGN_MIDDLELEFT;$YLabelOffset = 2;break;}if (!$RemoveXAxis) {if ($Floating) {$FloatingOffset = $YMargin;$this->drawLine($this->GraphAreaX1 + $Parameters["Margin"], $AxisPos["B"], $this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["B"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($this->GraphAreaX1, $AxisPos["B"], $this->GraphAreaX2, $AxisPos["B"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["B"], $this->GraphAreaX2 + ($ArrowSize * 2), $AxisPos["B"], ["FillR" => $AxisR,"FillG" => $AxisG,"FillB" => $AxisB,"Size" => $ArrowSize]);}}$Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2;$Step = ($Parameters["Rows"] == 0) ? $Width : $Width / ($Parameters["Rows"]);$MaxBottom = $AxisPos["B"];for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i;$YPos = $AxisPos["B"];if ($Abscissa != NULL) {if (isset($Data["Series"][$Abscissa]["Data"][$i])) {$Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i], $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = "";}} else {if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) {$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = $i;}}$ID++;$Skipped = TRUE;if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) && !$RemoveXAxis) {$Bounds = $this->drawText($XPos, $YPos + $OuterTickWidth + $YLabelOffset, $Value, ["Angle" => $LabelRotation,"Align" => $LabelAlign]);$TxtBottom = $YPos + $OuterTickWidth + 2 + ($Bounds[0]["Y"] - $Bounds[2]["Y"]);$MaxBottom = max($MaxBottom, $TxtBottom);$LastValue = $Value;$Skipped = FALSE;}($RemoveXAxis) AND $Skipped = FALSE;if ($Skipped) {if ($DrawXLines && !$RemoveSkippedAxis) {$this->drawLine($XPos, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, $SkippedAxisColor);}if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis) {$this->drawLine($XPos, $YPos - $SkippedInnerTickWidth, $XPos, $YPos + $SkippedOuterTickWidth, $SkippedTickColor);}} else {if ($DrawXLines && ($XPos != $this->GraphAreaX1 && $XPos != $this->GraphAreaX2)) {$this->drawLine($XPos, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) {$this->drawLine($XPos, $YPos - $InnerTickWidth, $XPos, $YPos + $OuterTickWidth, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);}}}if (isset($Parameters["Name"]) && !$RemoveXAxis) {$YPos = $MaxBottom + 2;$XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_TOPMIDDLE]);$MaxBottom = $Bounds[0]["Y"];$this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize;}$AxisPos["B"] = $MaxBottom + $ScaleSpacing;} elseif ($Parameters["Position"] == AXIS_POSITION_TOP) {switch(TRUE){case ($LabelRotation == 0):$LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE;$YLabelOffset = 2;break;case ($LabelRotation > 0 && $LabelRotation < 190):$LabelAlign = TEXT_ALIGN_MIDDLELEFT;$YLabelOffset = 2;break;case ($LabelRotation == 180):$LabelAlign = TEXT_ALIGN_TOPMIDDLE;$YLabelOffset = 5;break;case ($LabelRotation > 180 && $LabelRotation < 360):$LabelAlign = TEXT_ALIGN_MIDDLERIGHT;$YLabelOffset = 5;break;}if (!$RemoveXAxis) {if ($Floating) {$FloatingOffset = $YMargin;$this->drawLine($this->GraphAreaX1 + $Parameters["Margin"], $AxisPos["T"], $this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["T"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($this->GraphAreaX1, $AxisPos["T"], $this->GraphAreaX2, $AxisPos["T"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["T"], $this->GraphAreaX2 + ($ArrowSize * 2), $AxisPos["T"],["FillR" => $AxisR,"FillG" => $AxisG,"FillB" => $AxisB,"Size" => $ArrowSize]);}}$Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2;$Step = ($Parameters["Rows"] == 0) ? $Width : $Width / $Parameters["Rows"];$MinTop = $AxisPos["T"];for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i;$YPos = $AxisPos["T"];if ($Abscissa != NULL) {if (isset($Data["Series"][$Abscissa]["Data"][$i])) {$Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i], $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = "";}} else {if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) {$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = $i;}}$ID++;$Skipped = TRUE;if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) && !$RemoveXAxis) {$Bounds = $this->drawText($XPos, $YPos - $OuterTickWidth - $YLabelOffset, $Value, ["Angle" => $LabelRotation,"Align" => $LabelAlign]);$TxtBox = $YPos - $OuterTickWidth - 2 - ($Bounds[0]["Y"] - $Bounds[2]["Y"]);$MinTop = min($MinTop, $TxtBox);$LastValue = $Value;$Skipped = FALSE;}($RemoveXAxis) AND $Skipped = FALSE;if ($Skipped) {if ($DrawXLines && !$RemoveSkippedAxis) {$this->drawLine($XPos, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, $SkippedAxisColor);}if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis) {$this->drawLine($XPos, $YPos + $SkippedInnerTickWidth, $XPos, $YPos - $SkippedOuterTickWidth, $SkippedTickColor);}} else {if ($DrawXLines) {$this->drawLine($XPos, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) {$this->drawLine($XPos, $YPos + $InnerTickWidth, $XPos, $YPos - $OuterTickWidth, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);}}}if (isset($Parameters["Name"]) && !$RemoveXAxis) {$YPos = $MinTop - 2;$XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_BOTTOMMIDDLE]);$MinTop = $Bounds[2]["Y"];$this->DataSet->Data["GraphArea"]["Y1"] = $MinTop;}$AxisPos["T"] = $MinTop - $ScaleSpacing;}} elseif ($Pos == SCALE_POS_TOPBOTTOM) {if ($Parameters["Position"] == AXIS_POSITION_LEFT) {switch(TRUE){case ($LabelRotation == 0):$LabelAlign = TEXT_ALIGN_MIDDLERIGHT;$XLabelOffset = - 2;break;case ($LabelRotation > 0 && $LabelRotation < 190):$LabelAlign = TEXT_ALIGN_MIDDLERIGHT;$XLabelOffset = - 6;break;case ($LabelRotation == 180):$LabelAlign = TEXT_ALIGN_MIDDLELEFT;$XLabelOffset = - 2;break;case ($LabelRotation > 180 && $LabelRotation < 360):$LabelAlign = TEXT_ALIGN_MIDDLELEFT;$XLabelOffset = - 5;break;}if (!$RemoveXAxis) {if ($Floating) {$FloatingOffset = $YMargin;$this->drawLine($AxisPos["L"], $this->GraphAreaY1 + $Parameters["Margin"], $AxisPos["L"], $this->GraphAreaY2 - $Parameters["Margin"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($AxisPos["L"], $this->GraphAreaY1, $AxisPos["L"], $this->GraphAreaY2, ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($AxisPos["L"], $this->GraphAreaY2 - $Parameters["Margin"], $AxisPos["L"], $this->GraphAreaY2 + ($ArrowSize * 2), ["FillR" => $AxisR,"FillG" => $AxisG,"FillB" => $AxisB,"Size" => $ArrowSize]);}}$Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2;$Step = ($Parameters["Rows"] == 0) ? $Height : $Height / $Parameters["Rows"];$MinLeft = $AxisPos["L"];for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step * $i;$XPos = $AxisPos["L"];if ($Abscissa != NULL) {if (isset($Data["Series"][$Abscissa]["Data"][$i])) {$Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i], $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = "";}} else {if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) {$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = $i;}}$ID++;$Skipped = TRUE;if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) && !$RemoveXAxis) {$Bounds = $this->drawText($XPos - $OuterTickWidth + $XLabelOffset, $YPos, $Value, ["Angle" => $LabelRotation,"Align" => $LabelAlign]);$TxtBox = $XPos - $OuterTickWidth - 2 - ($Bounds[1]["X"] - $Bounds[0]["X"]);$MinLeft = min($MinLeft, $TxtBox);$LastValue = $Value;$Skipped = FALSE;}($RemoveXAxis) AND $Skipped = FALSE;if ($Skipped) {if ($DrawXLines && !$RemoveSkippedAxis) {$this->drawLine($this->GraphAreaX1 + $FloatingOffset, $YPos, $this->GraphAreaX2 - $FloatingOffset, $YPos, $SkippedAxisColor);}if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis) {$this->drawLine($XPos - $SkippedOuterTickWidth, $YPos, $XPos + $SkippedInnerTickWidth, $YPos, $SkippedTickColor);}} else {if ($DrawXLines && ($YPos != $this->GraphAreaY1 && $YPos != $this->GraphAreaY2)) {$this->drawLine($this->GraphAreaX1 + $FloatingOffset, $YPos, $this->GraphAreaX2 - $FloatingOffset, $YPos, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) {$this->drawLine($XPos - $OuterTickWidth, $YPos, $XPos + $InnerTickWidth, $YPos, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);}}}if (isset($Parameters["Name"]) && !$RemoveXAxis) {$XPos = $MinLeft - 2;$YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_BOTTOMMIDDLE,"Angle" => 90]);$MinLeft = $Bounds[0]["X"];$this->DataSet->Data["GraphArea"]["X1"] = $MinLeft;}$AxisPos["L"] = $MinLeft - $ScaleSpacing;} elseif ($Parameters["Position"] == AXIS_POSITION_RIGHT) {switch(TRUE){case ($LabelRotation == 0):$LabelAlign = TEXT_ALIGN_MIDDLELEFT;$XLabelOffset = 2;break;case ($LabelRotation > 0 && $LabelRotation < 190):$LabelAlign = TEXT_ALIGN_MIDDLELEFT;$XLabelOffset = 6;break;case ($LabelRotation == 180):$LabelAlign = TEXT_ALIGN_MIDDLERIGHT;$XLabelOffset = 5;break;case ($LabelRotation > 180 && $LabelRotation < 360):$LabelAlign = TEXT_ALIGN_MIDDLERIGHT;$XLabelOffset = 7;break;}if (!$RemoveXAxis) {if ($Floating) {$FloatingOffset = $YMargin;$this->drawLine($AxisPos["R"], $this->GraphAreaY1 + $Parameters["Margin"], $AxisPos["R"], $this->GraphAreaY2 - $Parameters["Margin"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($AxisPos["R"], $this->GraphAreaY1, $AxisPos["R"], $this->GraphAreaY2, ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($AxisPos["R"], $this->GraphAreaY2 - $Parameters["Margin"], $AxisPos["R"], $this->GraphAreaY2 + ($ArrowSize * 2), ["FillR" => $AxisR,"FillG" => $AxisG,"FillB" => $AxisB,"Size" => $ArrowSize]);}}$Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2;$Step = ($Parameters["Rows"] == 0) ? $Height : $Height / $Parameters["Rows"];$MaxRight = $AxisPos["R"];for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step * $i;$XPos = $AxisPos["R"];if ($Abscissa != NULL) {if (isset($Data["Series"][$Abscissa]["Data"][$i])) {$Value = $this->scaleFormat($Data["Series"][$Abscissa]["Data"][$i], $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = "";}} else {if (isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) {$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Data["XAxisDisplay"], $Data["XAxisFormat"], $Data["XAxisUnit"]);} else {$Value = $i;}}$ID++;$Skipped = TRUE;if ($this->isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip) && !$RemoveXAxis) {$Bounds = $this->drawText($XPos + $OuterTickWidth + $XLabelOffset, $YPos, $Value, ["Angle" => $LabelRotation,"Align" => $LabelAlign]);$TxtBox = $XPos + $OuterTickWidth + 2 + ($Bounds[1]["X"] - $Bounds[0]["X"]);$MaxRight = max($MaxRight, $TxtBox);$LastValue = $Value;$Skipped = FALSE;}($RemoveXAxis) AND $Skipped = FALSE;if ($Skipped) {if ($DrawXLines && !$RemoveSkippedAxis) {$this->drawLine($this->GraphAreaX1 + $FloatingOffset, $YPos, $this->GraphAreaX2 - $FloatingOffset, $YPos, $SkippedAxisColor);}if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) && !$RemoveXAxis && !$RemoveSkippedAxis) {$this->drawLine($XPos + $SkippedOuterTickWidth, $YPos, $XPos - $SkippedInnerTickWidth, $YPos, $SkippedTickColor);}} else {if ($DrawXLines) {$this->drawLine($this->GraphAreaX1 + $FloatingOffset, $YPos, $this->GraphAreaX2 - $FloatingOffset, $YPos, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis) {$this->drawLine($XPos + $OuterTickWidth, $YPos, $XPos - $InnerTickWidth, $YPos, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);}}}if (isset($Parameters["Name"]) && !$RemoveXAxis) {$XPos = $MaxRight + 4;$YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_BOTTOMMIDDLE,"Angle" => 270]);$MaxRight = $Bounds[1]["X"];$this->DataSet->Data["GraphArea"]["X2"] = $MaxRight + $this->FontSize;}$AxisPos["R"] = $MaxRight + $ScaleSpacing;}}} elseif ($Parameters["Identity"] == AXIS_Y) {if ($Pos == SCALE_POS_LEFTRIGHT) {if ($Parameters["Position"] == AXIS_POSITION_LEFT) {if ($Floating) {$FloatingOffset = $XMargin;$this->drawLine($AxisPos["L"], $this->GraphAreaY1 + $Parameters["Margin"], $AxisPos["L"], $this->GraphAreaY2 - $Parameters["Margin"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($AxisPos["L"], $this->GraphAreaY1, $AxisPos["L"], $this->GraphAreaY2, ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($AxisPos["L"], $this->GraphAreaY1 + $Parameters["Margin"], $AxisPos["L"], $this->GraphAreaY1 - ($ArrowSize * 2), ["FillR" => $AxisR,"FillG" => $AxisG,"FillB" => $AxisB,"Size" => $ArrowSize]);}$Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2;$Step = $Height / $Parameters["Rows"];$SubTicksSize = $Step / 2;$MinLeft = $AxisPos["L"];$LastY = NULL;for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step * $i;$XPos = $AxisPos["L"];$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Parameters["Display"], $Parameters["Format"], $Parameters["Unit"]);if ($i % 2 == 1) {$BGColor = ["R" => $BackgroundR1,"G" => $BackgroundG1,"B" => $BackgroundB1,"Alpha" => $BackgroundAlpha1];} else {$BGColor = ["R" => $BackgroundR2,"G" => $BackgroundG2,"B" => $BackgroundB2,"Alpha" => $BackgroundAlpha2];}if ($LastY != NULL && $CycleBackground && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines))) {$this->drawFilledRectangle($this->GraphAreaX1 + $FloatingOffset, $LastY, $this->GraphAreaX2 - $FloatingOffset, $YPos, $BGColor);}if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) {$this->drawLine($this->GraphAreaX1 + $FloatingOffset, $YPos, $this->GraphAreaX2 - $FloatingOffset, $YPos, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if ($DrawSubTicks && $i != $Parameters["Rows"]) {$this->drawLine($XPos - $OuterSubTickWidth, $YPos - $SubTicksSize, $XPos + $InnerSubTickWidth, $YPos - $SubTicksSize, ["R" => $SubTickR,"G" => $SubTickG,"B" => $SubTickB,"Alpha" => $SubTickAlpha]);}$this->drawLine($XPos - $OuterTickWidth, $YPos, $XPos + $InnerTickWidth, $YPos, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);$Bounds = $this->drawText($XPos - $OuterTickWidth - 2, $YPos, $Value, ["Align" => TEXT_ALIGN_MIDDLERIGHT]);$TxtLeft = $XPos - $OuterTickWidth - 2 - ($Bounds[1]["X"] - $Bounds[0]["X"]);$MinLeft = min($MinLeft, $TxtLeft);$LastY = $YPos;}if (isset($Parameters["Name"])) {$XPos = $MinLeft - 2;$YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_BOTTOMMIDDLE,"Angle" => 90]);$MinLeft = $Bounds[2]["X"];$this->DataSet->Data["GraphArea"]["X1"] = $MinLeft;}$AxisPos["L"] = $MinLeft - $ScaleSpacing;} elseif ($Parameters["Position"] == AXIS_POSITION_RIGHT) {if ($Floating) {$FloatingOffset = $XMargin;$this->drawLine($AxisPos["R"], $this->GraphAreaY1 + $Parameters["Margin"], $AxisPos["R"], $this->GraphAreaY2 - $Parameters["Margin"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($AxisPos["R"], $this->GraphAreaY1, $AxisPos["R"], $this->GraphAreaY2, ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($AxisPos["R"], $this->GraphAreaY1 + $Parameters["Margin"], $AxisPos["R"], $this->GraphAreaY1 - ($ArrowSize * 2), ["FillR" => $AxisR,"FillG" => $AxisG, "FillB" => $AxisB,"Size" => $ArrowSize]);}$Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"] * 2;$Step = $Height / $Parameters["Rows"];$SubTicksSize = $Step / 2;$MaxLeft = $AxisPos["R"];$LastY = NULL;for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step * $i;$XPos = $AxisPos["R"];$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Parameters["Display"], $Parameters["Format"], $Parameters["Unit"]);if ($i % 2 == 1) {$BGColor = ["R" => $BackgroundR1,"G" => $BackgroundG1,"B" => $BackgroundB1,"Alpha" => $BackgroundAlpha1];} else {$BGColor = ["R" => $BackgroundR2,"G" => $BackgroundG2,"B" => $BackgroundB2,"Alpha" => $BackgroundAlpha2];}if ($LastY != NULL && $CycleBackground && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines))) {$this->drawFilledRectangle($this->GraphAreaX1 + $FloatingOffset, $LastY, $this->GraphAreaX2 - $FloatingOffset, $YPos, $BGColor);}if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) {$this->drawLine($this->GraphAreaX1 + $FloatingOffset, $YPos, $this->GraphAreaX2 - $FloatingOffset, $YPos, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if ($DrawSubTicks && $i != $Parameters["Rows"]) {$this->drawLine($XPos - $OuterSubTickWidth, $YPos - $SubTicksSize, $XPos + $InnerSubTickWidth, $YPos - $SubTicksSize, ["R" => $SubTickR,"G" => $SubTickG,"B" => $SubTickB,"Alpha" => $SubTickAlpha]);}$this->drawLine($XPos - $InnerTickWidth, $YPos, $XPos + $OuterTickWidth, $YPos, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);$Bounds = $this->drawText($XPos + $OuterTickWidth + 2, $YPos, $Value, ["Align" => TEXT_ALIGN_MIDDLELEFT]);$TxtLeft = $XPos + $OuterTickWidth + 2 + ($Bounds[1]["X"] - $Bounds[0]["X"]);$MaxLeft = max($MaxLeft, $TxtLeft);$LastY = $YPos;}if (isset($Parameters["Name"])) {$XPos = $MaxLeft + 6;$YPos = $this->GraphAreaY1 + ($this->GraphAreaY2 - $this->GraphAreaY1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_BOTTOMMIDDLE,"Angle" => 270]);$MaxLeft = $Bounds[2]["X"];$this->DataSet->Data["GraphArea"]["X2"] = $MaxLeft + $this->FontSize;}$AxisPos["R"] = $MaxLeft + $ScaleSpacing;}} elseif ($Pos == SCALE_POS_TOPBOTTOM) {if ($Parameters["Position"] == AXIS_POSITION_TOP) {if ($Floating) {$FloatingOffset = $XMargin;$this->drawLine($this->GraphAreaX1 + $Parameters["Margin"], $AxisPos["T"], $this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["T"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($this->GraphAreaX1, $AxisPos["T"], $this->GraphAreaX2, $AxisPos["T"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["T"], $this->GraphAreaX2 + ($ArrowSize * 2), $AxisPos["T"], ["FillR" => $AxisR,"FillG" => $AxisG, "FillB" => $AxisB,"Size" => $ArrowSize]);}$Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2;$Step = $Width / $Parameters["Rows"];$SubTicksSize = $Step / 2;$MinTop = $AxisPos["T"];$LastX = NULL;for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i;$YPos = $AxisPos["T"];$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Parameters["Display"], $Parameters["Format"], $Parameters["Unit"]);if ($i % 2 == 1) {$BGColor = $BGColor = ["R" => $BackgroundR1,"G" => $BackgroundG1,"B" => $BackgroundB1,"Alpha" => $BackgroundAlpha1];} else {$BGColor = ["R" => $BackgroundR2,"G" => $BackgroundG2,"B" => $BackgroundB2,"Alpha" => $BackgroundAlpha2];}if ($LastX != NULL && $CycleBackground && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines))) {$this->drawFilledRectangle($LastX, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, $BGColor);}if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) {$this->drawLine($XPos, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if ($DrawSubTicks && $i != $Parameters["Rows"]) {$this->drawLine($XPos + $SubTicksSize, $YPos - $OuterSubTickWidth, $XPos + $SubTicksSize, $YPos + $InnerSubTickWidth, ["R" => $SubTickR,"G" => $SubTickG,"B" => $SubTickB,"Alpha" => $SubTickAlpha]);}$this->drawLine($XPos, $YPos - $OuterTickWidth, $XPos, $YPos + $InnerTickWidth, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);$Bounds = $this->drawText($XPos, $YPos - $OuterTickWidth - 2, $Value, ["Align" => TEXT_ALIGN_BOTTOMMIDDLE]);$TxtHeight = $YPos - $OuterTickWidth - 2 - ($Bounds[1]["Y"] - $Bounds[2]["Y"]);$MinTop = min($MinTop, $TxtHeight);$LastX = $XPos;}if (isset($Parameters["Name"])) {$YPos = $MinTop - 2;$XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_BOTTOMMIDDLE]);$MinTop = $Bounds[2]["Y"];$this->DataSet->Data["GraphArea"]["Y1"] = $MinTop;}$AxisPos["T"] = $MinTop - $ScaleSpacing;} elseif ($Parameters["Position"] == AXIS_POSITION_BOTTOM) {if ($Floating) {$FloatingOffset = $XMargin;$this->drawLine($this->GraphAreaX1 + $Parameters["Margin"], $AxisPos["B"], $this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["B"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);} else {$FloatingOffset = 0;$this->drawLine($this->GraphAreaX1, $AxisPos["B"], $this->GraphAreaX2, $AxisPos["B"], ["R" => $AxisR,"G" => $AxisG,"B" => $AxisB,"Alpha" => $AxisAlpha]);}if ($DrawArrows) {$this->drawArrow($this->GraphAreaX2 - $Parameters["Margin"], $AxisPos["B"], $this->GraphAreaX2 + ($ArrowSize * 2), $AxisPos["B"], ["FillR" => $AxisR,"FillG" => $AxisG, "FillB" => $AxisB,"Size" => $ArrowSize]);}$Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"] * 2;$Step = $Width / $Parameters["Rows"];$SubTicksSize = $Step / 2;$MaxBottom = $AxisPos["B"];$LastX = NULL;for ($i = 0; $i <= $Parameters["Rows"]; $i++) {$XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step * $i;$YPos = $AxisPos["B"];$Value = $this->scaleFormat($Parameters["ScaleMin"] + $Parameters["RowHeight"] * $i, $Parameters["Display"], $Parameters["Format"], $Parameters["Unit"]);if ($i % 2 == 1) {$BGColor = ["R" => $BackgroundR1,"G" => $BackgroundG1,"B" => $BackgroundB1,"Alpha" => $BackgroundAlpha1];} else {$BGColor = ["R" => $BackgroundR2,"G" => $BackgroundG2,"B" => $BackgroundB2,"Alpha" => $BackgroundAlpha2];}if ($LastX != NULL && $CycleBackground && ($DrawYLines == ALL || in_array($AxisID, $DrawYLines))) {$this->drawFilledRectangle($LastX, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, $BGColor);}if ($DrawYLines == ALL || in_array($AxisID, $DrawYLines)) {$this->drawLine($XPos, $this->GraphAreaY1 + $FloatingOffset, $XPos, $this->GraphAreaY2 - $FloatingOffset, ["R" => $GridR,"G" => $GridG,"B" => $GridB,"Alpha" => $GridAlpha,"Ticks" => $GridTicks]);}if ($DrawSubTicks && $i != $Parameters["Rows"]) {$this->drawLine($XPos + $SubTicksSize, $YPos - $OuterSubTickWidth, $XPos + $SubTicksSize, $YPos + $InnerSubTickWidth, ["R" => $SubTickR,"G" => $SubTickG,"B" => $SubTickB,"Alpha" => $SubTickAlpha]);}$this->drawLine($XPos, $YPos - $OuterTickWidth, $XPos, $YPos + $InnerTickWidth, ["R" => $TickR,"G" => $TickG,"B" => $TickB,"Alpha" => $TickAlpha]);$Bounds = $this->drawText($XPos, $YPos + $OuterTickWidth + 2, $Value, ["Align" => TEXT_ALIGN_TOPMIDDLE]);$TxtHeight = $YPos + $OuterTickWidth + 2 + ($Bounds[1]["Y"] - $Bounds[2]["Y"]);$MaxBottom = max($MaxBottom, $TxtHeight);$LastX = $XPos;}if (isset($Parameters["Name"])) {$YPos = $MaxBottom + 2;$XPos = $this->GraphAreaX1 + ($this->GraphAreaX2 - $this->GraphAreaX1) / 2;$Bounds = $this->drawText($XPos, $YPos, $Parameters["Name"], ["Align" => TEXT_ALIGN_TOPMIDDLE]);$MaxBottom = $Bounds[0]["Y"];$this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize;}$AxisPos["B"] = $MaxBottom + $ScaleSpacing;}}}}}function isValidLabel($Value, $LastValue, $LabelingMethod, $ID, $LabelSkip){$ret = TRUE;switch(TRUE){case ($LabelingMethod == LABELING_DIFFERENT && $Value != $LastValue):break;case ($LabelingMethod == LABELING_DIFFERENT && $Value == $LastValue):$ret = FALSE;break;case ($LabelingMethod == LABELING_ALL && $LabelSkip == 0):break;case ($LabelingMethod == LABELING_ALL && ($ID + $LabelSkip) % ($LabelSkip + 1) != 1):$ret = FALSE;break;}return $ret;}/* Compute the scale, check for the best visual factors */function computeScale($XMin, $XMax, $MaxDivs, $Factors, $AxisID = 0){/* Compute each factors */$Results = [];foreach($Factors as $Key => $Factor) {$Results[$Factor] = $this->processScale($XMin, $XMax, $MaxDivs, [$Factor], $AxisID);}/* Remove scales that are creating to much decimals */$GoodScaleFactors = [];foreach($Results as $Key => $Result) {$Decimals = explode(".", $Result["RowHeight"]);if ((!isset($Decimals[1])) || (strlen($Decimals[1]) < 6)) {$GoodScaleFactors[] = $Key;}}/* Found no correct scale, shame,... returns the 1st one as default */// if ( $GoodScaleFactors == "" ) { return($Results[$Factors[0]]); }if (count($GoodScaleFactors) == 0) {return $Results[$Factors[0]];}/* Find the factor that cause the maximum number of Rows */$MaxRows = 0;$BestFactor = 0;foreach($GoodScaleFactors as $Key => $Factor) {if ($Results[$Factor]["Rows"] > $MaxRows) {$MaxRows = $Results[$Factor]["Rows"];$BestFactor = $Factor;}}/* Return the best visual scale */return $Results[$BestFactor];}/* Compute the best matching scale based on size & factors */function processScale($XMin, $XMax, $MaxDivs, $Factors, $AxisID){$ScaleHeight = abs(ceil($XMax) - floor($XMin));$Format = (isset($this->DataSet->Data["Axis"][$AxisID]["Format"])) ? $this->DataSet->Data["Axis"][$AxisID]["Format"] : NULL;$Mode = (isset($this->DataSet->Data["Axis"][$AxisID]["Display"])) ? $this->DataSet->Data["Axis"][$AxisID]["Display"] : AXIS_FORMAT_DEFAULT;$Scale = [];if ($XMin != $XMax) {$Found = FALSE;$Rescaled = FALSE;$Scaled10Factor = .0001;$Result = 0;while (!$Found) {foreach($Factors as $Key => $Factor) {if (!$Found) {$XMinRescaled = (!($this->modulo($XMin, $Factor * $Scaled10Factor) == 0) || ($XMin != floor($XMin))) ? (floor($XMin / ($Factor * $Scaled10Factor)) * $Factor * $Scaled10Factor) : $XMin;$XMaxRescaled = (!($this->modulo($XMax, $Factor * $Scaled10Factor) == 0) || ($XMax != floor($XMax))) ? (floor($XMax / ($Factor * $Scaled10Factor)) * $Factor * $Scaled10Factor + ($Factor * $Scaled10Factor)) : $XMax;$ScaleHeightRescaled = abs($XMaxRescaled - $XMinRescaled);if (!$Found && floor($ScaleHeightRescaled / ($Factor * $Scaled10Factor)) <= $MaxDivs) {$Found = TRUE;$Rescaled = TRUE;$Result = $Factor * $Scaled10Factor;}}}$Scaled10Factor = $Scaled10Factor * 10;}/* ReCall Min / Max / Height */if ($Rescaled) {$XMin = $XMinRescaled;$XMax = $XMaxRescaled;$ScaleHeight = $ScaleHeightRescaled;}/* Compute rows size */$Rows = floor($ScaleHeight / $Result);($Rows == 0) AND $Rows = 1;$RowHeight = $ScaleHeight / $Rows;/* Return the results */$Scale["Rows"] = $Rows;$Scale["RowHeight"] = $RowHeight;$Scale["XMin"] = $XMin;$Scale["XMax"] = $XMax;/* Compute the needed decimals for the metric view to avoid repetition of the same X Axis labels */if ($Mode == AXIS_FORMAT_METRIC && $Format == NULL) {$Done = FALSE;$GoodDecimals = 0;for ($Decimals = 0; $Decimals <= 10; $Decimals++) {if (!$Done) {$LastLabel = "zob";$ScaleOK = TRUE;for ($i = 0; $i <= $Rows; $i++) {$Value = $XMin + $i * $RowHeight;$Label = $this->scaleFormat($Value, AXIS_FORMAT_METRIC, $Decimals);($LastLabel == $Label) AND $ScaleOK = FALSE;$LastLabel = $Label;}if ($ScaleOK) {$Done = TRUE;$GoodDecimals = $Decimals;}}}$Scale["Format"] = $GoodDecimals;}} else {/* If all values are the same we keep a +1/-1 scale */$Scale["Rows"] = 2;$Scale["RowHeight"] = 1;$Scale["XMin"] = $XMax - 1;$Scale["XMax"] = $XMax + 1;}return $Scale;}function modulo($Value1, $Value2){return (floor($Value2) == 0) ? 0 : ($Value1 % $Value2);#if (floor($Value2) == 0) {# return 0;#}#if (floor($Value2) != 0) {# return ($Value1 % $Value2);#}#$MinValue = min($Value1, $Value2); # Momchil TODO: Does it ever get here ?#$Factor = 10;#while (floor($MinValue * $Factor) == 0) {# $Factor = $Factor * 10;#}#return (($Value1 * $Factor) % ($Value2 * $Factor));}/* Draw an X threshold */function drawXThreshold($Value, array $Format = []){$R = 255;$G = 0;$B = 0;$Alpha = 50;$Weight = NULL;$Ticks = 6;$Wide = FALSE;$WideFactor = 5;$WriteCaption = FALSE;$Caption = NULL;$CaptionAlign = CAPTION_LEFT_TOP;$CaptionOffset = 5;$CaptionR = 255;$CaptionG = 255;$CaptionB = 255;$CaptionAlpha = 100;$DrawBox = TRUE;$DrawBoxBorder = FALSE;$BorderOffset = 3;$BoxRounded = TRUE;$RoundedRadius = 3;$BoxR = 0;$BoxG = 0;$BoxB = 0;$BoxAlpha = 30;$BoxSurrounding = "";$BoxBorderR = 255;$BoxBorderG = 255;$BoxBorderB = 255;$BoxBorderAlpha = 100;$ValueIsLabel = FALSE;/* Override defaults */extract($Format);$Data = $this->DataSet->getData();$AbscissaMargin = $this->getAbscissaMargin($Data);$XScale = $this->scaleGetXSettings();if (is_array($Value)) {foreach($Value as $Key => $ID) {$this->drawXThreshold($ID, $Format);}return 0;}if ($ValueIsLabel) {$Format["ValueIsLabel"] = FALSE;foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $SerieValue) {if ($SerieValue == $Value) {$this->drawXThreshold($Key, $Format);}}return 0;}$CaptionSettings = ["DrawBox" => $DrawBox,"DrawBoxBorder" => $DrawBoxBorder,"BorderOffset" => $BorderOffset,"BoxRounded" => $BoxRounded,"RoundedRadius" => $RoundedRadius,"BoxR" => $BoxR,"BoxG" => $BoxG,"BoxB" => $BoxB,"BoxAlpha" => $BoxAlpha,"BoxSurrounding" => $BoxSurrounding,"BoxBorderR" => $BoxBorderR,"BoxBorderG" => $BoxBorderG,"BoxBorderB" => $BoxBorderB,"BoxBorderAlpha" => $BoxBorderAlpha,"R" => $CaptionR,"G" => $CaptionG,"B" => $CaptionB,"Alpha" => $CaptionAlpha];if ($Caption == NULL) {if (isset($Data["Abscissa"])) {$Caption = (isset($Data["Series"][$Data["Abscissa"]]["Data"][$Value])) ? $Data["Series"][$Data["Abscissa"]]["Data"][$Value] : $Value;} else {$Caption = $Value;}}if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {$XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] * 2) / $XScale[1];$XPos = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value;$YPos1 = $this->GraphAreaY1 + $Data["YMargin"];$YPos2 = $this->GraphAreaY2 - $Data["YMargin"];if ($XPos >= $this->GraphAreaX1 + $AbscissaMargin && $XPos <= $this->GraphAreaX2 - $AbscissaMargin) {$this->drawLine($XPos, $YPos1, $XPos, $YPos2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);if ($Wide) {$this->drawLine($XPos - 1, $YPos1, $XPos - 1, $YPos2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);$this->drawLine($XPos + 1, $YPos1, $XPos + 1, $YPos2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);}if ($WriteCaption) {if ($CaptionAlign == CAPTION_LEFT_TOP) {$Y = $YPos1 + $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE;} else {$Y = $YPos2 - $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE;}$this->drawText($XPos, $Y, $Caption, $CaptionSettings);}return ["X" => $XPos];}} elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) {$XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] * 2) / $XScale[1];$XPos = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value;$YPos1 = $this->GraphAreaX1 + $Data["YMargin"];$YPos2 = $this->GraphAreaX2 - $Data["YMargin"];if ($XPos >= $this->GraphAreaY1 + $AbscissaMargin && $XPos <= $this->GraphAreaY2 - $AbscissaMargin) {$this->drawLine($YPos1, $XPos, $YPos2, $XPos, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);if ($Wide) {$this->drawLine($YPos1, $XPos - 1, $YPos2, $XPos - 1, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);$this->drawLine($YPos1, $XPos + 1, $YPos2, $XPos + 1, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);}if ($WriteCaption) {if ($CaptionAlign == CAPTION_LEFT_TOP) {$Y = $YPos1 + $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT;} else {$Y = $YPos2 - $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT;}$this->drawText($Y, $XPos, $Caption, $CaptionSettings);}return ["X" => $XPos];}}}/* Draw an X threshold area */function drawXThresholdArea($Value1, $Value2, array $Format = []){$R = isset($Format["R"]) ? $Format["R"] : 255;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20;$Border = TRUE;$BorderR = $R;$BorderG = $G;$BorderB = $B;$BorderAlpha = $Alpha + 20;$BorderTicks = 2;$AreaName = NULL;$NameAngle = ZONE_NAME_ANGLE_AUTO;$NameR = 255;$NameG = 255;$NameB = 255;$NameAlpha = 100;$DisableShadowOnArea = TRUE;extract($Format);$RestoreShadow = $this->Shadow;($DisableShadowOnArea && $this->Shadow) AND $this->Shadow = FALSE;($BorderAlpha > 100) AND $BorderAlpha = 100;$Data = $this->DataSet->getData();$XScale = $this->scaleGetXSettings();$AbscissaMargin = $this->getAbscissaMargin($Data);if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {$XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] * 2) / $XScale[1];$XPos1 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value1;$XPos2 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value2;$YPos1 = $this->GraphAreaY1 + $Data["YMargin"];$YPos2 = $this->GraphAreaY2 - $Data["YMargin"];($XPos1 < $this->GraphAreaX1 + $XScale[0]) AND $XPos1 = $this->GraphAreaX1 + $XScale[0];($XPos1 > $this->GraphAreaX2 - $XScale[0]) AND $XPos1 = $this->GraphAreaX2 - $XScale[0];($XPos2 < $this->GraphAreaX1 + $XScale[0]) AND $XPos2 = $this->GraphAreaX1 + $XScale[0];($XPos2 > $this->GraphAreaX2 - $XScale[0]) AND $XPos2 = $this->GraphAreaX2 - $XScale[0];$this->drawFilledRectangle($XPos1, $YPos1, $XPos2, $YPos2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha]);if ($Border) {$this->drawLine($XPos1, $YPos1, $XPos1, $YPos2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);$this->drawLine($XPos2, $YPos1, $XPos2, $YPos2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);}if ($AreaName != NULL) {$XPos = ($XPos2 - $XPos1) / 2 + $XPos1;$YPos = ($YPos2 - $YPos1) / 2 + $YPos1;if ($NameAngle == ZONE_NAME_ANGLE_AUTO) {$TxtPos = $this->getTextBox($XPos, $YPos, $this->FontName, $this->FontSize, 0, $AreaName);$TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"];$NameAngle = (abs($XPos2 - $XPos1) > $TxtWidth) ? 0 : 90;}$this->Shadow = $RestoreShadow;$this->drawText($XPos, $YPos, $AreaName, ["R" => $NameR,"G" => $NameG,"B" => $NameB,"Alpha" => $NameAlpha,"Angle" => $NameAngle,"Align" => TEXT_ALIGN_MIDDLEMIDDLE]);if ($DisableShadowOnArea) {$this->Shadow = FALSE;}}$this->Shadow = $RestoreShadow;return ["X1" => $XPos1,"X2" => $XPos2];} elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) {$XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] * 2) / $XScale[1];$XPos1 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value1;$XPos2 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value2;$YPos1 = $this->GraphAreaX1 + $Data["YMargin"];$YPos2 = $this->GraphAreaX2 - $Data["YMargin"];($XPos1 < $this->GraphAreaY1 + $XScale[0]) AND $XPos1 = $this->GraphAreaY1 + $XScale[0];($XPos1 > $this->GraphAreaY2 - $XScale[0]) AND $XPos1 = $this->GraphAreaY2 - $XScale[0];($XPos2 < $this->GraphAreaY1 + $XScale[0]) AND $XPos2 = $this->GraphAreaY1 + $XScale[0];($XPos2 > $this->GraphAreaY2 - $XScale[0]) AND $XPos2 = $this->GraphAreaY2 - $XScale[0];$this->drawFilledRectangle($YPos1, $XPos1, $YPos2, $XPos2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha]);if ($Border) {$this->drawLine($YPos1, $XPos1, $YPos2, $XPos1, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);$this->drawLine($YPos1, $XPos2, $YPos2, $XPos2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);}if ($AreaName != NULL) {$XPos = ($XPos2 - $XPos1) / 2 + $XPos1;$YPos = ($YPos2 - $YPos1) / 2 + $YPos1;$this->Shadow = $RestoreShadow;$this->drawText($YPos, $XPos, $AreaName, ["R" => $NameR,"G" => $NameG,"B" => $NameB,"Alpha" => $NameAlpha,"Angle" => 0,"Align" => TEXT_ALIGN_MIDDLEMIDDLE]);if ($DisableShadowOnArea) {$this->Shadow = FALSE;}}$this->Shadow = $RestoreShadow;return ["X1" => $XPos1,"X2" => $XPos2];}}/* Draw an Y threshold with the computed scale */function drawThreshold($Value, array $Format = []){$AxisID = 0;$R = 255;$G = 0;$B = 0;$Alpha = 50;$Weight = NULL;$Ticks = 6;$Wide = FALSE;$WideFactor = 5;$WriteCaption = FALSE;$Caption = NULL;$CaptionAlign = CAPTION_LEFT_TOP;$CaptionOffset = 10;$CaptionR = 255;$CaptionG = 255;$CaptionB = 255;$CaptionAlpha = 100;$DrawBox = TRUE;$DrawBoxBorder = FALSE;$BorderOffset = 5;$BoxRounded = TRUE;$RoundedRadius = 3;$BoxR = 0;$BoxG = 0;$BoxB = 0;$BoxAlpha = 20;$BoxSurrounding = "";$BoxBorderR = 255;$BoxBorderG = 255;$BoxBorderB = 255;$BoxBorderAlpha = 100;$NoMargin = FALSE;/* Override defaults */extract($Format);$Data = $this->DataSet->getData();if (!isset($Data["Axis"][$AxisID])) {return -1;}if (is_array($Value)) {foreach($Value as $Key => $ID) {$this->drawThreshold($ID, $Format);}return 0;}$CaptionSettings = ["DrawBox" => $DrawBox,"DrawBoxBorder" => $DrawBoxBorder,"BorderOffset" => $BorderOffset,"BoxRounded" => $BoxRounded,"RoundedRadius" => $RoundedRadius,"BoxR" => $BoxR,"BoxG" => $BoxG,"BoxB" => $BoxB,"BoxAlpha" => $BoxAlpha,"BoxSurrounding" => $BoxSurrounding,"BoxBorderR" => $BoxBorderR,"BoxBorderG" => $BoxBorderG,"BoxBorderB" => $BoxBorderB,"BoxBorderAlpha" => $BoxBorderAlpha,"R" => $CaptionR,"G" => $CaptionG,"B" => $CaptionB,"Alpha" => $CaptionAlpha];$AbscissaMargin = $this->getAbscissaMargin($Data);($NoMargin) AND $AbscissaMargin = 0;($Caption == NULL) AND $Caption = $Value;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {$YPos = $this->scaleComputeY($Value, ["AxisID" => $AxisID]);if ($YPos >= $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"] && $YPos <= $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]) {$X1 = $this->GraphAreaX1 + $AbscissaMargin;$X2 = $this->GraphAreaX2 - $AbscissaMargin;$this->drawLine($X1, $YPos, $X2, $YPos, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);if ($Wide) {$this->drawLine($X1, $YPos - 1, $X2, $YPos - 1, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);$this->drawLine($X1, $YPos + 1, $X2, $YPos + 1, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);}if ($WriteCaption) {if ($CaptionAlign == CAPTION_LEFT_TOP) {$X = $X1 + $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT;} else {$X = $X2 - $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT;}$this->drawText($X, $YPos, $Caption, $CaptionSettings);}}return ["Y" => $YPos];}if ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) {$XPos = $this->scaleComputeY($Value,["AxisID" => $AxisID]);if ($XPos >= $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] && $XPos <= $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]) {$Y1 = $this->GraphAreaY1 + $AbscissaMargin;$Y2 = $this->GraphAreaY2 - $AbscissaMargin;$this->drawLine($XPos, $Y1, $XPos, $Y2,["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);if ($Wide) {$this->drawLine($XPos - 1, $Y1, $XPos - 1, $Y2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);$this->drawLine($XPos + 1, $Y1, $XPos + 1, $Y2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / $WideFactor,"Ticks" => $Ticks]);}if ($WriteCaption) {if ($CaptionAlign == CAPTION_LEFT_TOP) {$Y = $Y1 + $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE;} else {$Y = $Y2 - $CaptionOffset;$CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE;}$CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE;$this->drawText($XPos, $Y, $Caption, $CaptionSettings);}}return ["Y" => $XPos];}}/* Draw a threshold with the computed scale */function drawThresholdArea($Value1, $Value2, array $Format = []){$AxisID = 0;$R = isset($Format["R"]) ? $Format["R"] : 255;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20;$Border = TRUE;$BorderR = $R;$BorderG = $G;$BorderB = $B;$BorderAlpha = $Alpha + 20;$BorderTicks = 2;$AreaName = NULL;$NameAngle = ZONE_NAME_ANGLE_AUTO;$NameR = 255;$NameG = 255;$NameB = 255;$NameAlpha = 100;$DisableShadowOnArea = TRUE;$NoMargin = FALSE;extract($Format);$Data = $this->DataSet->getData();if (!isset($Data["Axis"][$AxisID])) {return -1;}if ($Value1 > $Value2) {list($Value1, $Value2) = [$Value2,$Value1];}$RestoreShadow = $this->Shadow;($DisableShadowOnArea && $this->Shadow) AND $this->Shadow = FALSE;($BorderAlpha > 100) AND $BorderAlpha = 100;$AbscissaMargin = $this->getAbscissaMargin($Data);($NoMargin) AND $AbscissaMargin = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {$XPos1 = $this->GraphAreaX1 + $AbscissaMargin;$XPos2 = $this->GraphAreaX2 - $AbscissaMargin;$YPos1 = $this->scaleComputeY($Value1, ["AxisID" => $AxisID]);$YPos2 = $this->scaleComputeY($Value2, ["AxisID" => $AxisID]);($YPos1 < $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]) AND $YPos1 = $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"];($YPos1 > $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]) AND $YPos1 = $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"];($YPos2 < $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]) AND $YPos2 = $this->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"];($YPos2 > $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]) AND $YPos2 = $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"];$this->drawFilledRectangle($XPos1, $YPos1, $XPos2, $YPos2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha]);if ($Border) {$this->drawLine($XPos1, $YPos1, $XPos2, $YPos1, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);$this->drawLine($XPos1, $YPos2, $XPos2, $YPos2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);}if ($AreaName != NULL) {$XPos = ($XPos2 - $XPos1) / 2 + $XPos1;$YPos = ($YPos2 - $YPos1) / 2 + $YPos1;$this->Shadow = $RestoreShadow;$this->drawText($XPos, $YPos, $AreaName, ["R" => $NameR,"G" => $NameG,"B" => $NameB,"Alpha" => $NameAlpha,"Angle" => 0,"Align" => TEXT_ALIGN_MIDDLEMIDDLE]);if ($DisableShadowOnArea) {$this->Shadow = FALSE;}}$this->Shadow = $RestoreShadow;return ["Y1" => $YPos1,"Y2" => $YPos2];} elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) {$YPos1 = $this->GraphAreaY1 + $AbscissaMargin;$YPos2 = $this->GraphAreaY2 - $AbscissaMargin;$XPos1 = $this->scaleComputeY($Value1, ["AxisID" => $AxisID]);$XPos2 = $this->scaleComputeY($Value2, ["AxisID" => $AxisID]);($XPos1 < $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]) AND $XPos1 = $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"];($XPos1 > $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]) AND $XPos1 = $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"];($XPos2 < $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]) AND $XPos2 = $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"];($XPos2 > $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]) AND $XPos2 = $this->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"];$this->drawFilledRectangle($XPos1, $YPos1, $XPos2, $YPos2, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha]);if ($Border) {$this->drawLine($XPos1, $YPos1, $XPos1, $YPos2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);$this->drawLine($XPos2, $YPos1, $XPos2, $YPos2, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Ticks" => $BorderTicks]);}if ($AreaName != NULL) {$XPos = ($YPos2 - $YPos1) / 2 + $YPos1;$YPos = ($XPos2 - $XPos1) / 2 + $XPos1;if ($NameAngle == ZONE_NAME_ANGLE_AUTO) {$TxtPos = $this->getTextBox($XPos, $YPos, $this->FontName, $this->FontSize, 0, $AreaName);$TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"];$NameAngle = (abs($XPos2 - $XPos1) > $TxtWidth) ? 0 : 90;}$this->Shadow = $RestoreShadow;$this->drawText($YPos, $XPos, $AreaName, ["R" => $NameR,"G" => $NameG,"B" => $NameB,"Alpha" => $NameAlpha,"Angle" => $NameAngle,"Align" => TEXT_ALIGN_MIDDLEMIDDLE]);if ($DisableShadowOnArea) {$this->Shadow = FALSE;}}$this->Shadow = $RestoreShadow;return ["Y1" => $XPos1,"Y2" => $XPos2];}}function scaleGetXSettings(){$Data = $this->DataSet->getData();foreach($Data["Axis"] as $AxisID => $Settings) {if ($Settings["Identity"] == AXIS_X) {return [$Settings["Margin"],$Settings["Rows"]];}}}function scaleComputeY($Values, array $Option, $ReturnOnly0Height = FALSE) // $values is often set to 0 not [0]{$Values = $this->convertToArray($Values);if (count($Values) == 0) { // Momchil$Values = [0];}$AxisID = isset($Option["AxisID"]) ? $Option["AxisID"] : 0;$SerieName = isset($Option["SerieName"]) ? $Option["SerieName"] : NULL;$Data = $this->DataSet->getData();if (!isset($Data["Axis"][$AxisID])) {return -1;}if ($SerieName != NULL) {$AxisID = $Data["Series"][$SerieName]["Axis"];}$Result = [];if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {$Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Data["Axis"][$AxisID]["Margin"] * 2;$ScaleHeight = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"];$Step = $Height / $ScaleHeight;if ($ReturnOnly0Height) {foreach($Values as $Key => $Value) {$Result[] = ($Value == VOID) ? VOID : $Step * $Value;}} else {foreach($Values as $Key => $Value) {if ($Value == VOID) {$Result[] = VOID;} else {if (!is_numeric($Value)) { // Momchil: No idea how that will affect the overall image$Value = 1;}$Result[] = $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"] - ($Step * ($Value - $Data["Axis"][$AxisID]["ScaleMin"]));}}}} else {$Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Data["Axis"][$AxisID]["Margin"] * 2;$ScaleWidth = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"];$Step = $Width / $ScaleWidth;if ($ReturnOnly0Height) {foreach($Values as $Key => $Value) {$Result[] = ($Value == VOID) ? VOID : $Step * $Value;}} else {foreach($Values as $Key => $Value) {if ($Value == VOID) {$Result[] = VOID;} else {if (!is_numeric($Value)) { // Momchil: No idea how that will affect the overall image$Value = 1;}$Result[] = $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] + ($Step * ($Value - $Data["Axis"][$AxisID]["ScaleMin"]));}}}}return (count($Result) == 1) ? $Result[0] : $Result;}/* Format the axis values */function scaleFormat($Value, $Mode = NULL, $Format = NULL, $Unit = NULL){if ($Value == VOID) {return "";}$ret = $Value . $Unit; # Momchil: this is not the same as default for the switchswitch ($Mode) {case AXIS_FORMAT_TRAFFIC:if ($Value == 0) {$ret = "0B";} else {$Units = ["B","KB","MB","GB","TB","PB"];$Sign = "";if ($Value < 0) {$Value = abs($Value);$Sign = "-";}$Value = number_format($Value / pow(1024, ($Scale = floor(log($Value, 1024)))), 2, ",", ".");$ret = $Sign . $Value . " " . $Units[$Scale];}break;case AXIS_FORMAT_CUSTOM:if (function_exists($Format)) {$ret = (call_user_func($Format, $Value));}break;case AXIS_FORMAT_DATE:$Pattern = ($Format == NULL) ? "d/m/Y" : $Format;$ret = gmdate($Pattern, $Value);break;case AXIS_FORMAT_TIME:$Pattern = ($Format == NULL) ? "H:i:s" : $Format;$ret = gmdate($Pattern, $Value);break;case AXIS_FORMAT_CURRENCY:$ret = $Format . number_format($Value, 2);break;case AXIS_FORMAT_METRIC:if (abs($Value) >= 1000) {$ret = (round($Value / 1000, $Format) . "k" . $Unit);} elseif (abs($Value) > 1000000) {$ret = (round($Value / 1000000, $Format) . "m" . $Unit);} elseif (abs($Value) > 1000000000) {$ret = (round($Value / 1000000000, $Format) . "g" . $Unit);}break;}return $ret;}/* Write Max value on a chart */function writeBounds($Type = BOUND_BOTH, array $Format = []){$MaxLabelTxt = "max=";$MinLabelTxt = "min=";$Decimals = 1;$ExcludedSeries = "";$DisplayOffset = 4;$DisplayColor = DISPLAY_MANUAL;$MaxDisplayR = 0;$MaxDisplayG = 0;$MaxDisplayB = 0;$MinDisplayR = 255;$MinDisplayG = 255;$MinDisplayB = 255;$MinLabelPos = BOUND_LABEL_POS_AUTO;$MaxLabelPos = BOUND_LABEL_POS_AUTO;$DrawBox = TRUE;$DrawBoxBorder = FALSE;$BorderOffset = 5;$BoxRounded = TRUE;$RoundedRadius = 3;$BoxR = 0;$BoxG = 0;$BoxB = 0;$BoxAlpha = 20;$BoxSurrounding = "";$BoxBorderR = 255;$BoxBorderG = 255;$BoxBorderB = 255;$BoxBorderAlpha = 100;/* Override defaults */extract($Format);$CaptionSettings = ["DrawBox" => $DrawBox,"DrawBoxBorder" => $DrawBoxBorder,"BorderOffset" => $BorderOffset,"BoxRounded" => $BoxRounded,"RoundedRadius" => $RoundedRadius,"BoxR" => $BoxR,"BoxG" => $BoxG,"BoxB" => $BoxB,"BoxAlpha" => $BoxAlpha,"BoxSurrounding" => $BoxSurrounding,"BoxBorderR" => $BoxBorderR,"BoxBorderG" => $BoxBorderG,"BoxBorderB" => $BoxBorderB,"BoxBorderAlpha" => $BoxBorderAlpha];list($XMargin, $XDivs) = $this->scaleGetXSettings();$Data = $this->DataSet->getData();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"] && !isset($ExcludedSeries[$SerieName])) {#$R = $Serie["Color"]["R"];#$G = $Serie["Color"]["G"]; # Momchil: UNUSED#$B = $Serie["Color"]["B"];#$Alpha = $Serie["Color"]["Alpha"];#$Ticks = $Serie["Ticks"];if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $Serie["Color"]["R"];$DisplayG = $Serie["Color"]["G"];$DisplayB = $Serie["Color"]["B"];}$MinValue = $this->DataSet->getMin($SerieName);$MaxValue = $this->DataSet->getMax($SerieName);$MinPos = VOID;$MaxPos = VOID;foreach($Serie["Data"] as $Key => $Value) {if ($Value == $MinValue && $MinPos == VOID) {$MinPos = $Key;}if ($Value == $MaxValue) {$MaxPos = $Key;}}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;$X = $this->GraphAreaX1 + $XMargin;$SerieOffset = isset($Serie["XOffset"]) ? $Serie["XOffset"] : 0;if ($Type == BOUND_MAX || $Type == BOUND_BOTH) {if ($MaxLabelPos == BOUND_LABEL_POS_TOP || ($MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue >= 0)) {$YPos = $PosArray[$MaxPos] - $DisplayOffset + 2;$Align = TEXT_ALIGN_BOTTOMMIDDLE;}if ($MaxLabelPos == BOUND_LABEL_POS_BOTTOM || ($MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue < 0)) {$YPos = $PosArray[$MaxPos] + $DisplayOffset + 2;$Align = TEXT_ALIGN_TOPMIDDLE;}$XPos = $X + $MaxPos * $XStep + $SerieOffset;$Label = $MaxLabelTxt . $this->scaleFormat(round($MaxValue, $Decimals), $Mode, $Format, $Unit);$TxtPos = $this->getTextBox($XPos, $YPos, $this->FontName, $this->FontSize, 0, $Label);$XOffset = 0;$YOffset = 0;($TxtPos[0]["X"] < $this->GraphAreaX1) AND $XOffset = (($this->GraphAreaX1 - $TxtPos[0]["X"]) / 2);($TxtPos[1]["X"] > $this->GraphAreaX2) AND $XOffset = - (($TxtPos[1]["X"] - $this->GraphAreaX2) / 2);($TxtPos[2]["Y"] < $this->GraphAreaY1) AND $YOffset = $this->GraphAreaY1 - $TxtPos[2]["Y"];($TxtPos[0]["Y"] > $this->GraphAreaY2) AND $YOffset = - ($TxtPos[0]["Y"] - $this->GraphAreaY2);$CaptionSettings["R"] = $MaxDisplayR;$CaptionSettings["G"] = $MaxDisplayG;$CaptionSettings["B"] = $MaxDisplayB;$CaptionSettings["Align"] = $Align;$this->drawText($XPos + $XOffset, $YPos + $YOffset, $Label, $CaptionSettings);}if ($Type == BOUND_MIN || $Type == BOUND_BOTH) {if ($MinLabelPos == BOUND_LABEL_POS_TOP || ($MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue >= 0)) {$YPos = $PosArray[$MinPos] - $DisplayOffset + 2;$Align = TEXT_ALIGN_BOTTOMMIDDLE;}if ($MinLabelPos == BOUND_LABEL_POS_BOTTOM || ($MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue < 0)) {$YPos = $PosArray[$MinPos] + $DisplayOffset + 2;$Align = TEXT_ALIGN_TOPMIDDLE;}$XPos = $X + $MinPos * $XStep + $SerieOffset;$Label = $MinLabelTxt . $this->scaleFormat(round($MinValue, $Decimals), $Mode, $Format, $Unit);$TxtPos = $this->getTextBox($XPos, $YPos, $this->FontName, $this->FontSize, 0, $Label);$XOffset = 0;$YOffset = 0;($TxtPos[0]["X"] < $this->GraphAreaX1) AND $XOffset = (($this->GraphAreaX1 - $TxtPos[0]["X"]) / 2);($TxtPos[1]["X"] > $this->GraphAreaX2) AND $XOffset = - (($TxtPos[1]["X"] - $this->GraphAreaX2) / 2);($TxtPos[2]["Y"] < $this->GraphAreaY1) AND $YOffset = $this->GraphAreaY1 - $TxtPos[2]["Y"];($TxtPos[0]["Y"] > $this->GraphAreaY2) AND $YOffset = - ($TxtPos[0]["Y"] - $this->GraphAreaY2);$CaptionSettings["R"] = $MinDisplayR;$CaptionSettings["G"] = $MinDisplayG;$CaptionSettings["B"] = $MinDisplayB;$CaptionSettings["Align"] = $Align;$this->drawText($XPos + $XOffset, $YPos - $DisplayOffset + $YOffset, $Label, $CaptionSettings);}} else {$XStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;$X = $this->GraphAreaY1 + $XMargin;$SerieOffset = isset($Serie["XOffset"]) ? $Serie["XOffset"] : 0;if ($Type == BOUND_MAX || $Type == BOUND_BOTH) {if ($MaxLabelPos == BOUND_LABEL_POS_TOP || ($MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue >= 0)) {$YPos = $PosArray[$MaxPos] + $DisplayOffset + 2;$Align = TEXT_ALIGN_MIDDLELEFT;}if ($MaxLabelPos == BOUND_LABEL_POS_BOTTOM || ($MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue < 0)) {$YPos = $PosArray[$MaxPos] - $DisplayOffset + 2;$Align = TEXT_ALIGN_MIDDLERIGHT;}$XPos = $X + $MaxPos * $XStep + $SerieOffset;$Label = $MaxLabelTxt . $this->scaleFormat($MaxValue, $Mode, $Format, $Unit);$TxtPos = $this->getTextBox($YPos, $XPos, $this->FontName, $this->FontSize, 0, $Label);$XOffset = 0;$YOffset = 0;($TxtPos[0]["X"] < $this->GraphAreaX1) AND $XOffset = $this->GraphAreaX1 - $TxtPos[0]["X"];($TxtPos[1]["X"] > $this->GraphAreaX2) AND $XOffset = - ($TxtPos[1]["X"] - $this->GraphAreaX2);($TxtPos[2]["Y"] < $this->GraphAreaY1) AND $YOffset = ($this->GraphAreaY1 - $TxtPos[2]["Y"]) / 2;($TxtPos[0]["Y"] > $this->GraphAreaY2) AND $YOffset = - (($TxtPos[0]["Y"] - $this->GraphAreaY2) / 2);$CaptionSettings["R"] = $MaxDisplayR;$CaptionSettings["G"] = $MaxDisplayG;$CaptionSettings["B"] = $MaxDisplayB;$CaptionSettings["Align"] = $Align;$this->drawText($YPos + $XOffset, $XPos + $YOffset, $Label, $CaptionSettings);}if ($Type == BOUND_MIN || $Type == BOUND_BOTH) {if ($MinLabelPos == BOUND_LABEL_POS_TOP || ($MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue >= 0)) {$YPos = $PosArray[$MinPos] + $DisplayOffset + 2;$Align = TEXT_ALIGN_MIDDLELEFT;}if ($MinLabelPos == BOUND_LABEL_POS_BOTTOM || ($MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue < 0)) {$YPos = $PosArray[$MinPos] - $DisplayOffset + 2;$Align = TEXT_ALIGN_MIDDLERIGHT;}$XPos = $X + $MinPos * $XStep + $SerieOffset;$Label = $MinLabelTxt . $this->scaleFormat($MinValue, $Mode, $Format, $Unit);$TxtPos = $this->getTextBox($YPos, $XPos, $this->FontName, $this->FontSize, 0, $Label);$XOffset = 0;$YOffset = 0;($TxtPos[0]["X"] < $this->GraphAreaX1) AND $XOffset = $this->GraphAreaX1 - $TxtPos[0]["X"];($TxtPos[1]["X"] > $this->GraphAreaX2) AND $XOffset = - ($TxtPos[1]["X"] - $this->GraphAreaX2);($TxtPos[2]["Y"] < $this->GraphAreaY1) AND $YOffset = ($this->GraphAreaY1 - $TxtPos[2]["Y"]) / 2;($TxtPos[0]["Y"] > $this->GraphAreaY2) AND $YOffset = - (($TxtPos[0]["Y"] - $this->GraphAreaY2) / 2);$CaptionSettings["R"] = $MinDisplayR;$CaptionSettings["G"] = $MinDisplayG;$CaptionSettings["B"] = $MinDisplayB;$CaptionSettings["Align"] = $Align;$this->drawText($YPos + $XOffset, $XPos + $YOffset, $Label, $CaptionSettings);}}}}}/* Draw a plot chart */function drawPlotChart(array $Format = []){$PlotSize = NULL;$PlotBorder = FALSE;$BorderR = 50;$BorderG = 50;$BorderB = 50;$BorderAlpha = 30;$BorderSize = 2;$Surrounding = NULL;$DisplayValues = FALSE;$DisplayOffset = 4;$DisplayColor = DISPLAY_MANUAL;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$RecordImageMap = FALSE;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$SerieWeight = (isset($Serie["Weight"])) ? $Serie["Weight"] + 2 : 2;($PlotSize != NULL) AND $SerieWeight = $PlotSize;$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}if (isset($Serie["Picture"])) {$Picture = $Serie["Picture"];list($PicWidth, $PicHeight, $PicType) = $this->getPicInfo($Picture);} else {$Picture = NULL;$PicOffset = 0;}if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}$AxisID = $Serie["Axis"];$Shape = $Serie["Shape"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$SerieDescription = (isset($Serie["Description"])) ? $Serie["Description"] : $SerieName;$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}if ($Picture != NULL) {$PicOffset = $PicHeight / 2;$SerieWeight = 0;}$X = $this->GraphAreaX1 + $XMargin;$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $Y) {if ($DisplayValues) $this->drawText($X, $Y - $DisplayOffset - $SerieWeight - $BorderSize - $PicOffset, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), array("R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_BOTTOMMIDDLE));if ($Y != VOID) {if ($RecordImageMap) {$this->addToImageMap("CIRCLE", floor($X) . "," . floor($Y) . "," . $SerieWeight, $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Picture != NULL) {$this->drawFromPicture($PicType, $Picture, $X - $PicWidth / 2, $Y - $PicHeight / 2);} else {$this->drawShape($X, $Y, $Shape, $SerieWeight, $PlotBorder, $BorderSize, $R, $G, $B, $Alpha, $BorderR, $BorderG, $BorderB, $BorderAlpha);}}$X = $X + $XStep;}} else {if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}if ($Picture != NULL) {$PicOffset = $PicWidth / 2;$SerieWeight = 0;}$Y = $this->GraphAreaY1 + $XMargin;$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $X) {if ($DisplayValues) $this->drawText($X + $DisplayOffset + $SerieWeight + $BorderSize + $PicOffset, $Y, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), array("Angle" => 270,"R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_BOTTOMMIDDLE));if ($X != VOID) {if ($RecordImageMap) {$this->addToImageMap("CIRCLE", floor($X) . "," . floor($Y) . "," . $SerieWeight, $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Picture != NULL) {$this->drawFromPicture($PicType, $Picture, $X - $PicWidth / 2, $Y - $PicHeight / 2);} else {$this->drawShape($X, $Y, $Shape, $SerieWeight, $PlotBorder, $BorderSize, $R, $G, $B, $Alpha, $BorderR, $BorderG, $BorderB, $BorderAlpha);}}$Y = $Y + $YStep;}}}}}/* Draw a spline chart */function drawSplineChart($Format = []){# Momchil: The sandbox system requires it$Format = $this->convertToArray($Format);$BreakVoid = TRUE;$VoidTicks = 4;$BreakR = NULL; // 234$BreakG = NULL; // 55$BreakB = NULL; // 26$DisplayValues = FALSE;$DisplayOffset = 2;$DisplayColor = DISPLAY_MANUAL;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$RecordImageMap = FALSE;$ImageMapPlotSize = 5;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];$Weight = $Serie["Weight"];if ($BreakR == NULL) {$BreakSettings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $VoidTicks];} else {$BreakSettings = ["R" => $BreakR,"G" => $BreakG,"B" => $BreakB,"Alpha" => $Alpha,"Ticks" => $VoidTicks,"Weight" => $Weight];}if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$SerieDescription = (isset($Serie["Description"])) ? $Serie["Description"] : $SerieName;$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$WayPoints = [];$Force = $XStep / 5;$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;$LastX = 1;$LastY = 1;foreach($PosArray as $Key => $Y) {if ($DisplayValues) $this->drawText($X, $Y - $DisplayOffset, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), array("R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_BOTTOMMIDDLE));if ($RecordImageMap && $Y != VOID) {$this->addToImageMap("CIRCLE", floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Y == VOID && $LastY != NULL) {$this->drawSpline($WayPoints, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);$WayPoints = [];}if ($Y != VOID && $LastY == NULL && $LastGoodY != NULL && !$BreakVoid) {$this->drawLine($LastGoodX, $LastGoodY, $X, $Y, $BreakSettings);}if ($Y != VOID) $WayPoints[] = [$X,$Y];if ($Y != VOID) {$LastGoodY = $Y;$LastGoodX = $X;}if ($Y == VOID) {$Y = NULL;}$LastX = $X;$LastY = $Y;$X = $X + $XStep;}$this->drawSpline($WayPoints, ["Force" => $Force,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);} else {if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$WayPoints = [];$Force = $YStep / 5;$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;$LastX = 1;$LastY = 1;foreach($PosArray as $Key => $X) {if ($DisplayValues) {$this->drawText($X + $DisplayOffset, $Y, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["Angle" => 270,"R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_BOTTOMMIDDLE]);}if ($RecordImageMap && $X != VOID) {$this->addToImageMap("CIRCLE", floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($X == VOID && $LastX != NULL) {$this->drawSpline($WayPoints, ["Force" => $Force,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);$WayPoints = [];}if ($X != VOID && $LastX == NULL && $LastGoodX != NULL && !$BreakVoid) {$this->drawLine($LastGoodX, $LastGoodY, $X, $Y, $BreakSettings);}if ($X != VOID) {$WayPoints[] = [$X, $Y];#} # Momchil#if ($X != VOID) {$LastGoodX = $X;$LastGoodY = $Y;} else {#if ($X == VOID) {$X = NULL;}$LastX = $X;$LastY = $Y;$Y = $Y + $YStep;}$this->drawSpline($WayPoints, ["Force" => $Force,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);}}}}/* Draw a filled spline chart */function drawFilledSplineChart(array $Format = []){$DisplayValues = FALSE;$DisplayOffset = 2;$DisplayColor = DISPLAY_MANUAL;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$AroundZero = TRUE;$Threshold = NULL;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);if ($AroundZero) {$YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]);}if ($Threshold != NULL) {foreach($Threshold as $Key => $Params) {$Threshold[$Key]["MinX"] = $this->scaleComputeY($Params["Min"], ["AxisID" => $Serie["Axis"]]);$Threshold[$Key]["MaxX"] = $this->scaleComputeY($Params["Max"], ["AxisID" => $Serie["Axis"]]);}}$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$WayPoints = [];$Force = $XStep / 5;if (!$AroundZero) {$YZero = $this->GraphAreaY2 - 1;}if ($YZero > $this->GraphAreaY2 - 1) {$YZero = $this->GraphAreaY2 - 1;}if ($YZero < $this->GraphAreaY1 + 1) {$YZero = $this->GraphAreaY1 + 1;}// $LastX = ""; $LastY = ""; # UNUSED$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $Y) {if ($DisplayValues) {$this->drawText($X, $Y - $DisplayOffset, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_BOTTOMMIDDLE]);}if ($Y == VOID) {$Area = $this->drawSpline($WayPoints, ["Force" => $Force,"PathOnly" => TRUE]);if (count($Area) > 0) //if ( $Area != "" ){foreach($Area as $key => $Points) {$Corners = [$Area[$key][0]["X"], $YZero];foreach($Points as $subKey => $Point) {$Corners[] = ($subKey == count($Points) - 1) ? $Point["X"] - 1 : $Point["X"];$Corners[] = $Point["Y"] + 1;}$Corners[] = $Points[$subKey]["X"] - 1;$Corners[] = $YZero;$this->drawPolygonChart($Corners, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / 2,"NoBorder" => TRUE,"Threshold" => $Threshold]);}$this->drawSpline($WayPoints, ["Force" => $Force,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks]);}$WayPoints = [];} else {$WayPoints[] = [$X,$Y - .5]; /* -.5 for AA visual fix */}$X = $X + $XStep;}$Area = $this->drawSpline($WayPoints, ["Force" => $Force,"PathOnly" => TRUE]);if (count($Area) > 0) //if ( $Area != "" ){foreach($Area as $key => $Points) {$Corners = [$Area[$key][0]["X"], $YZero];foreach($Points as $subKey => $Point) {$Corners[] = ($subKey == count($Points) - 1) ? $Point["X"] - 1 : $Point["X"];$Corners[] = $Point["Y"] + 1;}$Corners[] = $Points[$subKey]["X"] - 1;$Corners[] = $YZero;$this->drawPolygonChart($Corners, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / 2,"NoBorder" => TRUE,"Threshold" => $Threshold]);}$this->drawSpline($WayPoints, ["Force" => $Force,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks]);}} else {if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$WayPoints = [];$Force = $YStep / 5;if (!$AroundZero) {$YZero = $this->GraphAreaX1 + 1;}if ($YZero > $this->GraphAreaX2 - 1) {$YZero = $this->GraphAreaX2 - 1;}if ($YZero < $this->GraphAreaX1 + 1) {$YZero = $this->GraphAreaX1 + 1;}$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $X) {if ($DisplayValues) {$this->drawText($X + $DisplayOffset, $Y, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), array("Angle" => 270,"R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_BOTTOMMIDDLE));}if ($X == VOID) {$Area = $this->drawSpline($WayPoints, ["Force" => $Force,"PathOnly" => TRUE]);if (count($Area) > 0) // if ( $Area != "" ){foreach($Area as $key => $Points) {$Corners = [$YZero,$Area[$key][0]["Y"]];foreach($Points as $subKey => $Point) {$Corners[] = ($subKey == count($Points) - 1) ? $Point["X"] - 1 : $Point["X"];$Corners[] = $Point["Y"];}$Corners[] = $YZero;$Corners[] = $Points[$subKey]["Y"] - 1;$this->drawPolygonChart($Corners, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / 2,"NoBorder" => TRUE,"Threshold" => $Threshold]);}$this->drawSpline($WayPoints, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha / 2,"NoBorder" => TRUE,"Threshold" => $Threshold]);}$WayPoints = [];} else {$WayPoints[] = [$X,$Y];}$Y = $Y + $YStep;}$Area = $this->drawSpline($WayPoints, ["Force" => $Force,"PathOnly" => TRUE]);if (count($Area) > 0) // if ( $Area != "" ){foreach($Area as $key => $Points) {$Corners = [];$Corners[] = $YZero;$Corners[] = $Area[$key][0]["Y"];foreach($Points as $subKey => $Point) {$Corners[] = ($subKey == count($Points) - 1) ? $Point["X"] - 1 : $Point["X"];$Corners[] = $Point["Y"];}$Corners[] = $YZero;$Corners[] = $Points[$subKey]["Y"] - 1;$this->drawPolygonChart($Corners, ["Force" => $Force,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks]);}$this->drawSpline($WayPoints, ["Force" => $Force,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks]);}}}}}/* Draw a line chart */function drawLineChart(array $Format = []){$BreakVoid = TRUE;$VoidTicks = 4;$BreakR = NULL;$BreakG = NULL;$BreakB = NULL;$DisplayValues = FALSE;$DisplayOffset = 2;$DisplayColor = DISPLAY_MANUAL;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$RecordImageMap = FALSE;$ImageMapPlotSize = 5;$ForceColor = FALSE;$ForceR = 0;$ForceG = 0;$ForceB = 0;$ForceAlpha = 100;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];$Weight = $Serie["Weight"];if ($ForceColor) {$R = $ForceR;$G = $ForceG;$B = $ForceB;$Alpha = $ForceAlpha;}if ($BreakR == NULL) {$BreakSettings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $VoidTicks,"Weight" => $Weight];} else {$BreakSettings = ["R" => $BreakR,"G" => $BreakG,"B" => $BreakB,"Alpha" => $Alpha,"Ticks" => $VoidTicks,"Weight" => $Weight];}if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$SerieDescription = (isset($Serie["Description"])) ? $Serie["Description"] : $SerieName;$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$LastX = NULL;$LastY = NULL;$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;foreach($PosArray as $Key => $Y) {if ($DisplayValues && $Serie["Data"][$Key] != VOID) {if ($Serie["Data"][$Key] > 0) {$Align = TEXT_ALIGN_BOTTOMMIDDLE;$Offset = $DisplayOffset;} else {$Align = TEXT_ALIGN_TOPMIDDLE;$Offset = - $DisplayOffset;}$this->drawText($X, $Y - $Offset - $Weight, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => $Align]);}if ($RecordImageMap && $Y != VOID) {$this->addToImageMap("CIRCLE", floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Y != VOID && $LastX != NULL && $LastY != NULL) $this->drawLine($LastX, $LastY, $X, $Y, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks, "Weight" => $Weight]);if ($Y != VOID && $LastY == NULL && $LastGoodY != NULL && !$BreakVoid) {$this->drawLine($LastGoodX, $LastGoodY, $X, $Y, $BreakSettings);$LastGoodY = NULL;}if ($Y != VOID) {$LastGoodY = $Y;$LastGoodX = $X;}if ($Y == VOID) {$Y = NULL;}$LastX = $X;$LastY = $Y;$X = $X + $XStep;}} else {if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$LastX = NULL;$LastY = NULL;$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;foreach($PosArray as $Key => $X) {if ($DisplayValues && $Serie["Data"][$Key] != VOID) {$this->drawText($X + $DisplayOffset + $Weight, $Y, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["Angle" => 270,"R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_BOTTOMMIDDLE]);}if ($RecordImageMap && $X != VOID) {$this->addToImageMap("CIRCLE", floor($X) . "," . floor($Y) . "," . $ImageMapPlotSize, $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($X != VOID && $LastX != NULL && $LastY != NULL) $this->drawLine($LastX, $LastY, $X, $Y, ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight]);if ($X != VOID && $LastX == NULL && $LastGoodY != NULL && !$BreakVoid) {$this->drawLine($LastGoodX, $LastGoodY, $X, $Y, $BreakSettings);$LastGoodY = NULL;}if ($X != VOID) {$LastGoodY = $Y;$LastGoodX = $X;}if ($X == VOID) {$X = NULL;}$LastX = $X;$LastY = $Y;$Y = $Y + $YStep;}}}}}/* Draw a line chart */function drawZoneChart($SerieA, $SerieB, array $Format = []){$AxisID = 0;$LineR = 150;$LineG = 150;$LineB = 150;$LineAlpha = 50;$LineTicks = 1;$AreaR = 150;$AreaG = 150;$AreaB = 150;$AreaAlpha = 5;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();if (!isset($Data["Series"][$SerieA]["Data"]) || !isset($Data["Series"][$SerieB]["Data"])) {return 0;}$SerieAData = $Data["Series"][$SerieA]["Data"];$SerieBData = $Data["Series"][$SerieB]["Data"];list($XMargin, $XDivs) = $this->scaleGetXSettings();$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$PosArrayA = $this->scaleComputeY($SerieAData, ["AxisID" => $AxisID]);$PosArrayB = $this->scaleComputeY($SerieBData, ["AxisID" => $AxisID]);if (count($PosArrayA) != count($PosArrayB)) {return 0;}if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$LastX = NULL;$LastY = NULL;$LastX = NULL;$LastY1 = NULL;$LastY2 = NULL;$BoundsA = [];$BoundsB = [];foreach($PosArrayA as $Key => $Y1) {$Y2 = $PosArrayB[$Key];$BoundsA[] = $X;$BoundsA[] = $Y1;$BoundsB[] = $X;$BoundsB[] = $Y2;$LastX = $X;$LastY1 = $Y1;$LastY2 = $Y2;$X = $X + $XStep;}$Bounds = array_merge($BoundsA, $this->reversePlots($BoundsB));$this->drawPolygonChart($Bounds, ["R" => $AreaR,"G" => $AreaG,"B" => $AreaB,"Alpha" => $AreaAlpha]);for ($i = 0; $i <= count($BoundsA) - 4; $i = $i + 2) {$this->drawLine($BoundsA[$i], $BoundsA[$i + 1], $BoundsA[$i + 2], $BoundsA[$i + 3], ["R" => $LineR,"G" => $LineG,"B" => $LineB,"Alpha" => $LineAlpha,"Ticks" => $LineTicks]);$this->drawLine($BoundsB[$i], $BoundsB[$i + 1], $BoundsB[$i + 2], $BoundsB[$i + 3], ["R" => $LineR,"G" => $LineG,"B" => $LineB,"Alpha" => $LineAlpha,"Ticks" => $LineTicks]);}} else {if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$LastX = NULL;$LastY = NULL;$LastY = NULL;$LastX1 = NULL;$LastX2 = NULL;$BoundsA = [];$BoundsB = [];foreach($PosArrayA as $Key => $X1) {$X2 = $PosArrayB[$Key];$BoundsA[] = $X1;$BoundsA[] = $Y;$BoundsB[] = $X2;$BoundsB[] = $Y;$LastY = $Y;$LastX1 = $X1;$LastX2 = $X2;$Y = $Y + $YStep;}$Bounds = array_merge($BoundsA, $this->reversePlots($BoundsB));$this->drawPolygonChart($Bounds, ["R" => $AreaR,"G" => $AreaG,"B" => $AreaB,"Alpha" => $AreaAlpha]);for ($i = 0; $i <= count($BoundsA) - 4; $i = $i + 2) {$this->drawLine($BoundsA[$i], $BoundsA[$i + 1], $BoundsA[$i + 2], $BoundsA[$i + 3], ["R" => $LineR,"G" => $LineG,"B" => $LineB,"Alpha" => $LineAlpha,"Ticks" => $LineTicks]);$this->drawLine($BoundsB[$i], $BoundsB[$i + 1], $BoundsB[$i + 2], $BoundsB[$i + 3], ["R" => $LineR,"G" => $LineG,"B" => $LineB,"Alpha" => $LineAlpha,"Ticks" => $LineTicks]);}}}/* Draw a step chart */function drawStepChart(array $Format = []){$BreakVoid = FALSE;$ReCenter = TRUE;$VoidTicks = 4;$BreakR = NULL;$BreakG = NULL;$BreakB = NULL;$DisplayValues = FALSE;$DisplayOffset = 2;$DisplayColor = DISPLAY_MANUAL;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$RecordImageMap = FALSE;$ImageMapPlotSize = 5;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];$Weight = $Serie["Weight"];$SerieDescription = (isset($Serie["Description"])) ? $Serie["Description"] : $SerieName;if ($BreakR == NULL) {$BreakSettings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $VoidTicks,"Weight" => $Weight];} else {$BreakSettings = ["R" => $BreakR,"G" => $BreakG,"B" => $BreakB,"Alpha" => $Alpha,"Ticks" => $VoidTicks,"Weight" => $Weight];}if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight];$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$LastX = NULL;$LastY = NULL;$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;$Init = FALSE;foreach($PosArray as $Key => $Y) {if ($DisplayValues && $Serie["Data"][$Key] != VOID) {if ($Y <= $LastY) {$Align = TEXT_ALIGN_BOTTOMMIDDLE;$Offset = $DisplayOffset;} else {$Align = TEXT_ALIGN_TOPMIDDLE;$Offset = - $DisplayOffset;}$this->drawText($X, $Y - $Offset - $Weight, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => $Align]);}if ($Y != VOID && $LastX != NULL && $LastY != NULL) {$this->drawLine($LastX, $LastY, $X, $LastY, $Color);$this->drawLine($X, $LastY, $X, $Y, $Color);if ($ReCenter && $X + $XStep < $this->GraphAreaX2 - $XMargin) {$this->drawLine($X, $Y, $X + $XStep, $Y, $Color);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X - $ImageMapPlotSize) . "," . floor($Y - $ImageMapPlotSize) . "," . floor($X + $XStep + $ImageMapPlotSize) . "," . floor($Y + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}} else {if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastX - $ImageMapPlotSize) . "," . floor($LastY - $ImageMapPlotSize) . "," . floor($X + $ImageMapPlotSize) . "," . floor($LastY + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}}}if ($Y != VOID && $LastY == NULL && $LastGoodY != NULL && !$BreakVoid) {if ($ReCenter) {$this->drawLine($LastGoodX + $XStep, $LastGoodY, $X, $LastGoodY, $BreakSettings);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastGoodX + $XStep - $ImageMapPlotSize) . "," . floor($LastGoodY - $ImageMapPlotSize) . "," . floor($X + $ImageMapPlotSize) . "," . floor($LastGoodY + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}} else {$this->drawLine($LastGoodX, $LastGoodY, $X, $LastGoodY, $BreakSettings);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastGoodX - $ImageMapPlotSize) . "," . floor($LastGoodY - $ImageMapPlotSize) . "," . floor($X + $ImageMapPlotSize) . "," . floor($LastGoodY + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}}$this->drawLine($X, $LastGoodY, $X, $Y, $BreakSettings);$LastGoodY = NULL;} elseif (!$BreakVoid && $LastGoodY == NULL && $Y != VOID) {$this->drawLine($this->GraphAreaX1 + $XMargin, $Y, $X, $Y, $BreakSettings);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($this->GraphAreaX1 + $XMargin - $ImageMapPlotSize) . "," . floor($Y - $ImageMapPlotSize) . "," . floor($X + $ImageMapPlotSize) . "," . floor($Y + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}}if ($Y != VOID) {$LastGoodY = $Y;$LastGoodX = $X;}if ($Y == VOID) {$Y = NULL;}if (!$Init && $ReCenter) {$X = $X - $XStep / 2;$Init = TRUE;}$LastX = $X;$LastY = $Y;if ($LastX < $this->GraphAreaX1 + $XMargin) {$LastX = $this->GraphAreaX1 + $XMargin;}$X = $X + $XStep;}if ($ReCenter) {$this->drawLine($LastX, $LastY, $this->GraphAreaX2 - $XMargin, $LastY, $Color);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastX - $ImageMapPlotSize) . "," . floor($LastY - $ImageMapPlotSize) . "," . floor($this->GraphAreaX2 - $XMargin + $ImageMapPlotSize) . "," . floor($LastY + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}}} else {if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$LastX = NULL;$LastY = NULL;$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;$Init = FALSE;foreach($PosArray as $Key => $X) {if ($DisplayValues && $Serie["Data"][$Key] != VOID) {if ($X >= $LastX) {$Align = TEXT_ALIGN_MIDDLELEFT;$Offset = $DisplayOffset;} else {$Align = TEXT_ALIGN_MIDDLERIGHT;$Offset = - $DisplayOffset;}$this->drawText($X + $Offset + $Weight, $Y, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => $Align]);}if ($X != VOID && $LastX != NULL && $LastY != NULL) {$this->drawLine($LastX, $LastY, $LastX, $Y, $Color);$this->drawLine($LastX, $Y, $X, $Y, $Color);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastX - $ImageMapPlotSize) . "," . floor($LastY - $ImageMapPlotSize) . "," . floor($LastX + $XStep + $ImageMapPlotSize) . "," . floor($Y + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}}if ($X != VOID && $LastX == NULL && $LastGoodY != NULL && !$BreakVoid) {$this->drawLine($LastGoodX, $LastGoodY, $LastGoodX, $LastGoodY + $YStep, $Color);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastGoodX - $ImageMapPlotSize) . "," . floor($LastGoodY - $ImageMapPlotSize) . "," . floor($LastGoodX + $ImageMapPlotSize) . "," . floor($LastGoodY + $YStep + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}$this->drawLine($LastGoodX, $LastGoodY + $YStep, $LastGoodX, $Y, $BreakSettings);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastGoodX - $ImageMapPlotSize) . "," . floor($LastGoodY + $YStep - $ImageMapPlotSize) . "," . floor($LastGoodX + $ImageMapPlotSize) . "," . floor($YStep + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}$this->drawLine($LastGoodX, $Y, $X, $Y, $BreakSettings);$LastGoodY = NULL;} elseif ($X != VOID && $LastGoodY == NULL && !$BreakVoid) {$this->drawLine($X, $this->GraphAreaY1 + $XMargin, $X, $Y, $BreakSettings);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X - $ImageMapPlotSize) . "," . floor($this->GraphAreaY1 + $XMargin - $ImageMapPlotSize) . "," . floor($X + $ImageMapPlotSize) . "," . floor($Y + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}}if ($X != VOID) {$LastGoodY = $Y;$LastGoodX = $X;}if ($X == VOID) {$X = NULL;}if (!$Init && $ReCenter) {$Y = $Y - $YStep / 2;$Init = TRUE;}$LastX = $X;$LastY = $Y;if ($LastY < $this->GraphAreaY1 + $XMargin) {$LastY = $this->GraphAreaY1 + $XMargin;}$Y = $Y + $YStep;}if ($ReCenter) {$this->drawLine($LastX, $LastY, $LastX, $this->GraphAreaY2 - $XMargin, $Color);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($LastX - $ImageMapPlotSize) . "," . floor($LastY - $ImageMapPlotSize) . "," . floor($LastX + $ImageMapPlotSize) . "," . floor($this->GraphAreaY2 - $XMargin + $ImageMapPlotSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}}}}}}/* Draw a step chart */function drawFilledStepChart(array $Format = []){$ReCenter = TRUE;$DisplayValues = FALSE;$DisplayOffset = 2;$DisplayColor = DISPLAY_MANUAL;$ForceTransparency = NULL;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$AroundZero = TRUE;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];$Weight = $Serie["Weight"];if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$Color = ["R" => $R,"G" => $G,"B" => $B];$Color["Alpha"] = ($ForceTransparency != NULL) ? $ForceTransparency : $Alpha;$PosArray = $this->scaleComputeY($Serie["Data"],["AxisID" => $Serie["Axis"]]);$YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]);$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($YZero > $this->GraphAreaY2 - 1) {$YZero = $this->GraphAreaY2 - 1;}if ($YZero < $this->GraphAreaY1 + 1) {$YZero = $this->GraphAreaY1 + 1;}if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$LastX = NULL;$LastY = NULL;if (!$AroundZero) {$YZero = $this->GraphAreaY2 - 1;}$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;$Points = [];$Init = FALSE;foreach($PosArray as $Key => $Y) {if ($Y == VOID && $LastX != NULL && $LastY != NULL && (count($Points) > 0)) {$Points[] = $LastX;$Points[] = $LastY;$Points[] = $X;$Points[] = $LastY;$Points[] = $X;$Points[] = $YZero;$this->drawPolygon($Points, $Color);$Points = [];}if ($Y != VOID && $LastX != NULL && $LastY != NULL) {if (count($Points) == 0) {$Points[] = $LastX;$Points[] = $YZero;}$Points[] = $LastX;$Points[] = $LastY;$Points[] = $X;$Points[] = $LastY;$Points[] = $X;$Points[] = $Y;}if ($Y != VOID) {$LastGoodY = $Y;$LastGoodX = $X;} else {$Y = NULL;}if (!$Init && $ReCenter) {$X = $X - $XStep / 2;$Init = TRUE;}$LastX = $X;$LastY = $Y;if ($LastX < $this->GraphAreaX1 + $XMargin) {$LastX = $this->GraphAreaX1 + $XMargin;}$X = $X + $XStep;}if ($ReCenter) {$Points[] = $LastX+$XStep/2; $Points[] = $LastY;$Points[] = $LastX+$XStep/2; $Points[] = $YZero;} else {$Points[] = $LastX;$Points[] = $YZero;}$this->drawPolygon($Points, $Color);} else {if ($YZero < $this->GraphAreaX1 + 1) {$YZero = $this->GraphAreaX1 + 1;}if ($YZero > $this->GraphAreaX2 - 1) {$YZero = $this->GraphAreaX2 - 1;}if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$LastX = NULL;$LastY = NULL;$PosArray = $this->convertToArray($PosArray);$LastGoodY = NULL;$LastGoodX = NULL;$Points = [];foreach($PosArray as $Key => $X) {if ($X == VOID && $LastX != NULL && $LastY != NULL && (count($Points) > 0)) {$Points[] = $LastX;$Points[] = $LastY;$Points[] = $LastX;$Points[] = $Y;$Points[] = $YZero;$Points[] = $Y;$this->drawPolygon($Points, $Color);$Points = [];}if ($X != VOID && $LastX != NULL && $LastY != NULL) {(count($Points) == 0) AND $Points = [$YZero, $LastY];$Points[] = $LastX;$Points[] = $LastY;$Points[] = $LastX;$Points[] = $Y;$Points[] = $X;$Points[] = $Y;}if ($X != VOID) {$LastGoodY = $Y;$LastGoodX = $X;} else {$X = NULL;}if ($LastX == NULL && $ReCenter) {$Y = $Y - $YStep / 2;}$LastX = $X;$LastY = $Y;if ($LastY < $this->GraphAreaY1 + $XMargin) {$LastY = $this->GraphAreaY1 + $XMargin;}$Y = $Y + $YStep;}if ($ReCenter) {$Points[] = $LastX;$Points[] = $LastY+$YStep/2;$Points[] = $YZero;$Points[] = $LastY+$YStep/2;} else {$Points[] = $YZero;$Points[] = $LastY;}$this->drawPolygon($Points, $Color);}}}}/* Draw an area chart */function drawAreaChart(array $Format = []){$DisplayValues = FALSE;$DisplayOffset = 2;$DisplayColor = DISPLAY_MANUAL;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$ForceTransparency = 25;$AroundZero = TRUE;$Threshold = NULL;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);$YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]);if ($Threshold != NULL) {foreach($Threshold as $Key => $Params) {$Threshold[$Key]["MinX"] = $this->scaleComputeY($Params["Min"], ["AxisID" => $Serie["Axis"]]);$Threshold[$Key]["MaxX"] = $this->scaleComputeY($Params["Max"], ["AxisID" => $Serie["Axis"]]);}}$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($YZero > $this->GraphAreaY2 - 1) {$YZero = $this->GraphAreaY2 - 1;}$Areas = [];$AreaID = 0;$Areas[$AreaID][] = $this->GraphAreaX1 + $XMargin;$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaY2 - 1;if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$LastX = NULL;$LastY = NULL;$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $Y) {if ($DisplayValues && $Serie["Data"][$Key] != VOID) {if ($Serie["Data"][$Key] > 0) {$Align = TEXT_ALIGN_BOTTOMMIDDLE;$Offset = $DisplayOffset;} else {$Align = TEXT_ALIGN_TOPMIDDLE;$Offset = - $DisplayOffset;}$this->drawText($X, $Y - $Offset, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => $Align]);}if ($Y == VOID && isset($Areas[$AreaID])) {$Areas[$AreaID][] = ($LastX == NULL) ? $X : $LastX;$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaY2 - 1;$AreaID++;} elseif ($Y != VOID) {if (!isset($Areas[$AreaID])) {$Areas[$AreaID][] = $X;$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaY2 - 1;}$Areas[$AreaID][] = $X;$Areas[$AreaID][] = $Y;}$LastX = $X;$X = $X + $XStep;}$Areas[$AreaID][] = $LastX;$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaY2 - 1;/* Handle shadows in the areas */if ($this->Shadow) {$ShadowArea = [];foreach($Areas as $Key => $Points) {$ShadowArea[$Key] = [];foreach($Points as $Key2 => $Value) {$ShadowArea[$Key][] = ($Key2 % 2 == 0) ? $Value + $this->ShadowX : $Value + $this->ShadowY;}}foreach($ShadowArea as $Key => $Points) {$this->drawPolygonChart($Points, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa]);}}$Alpha = $ForceTransparency != NULL ? $ForceTransparency : $Alpha;$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Threshold" => $Threshold];foreach($Areas as $Key => $Points){$this->drawPolygonChart($Points, $Color);}} else {if ($YZero < $this->GraphAreaX1 + 1) {$YZero = $this->GraphAreaX1 + 1;}if ($YZero > $this->GraphAreaX2 - 1) {$YZero = $this->GraphAreaX2 - 1;}$AreaID = 0;$Areas = [];$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaX1 + 1;$Areas[$AreaID][] = $this->GraphAreaY1 + $XMargin;if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$LastX = NULL;$LastY = NULL;$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $X) {if ($DisplayValues && $Serie["Data"][$Key] != VOID) {if ($Serie["Data"][$Key] > 0) {$Align = TEXT_ALIGN_BOTTOMMIDDLE;$Offset = $DisplayOffset;} else {$Align = TEXT_ALIGN_TOPMIDDLE;$Offset = - $DisplayOffset;}$this->drawText($X + $Offset, $Y, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit),["Angle" => 270,"R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => $Align]);}if ($X == VOID && isset($Areas[$AreaID])) {$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaX1 + 1;$Areas[$AreaID][] = ($LastY == NULL) ? $Y : $LastY;$AreaID++;} elseif ($X != VOID) {if (!isset($Areas[$AreaID])) {$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaX1 + 1;$Areas[$AreaID][] = $Y;}$Areas[$AreaID][] = $X;$Areas[$AreaID][] = $Y;}$LastX = $X;$LastY = $Y;$Y = $Y + $YStep;}$Areas[$AreaID][] = ($AroundZero) ? $YZero : $this->GraphAreaX1 + 1;$Areas[$AreaID][] = $LastY;/* Handle shadows in the areas */if ($this->Shadow) {$ShadowArea = [];foreach($Areas as $Key => $Points) {$ShadowArea[$Key] = [];foreach($Points as $Key2 => $Value) {$ShadowArea[$Key][] = ($Key2 % 2 == 0) ? ($Value + $this->ShadowX) : ($Value + $this->ShadowY);}}foreach($ShadowArea as $Key => $Points) {$this->drawPolygonChart($Points, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa]);}}$Alpha = $ForceTransparency != NULL ? $ForceTransparency : $Alpha;$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Threshold" => $Threshold];foreach($Areas as $Key => $Points) {$this->drawPolygonChart($Points, $Color);}}}}}/* Draw a bar chart */function drawBarChart(array $Format = []){$Floating0Serie = NULL;$Floating0Value = NULL;$Draw0Line = FALSE;$DisplayValues = FALSE;$DisplayOrientation = ORIENTATION_HORIZONTAL;$DisplayOffset = 2;$DisplayColor = DISPLAY_MANUAL;$DisplayFont = $this->FontName;$DisplaySize = $this->FontSize;$DisplayPos = LABEL_POS_OUTSIDE;$DisplayShadow = TRUE;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$AroundZero = TRUE;$Interleave = .5;$Rounded = FALSE;$RoundRadius = 4;$Surrounding = NULL;$BorderR = -1;$BorderG = -1;$BorderB = -1;$Gradient = FALSE;$GradientMode = GRADIENT_SIMPLE;$GradientAlpha = 20;$GradientStartR = 255;$GradientStartG = 255;$GradientStartB = 255;$GradientEndR = 0;$GradientEndG = 0;$GradientEndB = 0;$TxtMargin = 6;$OverrideColors = NULL;$OverrideSurrounding = 30;$InnerSurrounding = NULL;$InnerBorderR = -1;$InnerBorderG = -1;$InnerBorderB = -1;$RecordImageMap = FALSE;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();if ($OverrideColors != NULL) {$OverrideColors = $this->validatePalette($OverrideColors, $OverrideSurrounding);$this->DataSet->saveExtendedData("Palette", $OverrideColors);}$RestoreShadow = $this->Shadow;$SeriesCount = $this->countDrawableSeries();$CurrentSerie = 0;foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = $R;$DisplayG = $G;$DisplayB = $B;}if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}if ($InnerSurrounding != NULL) {$InnerBorderR = $R + $InnerSurrounding;$InnerBorderG = $G + $InnerSurrounding;$InnerBorderB = $B + $InnerSurrounding;}$InnerColor = ($InnerBorderR == - 1) ? NULL : ["R" => $InnerBorderR,"G" => $InnerBorderG,"B" => $InnerBorderB];$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"BorderR" => $BorderR,"BorderG" => $BorderG,"BorderB" => $BorderB];$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$SerieDescription = (isset($Serie["Description"])) ? $Serie["Description"] : $SerieName;$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);if ($Floating0Value != NULL) {$YZero = $this->scaleComputeY($Floating0Value, ["AxisID" => $Serie["Axis"]]);} else {$YZero = $this->scaleComputeY([], ["AxisID" => $Serie["Axis"]]);}if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {($YZero > $this->GraphAreaY2 - 1) AND $YZero = $this->GraphAreaY2 - 1;($YZero < $this->GraphAreaY1 + 1) AND $YZero = $this->GraphAreaY1 + 1;$XStep = ($XDivs == 0) ? 0 : ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;$X = $this->GraphAreaX1 + $XMargin;$Y1 = ($AroundZero) ? $YZero : $this->GraphAreaY2 - 1;if ($XDivs == 0) {$XSize = ($this->GraphAreaX2 - $this->GraphAreaX1) / ($SeriesCount + $Interleave);} else {$XSize = ($XStep / ($SeriesCount + $Interleave));}$XOffset = - ($XSize * $SeriesCount) / 2 + $CurrentSerie * $XSize;if ($X + $XOffset <= $this->GraphAreaX1) {$XOffset = $this->GraphAreaX1 - $X + 1;}$this->DataSet->Data["Series"][$SerieName]["XOffset"] = $XOffset + $XSize / 2;$XSpace = ($Rounded || $BorderR != - 1) ? 1 : 0;$PosArray = $this->convertToArray($PosArray);$ID = 0;foreach($PosArray as $Key => $Y2) {if ($Floating0Serie != NULL) {$Value = (isset($Data["Series"][$Floating0Serie]["Data"][$Key])) ? $Data["Series"][$Floating0Serie]["Data"][$Key] : 0;$YZero = $this->scaleComputeY($Value, ["AxisID" => $Serie["Axis"]]);($YZero > $this->GraphAreaY2 - 1) AND $YZero = $this->GraphAreaY2 - 1;($YZero < $this->GraphAreaY1 + 1) AND $YZero = $this->GraphAreaY1 + 1;$Y1 = ($AroundZero) ? $YZero : $this->GraphAreaY2 - 1;}if ($OverrideColors != NULL) {if (isset($OverrideColors[$ID])) {$Color = ["R" => $OverrideColors[$ID]["R"],"G" => $OverrideColors[$ID]["G"],"B" => $OverrideColors[$ID]["B"],"Alpha" => $OverrideColors[$ID]["Alpha"],"BorderR" => $OverrideColors[$ID]["BorderR"],"BorderG" => $OverrideColors[$ID]["BorderG"],"BorderB" => $OverrideColors[$ID]["BorderB"]];} else {$Color = $this->getRandomColor();}}if ($Y2 != VOID) {$BarHeight = $Y1 - $Y2;if ($Serie["Data"][$Key] == 0) {$this->drawLine($X + $XOffset + $XSpace, $Y1, $X + $XOffset + $XSize - $XSpace, $Y1, $Color);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X + $XOffset + $XSpace) . "," . floor($Y1 - 1) . "," . floor($X + $XOffset + $XSize - $XSpace) . "," . floor($Y1 + 1), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}} else {if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X + $XOffset + $XSpace) . "," . floor($Y1) . "," . floor($X + $XOffset + $XSize - $XSpace) . "," . floor($Y2), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Rounded){$this->drawRoundedFilledRectangle($X + $XOffset + $XSpace, $Y1, $X + $XOffset + $XSize - $XSpace, $Y2, $RoundRadius, $Color);} else {$this->drawFilledRectangle($X + $XOffset + $XSpace, $Y1, $X + $XOffset + $XSize - $XSpace, $Y2, $Color);if ($InnerColor != NULL) {$this->drawRectangle($X + $XOffset + $XSpace + 1, min($Y1, $Y2) + 1, $X + $XOffset + $XSize - $XSpace - 1, max($Y1, $Y2) - 1, $InnerColor);}if ($Gradient) {$this->Shadow = FALSE;if ($GradientMode == GRADIENT_SIMPLE) {if ($Serie["Data"][$Key] >= 0) {$GradienColor = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];} else {$GradienColor = ["StartR" => $GradientEndR,"StartG" => $GradientEndG,"StartB" => $GradientEndB,"EndR" => $GradientStartR,"EndG" => $GradientStartG,"EndB" => $GradientStartB,"Alpha" => $GradientAlpha];}$this->drawGradientArea($X + $XOffset + $XSpace, $Y1, $X + $XOffset + $XSize - $XSpace, $Y2, DIRECTION_VERTICAL, $GradienColor);} elseif ($GradientMode == GRADIENT_EFFECT_CAN) {$GradienColor1 = ["StartR" => $GradientEndR,"StartG" => $GradientEndG,"StartB" => $GradientEndB,"EndR" => $GradientStartR,"EndG" => $GradientStartG,"EndB" => $GradientStartB,"Alpha" => $GradientAlpha];$GradienColor2 = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];$XSpan = floor($XSize / 3);$this->drawGradientArea($X + $XOffset + $XSpace, $Y1, $X + $XOffset + $XSpan - $XSpace, $Y2, DIRECTION_HORIZONTAL, $GradienColor1);$this->drawGradientArea($X + $XOffset + $XSpan + $XSpace, $Y1, $X + $XOffset + $XSize - $XSpace, $Y2, DIRECTION_HORIZONTAL, $GradienColor2);}$this->Shadow = $RestoreShadow;}}if ($Draw0Line) {$Line0Color = ["R" => 0,"G" => 0,"B" => 0,"Alpha" => 20];$Line0Width = (abs($Y1 - $Y2) > 3) ? 3 : 1;($Y1 - $Y2 < 0) AND $Line0Width = - $Line0Width;$this->drawFilledRectangle($X + $XOffset + $XSpace, floor($Y1), $X + $XOffset + $XSize - $XSpace, floor($Y1) - $Line0Width, $Line0Color);$this->drawLine($X + $XOffset + $XSpace, floor($Y1), $X + $XOffset + $XSize - $XSpace, floor($Y1), $Line0Color);}}if ($DisplayValues && $Serie["Data"][$Key] != VOID) {($DisplayShadow) AND $this->Shadow = TRUE;$Caption = $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit);$TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 90, $Caption);$TxtHeight = $TxtPos[0]["Y"] - $TxtPos[1]["Y"] + $TxtMargin;if ($DisplayPos == LABEL_POS_INSIDE && abs($TxtHeight) < abs($BarHeight)) {$CenterX = (($X + $XOffset + $XSize - $XSpace) - ($X + $XOffset + $XSpace)) / 2 + $X + $XOffset + $XSpace;$CenterY = ($Y2 - $Y1) / 2 + $Y1;$this->drawText($CenterX, $CenterY, $Caption, ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_MIDDLEMIDDLE,"FontSize" => $DisplaySize,"Angle" => 90]);} else {if ($Serie["Data"][$Key] >= 0) {$Align = TEXT_ALIGN_BOTTOMMIDDLE;$Offset = $DisplayOffset;} else {$Align = TEXT_ALIGN_TOPMIDDLE;$Offset = - $DisplayOffset;}$this->drawText($X + $XOffset + $XSize / 2, $Y2 - $Offset, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => $Align,"FontSize" => $DisplaySize]);}$this->Shadow = $RestoreShadow;}}$X = $X + $XStep;$ID++;}} else {($YZero < $this->GraphAreaX1 + 1) AND $YZero = $this->GraphAreaX1 + 1;($YZero > $this->GraphAreaX2 - 1) AND $YZero = $this->GraphAreaX2 - 1;$YStep = ($XDivs == 0) ? 0 : ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;$Y = $this->GraphAreaY1 + $XMargin;$X1 = ($AroundZero) ? $YZero : $this->GraphAreaX1 + 1;if ($XDivs == 0) {$YSize = ($this->GraphAreaY2 - $this->GraphAreaY1) / ($SeriesCount + $Interleave);} else {$YSize = ($YStep / ($SeriesCount + $Interleave));}$YOffset = - ($YSize * $SeriesCount) / 2 + $CurrentSerie * $YSize;if ($Y + $YOffset <= $this->GraphAreaY1) {$YOffset = $this->GraphAreaY1 - $Y + 1;}$this->DataSet->Data["Series"][$SerieName]["XOffset"] = $YOffset + $YSize / 2;$YSpace = ($Rounded || $BorderR != - 1) ? 1 : 0;$PosArray = $this->convertToArray($PosArray);$ID = 0;foreach($PosArray as $Key => $X2) {if ($Floating0Serie != NULL) {$Value = (isset($Data["Series"][$Floating0Serie]["Data"][$Key])) ? $Data["Series"][$Floating0Serie]["Data"][$Key] : 0;$YZero = $this->scaleComputeY($Value, ["AxisID" => $Serie["Axis"]]);($YZero < $this->GraphAreaX1 + 1) AND $YZero = $this->GraphAreaX1 + 1;($YZero > $this->GraphAreaX2 - 1) AND $YZero = $this->GraphAreaX2 - 1;$X1 = ($AroundZero) ? $YZero : $this->GraphAreaX1 + 1;}if ($OverrideColors != NULL) {if (isset($OverrideColors[$ID])) {$Color = ["R" => $OverrideColors[$ID]["R"],"G" => $OverrideColors[$ID]["G"],"B" => $OverrideColors[$ID]["B"],"Alpha" => $OverrideColors[$ID]["Alpha"],"BorderR" => $OverrideColors[$ID]["BorderR"],"BorderG" => $OverrideColors[$ID]["BorderG"],"BorderB" => $OverrideColors[$ID]["BorderB"]];} else {$Color = $this->getRandomColor();}}if ($X2 != VOID) {$BarWidth = $X2 - $X1;if ($Serie["Data"][$Key] == 0) {$this->drawLine($X1, $Y + $YOffset + $YSpace, $X1, $Y + $YOffset + $YSize - $YSpace, $Color);if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X1 - 1) . "," . floor($Y + $YOffset + $YSpace) . "," . floor($X1 + 1) . "," . floor($Y + $YOffset + $YSize - $YSpace), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}} else {if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X1) . "," . floor($Y + $YOffset + $YSpace) . "," . floor($X2) . "," . floor($Y + $YOffset + $YSize - $YSpace), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Rounded) {$this->drawRoundedFilledRectangle($X1 + 1, $Y + $YOffset + $YSpace, $X2, $Y + $YOffset + $YSize - $YSpace, $RoundRadius, $Color);} else {$this->drawFilledRectangle($X1, $Y + $YOffset + $YSpace, $X2, $Y + $YOffset + $YSize - $YSpace, $Color);if ($InnerColor != NULL) {$this->drawRectangle(min($X1, $X2) + 1, $Y + $YOffset + $YSpace + 1, max($X1, $X2) - 1, $Y + $YOffset + $YSize - $YSpace - 1, $InnerColor);}if ($Gradient) {$this->Shadow = FALSE;if ($GradientMode == GRADIENT_SIMPLE) {if ($Serie["Data"][$Key] >= 0) {$GradienColor = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];} else {$GradienColor = ["StartR" => $GradientEndR,"StartG" => $GradientEndG,"StartB" => $GradientEndB,"EndR" => $GradientStartR,"EndG" => $GradientStartG,"EndB" => $GradientStartB,"Alpha" => $GradientAlpha];}$this->drawGradientArea($X1, $Y + $YOffset + $YSpace, $X2, $Y + $YOffset + $YSize - $YSpace, DIRECTION_HORIZONTAL, $GradienColor);} elseif ($GradientMode == GRADIENT_EFFECT_CAN) {$GradienColor1 = ["StartR" => $GradientEndR,"StartG" => $GradientEndG,"StartB" => $GradientEndB,"EndR" => $GradientStartR,"EndG" => $GradientStartG,"EndB" => $GradientStartB,"Alpha" => $GradientAlpha];$GradienColor2 = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];$YSpan = floor($YSize / 3);$this->drawGradientArea($X1, $Y + $YOffset + $YSpace, $X2, $Y + $YOffset + $YSpan - $YSpace, DIRECTION_VERTICAL, $GradienColor1);$this->drawGradientArea($X1, $Y + $YOffset + $YSpan, $X2, $Y + $YOffset + $YSize - $YSpace, DIRECTION_VERTICAL, $GradienColor2);}$this->Shadow = $RestoreShadow;}}if ($Draw0Line) {$Line0Color = ["R" => 0,"G" => 0,"B" => 0,"Alpha" => 20];$Line0Width = (abs($X1 - $X2) > 3) ? 3 : 1;($X2 - $X1 < 0) AND $Line0Width = - $Line0Width;$this->drawFilledRectangle(floor($X1), $Y + $YOffset + $YSpace, floor($X1) + $Line0Width, $Y + $YOffset + $YSize - $YSpace, $Line0Color);$this->drawLine(floor($X1), $Y + $YOffset + $YSpace, floor($X1), $Y + $YOffset + $YSize - $YSpace, $Line0Color);}}if ($DisplayValues && $Serie["Data"][$Key] != VOID) {($DisplayShadow) AND $this->Shadow = TRUE;$Caption = $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit);$TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 0, $Caption);$TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"] + $TxtMargin;if ($DisplayPos == LABEL_POS_INSIDE && abs($TxtWidth) < abs($BarWidth)) {$CenterX = ($X2 - $X1) / 2 + $X1;$CenterY = (($Y + $YOffset + $YSize - $YSpace) - ($Y + $YOffset + $YSpace)) / 2 + ($Y + $YOffset + $YSpace);$this->drawText($CenterX, $CenterY, $Caption, ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_MIDDLEMIDDLE,"FontSize" => $DisplaySize]);} else {if ($Serie["Data"][$Key] >= 0) {$Align = TEXT_ALIGN_MIDDLELEFT;$Offset = $DisplayOffset;} else {$Align = TEXT_ALIGN_MIDDLERIGHT;$Offset = - $DisplayOffset;}$this->drawText($X2 + $Offset, $Y + $YOffset + $YSize / 2, $Caption, ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => $Align,"FontSize" => $DisplaySize]);}$this->Shadow = $RestoreShadow;}}$Y = $Y + $YStep;$ID++;}}$CurrentSerie++;}}}/* Draw a bar chart */function drawStackedBarChart(array $Format = []){$DisplayValues = FALSE;$DisplayOrientation = ORIENTATION_AUTO;$DisplayRound = 0;$DisplayColor = DISPLAY_MANUAL;$DisplayFont = $this->FontName;$DisplaySize = $this->FontSize;$DisplayR = 0;$DisplayG = 0;$DisplayB = 0;$Interleave = .5;$Rounded = FALSE;$RoundRadius = 4;$Surrounding = NULL;$BorderR = -1;$BorderG = -1;$BorderB = -1;$Gradient = FALSE;$GradientMode = GRADIENT_SIMPLE;$GradientAlpha = 20;$GradientStartR = 255;$GradientStartG = 255;$GradientStartB = 255;$GradientEndR = 0;$GradientEndG = 0;$GradientEndB = 0;$InnerSurrounding = NULL;$InnerBorderR = -1;$InnerBorderG = -1;$InnerBorderB = -1;$RecordImageMap = FALSE;$FontFactor = 8;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_STACKED;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();$RestoreShadow = $this->Shadow;$LastX = [];$LastY = [];foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];if ($DisplayColor == DISPLAY_AUTO) {$DisplayR = 255;$DisplayG = 255;$DisplayB = 255;}if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}if ($InnerSurrounding != NULL) {$InnerBorderR = $R + $InnerSurrounding;$InnerBorderG = $G + $InnerSurrounding;$InnerBorderB = $B + $InnerSurrounding;}$InnerColor = ($InnerBorderR == - 1) ? NULL : ["R" => $InnerBorderR,"G" => $InnerBorderG,"B" => $InnerBorderB];$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$SerieDescription = (isset($Serie["Description"])) ? $Serie["Description"] : $SerieName;$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]], TRUE);$YZero = $this->scaleComputeY(0, ["AxisID" => $Serie["Axis"]]);$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;$Color = ["TransCorner" => TRUE,"R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"BorderR" => $BorderR,"BorderG" => $BorderG,"BorderB" => $BorderB];if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {($YZero > $this->GraphAreaY2 - 1) AND $YZero = $this->GraphAreaY2 - 1;($YZero > $this->GraphAreaY2 - 1) AND $YZero = $this->GraphAreaY2 - 1;if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$XSize = ($XStep / (1 + $Interleave));$XOffset = - ($XSize / 2);$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $Height) {if ($Height != VOID && $Serie["Data"][$Key] != 0) {$Pos = ($Serie["Data"][$Key] > 0) ? "+" : "-";(!isset($LastY[$Key])) AND $LastY[$Key] = [];(!isset($LastY[$Key][$Pos])) AND $LastY[$Key][$Pos] = $YZero;$Y1 = $LastY[$Key][$Pos];$Y2 = $Y1 - $Height;$YSpaceUp = (($Rounded || $BorderR != - 1) && ($Pos == "+" && $Y1 != $YZero)) ? 1 : 0;$YSpaceDown = (($Rounded || $BorderR != - 1) && ($Pos == "-" && $Y1 != $YZero)) ? 1 : 0;if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X + $XOffset) . "," . floor($Y1 - $YSpaceUp + $YSpaceDown) . "," . floor($X + $XOffset + $XSize) . "," . floor($Y2), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Rounded) {$this->drawRoundedFilledRectangle($X + $XOffset, $Y1 - $YSpaceUp + $YSpaceDown, $X + $XOffset + $XSize, $Y2, $RoundRadius, $Color);} else {$this->drawFilledRectangle($X + $XOffset, $Y1 - $YSpaceUp + $YSpaceDown, $X + $XOffset + $XSize, $Y2, $Color);if ($InnerColor != NULL) {$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;$this->drawRectangle(min($X + $XOffset + 1, $X + $XOffset + $XSize), min($Y1 - $YSpaceUp + $YSpaceDown, $Y2) + 1, max($X + $XOffset + 1, $X + $XOffset + $XSize) - 1, max($Y1 - $YSpaceUp + $YSpaceDown, $Y2) - 1, $InnerColor);$this->Shadow = $RestoreShadow;}if ($Gradient) {$this->Shadow = FALSE;if ($GradientMode == GRADIENT_SIMPLE) {$GradientColor = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];$this->drawGradientArea($X + $XOffset, $Y1 - 1 - $YSpaceUp + $YSpaceDown, $X + $XOffset + $XSize, $Y2 + 1, DIRECTION_VERTICAL, $GradientColor);} elseif ($GradientMode == GRADIENT_EFFECT_CAN) {$GradientColor1 = ["StartR" => $GradientEndR,"StartG" => $GradientEndG,"StartB" => $GradientEndB,"EndR" => $GradientStartR,"EndG" => $GradientStartG,"EndB" => $GradientStartB,"Alpha" => $GradientAlpha];$GradientColor2 = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];$XSpan = floor($XSize / 3);$this->drawGradientArea($X + $XOffset - .5, $Y1 - .5 - $YSpaceUp + $YSpaceDown, $X + $XOffset + $XSpan, $Y2 + .5, DIRECTION_HORIZONTAL, $GradientColor1);$this->drawGradientArea($X + $XSpan + $XOffset - .5, $Y1 - .5 - $YSpaceUp + $YSpaceDown, $X + $XOffset + $XSize, $Y2 + .5, DIRECTION_HORIZONTAL, $GradientColor2);}$this->Shadow = $RestoreShadow;}}if ($DisplayValues) {$BarHeight = abs($Y2 - $Y1) - 2;$BarWidth = $XSize + ($XOffset / 2) - $FontFactor;$Caption = $this->scaleFormat(round($Serie["Data"][$Key], $DisplayRound), $Mode, $Format, $Unit);$TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 0, $Caption);$TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]);$TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]);$XCenter = (($X + $XOffset + $XSize) - ($X + $XOffset)) / 2 + $X + $XOffset;$YCenter = (($Y2) - ($Y1 - $YSpaceUp + $YSpaceDown)) / 2 + $Y1 - $YSpaceUp + $YSpaceDown;$Done = FALSE;if ($DisplayOrientation == ORIENTATION_HORIZONTAL || $DisplayOrientation == ORIENTATION_AUTO) {if ($TxtHeight < $BarHeight && $TxtWidth < $BarWidth) {$this->drawText($XCenter, $YCenter, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_MIDDLEMIDDLE,"FontSize" => $DisplaySize,"FontName" => $DisplayFont]);$Done = TRUE;}}if ($DisplayOrientation == ORIENTATION_VERTICAL || ($DisplayOrientation == ORIENTATION_AUTO && !$Done)) {if ($TxtHeight < $BarWidth && $TxtWidth < $BarHeight) {$this->drawText($XCenter, $YCenter, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Angle" => 90,"Align" => TEXT_ALIGN_MIDDLEMIDDLE,"FontSize" => $DisplaySize,"FontName" => $DisplayFont]);}}}$LastY[$Key][$Pos] = $Y2;}$X = $X + $XStep;}} else { # SCALE_POS_LEFTRIGHT($YZero < $this->GraphAreaX1 + 1) AND $YZero = $this->GraphAreaX1 + 1;($YZero > $this->GraphAreaX2 - 1) AND $YZero = $this->GraphAreaX2 - 1;if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$YSize = $YStep / (1 + $Interleave);$YOffset = - ($YSize / 2);$PosArray = $this->convertToArray($PosArray);foreach($PosArray as $Key => $Width) {if ($Width != VOID && $Serie["Data"][$Key] != 0) {$Pos = ($Serie["Data"][$Key] > 0) ? "+" : "-";(!isset($LastX[$Key])) AND $LastX[$Key] = [];(!isset($LastX[$Key][$Pos])) AND $LastX[$Key][$Pos] = $YZero;$X1 = $LastX[$Key][$Pos];$X2 = $X1 + $Width;$XSpaceLeft = (($Rounded || $BorderR != - 1) && ($Pos == "+" && $X1 != $YZero)) ? 2 : 0;$XSpaceRight = (($Rounded || $BorderR != - 1) && ($Pos == "-" && $X1 != $YZero)) ? 2 : 0;if ($RecordImageMap) {$this->addToImageMap("RECT", floor($X1 + $XSpaceLeft) . "," . floor($Y + $YOffset) . "," . floor($X2 - $XSpaceRight) . "," . floor($Y + $YOffset + $YSize), $this->toHTMLColor($R, $G, $B), $SerieDescription, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit));}if ($Rounded) {$this->drawRoundedFilledRectangle($X1 + $XSpaceLeft, $Y + $YOffset, $X2 - $XSpaceRight, $Y + $YOffset + $YSize, $RoundRadius, $Color);} else {$this->drawFilledRectangle($X1 + $XSpaceLeft, $Y + $YOffset, $X2 - $XSpaceRight, $Y + $YOffset + $YSize, $Color);if ($InnerColor != NULL) {$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;$this->drawRectangle(min($X1 + $XSpaceLeft, $X2 - $XSpaceRight) + 1, min($Y + $YOffset, $Y + $YOffset + $YSize) + 1, max($X1 + $XSpaceLeft, $X2 - $XSpaceRight) - 1, max($Y + $YOffset, $Y + $YOffset + $YSize) - 1, $InnerColor);$this->Shadow = $RestoreShadow;}if ($Gradient) {$this->Shadow = FALSE;if ($GradientMode == GRADIENT_SIMPLE) {$GradientColor = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];$this->drawGradientArea($X1 + $XSpaceLeft, $Y + $YOffset, $X2 - $XSpaceRight, $Y + $YOffset + $YSize, DIRECTION_HORIZONTAL, $GradientColor);} elseif ($GradientMode == GRADIENT_EFFECT_CAN) {$GradientColor1 = ["StartR" => $GradientEndR,"StartG" => $GradientEndG,"StartB" => $GradientEndB,"EndR" => $GradientStartR,"EndG" => $GradientStartG,"EndB" => $GradientStartB,"Alpha" => $GradientAlpha];$GradientColor2 = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $GradientAlpha];$YSpan = floor($YSize / 3);$this->drawGradientArea($X1 + $XSpaceLeft, $Y + $YOffset, $X2 - $XSpaceRight, $Y + $YOffset + $YSpan, DIRECTION_VERTICAL, $GradientColor1);$this->drawGradientArea($X1 + $XSpaceLeft, $Y + $YOffset + $YSpan, $X2 - $XSpaceRight, $Y + $YOffset + $YSize, DIRECTION_VERTICAL, $GradientColor2);}$this->Shadow = $RestoreShadow;}}if ($DisplayValues) {$BarWidth = abs($X2 - $X1) - $FontFactor;$BarHeight = $YSize + ($YOffset / 2) - $FontFactor / 2;$Caption = $this->scaleFormat(round($Serie["Data"][$Key], $DisplayRound), $Mode, $Format, $Unit);$TxtPos = $this->getTextBox(0, 0, $DisplayFont, $DisplaySize, 0, $Caption);$TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]);$TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]);$XCenter = ($X2 - $X1) / 2 + $X1;$YCenter = (($Y + $YOffset + $YSize) - ($Y + $YOffset)) / 2 + $Y + $YOffset;$Done = FALSE;if ($DisplayOrientation == ORIENTATION_HORIZONTAL || $DisplayOrientation == ORIENTATION_AUTO) {if ($TxtHeight < $BarHeight && $TxtWidth < $BarWidth) {$this->drawText($XCenter, $YCenter, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Align" => TEXT_ALIGN_MIDDLEMIDDLE,"FontSize" => $DisplaySize,"FontName" => $DisplayFont]);$Done = TRUE;}}if ($DisplayOrientation == ORIENTATION_VERTICAL || ($DisplayOrientation == ORIENTATION_AUTO && !$Done)) {if ($TxtHeight < $BarWidth && $TxtWidth < $BarHeight) {$this->drawText($XCenter, $YCenter, $this->scaleFormat($Serie["Data"][$Key], $Mode, $Format, $Unit), ["R" => $DisplayR,"G" => $DisplayG,"B" => $DisplayB,"Angle" => 90,"Align" => TEXT_ALIGN_MIDDLEMIDDLE,"FontSize" => $DisplaySize,"FontName" => $DisplayFont]);}}}$LastX[$Key][$Pos] = $X2;}$Y = $Y + $YStep;}}}}}/* Draw a stacked area chart */function drawStackedAreaChart(array $Format = []){$DrawLine = FALSE;$LineSurrounding = NULL;$LineR = VOID;$LineG = VOID;$LineB = VOID;$LineAlpha = 100;$DrawPlot = FALSE;$PlotRadius = 2;$PlotBorder = 1;$PlotBorderSurrounding = NULL;$PlotBorderR = 0;$PlotBorderG = 0;$PlotBorderB = 0;$PlotBorderAlpha = 50;$ForceTransparency = NULL;/* Override defaults */extract($Format);$this->LastChartLayout = CHART_LAST_LAYOUT_STACKED;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;/* Build the offset data series */// $OffsetData = ""; # UNUSED$OverallOffset = [];$SerieOrder = [];foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$SerieOrder[] = $SerieName;foreach($Serie["Data"] as $Key => $Value) {($Value == VOID) AND $Value = 0;$Sign = ($Value >= 0) ? "+" : "-";(!isset($OverallOffset[$Key]) || !isset($OverallOffset[$Key][$Sign])) AND $OverallOffset[$Key][$Sign] = 0;$Data["Series"][$SerieName]["Data"][$Key] = ($Sign == "+") ? $Value + $OverallOffset[$Key][$Sign] : $Value - $OverallOffset[$Key][$Sign];$OverallOffset[$Key][$Sign] = $OverallOffset[$Key][$Sign] + abs($Value);}}}$SerieOrder = array_reverse($SerieOrder);// $LastX = ""; $LastY = ""; # UNUSEDforeach($SerieOrder as $Key => $SerieName) {$Serie = $Data["Series"][$SerieName];if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];($ForceTransparency != NULL) AND $Alpha = $ForceTransparency;$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];if ($LineSurrounding != NULL) {$LineColor = ["R" => $R + $LineSurrounding,"G" => $G + $LineSurrounding,"B" => $B + $LineSurrounding,"Alpha" => $Alpha];} elseif ($LineR != VOID) {$LineColor = ["R" => $LineR,"G" => $LineG,"B" => $LineB,"Alpha" => $LineAlpha];} else {$LineColor = $Color;}if ($PlotBorderSurrounding != NULL) {$PlotBorderColor = ["R" => $R + $PlotBorderSurrounding,"G" => $G + $PlotBorderSurrounding,"B" => $B + $PlotBorderSurrounding,"Alpha" => $PlotBorderAlpha];} else {$PlotBorderColor = ["R" => $PlotBorderR,"G" => $PlotBorderG,"B" => $PlotBorderB,"Alpha" => $PlotBorderAlpha];}$AxisID = $Serie["Axis"];$Mode = $Data["Axis"][$AxisID]["Display"];$Format = $Data["Axis"][$AxisID]["Format"];$Unit = $Data["Axis"][$AxisID]["Unit"];$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]], TRUE);$YZero = $this->scaleComputeY([0], ["AxisID" => $Serie["Axis"]]);$this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0;if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {($YZero < $this->GraphAreaY1 + 1) AND $YZero = $this->GraphAreaY1 + 1;($YZero > $this->GraphAreaY2 - 1) AND $YZero = $this->GraphAreaY2 - 1;if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$PosArray = $this->convertToArray($PosArray);$Plots = [$X, $YZero];foreach($PosArray as $Key => $Height) {if ($Height != VOID) {$Plots[] = $X;$Plots[] = $YZero - $Height;}$X = $X + $XStep;}$Plots[] = $X - $XStep;$Plots[] = $YZero;$this->drawPolygon($Plots, $Color);$this->Shadow = $RestoreShadow;if ($DrawLine) {for ($i = 2; $i <= count($Plots) - 6; $i = $i + 2) {$this->drawLine($Plots[$i], $Plots[$i + 1], $Plots[$i + 2], $Plots[$i + 3], $LineColor);}}if ($DrawPlot) {for ($i = 2; $i <= count($Plots) - 4; $i = $i + 2) {if ($PlotBorder != 0) {$this->drawFilledCircle($Plots[$i], $Plots[$i + 1], $PlotRadius + $PlotBorder, $PlotBorderColor);}$this->drawFilledCircle($Plots[$i], $Plots[$i + 1], $PlotRadius, $Color);}}$this->Shadow = FALSE;} elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) {($YZero < $this->GraphAreaX1 + 1) AND $YZero = $this->GraphAreaX1 + 1;($YZero > $this->GraphAreaX2 - 1) AND $YZero = $this->GraphAreaX2 - 1;if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$PosArray = $this->convertToArray($PosArray);$Plots = [$YZero, $Y];foreach($PosArray as $Key => $Height) {if ($Height != VOID) {$Plots[] = $YZero + $Height;$Plots[] = $Y;}$Y = $Y + $YStep;}$Plots[] = $YZero;$Plots[] = $Y - $YStep;$this->drawPolygon($Plots, $Color);$this->Shadow = $RestoreShadow;if ($DrawLine) {for ($i = 2; $i <= count($Plots) - 6; $i = $i + 2) {$this->drawLine($Plots[$i], $Plots[$i + 1], $Plots[$i + 2], $Plots[$i + 3], $LineColor);}}if ($DrawPlot) {for ($i = 2; $i <= count($Plots) - 4; $i = $i + 2) {if ($PlotBorder != 0) {$this->drawFilledCircle($Plots[$i], $Plots[$i + 1], $PlotRadius + $PlotBorder, $PlotBorderColor);}$this->drawFilledCircle($Plots[$i], $Plots[$i + 1], $PlotRadius, $Color);}}$this->Shadow = FALSE;}}}$this->Shadow = $RestoreShadow;}/* Returns a random color */function getRandomColor($Alpha = 100){return ["R" => rand(0, 255),"G" => rand(0, 255),"B" => rand(0, 255),"Alpha" => $Alpha];}/* Validate a palette */function validatePalette($Colors, $Surrounding = NULL){$Result = [];if (!is_array($Colors)) {return ($this->getRandomColor());}foreach($Colors as $Key => $Values) {$Result[$Key]["R"] = (isset($Values["R"])) ? $Values["R"] : rand(0, 255);$Result[$Key]["G"] = (isset($Values["G"])) ? $Values["G"] : rand(0, 255);$Result[$Key]["B"] = (isset($Values["B"])) ? $Values["B"] : rand(0, 255);$Result[$Key]["Alpha"] = (isset($Values["Alpha"])) ? $Values["Alpha"] : 100;if ($Surrounding != NULL) {$Result[$Key]["BorderR"] = $Result[$Key]["R"] + $Surrounding;$Result[$Key]["BorderG"] = $Result[$Key]["G"] + $Surrounding;$Result[$Key]["BorderB"] = $Result[$Key]["B"] + $Surrounding;} else {$Result[$Key]["BorderR"] = (isset($Values["BorderR"])) ? $Values["BorderR"] : $Result[$Key]["R"];$Result[$Key]["BorderG"] = (isset($Values["BorderG"])) ? $Values["BorderG"] : $Result[$Key]["G"];$Result[$Key]["BorderB"] = (isset($Values["BorderB"])) ? $Values["BorderB"] : $Result[$Key]["B"];$Result[$Key]["BorderAlpha"] = (isset($Values["BorderAlpha"])) ? $Values["BorderAlpha"] : $Result[$Key]["Alpha"];}}return ($Result);}/* Draw the derivative chart associated to the data series */function drawDerivative(array $Format = []){$Offset = 10;$SerieSpacing = 3;$DerivativeHeight = 4;$ShadedSlopeBox = FALSE;$DrawBackground = TRUE;$BackgroundR = 255;$BackgroundG = 255;$BackgroundB = 255;$BackgroundAlpha = 20;$DrawBorder = TRUE;$BorderR = 0;$BorderG = 0;$BorderB = 0;$BorderAlpha = 100;$Caption = TRUE;$CaptionHeight = 10;$CaptionWidth = 20;$CaptionMargin = 4;$CaptionLine = FALSE;$CaptionBox = FALSE;$CaptionBorderR = 0;$CaptionBorderG = 0;$CaptionBorderB = 0;$CaptionFillR = 255;$CaptionFillG = 255;$CaptionFillB = 255;$CaptionFillAlpha = 80;$PositiveSlopeStartR = 184;$PositiveSlopeStartG = 234;$PositiveSlopeStartB = 88;$PositiveSlopeEndR = 239;$PositiveSlopeEndG = 31;$PositiveSlopeEndB = 36;$NegativeSlopeStartR = 184;$NegativeSlopeStartG = 234;$NegativeSlopeStartB = 88;$NegativeSlopeEndR = 67;$NegativeSlopeEndG = 124;$NegativeSlopeEndB = 227;/* Override defaults */extract($Format);$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {$YPos = $this->DataSet->Data["GraphArea"]["Y2"] + $Offset;} else {$XPos = $this->DataSet->Data["GraphArea"]["X2"] + $Offset;}foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];$Alpha = $Serie["Color"]["Alpha"];$Ticks = $Serie["Ticks"];$Weight = $Serie["Weight"];$AxisID = $Serie["Axis"];$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($Caption) {if ($CaptionLine) {$StartX = floor($this->GraphAreaX1 - $CaptionWidth + $XMargin - $CaptionMargin);$EndX = floor($this->GraphAreaX1 - $CaptionMargin + $XMargin);$CaptionSettings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight];if ($CaptionBox) {$this->drawFilledRectangle($StartX, $YPos, $EndX, $YPos + $CaptionHeight, ["R" => $CaptionFillR,"G" => $CaptionFillG,"B" => $CaptionFillB,"BorderR" => $CaptionBorderR,"BorderG" => $CaptionBorderG,"BorderB" => $CaptionBorderB,"Alpha" => $CaptionFillAlpha]);}$this->drawLine($StartX + 2, $YPos + ($CaptionHeight / 2), $EndX - 2, $YPos + ($CaptionHeight / 2), $CaptionSettings);} else {$this->drawFilledRectangle($this->GraphAreaX1 - $CaptionWidth + $XMargin - $CaptionMargin, $YPos, $this->GraphAreaX1 - $CaptionMargin + $XMargin, $YPos + $CaptionHeight, ["R" => $R,"G" => $G,"B" => $B,"BorderR" => $CaptionBorderR,"BorderG" => $CaptionBorderG,"BorderB" => $CaptionBorderB]);}}if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$TopY = $YPos + ($CaptionHeight / 2) - ($DerivativeHeight / 2);$BottomY = $YPos + ($CaptionHeight / 2) + ($DerivativeHeight / 2);$StartX = floor($this->GraphAreaX1 + $XMargin);$EndX = floor($this->GraphAreaX2 - $XMargin);if ($DrawBackground) {$this->drawFilledRectangle($StartX - 1, $TopY - 1, $EndX + 1, $BottomY + 1, ["R" => $BackgroundR,"G" => $BackgroundG,"B" => $BackgroundB,"Alpha" => $BackgroundAlpha]);}if ($DrawBorder) {$this->drawRectangle($StartX - 1, $TopY - 1, $EndX + 1, $BottomY + 1, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha]);}$PosArray = $this->convertToArray($PosArray);$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;/* Determine the Max slope index */$LastX = NULL;$LastY = NULL;$MinSlope = 0;$MaxSlope = 1;foreach($PosArray as $Key => $Y) {if ($Y != VOID && $LastX != NULL) {$Slope = ($LastY - $Y);($Slope > $MaxSlope) AND $MaxSlope = $Slope;($Slope < $MinSlope) AND $MinSlope = $Slope;}if ($Y == VOID) {$LastX = NULL;$LastY = NULL;} else {$LastX = $X;$LastY = $Y;}}$LastX = NULL;$LastY = NULL;$LastColor = NULL;foreach($PosArray as $Key => $Y) {if ($Y != VOID && $LastY != NULL) {$Slope = ($LastY - $Y);if ($Slope >= 0) {$SlopeIndex = (100 / $MaxSlope) * $Slope;$R = (($PositiveSlopeEndR - $PositiveSlopeStartR) / 100) * $SlopeIndex + $PositiveSlopeStartR;$G = (($PositiveSlopeEndG - $PositiveSlopeStartG) / 100) * $SlopeIndex + $PositiveSlopeStartG;$B = (($PositiveSlopeEndB - $PositiveSlopeStartB) / 100) * $SlopeIndex + $PositiveSlopeStartB;} elseif ($Slope < 0) {$SlopeIndex = (100 / abs($MinSlope)) * abs($Slope);$R = (($NegativeSlopeEndR - $NegativeSlopeStartR) / 100) * $SlopeIndex + $NegativeSlopeStartR;$G = (($NegativeSlopeEndG - $NegativeSlopeStartG) / 100) * $SlopeIndex + $NegativeSlopeStartG;$B = (($NegativeSlopeEndB - $NegativeSlopeStartB) / 100) * $SlopeIndex + $NegativeSlopeStartB;}$Color = ["R" => $R,"G" => $G,"B" => $B];if ($ShadedSlopeBox && $LastColor != NULL) // && $Slope != 0{$GradientSettings = ["StartR" => $LastColor["R"],"StartG" => $LastColor["G"],"StartB" => $LastColor["B"],"EndR" => $R,"EndG" => $G,"EndB" => $B];$this->drawGradientArea($LastX, $TopY, $X, $BottomY, DIRECTION_HORIZONTAL, $GradientSettings);} elseif (!$ShadedSlopeBox || $LastColor == NULL) { // || $Slope == 0$this->drawFilledRectangle(floor($LastX), $TopY, floor($X), $BottomY, $Color);}$LastColor = $Color;}if ($Y == VOID) {$LastY = NULL;} else {$LastX = $X;$LastY = $Y;}$X = $X + $XStep;}$YPos = $YPos + $CaptionHeight + $SerieSpacing;} else { # ($Data["Orientation"] == SCALE_POS_LEFTRIGHT)if ($Caption) {$StartY = floor($this->GraphAreaY1 - $CaptionWidth + $XMargin - $CaptionMargin);$EndY = floor($this->GraphAreaY1 - $CaptionMargin + $XMargin);if ($CaptionLine) {$CaptionSettings = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks,"Weight" => $Weight];if ($CaptionBox) {$this->drawFilledRectangle($XPos, $StartY, $XPos + $CaptionHeight, $EndY, ["R" => $CaptionFillR,"G" => $CaptionFillG,"B" => $CaptionFillB,"BorderR" => $CaptionBorderR,"BorderG" => $CaptionBorderG,"BorderB" => $CaptionBorderB,"Alpha" => $CaptionFillAlpha]);}$this->drawLine($XPos + ($CaptionHeight / 2), $StartY + 2, $XPos + ($CaptionHeight / 2), $EndY - 2, $CaptionSettings);} else {$this->drawFilledRectangle($XPos, $StartY, $XPos + $CaptionHeight, $EndY, ["R" => $R,"G" => $G,"B" => $B,"BorderR" => $CaptionBorderR,"BorderG" => $CaptionBorderG,"BorderB" => $CaptionBorderB]);}}if ($XDivs == 0) {$XStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$XStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$TopX = $XPos + ($CaptionHeight / 2) - ($DerivativeHeight / 2);$BottomX = $XPos + ($CaptionHeight / 2) + ($DerivativeHeight / 2);$StartY = floor($this->GraphAreaY1 + $XMargin);$EndY = floor($this->GraphAreaY2 - $XMargin);if ($DrawBackground) {$this->drawFilledRectangle($TopX - 1, $StartY - 1, $BottomX + 1, $EndY + 1, ["R" => $BackgroundR,"G" => $BackgroundG,"B" => $BackgroundB,"Alpha" => $BackgroundAlpha]);}if ($DrawBorder) {$this->drawRectangle($TopX - 1, $StartY - 1, $BottomX + 1, $EndY + 1, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha]);}$PosArray = $this->convertToArray($PosArray);$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;/* Determine the Max slope index */$LastX = NULL;$LastY = NULL;$MinSlope = 0;$MaxSlope = 1;foreach($PosArray as $Key => $X) {if ($X != VOID && $LastX != NULL) {$Slope = ($X - $LastX);($Slope > $MaxSlope) AND $MaxSlope = $Slope;($Slope < $MinSlope) AND $MinSlope = $Slope;}$LastX = ($X == VOID) ? NULL : $X;}$LastX = NULL;$LastY = NULL;$LastColor = NULL;foreach($PosArray as $Key => $X) {if ($X != VOID && $LastX != NULL) {$Slope = ($X - $LastX);if ($Slope >= 0) {$SlopeIndex = (100 / $MaxSlope) * $Slope;$R = (($PositiveSlopeEndR - $PositiveSlopeStartR) / 100) * $SlopeIndex + $PositiveSlopeStartR;$G = (($PositiveSlopeEndG - $PositiveSlopeStartG) / 100) * $SlopeIndex + $PositiveSlopeStartG;$B = (($PositiveSlopeEndB - $PositiveSlopeStartB) / 100) * $SlopeIndex + $PositiveSlopeStartB;} elseif ($Slope < 0) {$SlopeIndex = (100 / abs($MinSlope)) * abs($Slope);$R = (($NegativeSlopeEndR - $NegativeSlopeStartR) / 100) * $SlopeIndex + $NegativeSlopeStartR;$G = (($NegativeSlopeEndG - $NegativeSlopeStartG) / 100) * $SlopeIndex + $NegativeSlopeStartG;$B = (($NegativeSlopeEndB - $NegativeSlopeStartB) / 100) * $SlopeIndex + $NegativeSlopeStartB;}$Color = ["R" => $R,"G" => $G,"B" => $B];if ($ShadedSlopeBox && $LastColor != NULL) {$GradientSettings = ["StartR" => $LastColor["R"],"StartG" => $LastColor["G"],"StartB" => $LastColor["B"],"EndR" => $R,"EndG" => $G,"EndB" => $B];$this->drawGradientArea($TopX, $LastY, $BottomX, $Y, DIRECTION_VERTICAL, $GradientSettings);} elseif (!$ShadedSlopeBox || $LastColor == NULL) {$this->drawFilledRectangle($TopX, floor($LastY), $BottomX, floor($Y), $Color);}$LastColor = $Color;}if ($X == VOID) {$LastX = NULL;} else {$LastX = $X;$LastY = $Y;}$Y = $Y + $XStep;}$XPos = $XPos + $CaptionHeight + $SerieSpacing;}$this->Shadow = $RestoreShadow;}}}/* Draw the line of best fit */function drawBestFit(array $Format = []){$OverrideTicks = isset($Format["Ticks"]) ? $Format["Ticks"] : NULL;$OverrideR = isset($Format["R"]) ? $Format["R"] : VOID;$OverrideG = isset($Format["G"]) ? $Format["G"] : VOID;$OverrideB = isset($Format["B"]) ? $Format["B"] : VOID;$OverrideAlpha = isset($Format["Alpha"]) ? $Format["Alpha"] : VOID;$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();foreach($Data["Series"] as $SerieName => $Serie) {if ($Serie["isDrawable"] == TRUE && $SerieName != $Data["Abscissa"]) {if ($OverrideR != VOID && $OverrideG != VOID && $OverrideB != VOID) {$R = $OverrideR;$G = $OverrideG;$B = $OverrideB;} else {$R = $Serie["Color"]["R"];$G = $Serie["Color"]["G"];$B = $Serie["Color"]["B"];}$Ticks = ($OverrideTicks == NULL) ? $Serie["Ticks"] : $OverrideTicks;$Alpha = ($OverrideAlpha == VOID) ? $Serie["Color"]["Alpha"] : $OverrideAlpha;$Color = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha,"Ticks" => $Ticks];$AxisID = $Serie["Axis"];$PosArray = $this->scaleComputeY($Serie["Data"], ["AxisID" => $Serie["Axis"]]);if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin;$PosArray = $this->convertToArray($PosArray);$Sxy = 0;$Sx = 0;$Sy = 0;$Sxx = 0;foreach($PosArray as $Key => $Y) {if ($Y != VOID) {$Sxy = $Sxy + $X * $Y;$Sx = $Sx + $X;$Sy = $Sy + $Y;$Sxx = $Sxx + $X * $X;}$X = $X + $XStep;}$n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray);$M = (($n * $Sxy) - ($Sx * $Sy)) / (($n * $Sxx) - ($Sx * $Sx));$B = (($Sy) - ($M * $Sx)) / ($n);$X1 = $this->GraphAreaX1 + $XMargin;$Y1 = $M * $X1 + $B;$X2 = $this->GraphAreaX2 - $XMargin;$Y2 = $M * $X2 + $B;if ($Y1 < $this->GraphAreaY1) {$X1 = $X1 + ($this->GraphAreaY1 - $Y1);$Y1 = $this->GraphAreaY1;}if ($Y1 > $this->GraphAreaY2) {$X1 = $X1 + ($Y1 - $this->GraphAreaY2);$Y1 = $this->GraphAreaY2;}if ($Y2 < $this->GraphAreaY1) {$X2 = $X2 - ($this->GraphAreaY1 - $Y2);$Y2 = $this->GraphAreaY1;}if ($Y2 > $this->GraphAreaY2) {$X2 = $X2 - ($Y2 - $this->GraphAreaY2);$Y2 = $this->GraphAreaY2;}$this->drawLine($X1, $Y1, $X2, $Y2, $Color);} else {if ($XDivs == 0) {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$YStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin;$PosArray = $this->convertToArray($PosArray);$Sxy = 0;$Sx = 0;$Sy = 0;$Sxx = 0;foreach($PosArray as $Key => $X) {if ($X != VOID) {$Sxy = $Sxy + $X * $Y;$Sx = $Sx + $Y;$Sy = $Sy + $X;$Sxx = $Sxx + $Y * $Y;}$Y = $Y + $YStep;}$n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray);$M = (($n * $Sxy) - ($Sx * $Sy)) / (($n * $Sxx) - ($Sx * $Sx));$B = (($Sy) - ($M * $Sx)) / ($n);$Y1 = $this->GraphAreaY1 + $XMargin;$X1 = $M * $Y1 + $B;$Y2 = $this->GraphAreaY2 - $XMargin;$X2 = $M * $Y2 + $B;if ($X1 < $this->GraphAreaX1) {$Y1 = $Y1 + ($this->GraphAreaX1 - $X1);$X1 = $this->GraphAreaX1;}if ($X1 > $this->GraphAreaX2) {$Y1 = $Y1 + ($X1 - $this->GraphAreaX2);$X1 = $this->GraphAreaX2;}if ($X2 < $this->GraphAreaX1) {$Y2 = $Y2 - ($this->GraphAreaY1 - $X2);$X2 = $this->GraphAreaX1;}if ($X2 > $this->GraphAreaX2) {$Y2 = $Y2 - ($X2 - $this->GraphAreaX2);$X2 = $this->GraphAreaX2;}$this->drawLine($X1, $Y1, $X2, $Y2, $Color);}}}}/* Write labels */function writeLabel($SeriesName, $Indexes, array $Format = []){$OverrideTitle = NULL;$ForceLabels = NULL;$DrawPoint = LABEL_POINT_BOX;$DrawVerticalLine = FALSE;$VerticalLineR = 0;$VerticalLineG = 0;$VerticalLineB = 0;$VerticalLineAlpha = 40;$VerticalLineTicks = 2;/* Override defaults */extract($Format);$Data = $this->DataSet->getData();list($XMargin, $XDivs) = $this->scaleGetXSettings();$Indexes = $this->convertToArray($Indexes);$SeriesName = $this->convertToArray($SeriesName);if ($ForceLabels != NULL) {$ForceLabels = $this->convertToArray($ForceLabels);}foreach($Indexes as $Key => $Index) {$Series = [];if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) {if ($XDivs == 0) {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1) / 4;} else {$XStep = ($this->GraphAreaX2 - $this->GraphAreaX1 - $XMargin * 2) / $XDivs;}$X = $this->GraphAreaX1 + $XMargin + $Index * $XStep;if ($DrawVerticalLine) {$this->drawLine($X, $this->GraphAreaY1 + $Data["YMargin"], $X, $this->GraphAreaY2 - $Data["YMargin"], ["R" => $VerticalLineR,"G" => $VerticalLineG,"B" => $VerticalLineB,"Alpha" => $VerticalLineAlpha,"Ticks" => $VerticalLineTicks]);}$MinY = $this->GraphAreaY2;foreach($SeriesName as $iKey => $SerieName) {if (isset($Data["Series"][$SerieName]["Data"][$Index])) {$AxisID = $Data["Series"][$SerieName]["Axis"];$XAxisMode = $Data["XAxisDisplay"];$XAxisFormat = $Data["XAxisFormat"];$XAxisUnit = $Data["XAxisUnit"];$AxisMode = $Data["Axis"][$AxisID]["Display"];$AxisFormat = $Data["Axis"][$AxisID]["Format"];$AxisUnit = $Data["Axis"][$AxisID]["Unit"];if (isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index])) {$XLabel = $this->scaleFormat($Data["Series"][$Data["Abscissa"]]["Data"][$Index], $XAxisMode, $XAxisFormat, $XAxisUnit);} else {$XLabel = "";}if ($OverrideTitle != NULL) {$Description = $OverrideTitle;} elseif (count($SeriesName) == 1) {$Description = $Data["Series"][$SerieName]["Description"] . " - " . $XLabel;} elseif (isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index])) {$Description = $XLabel;}$Serie = ["R" => $Data["Series"][$SerieName]["Color"]["R"],"G" => $Data["Series"][$SerieName]["Color"]["G"],"B" => $Data["Series"][$SerieName]["Color"]["B"],"Alpha" => $Data["Series"][$SerieName]["Color"]["Alpha"]];$SerieOffset = (count($SeriesName) == 1 && isset($Data["Series"][$SerieName]["XOffset"])) ? $Data["Series"][$SerieName]["XOffset"] : 0;$Value = $Data["Series"][$SerieName]["Data"][$Index];($Value == VOID) AND $Value = "NaN";if ($ForceLabels != NULL) {$Caption = isset($ForceLabels[$Key]) ? $ForceLabels[$Key] : "Not set";} else {$Caption = $this->scaleFormat($Value, $AxisMode, $AxisFormat, $AxisUnit);}if ($this->LastChartLayout == CHART_LAST_LAYOUT_STACKED) {$LookFor = ($Value >= 0) ? "+" : "-";$Value = 0;foreach($Data["Series"] as $Name => $SerieLookup) {if ($SerieLookup["isDrawable"] == TRUE && $Name != $Data["Abscissa"]) {if (isset($Data["Series"][$Name]["Data"][$Index]) && $Data["Series"][$Name]["Data"][$Index] != VOID) {if ($Data["Series"][$Name]["Data"][$Index] >= 0 && $LookFor == "+") {$Value = $Value + $Data["Series"][$Name]["Data"][$Index];}if ($Data["Series"][$Name]["Data"][$Index] < 0 && $LookFor == "-") {$Value = $Value - $Data["Series"][$Name]["Data"][$Index];}if ($Name == $SerieName) {break;}}}}}$X = floor($this->GraphAreaX1 + $XMargin + $Index * $XStep + $SerieOffset);$Y = floor($this->scaleComputeY($Value, ["AxisID" => $AxisID]));if ($Y < $MinY) {$MinY = $Y;}if ($DrawPoint == LABEL_POINT_CIRCLE) {$this->drawFilledCircle($X, $Y, 3, ["R" => 255,"G" => 255,"B" => 255,"BorderR" => 0,"BorderG" => 0,"BorderB" => 0]);} elseif ($DrawPoint == LABEL_POINT_BOX) {$this->drawFilledRectangle($X - 2, $Y - 2, $X + 2, $Y + 2, ["R" => 255,"G" => 255,"B" => 255,"BorderR" => 0,"BorderG" => 0,"BorderB" => 0]);}$Series[] = ["Format" => $Serie,"Caption" => $Caption];}}$this->drawLabelBox($X, $MinY - 3, $Description, $Series, $Format);} else {if ($XDivs == 0) {$XStep = ($this->GraphAreaY2 - $this->GraphAreaY1) / 4;} else {$XStep = ($this->GraphAreaY2 - $this->GraphAreaY1 - $XMargin * 2) / $XDivs;}$Y = $this->GraphAreaY1 + $XMargin + $Index * $XStep;if ($DrawVerticalLine) {$this->drawLine($this->GraphAreaX1 + $Data["YMargin"], $Y, $this->GraphAreaX2 - $Data["YMargin"], $Y, ["R" => $VerticalLineR,"G" => $VerticalLineG,"B" => $VerticalLineB,"Alpha" => $VerticalLineAlpha,"Ticks" => $VerticalLineTicks]);}$MinX = $this->GraphAreaX2;foreach($SeriesName as $Key => $SerieName) {if (isset($Data["Series"][$SerieName]["Data"][$Index])) {$AxisID = $Data["Series"][$SerieName]["Axis"];$XAxisMode = $Data["XAxisDisplay"];$XAxisFormat = $Data["XAxisFormat"];$XAxisUnit = $Data["XAxisUnit"];$AxisMode = $Data["Axis"][$AxisID]["Display"];$AxisFormat = $Data["Axis"][$AxisID]["Format"];$AxisUnit = $Data["Axis"][$AxisID]["Unit"];if (isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index])) {$XLabel = $this->scaleFormat($Data["Series"][$Data["Abscissa"]]["Data"][$Index], $XAxisMode, $XAxisFormat, $XAxisUnit);} else {$XLabel = "";}if ($OverrideTitle != NULL) {$Description = $OverrideTitle;} elseif (count($SeriesName) == 1) {if (isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index])) $Description = $Data["Series"][$SerieName]["Description"] . " - " . $XLabel;} elseif (isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index])) {$Description = $XLabel;}$Serie = [];if (isset($Data["Extended"]["Palette"][$Index])) {$Serie["R"] = $Data["Extended"]["Palette"][$Index]["R"];$Serie["G"] = $Data["Extended"]["Palette"][$Index]["G"];$Serie["B"] = $Data["Extended"]["Palette"][$Index]["B"];$Serie["Alpha"] = $Data["Extended"]["Palette"][$Index]["Alpha"];} else {$Serie["R"] = $Data["Series"][$SerieName]["Color"]["R"];$Serie["G"] = $Data["Series"][$SerieName]["Color"]["G"];$Serie["B"] = $Data["Series"][$SerieName]["Color"]["B"];$Serie["Alpha"] = $Data["Series"][$SerieName]["Color"]["Alpha"];}if (count($SeriesName) == 1 && isset($Data["Series"][$SerieName]["XOffset"])) {$SerieOffset = $Data["Series"][$SerieName]["XOffset"];} else {$SerieOffset = 0;}$Value = $Data["Series"][$SerieName]["Data"][$Index];if ($ForceLabels != NULL) {$Caption = isset($ForceLabels[$Key]) ? $ForceLabels[$Key] : "Not set";} else {$Caption = $this->scaleFormat($Value, $AxisMode, $AxisFormat, $AxisUnit);}if ($Value == VOID) {$Value = "NaN";}if ($this->LastChartLayout == CHART_LAST_LAYOUT_STACKED) {$LookFor = ($Value >= 0) ? "+" : "-";$Value = 0;foreach($Data["Series"] as $Name => $SerieLookup) {if ($SerieLookup["isDrawable"] == TRUE && $Name != $Data["Abscissa"]) {if (isset($Data["Series"][$Name]["Data"][$Index]) && $Data["Series"][$Name]["Data"][$Index] != VOID) {if ($Data["Series"][$Name]["Data"][$Index] >= 0 && $LookFor == "+") {$Value = $Value + $Data["Series"][$Name]["Data"][$Index];}if ($Data["Series"][$Name]["Data"][$Index] < 0 && $LookFor == "-") {$Value = $Value - $Data["Series"][$Name]["Data"][$Index];}if ($Name == $SerieName) {break;}}}}}$X = floor($this->scaleComputeY($Value,["AxisID" => $AxisID]));$Y = floor($this->GraphAreaY1 + $XMargin + $Index * $XStep + $SerieOffset);if ($X < $MinX) {$MinX = $X;}if ($DrawPoint == LABEL_POINT_CIRCLE) {$this->drawFilledCircle($X, $Y, 3, ["R" => 255,"G" => 255,"B" => 255,"BorderR" => 0,"BorderG" => 0,"BorderB" => 0]);} elseif ($DrawPoint == LABEL_POINT_BOX) {$this->drawFilledRectangle($X - 2, $Y - 2, $X + 2, $Y + 2, ["R" => 255, "G" => 255,"B" => 255,"BorderR" => 0,"BorderG" => 0,"BorderB" => 0]);}$Series[] = ["Format" => $Serie,"Caption" => $Caption];}}$this->drawLabelBox($MinX, $Y - 3, $Description, $Series, $Format);}}}/* Draw a label box */function drawLabelBox($X, $Y, $Title, $Captions, array $Format = []){$NoTitle = NULL;$BoxWidth = 50;$DrawSerieColor = TRUE;$SerieR = NULL;$SerieG = NULL;$SerieB = NULL;$SerieAlpha = NULL;$SerieBoxSize = 6;$SerieBoxSpacing = 4;$VerticalMargin = 10;$HorizontalMargin = 8;$R = isset($Format["R"]) ? $Format["R"] : $this->FontColorR;$G = isset($Format["G"]) ? $Format["G"] : $this->FontColorG;$B = isset($Format["B"]) ? $Format["B"] : $this->FontColorB;$Alpha = $this->FontColorA;$FontName = $this->FontName;$FontSize = $this->FontSize;$TitleMode = LABEL_TITLE_NOBACKGROUND;$TitleR = $R;$TitleG = $G;$TitleB = $B;$TitleAlpha = 100;$TitleBackgroundR = 0;$TitleBackgroundG = 0;$TitleBackgroundB = 0;$TitleBackgroundAlpha = 100;$GradientStartR = 255;$GradientStartG = 255;$GradientStartB = 255;$GradientEndR = 220;$GradientEndG = 220;$GradientEndB = 220;$BoxAlpha = 100;/* Override defaults */extract($Format);if (!$DrawSerieColor) {$SerieBoxSize = 0;$SerieBoxSpacing = 0;}$TxtPos = $this->getTextBox($X, $Y, $FontName, $FontSize, 0, $Title);$TitleWidth = ($TxtPos[1]["X"] - $TxtPos[0]["X"]) + $VerticalMargin * 2;$TitleHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]);if ($NoTitle) {$TitleWidth = 0;$TitleHeight = 0;}$CaptionWidth = 0;$CaptionHeight = - $HorizontalMargin;if (isset($Captions["Caption"])){ # Momchil TODO No idea why I have to do that$TxtPos = $this->getTextBox($X, $Y, $FontName, $FontSize, 0, $Captions["Caption"]);$CaptionWidth = max($CaptionWidth, ($TxtPos[1]["X"] - $TxtPos[0]["X"]) + $VerticalMargin * 2);$CaptionHeight = $CaptionHeight + max(($TxtPos[0]["Y"] - $TxtPos[2]["Y"]), ($SerieBoxSize + 2)) + $HorizontalMargin;} else {foreach($Captions as $Caption) {$TxtPos = $this->getTextBox($X, $Y, $FontName, $FontSize, 0, $Caption["Caption"]);$CaptionWidth = max($CaptionWidth, ($TxtPos[1]["X"] - $TxtPos[0]["X"]) + $VerticalMargin * 2);$CaptionHeight = $CaptionHeight + max(($TxtPos[0]["Y"] - $TxtPos[2]["Y"]), ($SerieBoxSize + 2)) + $HorizontalMargin;}}if ($CaptionHeight <= 5) {$CaptionHeight = $CaptionHeight + $HorizontalMargin / 2;}if ($DrawSerieColor) {$CaptionWidth = $CaptionWidth + $SerieBoxSize + $SerieBoxSpacing;}$BoxWidth = max($BoxWidth, $TitleWidth, $CaptionWidth);$XMin = $X - 5 - floor(($BoxWidth - 10) / 2);$XMax = $X + 5 + floor(($BoxWidth - 10) / 2);$RestoreShadow = $this->Shadow;$ShadowX = $this->ShadowX; # Local var just for speedif ($this->Shadow == TRUE) {$this->Shadow = FALSE;$Poly = [$X + $ShadowX, $Y + $ShadowX, $X + 5 + $ShadowX, $Y - 5 + $ShadowX, $XMax + $ShadowX, $Y - 5 + $ShadowX];if ($NoTitle) {$Poly[] = $XMax + $ShadowX;$Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2 + $ShadowX;$Poly[] = $XMin + $ShadowX;$Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2 + $ShadowX;} else {$Poly[] = $XMax + $ShadowX;$Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3 + $ShadowX;$Poly[] = $XMin + $ShadowX;$Poly[] = $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3 + $ShadowX;}$Poly[] = $XMin + $ShadowX;$Poly[] = $Y - 5 + $ShadowX;$Poly[] = $X - 5 + $ShadowX;$Poly[] = $Y - 5 + $ShadowX;$this->drawPolygon($Poly, ["R" => $this->ShadowR,"G" => $this->ShadowG,"B" => $this->ShadowB,"Alpha" => $this->Shadowa]);}/* Draw the background */$GradientSettings = ["StartR" => $GradientStartR,"StartG" => $GradientStartG,"StartB" => $GradientStartB,"EndR" => $GradientEndR,"EndG" => $GradientEndG,"EndB" => $GradientEndB,"Alpha" => $BoxAlpha];if ($NoTitle) {$this->drawGradientArea($XMin, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $XMax, $Y - 6, DIRECTION_VERTICAL, $GradientSettings);} else {$this->drawGradientArea($XMin, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMax, $Y - 6, DIRECTION_VERTICAL, $GradientSettings);}$Poly = [$X, $Y, $X - 5, $Y - 5, $X + 5, $Y - 5];$this->drawPolygon($Poly, ["R" => $GradientEndR,"G" => $GradientEndG,"B" => $GradientEndB,"Alpha" => $BoxAlpha,"NoBorder" => TRUE]);/* Outer border */$OuterBorderColor = $this->allocateColor(100, 100, 100, $BoxAlpha);imageline($this->Picture, $XMin, $Y - 5, $X - 5, $Y - 5, $OuterBorderColor);imageline($this->Picture, $X, $Y, $X - 5, $Y - 5, $OuterBorderColor);imageline($this->Picture, $X, $Y, $X + 5, $Y - 5, $OuterBorderColor);imageline($this->Picture, $X + 5, $Y - 5, $XMax, $Y - 5, $OuterBorderColor);if ($NoTitle) {imageline($this->Picture, $XMin, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $XMin, $Y - 5, $OuterBorderColor);imageline($this->Picture, $XMax, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $XMax, $Y - 5, $OuterBorderColor);imageline($this->Picture, $XMin, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $XMax, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $OuterBorderColor);} else {imageline($this->Picture, $XMin, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMin, $Y - 5, $OuterBorderColor);imageline($this->Picture, $XMax, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMax, $Y - 5, $OuterBorderColor);imageline($this->Picture, $XMin, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMax, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $OuterBorderColor);}/* Inner border */$InnerBorderColor = $this->allocateColor(255, 255, 255, $BoxAlpha);imageline($this->Picture, $XMin + 1, $Y - 6, $X - 5, $Y - 6, $InnerBorderColor);imageline($this->Picture, $X, $Y - 1, $X - 5, $Y - 6, $InnerBorderColor);imageline($this->Picture, $X, $Y - 1, $X + 5, $Y - 6, $InnerBorderColor);imageline($this->Picture, $X + 5, $Y - 6, $XMax - 1, $Y - 6, $InnerBorderColor);if ($NoTitle) {imageline($this->Picture, $XMin + 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $XMin + 1, $Y - 6, $InnerBorderColor);imageline($this->Picture, $XMax - 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $XMax - 1, $Y - 6, $InnerBorderColor);imageline($this->Picture, $XMin + 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $XMax - 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 2, $InnerBorderColor);} else {imageline($this->Picture, $XMin + 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMin + 1, $Y - 6, $InnerBorderColor);imageline($this->Picture, $XMax - 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMax - 1, $Y - 6, $InnerBorderColor);imageline($this->Picture, $XMin + 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMax - 1, $Y - 4 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $InnerBorderColor);}/* Draw the separator line */if ($TitleMode == LABEL_TITLE_NOBACKGROUND && !$NoTitle) {$YPos = $Y - 7 - $CaptionHeight - $HorizontalMargin - $HorizontalMargin / 2;$XMargin = $VerticalMargin / 2;$this->drawLine($XMin + $XMargin, $YPos + 1, $XMax - $XMargin, $YPos + 1, ["R" => $GradientEndR,"G" => $GradientEndG,"B" => $GradientEndB,"Alpha" => $BoxAlpha]);$this->drawLine($XMin + $XMargin, $YPos, $XMax - $XMargin, $YPos, ["R" => $GradientStartR,"G" => $GradientStartG,"B" => $GradientStartB,"Alpha" => $BoxAlpha]);} elseif ($TitleMode == LABEL_TITLE_BACKGROUND) {$this->drawFilledRectangle($XMin, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin * 3, $XMax, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin + $HorizontalMargin / 2, array("R" => $TitleBackgroundR,"G" => $TitleBackgroundG,"B" => $TitleBackgroundB,"Alpha" => $BoxAlpha));imageline($this->Picture, $XMin + 1, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin + $HorizontalMargin / 2 + 1, $XMax - 1, $Y - 5 - $TitleHeight - $CaptionHeight - $HorizontalMargin + $HorizontalMargin / 2 + 1, $InnerBorderColor);}/* Write the description */if (!$NoTitle) {$this->drawText($XMin + $VerticalMargin, $Y - 7 - $CaptionHeight - $HorizontalMargin * 2, $Title, ["Align" => TEXT_ALIGN_BOTTOMLEFT,"R" => $TitleR,"G" => $TitleG, "B" => $TitleB]);}/* Write the value */$YPos = $Y - 5 - $HorizontalMargin;$XPos = $XMin + $VerticalMargin + $SerieBoxSize + $SerieBoxSpacing;if (isset($Captions["Caption"])){ # Momchil TODO No idea why I have to do that (same thing on line 6782)$TxtPos = $this->getTextBox($XPos, $YPos, $FontName, $FontSize, 0, $Captions["Caption"]);$CaptionHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]);/* Write the serie color if needed */if ($DrawSerieColor) {$BoxSettings = ["R" => $Captions["Format"]["R"],"G" => $Captions["Format"]["G"],"B" => $Captions["Format"]["B"],"Alpha" => $Captions["Format"]["Alpha"],"BorderR" => 0,"BorderG" => 0,"BorderB" => 0];$this->drawFilledRectangle($XMin + $VerticalMargin, $YPos - $SerieBoxSize, $XMin + $VerticalMargin + $SerieBoxSize, $YPos, $BoxSettings);}$this->drawText($XPos, $YPos, $Captions["Caption"], ["Align" => TEXT_ALIGN_BOTTOMLEFT]);$YPos = $YPos - $CaptionHeight - $HorizontalMargin;} else {foreach($Captions as $Key => $Caption) {$TxtPos = $this->getTextBox($XPos, $YPos, $FontName, $FontSize, 0, $Caption["Caption"]);$CaptionHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]);/* Write the serie color if needed */if ($DrawSerieColor) {$BoxSettings = ["R" => $Caption["Format"]["R"],"G" => $Caption["Format"]["G"],"B" => $Caption["Format"]["B"],"Alpha" => $Caption["Format"]["Alpha"],"BorderR" => 0,"BorderG" => 0,"BorderB" => 0];$this->drawFilledRectangle($XMin + $VerticalMargin, $YPos - $SerieBoxSize, $XMin + $VerticalMargin + $SerieBoxSize, $YPos, $BoxSettings);}$this->drawText($XPos, $YPos, $Caption["Caption"], ["Align" => TEXT_ALIGN_BOTTOMLEFT]);$YPos = $YPos - $CaptionHeight - $HorizontalMargin;}}$this->Shadow = $RestoreShadow;}/* Draw a basic shape */function drawShape($X, $Y, $Shape, $PlotSize, $PlotBorder, $BorderSize, $R, $G, $B, $Alpha, $BorderR, $BorderG, $BorderB, $BorderAlpha){$RGB = ["R" => $R,"G" => $G,"B" => $B,"Alpha" => $Alpha];switch ($Shape){case SERIE_SHAPE_FILLEDCIRCLE:if ($PlotBorder) {$this->drawFilledCircle($X, $Y, $PlotSize + $BorderSize, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha]);}$this->drawFilledCircle($X, $Y, $PlotSize, $RGB);break;case SERIE_SHAPE_FILLEDSQUARE:if ($PlotBorder) {$this->drawFilledRectangle($X - $PlotSize - $BorderSize, $Y - $PlotSize - $BorderSize, $X + $PlotSize + $BorderSize, $Y + $PlotSize + $BorderSize, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha]);}$this->drawFilledRectangle($X - $PlotSize, $Y - $PlotSize, $X + $PlotSize, $Y + $PlotSize, $RGB);break;case SERIE_SHAPE_FILLEDTRIANGLE:if ($PlotBorder) {$Pos = [$X, $Y - $PlotSize - $BorderSize, $X - $PlotSize - $BorderSize, $Y + $PlotSize + $BorderSize, $X + $PlotSize + $BorderSize, $Y + $PlotSize + $BorderSize];$this->drawPolygon($Pos, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha]);}$Pos = [$X, $Y - $PlotSize, $X - $PlotSize, $Y + $PlotSize, $X + $PlotSize, $Y + $PlotSize];$this->drawPolygon($Pos, $RGB);break;case SERIE_SHAPE_TRIANGLE:$this->drawLine($X, $Y - $PlotSize, $X - $PlotSize, $Y + $PlotSize, $RGB);$this->drawLine($X - $PlotSize, $Y + $PlotSize, $X + $PlotSize, $Y + $PlotSize, $RGB);$this->drawLine($X + $PlotSize, $Y + $PlotSize, $X, $Y - $PlotSize, $RGB);break;case SERIE_SHAPE_SQUARE:$this->drawRectangle($X - $PlotSize, $Y - $PlotSize, $X + $PlotSize, $Y + $PlotSize, $RGB);break;case SERIE_SHAPE_CIRCLE:$this->drawCircle($X, $Y, $PlotSize, $PlotSize, $RGB);break;case SERIE_SHAPE_DIAMOND:$Pos = [$X - $PlotSize, $Y, $X, $Y - $PlotSize, $X + $PlotSize, $Y, $X, $Y + $PlotSize];$this->drawPolygon($Pos, ["NoFill" => TRUE,"BorderR" => $R,"BorderG" => $G,"BorderB" => $B,"BorderAlpha" => $Alpha]);break;case SERIE_SHAPE_FILLEDDIAMOND:if ($PlotBorder) {$Pos = [$X - $PlotSize - $BorderSize, $Y, $X, $Y - $PlotSize - $BorderSize, $X + $PlotSize + $BorderSize, $Y, $X, $Y + $PlotSize + $BorderSize];$this->drawPolygon($Pos, ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha]);}$Pos = [$X - $PlotSize, $Y, $X, $Y - $PlotSize, $X + $PlotSize, $Y, $X, $Y + $PlotSize];$this->drawPolygon($Pos, $RGB);break;}}function drawPolygonChart($Points, array $Format = []){$R = isset($Format["R"]) ? $Format["R"] : 0;$G = isset($Format["G"]) ? $Format["G"] : 0;$B = isset($Format["B"]) ? $Format["B"] : 0;$Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;$Threshold = NULL;$NoFill = FALSE;$NoBorder = FALSE;$Surrounding = NULL;$BorderR = $R;$BorderG = $G;$BorderB = $B;$BorderAlpha = $Alpha / 2;extract($Format);if ($Surrounding != NULL) {$BorderR = $R + $Surrounding;$BorderG = $G + $Surrounding;$BorderB = $B + $Surrounding;}$RestoreShadow = $this->Shadow;$this->Shadow = FALSE;$AllIntegers = TRUE;for ($i = 0; $i <= count($Points) - 2; $i = $i + 2) {if ($this->getFirstDecimal($Points[$i + 1]) != 0) {$AllIntegers = FALSE;}}/* Convert polygon to segments */$Segments = [];for ($i = 2; $i <= count($Points) - 2; $i = $i + 2) {$Segments[] = ["X1" => $Points[$i - 2],"Y1" => $Points[$i - 1],"X2" => $Points[$i],"Y2" => $Points[$i + 1]];}$Segments[] = ["X1" => $Points[$i - 2],"Y1" => $Points[$i - 1],"X2" => $Points[0],"Y2" => $Points[1]];/* Simplify straight lines */$Result = [];$inHorizon = FALSE;$LastX = VOID;foreach($Segments as $Key => $Pos) {if ($Pos["Y1"] != $Pos["Y2"]) {if ($inHorizon) {$inHorizon = FALSE;$Result[] = ["X1" => $LastX,"Y1" => $Pos["Y1"],"X2" => $Pos["X1"],"Y2" => $Pos["Y1"]];}$Result[] = ["X1" => $Pos["X1"],"Y1" => $Pos["Y1"],"X2" => $Pos["X2"],"Y2" => $Pos["Y2"]];} else {if (!$inHorizon) {$inHorizon = TRUE;$LastX = $Pos["X1"];}}}$Segments = $Result;/* Do we have something to draw */if (count($Segments) == 0) {return 0;}/* For segments debugging purpose */// foreach($Segments as $Key => $Pos)// echo $Pos["X1"].",".$Pos["Y1"].",".$Pos["X2"].",".$Pos["Y2"]."\r\n";/* Find out the min & max Y boundaries */$MinY = OUT_OF_SIGHT;$MaxY = OUT_OF_SIGHT;foreach($Segments as $Key => $Coords) {if ($MinY == OUT_OF_SIGHT || $MinY > min($Coords["Y1"], $Coords["Y2"])) {$MinY = min($Coords["Y1"], $Coords["Y2"]);}if ($MaxY == OUT_OF_SIGHT || $MaxY < max($Coords["Y1"], $Coords["Y2"])) {$MaxY = max($Coords["Y1"], $Coords["Y2"]);}}$YStep = ($AllIntegers) ? 1 : .5;$MinY = floor($MinY);$MaxY = floor($MaxY);/* Scan each Y lines */$DefaultColor = $this->allocateColor($R, $G, $B, $Alpha);#$DebugLine = 0;$DebugColor = $this->allocateColor(255, 0, 0, 100);$MinY = floor($MinY);$MaxY = floor($MaxY);$YStep = 1;if (!$NoFill) {// if ( $DebugLine ) { $MinY = $DebugLine; $MaxY = $DebugLine; }for ($Y = $MinY; $Y <= $MaxY; $Y = $Y + $YStep) {$Intersections = [];$LastSlope = NULL;$RestoreLast = "-";foreach($Segments as $Key => $Coords) {$X1 = $Coords["X1"];$X2 = $Coords["X2"];$Y1 = $Coords["Y1"];$Y2 = $Coords["Y2"];if (min($Y1, $Y2) <= $Y && max($Y1, $Y2) >= $Y) {if ($Y1 == $Y2) {$X = $X1;} else {$X = $X1 + (($Y - $Y1) * $X2 - ($Y - $Y1) * $X1) / ($Y2 - $Y1);}$X = floor($X);if ($X2 == $X1) {$Slope = "!";} else {$SlopeC = ($Y2 - $Y1) / ($X2 - $X1);if ($SlopeC == 0) {$Slope = "=";} elseif ($SlopeC > 0) {$Slope = "+";} elseif ($SlopeC < 0) {$Slope = "-";}}if (!is_array($Intersections)) {$Intersections[] = $X;} elseif (!in_array($X, $Intersections)) {$Intersections[] = $X;} elseif (in_array($X, $Intersections)) {#if ($Y == $DebugLine) {# echo $Slope . "/" . $LastSlope . "(" . $X . ") ";#}if ($Slope == "=" && $LastSlope == "-") {$Intersections[] = $X;}if ($Slope != $LastSlope && $LastSlope != "!" && $LastSlope != "=") {$Intersections[] = $X;}if ($Slope != $LastSlope && $LastSlope == "!" && $Slope == "+") {$Intersections[] = $X;}}if (is_array($Intersections) && in_array($X, $Intersections) && $LastSlope == "=" && ($Slope == "-")) {$Intersections[] = $X;}$LastSlope = $Slope;}}if ($RestoreLast != "-") {$Intersections[] = $RestoreLast;echo "@" . $Y . "\r\n";}if (is_array($Intersections)) {sort($Intersections);#if ($Y == $DebugLine) {# print_r($Intersections);#}/* Remove NULL plots */$Result = [];for ($i = 0; $i <= count($Intersections) - 1; $i = $i + 2) {if (isset($Intersections[$i + 1])) {if ($Intersections[$i] != $Intersections[$i + 1]) {$Result[] = $Intersections[$i];$Result[] = $Intersections[$i + 1];}}}// if ( is_array($Result) )if (count($Result) > 0) {$Intersections = $Result;$LastX = OUT_OF_SIGHT;foreach($Intersections as $Key => $X) {if ($LastX == OUT_OF_SIGHT) {$LastX = $X;} elseif ($LastX != OUT_OF_SIGHT) {if ($this->getFirstDecimal($LastX) > 1) {$LastX++;}$Color = $DefaultColor;if ($Threshold != NULL) {foreach($Threshold as $Key => $Parameters) {if ($Y <= $Parameters["MinX"] && $Y >= $Parameters["MaxX"]) {$R = (isset($Parameters["R"])) ? $Parameters["R"] : 0;$G = (isset($Parameters["G"])) ? $Parameters["G"] : 0;$B = (isset($Parameters["B"])) ? $Parameters["B"] : 0;$Alpha = (isset($Parameters["Alpha"])) ? $Parameters["Alpha"] : 100;$Color = $this->allocateColor($R, $G, $B, $Alpha);}}}imageline($this->Picture, $LastX, $Y, $X, $Y, $Color);#if ($Y == $DebugLine) {# imageline($this->Picture, $LastX, $Y, $X, $Y, $DebugColor);#}$LastX = OUT_OF_SIGHT;}}}}}} # No Fill/* Draw the polygon border, if required */if (!$NoBorder) {foreach($Segments as $Key => $Coords) {$this->drawLine($Coords["X1"], $Coords["Y1"], $Coords["X2"], $Coords["Y2"], ["R" => $BorderR,"G" => $BorderG,"B" => $BorderB,"Alpha" => $BorderAlpha,"Threshold" => $Threshold]);}}$this->Shadow = $RestoreShadow;}/* Return the abscissa margin */function getAbscissaMargin($Data){foreach($Data["Axis"] as $AxisID => $Values) {if ($Values["Identity"] == AXIS_X) {return ($Values["Margin"]);}}return 0;}/* Convert a string to a single element array */function convertToArray($Value){return (is_array($Value)) ? $Value : [$Value];}}?>