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