1: <?php
2: namespace SamChristy\PieChart;
3: include 'PieChart.php';
4:
5: 6: 7: 8: 9: 10: 11: 12:
13: class PieChartGD extends PieChart {
14: public function destroy() {
15: imageDestroy($this->canvas);
16: }
17:
18: 19: 20: 21:
22: public function draw($aa = 4) {
23: $this->canvas = imageCreateTrueColor($this->width, $this->height);
24:
25:
26: imageAntiAlias($this->canvas, true);
27:
28: imageFilledRectangle($this->canvas, 0, 0, $this->width, $this->height,
29: $this->_convertColor($this->backgroundColor));
30:
31: $total = 0;
32: $sliceStart = -90;
33:
34: $titleHeight = $this->_drawTitle();
35: $legendWidth = $this->_drawLegend($titleHeight);
36:
37:
38: $pieCentreX = ($this->width - $legendWidth) / 2;
39:
40:
41: $pieCentreY = $titleHeight + ($this->height - $titleHeight) / 2;
42:
43:
44: $pieDiameter = round(
45: min($this->width - $legendWidth, $this->height - $titleHeight) * 0.85
46: );
47:
48: foreach ($this->slices as $slice)
49: $total += $slice['value'];
50:
51:
52:
53: if ($aa > 0) {
54: $ssDiameter = $pieDiameter * $aa;
55: $ssCentreX = $ssCentreY = $ssDiameter / 2 ;
56: $superSample = imageCreateTrueColor($ssDiameter, $ssDiameter);
57: imageFilledRectangle($superSample, 0, 0, $ssDiameter, $ssDiameter,
58: $this->_convertColor($this->backgroundColor));
59:
60: foreach ($this->slices as $slice) {
61: $sliceWidth = 360 * $slice['value'] / $total;
62:
63:
64: if ($sliceWidth == 0)
65: continue;
66:
67: $sliceEnd = $sliceStart + $sliceWidth;
68:
69: imageFilledArc(
70: $superSample,
71: $ssCentreX,
72: $ssCentreY,
73: $ssDiameter,
74: $ssDiameter,
75: $sliceStart,
76: $sliceEnd,
77: $this->_convertColor($slice['color']),
78: IMG_ARC_PIE
79: );
80:
81:
82: $sliceStart = $sliceEnd;
83: }
84:
85: imageCopyResampled(
86: $this->canvas, $superSample,
87: $pieCentreX - $pieDiameter / 2, $pieCentreY - $pieDiameter / 2,
88: 0, 0,
89: $pieDiameter, $pieDiameter,
90: $ssDiameter, $ssDiameter
91: );
92:
93: imageDestroy($superSample);
94: }
95: else {
96:
97: foreach ($this->slices as $slice) {
98: $sliceWidth = 360 * $slice['value'] / $total;
99:
100:
101: if ($sliceWidth == 0)
102: continue;
103:
104: $sliceEnd = $sliceStart + $sliceWidth;
105:
106: imageFilledArc(
107: $this->canvas,
108: $pieCentreX,
109: $pieCentreY,
110: $pieDiameter,
111: $pieDiameter,
112: $sliceStart,
113: $sliceEnd,
114: $this->_convertColor($slice['color']),
115: IMG_ARC_PIE
116: );
117:
118:
119: $sliceStart = $sliceEnd;
120: }
121: }
122: }
123:
124: protected function _output($method, $format, $filename) {
125: switch ($format) {
126: case parent::FORMAT_GIF:
127: if ($method == parent::OUTPUT_INLINE || $method == parent::OUTPUT_DOWNLOAD) {
128: return imageGIF($this->canvas);
129: }
130: else if ($method == parent::OUTPUT_SAVE) {
131: return imageGIF($this->canvas, $filename);
132: }
133: break;
134:
135: case parent::FORMAT_JPEG:
136: if ($method == parent::OUTPUT_INLINE || $method == parent::OUTPUT_DOWNLOAD) {
137: return imageJPEG($this->canvas, NULL, $this->quality);
138: }
139: else if ($method == parent::OUTPUT_SAVE) {
140: return imageJPEG($this->canvas, $filename, $this->quality);
141: }
142: break;
143:
144: case parent::FORMAT_PNG:
145: if ($method == parent::OUTPUT_INLINE || $method == parent::OUTPUT_DOWNLOAD) {
146: return imagePNG($this->canvas);
147: }
148: else if ($method == parent::OUTPUT_SAVE) {
149: return imagePNG($this->canvas, $filename);
150: }
151: break;
152: }
153:
154: return false;
155: }
156:
157: 158: 159: 160: 161:
162: protected function _drawLegend($legendOffset) {
163: if (!$this->hasLegend)
164: return 0;
165:
166:
167: $legendFontSize = $this->width * 0.022;
168:
169:
170: if (ceil($legendFontSize) < 8)
171: return 0;
172:
173:
174: $squareSize = $this->height * 0.060;
175: $squarePadding = $this->height * 0.025;
176: $labelPadding = $this->height * 0.025;
177:
178: $sliceCount = count($this->slices);
179:
180: $legendPadding = 0.05 * $this->width;
181:
182:
183: $legendWidth = $squareSize + $labelPadding + $this->_maxLabelWidth($legendFontSize);
184: $legendHeight = $sliceCount * ($squareSize + $squarePadding) - $squarePadding;
185:
186:
187: if ($legendWidth + $legendPadding * 2 > $this->width / 2)
188: return 0;
189:
190: if ($legendHeight > $this->height - $legendOffset - $legendPadding * 2)
191: return 0;
192:
193: $legendX = $this->width - $legendWidth - $legendPadding;
194: $legendY = ($this->height - $legendOffset) / 2 + $legendOffset - $legendHeight / 2;
195:
196: $i = 0;
197: foreach ($this->slices as $sliceName => $slice) {
198:
199: $OffsetY = $i++ * ($squareSize + $squarePadding);
200:
201: $this->_drawLegendKey(
202: $legendX,
203: $legendY + $OffsetY,
204: $slice['color'],
205: $sliceName,
206: $squareSize,
207: $labelPadding,
208: $legendFontSize
209: );
210: }
211:
212: return $legendWidth + $legendPadding * 2;
213: }
214:
215: 216: 217: 218: 219: 220: 221: 222: 223: 224:
225: protected function _drawLegendKey($x, $y, $color, $label, $squareSize, $labelPadding,
226: $fontSize) {
227: $labelX = $x + $squareSize + $labelPadding;
228:
229:
230: $labelBBox = imageTTFBBox($fontSize, 0, $this->legendFont, $label);
231: $labelHeight = abs($labelBBox[7] - $labelBBox[1]);
232:
233: $labelY = $y + $squareSize / 2 - $labelHeight / 2;
234:
235: imageFilledRectangle(
236: $this->canvas, $x, $y, $x + $squareSize, $y + $squareSize, $this->_convertColor($color)
237: );
238:
239: imageTTFText(
240: $this->canvas,
241: $fontSize,
242: 0,
243: $labelX + abs($labelBBox[0]),
244: $labelY + abs($labelBBox[7]),
245: $this->_convertColor($this->textColor),
246: $this->legendFont,
247: $label
248: );
249: }
250:
251: 252: 253: 254:
255: protected function _maxLabelWidth($fontSize) {
256: $widestLabelWidth = 0;
257:
258: foreach ($this->slices as $sliceName => $slice) {
259:
260: $boundingBox = imageTTFBBox($fontSize, 0, $this->legendFont, $sliceName);
261: $labelWidth = $boundingBox[2] - $boundingBox[0];
262:
263: if ($labelWidth > $widestLabelWidth)
264: $widestLabelWidth = $labelWidth;
265: }
266:
267: return $widestLabelWidth;
268: }
269:
270: 271: 272: 273: 274: 275: 276:
277: protected function _drawTitle($x = 0, $y = 0) {
278: if (!$this->title)
279: return 0;
280:
281: $titleColor = $this->_convertColor($this->textColor);
282:
283:
284: $titleSize = 0.0675 * $this->height;
285: $minTitleSize = 10;
286:
287: do {
288: $titleBBox = imageTTFBBox($titleSize, 0, $this->titleFont, $this->title);
289: $titleWidth = $titleBBox[2] - $titleBBox[0];
290:
291:
292:
293: if ($titleWidth <= ($this->width * 0.9))
294: break;
295:
296: $titleSize -= 0.5;
297: } while ($titleSize >= $minTitleSize);
298:
299:
300:
301: if ($titleSize < $minTitleSize)
302: return 0;
303:
304: $titleHeight = abs($titleBBox[7] - $titleBBox[1]);
305:
306:
307: $titleTopPadding = 0.075 * $this->height;
308:
309:
310: $x = $this->width / 2 - $titleWidth / 2;
311: $y = $titleTopPadding;
312:
313: imageTtfText(
314: $this->canvas, $titleSize,
315: 0,
316: $x + abs($titleBBox[0]),
317: $y + abs($titleBBox[7]),
318: $titleColor,
319: $this->titleFont,
320: $this->title
321: );
322:
323: return $titleHeight + $titleTopPadding;
324: }
325:
326: 327: 328: 329:
330: private function _convertColor(PieChartColor $color) {
331:
332:
333: return imageColorAllocate($this->canvas, $color->r, $color->g, $color->b);
334: }
335: }