HuasoFoundries/jpgraph

View on GitHub
src/graph/PolarAxis.php

Summary

Maintainability
F
5 days
Test Coverage
<?php

/**
 * JPGraph v4.0.3
 */

namespace Amenadiel\JpGraph\Graph;

use Amenadiel\JpGraph\Text;
use Amenadiel\JpGraph\Util;

/**
 * @class PolarAxis
 */
class PolarAxis extends Axis
{
    private $angle_step        = 15;
    private $angle_color       = 'lightgray';
    private $angle_label_color = 'black';
    private $angle_fontfam     = FF_FONT1;
    private $angle_fontstyle   = FS_NORMAL;
    private $angle_fontsize    = 10;
    private $angle_fontcolor   = 'navy';
    private $gridminor_color   = 'lightgray';
    private $gridmajor_color   = 'lightgray';
    private $show_minor_grid   = false;
    private $show_major_grid   = true;
    private $show_angle_mark   = true;
    private $show_angle_grid   = true;
    private $show_angle_label  = true;
    private $angle_tick_len    = 3;
    private $angle_tick_len2   = 3;
    private $angle_tick_color  = 'black';
    private $show_angle_tick   = true;
    private $radius_tick_color = 'black';

    public function __construct($img, $aScale)
    {
        parent::__construct($img, $aScale);
    }

    public function ShowAngleDegreeMark($aFlg = true)
    {
        $this->show_angle_mark = $aFlg;
    }

    public function SetAngleStep($aStep)
    {
        $this->angle_step = $aStep;
    }

    public function HideTicks($aFlg = true, $aAngleFlg = true)
    {
        parent::HideTicks($aFlg, $aFlg);
        $this->show_angle_tick = !$aAngleFlg;
    }

    public function ShowAngleLabel($aFlg = true)
    {
        $this->show_angle_label = $aFlg;
    }

    public function ShowGrid($aMajor = true, $aMinor = false, $aAngle = true)
    {
        $this->show_minor_grid = $aMinor;
        $this->show_major_grid = $aMajor;
        $this->show_angle_grid = $aAngle;
    }

    public function SetAngleFont($aFontFam, $aFontStyle = FS_NORMAL, $aFontSize = 10)
    {
        $this->angle_fontfam   = $aFontFam;
        $this->angle_fontstyle = $aFontStyle;
        $this->angle_fontsize  = $aFontSize;
    }

    public function SetColor($aColor, $aRadColor = '', $aAngleColor = '')
    {
        if ($aAngleColor == '') {
            $aAngleColor = $aColor;
        }

        parent::SetColor($aColor, $aRadColor);
        $this->angle_fontcolor = $aAngleColor;
    }

    public function SetGridColor($aMajorColor, $aMinorColor = '', $aAngleColor = '')
    {
        if ($aMinorColor == '') {
            $aMinorColor = $aMajorColor;
        }

        if ($aAngleColor == '') {
            $aAngleColor = $aMajorColor;
        }

        $this->gridminor_color = $aMinorColor;
        $this->gridmajor_color = $aMajorColor;
        $this->angle_color     = $aAngleColor;
    }

    public function SetTickColors($aRadColor, $aAngleColor = '')
    {
        $this->radius_tick_color = $aRadColor;
        $this->angle_tick_color  = $aAngleColor;
    }

    // Private methods
    public function StrokeGrid($pos)
    {
        $x = round($this->img->left_margin + $this->img->plotwidth / 2);
        $this->scale->ticks->Stroke($this->img, $this->scale, $pos);

        // Stroke the minor arcs
        $pmin = [];
        $p    = $this->scale->ticks->ticks_pos;
        $n    = safe_count($p);
        $i    = 0;
        $this->img->SetColor($this->gridminor_color);
        while ($i < $n) {
            $r      = $p[$i] - $x + 1;
            $pmin[] = $r;
            if ($this->show_minor_grid) {
                $this->img->Circle($x, $pos, $r);
            }
            ++$i;
        }

        $limit = max($this->img->plotwidth, $this->img->plotheight) * 1.4;
        while ($r < $limit) {
            $off = $r;
            $i   = 1;
            $r   = $off + round($p[$i] - $x + 1);
            while ($r < $limit && $i < $n) {
                $r      = $off + $p[$i] - $x;
                $pmin[] = $r;
                if ($this->show_minor_grid) {
                    $this->img->Circle($x, $pos, $r);
                }
                ++$i;
            }
        }

        // Stroke the major arcs
        if ($this->show_major_grid) {
            // First determine how many minor step on
            // every major step. We have recorded the minor radius
            // in pmin and use these values. This is done in order
            // to avoid rounding errors if we were to recalculate the
            // different major radius.
            $pmaj = $this->scale->ticks->maj_ticks_pos;
            $p    = $this->scale->ticks->ticks_pos;
            if ($this->scale->name == 'lin') {
                $step = round(($pmaj[1] - $pmaj[0]) / ($p[1] - $p[0]));
            } else {
                $step = 9;
            }
            $n = round(safe_count($pmin) / $step);
            $i = 0;
            $this->img->SetColor($this->gridmajor_color);
            $limit = max($this->img->plotwidth, $this->img->plotheight) * 1.4;
            $off   = $r;
            $i     = 0;
            $r     = $pmin[$i * $step];
            while ($r < $limit && $i < $n) {
                $r = $pmin[$i * $step];
                $this->img->Circle($x, $pos, $r);
                ++$i;
            }
        }

        // Draw angles
        if ($this->show_angle_grid) {
            $this->img->SetColor($this->angle_color);
            $d            = max($this->img->plotheight, $this->img->plotwidth) * 1.4;
            $a            = 0;
            $p            = $this->scale->ticks->ticks_pos;
            $start_radius = $p[1] - $x;
            while ($a < 360) {
                if ($a == 90 || $a == 270) {
                    // Make sure there are no rounding problem with
                    // exactly vertical lines
                    $this->img->Line(
                        $x + $start_radius * cos($a / 180 * M_PI) + 1,
                        $pos - $start_radius * sin($a / 180 * M_PI),
                        $x + $start_radius * cos($a / 180 * M_PI) + 1,
                        $pos - $d * sin($a / 180 * M_PI)
                    );
                } else {
                    $this->img->Line(
                        $x + $start_radius * cos($a / 180 * M_PI) + 1,
                        $pos - $start_radius * sin($a / 180 * M_PI),
                        $x + $d * cos($a / 180 * M_PI),
                        $pos - $d * sin($a / 180 * M_PI)
                    );
                }
                $a += $this->angle_step;
            }
        }
    }

    public function StrokeAngleLabels($pos, $type)
    {
        if (!$this->show_angle_label) {
            return;
        }

        $x0 = round($this->img->left_margin + $this->img->plotwidth / 2) + 1;

        $d = max($this->img->plotwidth, $this->img->plotheight) * 1.42;
        $a = $this->angle_step;
        $t = new Text\Text();
        $t->SetColor($this->angle_fontcolor);
        $t->SetFont($this->angle_fontfam, $this->angle_fontstyle, $this->angle_fontsize);
        $xright  = $this->img->width - $this->img->right_margin;
        $ytop    = $this->img->top_margin;
        $xleft   = $this->img->left_margin;
        $ybottom = $this->img->height - $this->img->bottom_margin;
        $ha      = 'left';
        $va      = 'center';
        $w       = $this->img->plotwidth / 2;
        $h       = $this->img->plotheight / 2;
        $xt      = $x0;
        $yt      = $pos;
        $margin  = 5;

        $tl  = $this->angle_tick_len; // Outer len
        $tl2 = $this->angle_tick_len2; // Interior len

        $this->img->SetColor($this->angle_tick_color);
        $rot90 = $this->img->a == 90;

        if ($type == POLAR_360) {
            // Corner angles of the four corners
            $ca1 = atan($h / $w) / M_PI * 180;
            $ca2 = 180 - $ca1;
            $ca3 = $ca1 + 180;
            $ca4 = 360 - $ca1;
            $end = 360;

            while ($a < $end) {
                $ca = cos($a / 180 * M_PI);
                $sa = sin($a / 180 * M_PI);
                $x  = $d * $ca;
                $y  = $d * $sa;
                $xt = 1000;
                $yt = 1000;
                if ($a <= $ca1 || $a >= $ca4) {
                    $yt = $pos - $w * $y / $x;
                    $xt = $xright + $margin;
                    if ($rot90) {
                        $ha = 'center';
                        $va = 'top';
                    } else {
                        $ha = 'left';
                        $va = 'center';
                    }
                    $x1 = $xright - $tl2;
                    $x2 = $xright + $tl;
                    $y1 = $y2 = $yt;
                } elseif ($a > $ca1 && $a < $ca2) {
                    $xt = $x0 + $h * $x / $y;
                    $yt = $ytop - $margin;
                    if ($rot90) {
                        $ha = 'left';
                        $va = 'center';
                    } else {
                        $ha = 'center';
                        $va = 'bottom';
                    }
                    $y1 = $ytop + $tl2;
                    $y2 = $ytop - $tl;
                    $x1 = $x2 = $xt;
                } elseif ($a >= $ca2 && $a <= $ca3) {
                    $yt = $pos + $w * $y / $x;
                    $xt = $xleft - $margin;
                    if ($rot90) {
                        $ha = 'center';
                        $va = 'bottom';
                    } else {
                        $ha = 'right';
                        $va = 'center';
                    }
                    $x1 = $xleft + $tl2;
                    $x2 = $xleft - $tl;
                    $y1 = $y2 = $yt;
                } else {
                    $xt = $x0 - $h * $x / $y;
                    $yt = $ybottom + $margin;
                    if ($rot90) {
                        $ha = 'right';
                        $va = 'center';
                    } else {
                        $ha = 'center';
                        $va = 'top';
                    }
                    $y1 = $ybottom - $tl2;
                    $y2 = $ybottom + $tl;
                    $x1 = $x2 = $xt;
                }
                if ($a != 0 && $a != 180) {
                    $t->Align($ha, $va);
                    if ($this->scale->clockwise) {
                        $t->Set(360 - $a);
                    } else {
                        $t->Set($a);
                    }
                    if ($this->show_angle_mark && $t->font_family > 4) {
                        $a .= SymChar::Get('degree');
                    }
                    $t->Stroke($this->img, $xt, $yt);
                    if ($this->show_angle_tick) {
                        $this->img->Line($x1, $y1, $x2, $y2);
                    }
                }
                $a += $this->angle_step;
            }
        } else {
            // POLAR_HALF
            $ca1 = atan($h / $w * 2) / M_PI * 180;
            $ca2 = 180 - $ca1;
            $end = 180;
            while ($a < $end) {
                $ca = cos($a / 180 * M_PI);
                $sa = sin($a / 180 * M_PI);
                $x  = $d * $ca;
                $y  = $d * $sa;
                if ($a <= $ca1) {
                    $yt = $pos - $w * $y / $x;
                    $xt = $xright + $margin;
                    if ($rot90) {
                        $ha = 'center';
                        $va = 'top';
                    } else {
                        $ha = 'left';
                        $va = 'center';
                    }
                    $x1 = $xright - $tl2;
                    $x2 = $xright + $tl;
                    $y1 = $y2 = $yt;
                } elseif ($a > $ca1 && $a < $ca2) {
                    $xt = $x0 + 2 * $h * $x / $y;
                    $yt = $ytop - $margin;
                    if ($rot90) {
                        $ha = 'left';
                        $va = 'center';
                    } else {
                        $ha = 'center';
                        $va = 'bottom';
                    }
                    $y1 = $ytop + $tl2;
                    $y2 = $ytop - $tl;
                    $x1 = $x2 = $xt;
                } elseif ($a >= $ca2) {
                    $yt = $pos + $w * $y / $x;
                    $xt = $xleft - $margin;
                    if ($rot90) {
                        $ha = 'center';
                        $va = 'bottom';
                    } else {
                        $ha = 'right';
                        $va = 'center';
                    }
                    $x1 = $xleft + $tl2;
                    $x2 = $xleft - $tl;
                    $y1 = $y2 = $yt;
                }
                $t->Align($ha, $va);
                if ($this->show_angle_mark && $t->font_family > 4) {
                    $a .= SymChar::Get('degree');
                }
                $t->Set($a);
                $t->Stroke($this->img, $xt, $yt);
                if ($this->show_angle_tick) {
                    $this->img->Line($x1, $y1, $x2, $y2);
                }
                $a += $this->angle_step;
            }
        }
    }

    public function Stroke($pos, $dummy = true)
    {
        $this->img->SetLineWeight($this->weight);
        $this->img->SetColor($this->color);
        $this->img->SetFont($this->font_family, $this->font_style, $this->font_size);
        if (!$this->hide_line) {
            $this->img->FilledRectangle(
                $this->img->left_margin,
                $pos,
                $this->img->width - $this->img->right_margin,
                $pos + $this->weight - 1
            );
        }
        $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin;
        if ($this->title_adjust == 'high') {
            $this->title->SetPos($this->img->width - $this->img->right_margin, $y, 'right', 'top');
        } elseif ($this->title_adjust == 'middle' || $this->title_adjust == 'center') {
            $this->title->SetPos(
                ($this->img->width - $this->img->left_margin - $this->img->right_margin) / 2 + $this->img->left_margin,
                $y,
                'center',
                'top'
            );
        } elseif ($this->title_adjust == 'low') {
            $this->title->SetPos($this->img->left_margin, $y, 'left', 'top');
        } else {
            Util\JpGraphError::RaiseL(17002, $this->title_adjust);
            //('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')');
        }

        if (!$this->hide_labels) {
            $this->StrokeLabels($pos, false);
        }
        $this->img->SetColor($this->radius_tick_color);
        $this->scale->ticks->Stroke($this->img, $this->scale, $pos);

        //
        // Mirror the positions for the left side of the scale
        //
        $mid = 2 * ($this->img->left_margin + $this->img->plotwidth / 2);
        $n   = safe_count($this->scale->ticks->ticks_pos);
        $i   = 0;
        while ($i < $n) {
            $this->scale->ticks->ticks_pos[$i] =
            $mid - $this->scale->ticks->ticks_pos[$i];
            ++$i;
        }

        $n = safe_count($this->scale->ticks->maj_ticks_pos);
        $i = 0;
        while ($i < $n) {
            $this->scale->ticks->maj_ticks_pos[$i] =
            $mid - $this->scale->ticks->maj_ticks_pos[$i];
            ++$i;
        }

        $n = safe_count($this->scale->ticks->maj_ticklabels_pos);
        $i = 1;
        while ($i < $n) {
            $this->scale->ticks->maj_ticklabels_pos[$i] =
            $mid - $this->scale->ticks->maj_ticklabels_pos[$i];
            ++$i;
        }

        // Draw the left side of the scale
        $n  = safe_count($this->scale->ticks->ticks_pos);
        $yu = $pos - $this->scale->ticks->direction * $this->scale->ticks->GetMinTickAbsSize();

        // Minor ticks
        if (!$this->scale->ticks->supress_minor_tickmarks) {
            $i = 1;
            while ($i < $n / 2) {
                $x = round($this->scale->ticks->ticks_pos[$i]);
                $this->img->Line($x, $pos, $x, $yu);
                ++$i;
            }
        }

        $n  = safe_count($this->scale->ticks->maj_ticks_pos);
        $yu = $pos - $this->scale->ticks->direction * $this->scale->ticks->GetMajTickAbsSize();

        // Major ticks
        if (!$this->scale->ticks->supress_tickmarks) {
            $i = 1;
            while ($i < $n / 2) {
                $x = round($this->scale->ticks->maj_ticks_pos[$i]);
                $this->img->Line($x, $pos, $x, $yu);
                ++$i;
            }
        }
        if (!$this->hide_labels) {
            $this->StrokeLabels($pos, false);
        }
        $this->title->Stroke($this->img);
    }
}