<?php
/*
pDraw - class extension with drawing methods

Version     : 2.1.4
Made by     : Jean-Damien POGOLOTTI
Last Update : 19/01/2014

This file can be distributed under the license you can find at :

http://www.pchart.net/license

You 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 missing
				for ($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 = ""; # UNUSED
		for ($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 cases
		
			for ($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 param
			if (($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 > 0
			if ($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 optimization
		
			if ($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 used
			list($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 switch
		
		switch ($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 = ""; # UNUSED

		foreach($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 speed
		if ($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];
	}

}

?>