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