xref: /plugin/farmer/vendor/splitbrain/php-ringicon/src/RingIconSVG.php (revision c609f1dcc91a56df760d51ba92f6e25b7289002c)
1*c609f1dcSAndreas Gohr<?php
2*c609f1dcSAndreas Gohr
3*c609f1dcSAndreas Gohrnamespace splitbrain\RingIcon;
4*c609f1dcSAndreas Gohr
5*c609f1dcSAndreas Gohr
6*c609f1dcSAndreas Gohrclass RingIconSVG extends AbstractRingIcon
7*c609f1dcSAndreas Gohr{
8*c609f1dcSAndreas Gohr    public function __construct($size, $rings = 3)
9*c609f1dcSAndreas Gohr    {
10*c609f1dcSAndreas Gohr        parent::__construct($size, $rings);
11*c609f1dcSAndreas Gohr        // we don't downscale
12*c609f1dcSAndreas Gohr        $this->center = floor($this->size / 2);
13*c609f1dcSAndreas Gohr        $this->ringwidth = floor($this->size / $rings);
14*c609f1dcSAndreas Gohr    }
15*c609f1dcSAndreas Gohr
16*c609f1dcSAndreas Gohr    /**
17*c609f1dcSAndreas Gohr     * Generates an ring image svg suitable for inlining in html
18*c609f1dcSAndreas Gohr     *
19*c609f1dcSAndreas Gohr     * If a seed is given, the image will be based on that seed
20*c609f1dcSAndreas Gohr     *
21*c609f1dcSAndreas Gohr     * @param string $seed
22*c609f1dcSAndreas Gohr     *
23*c609f1dcSAndreas Gohr     * @return string
24*c609f1dcSAndreas Gohr     */
25*c609f1dcSAndreas Gohr    public function getInlineSVG($seed = '')
26*c609f1dcSAndreas Gohr    {
27*c609f1dcSAndreas Gohr        return $this->generateSVGImage($seed);
28*c609f1dcSAndreas Gohr    }
29*c609f1dcSAndreas Gohr
30*c609f1dcSAndreas Gohr    /**
31*c609f1dcSAndreas Gohr     * Generates an ring image svg
32*c609f1dcSAndreas Gohr     *
33*c609f1dcSAndreas Gohr     * If a seed is given, the image will be based on that seed
34*c609f1dcSAndreas Gohr     *
35*c609f1dcSAndreas Gohr     * @param string $seed initialize the genrator with this string
36*c609f1dcSAndreas Gohr     * @param string $file if given, the image is saved at that path, otherwise is printed as file to browser
37*c609f1dcSAndreas Gohr     */
38*c609f1dcSAndreas Gohr    public function createImage($seed = '', $file = '')
39*c609f1dcSAndreas Gohr    {
40*c609f1dcSAndreas Gohr        $svg = $this->generateSVGImage($seed, true);
41*c609f1dcSAndreas Gohr        if ($file) {
42*c609f1dcSAndreas Gohr            file_put_contents($file, $svg);
43*c609f1dcSAndreas Gohr        } else {
44*c609f1dcSAndreas Gohr            header("Content-type: image/svg+xml");
45*c609f1dcSAndreas Gohr            echo $svg;
46*c609f1dcSAndreas Gohr        }
47*c609f1dcSAndreas Gohr    }
48*c609f1dcSAndreas Gohr
49*c609f1dcSAndreas Gohr    /**
50*c609f1dcSAndreas Gohr     * Generates an ring image svg
51*c609f1dcSAndreas Gohr     *
52*c609f1dcSAndreas Gohr     * If a seed is given, the image will be based on that seed
53*c609f1dcSAndreas Gohr     *
54*c609f1dcSAndreas Gohr     * @param string $seed initialize the genrator with this string
55*c609f1dcSAndreas Gohr     * @param bool $file if true, the svg will have the markup suitable for being delivered as file
56*c609f1dcSAndreas Gohr     *
57*c609f1dcSAndreas Gohr     * @return string
58*c609f1dcSAndreas Gohr     */
59*c609f1dcSAndreas Gohr    protected function generateSVGImage($seed = '', $file = false)
60*c609f1dcSAndreas Gohr    {
61*c609f1dcSAndreas Gohr        if (!$seed) {
62*c609f1dcSAndreas Gohr            $seed = mt_rand() . time();
63*c609f1dcSAndreas Gohr        }
64*c609f1dcSAndreas Gohr        $this->seed = $seed;
65*c609f1dcSAndreas Gohr
66*c609f1dcSAndreas Gohr        // monochrome wanted?
67*c609f1dcSAndreas Gohr        if ($this->ismono) {
68*c609f1dcSAndreas Gohr            $this->generateMonoColor();
69*c609f1dcSAndreas Gohr        }
70*c609f1dcSAndreas Gohr
71*c609f1dcSAndreas Gohr        if ($file) {
72*c609f1dcSAndreas Gohr            $svgFileAttributes = array(
73*c609f1dcSAndreas Gohr                'xmlns' => 'http://www.w3.org/2000/svg',
74*c609f1dcSAndreas Gohr                'version' => '1.1',
75*c609f1dcSAndreas Gohr                'width' => $this->size,
76*c609f1dcSAndreas Gohr                'height' => $this->size,
77*c609f1dcSAndreas Gohr            );
78*c609f1dcSAndreas Gohr            $svgFileAttributes = implode(' ', array_map(
79*c609f1dcSAndreas Gohr                function ($k, $v) {
80*c609f1dcSAndreas Gohr                    return $k . '="' . htmlspecialchars($v) . '"';
81*c609f1dcSAndreas Gohr                },
82*c609f1dcSAndreas Gohr                array_keys($svgFileAttributes), $svgFileAttributes
83*c609f1dcSAndreas Gohr            ));
84*c609f1dcSAndreas Gohr        } else {
85*c609f1dcSAndreas Gohr            $svgFileAttributes = '';
86*c609f1dcSAndreas Gohr        }
87*c609f1dcSAndreas Gohr
88*c609f1dcSAndreas Gohr        $svg = "<svg $svgFileAttributes viewBox=\"0 0 $this->size $this->size\">";
89*c609f1dcSAndreas Gohr        $arcOuterRadious = $this->size / 2;
90*c609f1dcSAndreas Gohr        for ($i = $this->rings; $i > 0; $i--) {
91*c609f1dcSAndreas Gohr            $svg .= $this->createSVGArcPath($arcOuterRadious);
92*c609f1dcSAndreas Gohr            $arcOuterRadious -= $this->ringwidth / 2;
93*c609f1dcSAndreas Gohr        }
94*c609f1dcSAndreas Gohr        $svg .= '</svg>';
95*c609f1dcSAndreas Gohr
96*c609f1dcSAndreas Gohr        if ($file) {
97*c609f1dcSAndreas Gohr            $svgBoilerplate = '<?xml version="1.0" encoding="UTF-8"?>
98*c609f1dcSAndreas Gohr<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
99*c609f1dcSAndreas Gohr            $svg = $svgBoilerplate . $svg;
100*c609f1dcSAndreas Gohr        }
101*c609f1dcSAndreas Gohr
102*c609f1dcSAndreas Gohr        return $svg;
103*c609f1dcSAndreas Gohr    }
104*c609f1dcSAndreas Gohr
105*c609f1dcSAndreas Gohr    /**
106*c609f1dcSAndreas Gohr     * Draw a single arc
107*c609f1dcSAndreas Gohr     *
108*c609f1dcSAndreas Gohr     * @param float $outerRadius
109*c609f1dcSAndreas Gohr     *
110*c609f1dcSAndreas Gohr     * @return string
111*c609f1dcSAndreas Gohr     */
112*c609f1dcSAndreas Gohr    protected function createSVGArcPath($outerRadius)
113*c609f1dcSAndreas Gohr    {
114*c609f1dcSAndreas Gohr        $color = $this->randomCssColor();
115*c609f1dcSAndreas Gohr        $ringThickness = $this->ringwidth / 2;
116*c609f1dcSAndreas Gohr        $startAngle = $this->rand(20, 360);
117*c609f1dcSAndreas Gohr        $stopAngle = $this->rand(20, 360);
118*c609f1dcSAndreas Gohr        if ($stopAngle < $startAngle) {
119*c609f1dcSAndreas Gohr            list($startAngle, $stopAngle) = array($stopAngle, $startAngle);
120*c609f1dcSAndreas Gohr        }
121*c609f1dcSAndreas Gohr
122*c609f1dcSAndreas Gohr        list ($xStart, $yStart) = $this->polarToCartesian($outerRadius, $startAngle);
123*c609f1dcSAndreas Gohr        list ($xOuterEnd, $yOuterEnd) = $this->polarToCartesian($outerRadius, $stopAngle);
124*c609f1dcSAndreas Gohr
125*c609f1dcSAndreas Gohr        $innerRadius = $outerRadius - $ringThickness;
126*c609f1dcSAndreas Gohr        $SweepFlag = 0;
127*c609f1dcSAndreas Gohr        $innerSweepFlag = 1;
128*c609f1dcSAndreas Gohr        $largeArcFlag = (int)($stopAngle - $startAngle < 180);
129*c609f1dcSAndreas Gohr        list ($xInnerStart, $yInnerStart) = $this->polarToCartesian($outerRadius - $ringThickness, $stopAngle);
130*c609f1dcSAndreas Gohr        list ($xInnerEnd, $yInnerEnd) = $this->polarToCartesian($outerRadius - $ringThickness, $startAngle);
131*c609f1dcSAndreas Gohr
132*c609f1dcSAndreas Gohr        $fullPath = "<path fill='$color' d='
133*c609f1dcSAndreas Gohr            M $xStart $yStart
134*c609f1dcSAndreas Gohr            A $outerRadius $outerRadius 0 $largeArcFlag $SweepFlag $xOuterEnd $yOuterEnd
135*c609f1dcSAndreas Gohr            L $xInnerStart $yInnerStart
136*c609f1dcSAndreas Gohr            A $innerRadius $innerRadius 0 $largeArcFlag $innerSweepFlag $xInnerEnd $yInnerEnd
137*c609f1dcSAndreas Gohr            Z
138*c609f1dcSAndreas Gohr            '/>";
139*c609f1dcSAndreas Gohr        return $fullPath;
140*c609f1dcSAndreas Gohr    }
141*c609f1dcSAndreas Gohr
142*c609f1dcSAndreas Gohr    /**
143*c609f1dcSAndreas Gohr     * Create a random valid css color value
144*c609f1dcSAndreas Gohr     *
145*c609f1dcSAndreas Gohr     * @return string
146*c609f1dcSAndreas Gohr     */
147*c609f1dcSAndreas Gohr    protected function randomCssColor()
148*c609f1dcSAndreas Gohr    {
149*c609f1dcSAndreas Gohr        if ($this->ismono) {
150*c609f1dcSAndreas Gohr            $alpha = 1 - $this->rand(0, 96) / 100;
151*c609f1dcSAndreas Gohr            return "rgba({$this->monocolor[0]}, {$this->monocolor[1]}, {$this->monocolor[2]}, $alpha)";
152*c609f1dcSAndreas Gohr        }
153*c609f1dcSAndreas Gohr        $r = $this->rand(0, 255);
154*c609f1dcSAndreas Gohr        $g = $this->rand(0, 255);
155*c609f1dcSAndreas Gohr        $b = $this->rand(0, 255);
156*c609f1dcSAndreas Gohr        return "rgb($r, $g, $b)";
157*c609f1dcSAndreas Gohr    }
158*c609f1dcSAndreas Gohr
159*c609f1dcSAndreas Gohr    /**
160*c609f1dcSAndreas Gohr     * Calculate the x,y coordinate of a given angle at a given distance from the center
161*c609f1dcSAndreas Gohr     *
162*c609f1dcSAndreas Gohr     * 0 Degree is 3 o'clock
163*c609f1dcSAndreas Gohr     *
164*c609f1dcSAndreas Gohr     * @param float $radius
165*c609f1dcSAndreas Gohr     * @param float $angleInDegrees
166*c609f1dcSAndreas Gohr     *
167*c609f1dcSAndreas Gohr     * @return array
168*c609f1dcSAndreas Gohr     */
169*c609f1dcSAndreas Gohr    protected function polarToCartesian($radius, $angleInDegrees)
170*c609f1dcSAndreas Gohr    {
171*c609f1dcSAndreas Gohr        $angleInRadians = $angleInDegrees * M_PI / 180.0;
172*c609f1dcSAndreas Gohr
173*c609f1dcSAndreas Gohr        return array(
174*c609f1dcSAndreas Gohr            $this->size / 2 + ($radius * cos($angleInRadians)),
175*c609f1dcSAndreas Gohr            $this->size / 2 + ($radius * sin($angleInRadians)),
176*c609f1dcSAndreas Gohr        );
177*c609f1dcSAndreas Gohr    }
178*c609f1dcSAndreas Gohr
179*c609f1dcSAndreas Gohr}
180