Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

<?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];
        }

}

?>