Subversion Repositories Applications.gtt

Rev

Rev 61 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
60 jpm 1
<?php
2
/*
3
 * This work is hereby released into the Public Domain.
4
 * To view a copy of the public domain dedication,
5
 * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
6
 * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
7
 *
8
 */
9
 
10
require_once dirname(__FILE__)."/Component.class.php";
11
 
12
 
13
/**
14
 * Pie
15
 *
16
 * @package Artichow
17
 */
18
class awPie extends awComponent {
19
 
20
	/**
21
	 * A dark theme for pies
22
	 *
23
	 *
24
	 * @var int
25
	 */
26
	const DARK = 1;
27
 
28
	/**
29
	 * A colored theme for pies
30
	 *
31
	 * @var int
32
	 */
33
	const COLORED = 2;
34
 
35
	/**
36
	 * A water theme for pies
37
	 *
38
	 * @var int
39
	 */
40
	const AQUA = 3;
41
 
42
	/**
43
	 * A earth theme for pies
44
	 *
45
	 * @var int
46
	 */
47
	const EARTH = 4;
48
 
49
	/**
50
	 * Pie values
51
	 *
52
	 * @var array
53
	 */
54
	protected $values;
55
 
56
	/**
57
	 * Pie colors
58
	 *
59
	 * @var array
60
	 */
61
	protected $colors;
62
 
63
	/**
64
	 * Pie legend
65
	 *
66
	 * @var array
67
	 */
68
	protected $legendValues = array();
69
 
70
	/**
71
	 * Intensity of the 3D effect
72
	 *
73
	 * @var int
74
	 */
75
	protected $size;
76
 
77
	/**
78
	 * Border color
79
	 *
80
	 * @var Color
81
	 */
82
	protected $border;
83
 
84
	/**
85
	 * Pie explode
86
	 *
87
	 * @var array
88
	 */
89
	protected $explode = array();
90
 
91
	/**
92
	 * Initial angle
93
	 *
94
	 * @var int
95
	 */
96
	protected $angle = 0;
97
 
98
	/**
99
	 * Labels precision
100
	 *
101
	 * @var int
102
	 */
103
	protected $precision;
104
 
105
	/**
106
	 * Labels number
107
	 *
108
	 * @var int
109
	 */
110
	protected $number;
111
 
112
	/**
113
	 * Labels minimum
114
	 *
115
	 * @var int
116
	 */
117
	protected $minimum;
118
 
119
	/**
120
	 * Labels position
121
	 *
122
	 * @var int
123
	 */
124
	protected $position = 15;
125
 
126
	/**
127
	 * Labels of your pie
128
	 *
129
	 * @var Label
130
	 */
131
	public $label;
132
 
133
	/**
134
	 * Build the plot
135
	 *
136
	 * @param array $values Pie values
137
	 */
138
	public function __construct($values, $colors = awPie::COLORED) {
139
 
140
		$this->setValues($values);
141
 
142
		if(is_array($colors)) {
143
			$this->colors = $colors;
144
		} else {
145
 
146
			switch($colors) {
147
 
148
				case awPie::AQUA :
149
					$this->colors = array(
150
						new awColor(131, 220, 215),
151
						new awColor(131, 190, 215),
152
						new awColor(131, 160, 215),
153
						new awColor(160, 140, 215),
154
						new awColor(190, 131, 215),
155
						new awColor(220, 131, 215)
156
					);
157
					break;
158
 
159
				case awPie::EARTH :
160
					$this->colors = array(
161
						new awColor(97, 179, 110),
162
						new awColor(130, 179, 97),
163
						new awColor(168, 179, 97),
164
						new awColor(179, 147, 97),
165
						new awColor(179, 108, 97),
166
						new awColor(99, 107, 189),
167
						new awColor(99, 165, 189)
168
					);
169
					break;
170
 
171
				case awPie::DARK :
172
					$this->colors = array(
173
						new awColor(140, 100, 170),
174
						new awColor(130, 170, 100),
175
						new awColor(160, 160, 120),
176
						new awColor(150, 110, 140),
177
						new awColor(130, 150, 160),
178
						new awColor(90, 170, 140)
179
					);
180
					break;
181
 
182
				default :
183
					$this->colors = array(
184
						new awColor(187, 213, 151),
185
						new awColor(223, 177, 151),
186
						new awColor(111, 186, 132),
187
						new awColor(197, 160, 230),
188
						new awColor(165, 169, 63),
189
						new awColor(218, 177, 89),
190
						new awColor(116, 205, 121),
191
						new awColor(200, 201, 78),
192
						new awColor(127, 205, 177),
193
						new awColor(205, 160, 160),
194
						new awColor(190, 190, 190)
195
					);
196
					break;
197
 
198
			}
199
 
200
		}
201
 
202
		parent::__construct();
203
 
204
		$this->label = new awLabel;
205
		$this->label->setCallbackFunction('callbackPerCent');
206
 
207
	}
208
 
209
	/**
210
	 * Change legend values
211
	 *
212
	 * @param array $legend An array of values for each part of the pie
213
	 */
214
	public function setLegend($legend) {
215
 
216
		$this->legendValues = (array)$legend;
217
 
218
	}
219
 
220
	/**
221
	 * Set a border all around the pie
222
	 *
223
	 * @param awColor $color A color for the border
224
	 */
225
	public function setBorderColor(awColor $color) {
226
		$this->border = $color;
227
	}
228
 
229
	/**
230
	 * Set a border all around the pie
231
	 *
232
	 * @param awColor $color A color for the border
233
	 */
234
	public function setBorder(awColor $color) {
235
		if(ARTICHOW_DEPRECATED === TRUE) {
236
			awImage::drawError('Class Pie: Method setBorder() has been deprecated since Artichow 1.0.9. Please use setBorderColor() instead.');
237
		} else {
238
			$this->setBorderColor($color);
239
		}
240
	}
241
 
242
	/**
243
	 * Change 3D effect intensity
244
	 *
245
	 * @param int $size Effect size
246
	 */
247
	public function set3D($size) {
248
		$this->size = (int)$size;
249
	}
250
 
251
	/**
252
	 * Change initial angle
253
	 *
254
	 * @param int $angle New angle in degrees
255
	 */
256
	public function setStartAngle($angle) {
257
		$this->angle = (int)$angle;
258
	}
259
 
260
	/**
261
	 * Change label precision
262
	 *
263
	 * @param int $precision New precision
264
	 */
265
	public function setLabelPrecision($precision) {
266
		$this->precision = (int)$precision;
267
	}
268
 
269
	/**
270
	 * Change label position
271
	 *
272
	 * @param int $position New position in pixels
273
	 */
274
	public function setLabelPosition($position) {
275
		$this->position = (int)$position;
276
	}
277
 
278
	/**
279
	 * Change label number
280
	 *
281
	 * @param int $number New number
282
	 */
283
	public function setLabelNumber($number) {
284
		$this->number = is_null($number) ? $number : (int)$number;
285
	}
286
 
287
	/**
288
	 * Change label minimum
289
	 *
290
	 * @param int $minimum New minimum
291
	 */
292
	public function setLabelMinimum($minimum) {
293
		$this->minimum = is_null($minimum) ? $minimum : (int)$minimum;
294
	}
295
 
296
	/**
297
	 * Change Pie explode
298
	 *
299
	 * @param array $explode
300
	 */
301
	public function explode($explode) {
302
		$this->explode = (array)$explode;
303
	}
304
 
305
	public function drawEnvelope(awDriver $driver) {
306
 
307
	}
308
 
309
	public function drawComponent(awDriver $driver, $x1, $y1, $x2, $y2, $aliasing) {
310
 
311
		$count = count($this->values);
312
		$sum = array_sum($this->values);
313
 
314
		$width = $x2 - $x1;
315
		$height = $y2 - $y1;
316
 
317
		if($aliasing) {
318
			$x = $width / 2;
319
			$y = $height / 2;
320
		} else {
321
			$x = $width / 2 + $x1;
322
			$y = $height / 2 + $y1;
323
		}
324
 
325
		$position = $this->angle;
326
		$values = array();
327
		$parts = array();
328
		$angles = 0;
329
 
330
		if($aliasing) {
331
			$side = new awSide(0, 0, 0, 0);
332
		}
333
 
334
		foreach($this->values as $key => $value) {
335
 
336
			$angle = ($value / $sum * 360);
337
 
338
			if($key === $count - 1) {
339
				$angle = 360 - $angles;
340
			}
341
 
342
			$angles += $angle;
343
 
344
			if(array_key_exists($key, $this->explode)) {
345
				$middle = 360 - ($position + $angle / 2);
346
				$posX = $this->explode[$key] * cos($middle * M_PI / 180);
347
				$posY = $this->explode[$key] * sin($middle * M_PI / 180) * -1;
348
 
349
				if($aliasing) {
350
					$explode = new awPoint(
351
						$posX * 2,
352
						$posY * 2
353
					);
354
					$side->set(
355
						max($side->left, $posX * -2),
356
						max($side->right, $posX * 2),
357
						max($side->top, $posY * -2),
358
						max($side->bottom, $posY * 2)
359
					);
360
				} else {
361
					$explode = new awPoint(
362
						$posX,
363
						$posY
364
					);
365
				}
366
 
367
			} else {
368
				$explode = new awPoint(0, 0);
369
			}
370
 
371
			$values[$key] = array(
372
				$position, ($position + $angle), $explode
373
			);
374
 
375
			$color = $this->colors[$key % count($this->colors)];
376
			$parts[$key] = new awPiePart($color);
377
 
378
			// Add part to the legend
379
			$legend = array_key_exists($key, $this->legendValues) ? $this->legendValues[$key] : $key;
380
			$this->legend->add($parts[$key], $legend, awLegend::BACKGROUND);
381
 
382
			$position += $angle;
383
 
384
		}
385
 
386
		if($aliasing) {
387
 
388
			$mainDriver = $driver;
389
 
390
			$x *= 2;
391
			$y *= 2;
392
			$width *= 2;
393
			$height *= 2;
394
			$this->size *= 2;
395
 
396
			$image = new awImage;
397
			$image->border->hide();
398
 
399
			// Adds support for antialiased pies on non-white background
400
			$background = $this->getBackground();
401
 
402
			if($background instanceof awColor) {
403
				$image->setBackgroundColor($background);
404
			}
405
//			elseif($background instanceof awGradient) {
406
//				$image->setBackgroundColor(new White(100));
407
//			}
408
 
409
			$image->setSize(
410
				$width + $side->left + $side->right,
411
				$height + $side->top + $side->bottom + $this->size + 1 /* bugs.php.net ! */
412
			);
413
 
414
			$driver = $image->getDriver(
415
				$width / $image->width,
416
				$height / $image->height,
417
				($width / 2 + $side->left) / $image->width,
418
				($height / 2 + $side->top) / $image->height
419
			);
420
 
421
		}
422
 
423
		// Draw 3D effect
424
		for($i = $this->size; $i > 0; $i--) {
425
 
426
			foreach($values as $key => $value) {
427
 
428
				$color = clone $this->colors[$key % count($this->colors)];
429
				$color->brightness(-50);
430
 
431
				list($from, $to, $explode) = $value;
432
 
433
				$driver->filledArc($color, $explode->move($x, $y + $i), $width, $height, $from, $to);
434
 
435
				unset($color);
436
 
437
				if($this->border instanceof awColor) {
438
 
439
					$point = $explode->move($x, $y);
440
 
441
					if($i === $this->size) {
442
 
443
						$driver->arc($this->border, $point->move(0, $this->size), $width, $height, $from, $to);
444
 
445
					}
446
 
447
				}
448
 
449
			}
450
 
451
		}
452
 
453
		foreach($values as $key => $value) {
454
 
455
			$color = $this->colors[$key % count($this->colors)];
456
 
457
			list($from, $to, $explode) = $value;
458
 
459
			$driver->filledArc($color, $explode->move($x, $y), $width, $height, $from, $to);
460
 
461
			if($this->border instanceof awColor) {
462
 
463
				$point = $explode->move($x, $y);
464
				$driver->arc($this->border, $point, $width, $height, $from, $to);
465
			}
466
 
467
		}
468
 
469
		if($aliasing) {
470
 
471
			$x = $x / 2 + $x1;
472
			$y = $y / 2 + $y1;
473
			$width /= 2;
474
			$height /= 2;
475
			$this->size /= 2;
476
 
477
			foreach($values as $key => $value) {
478
				$old = $values[$key][2];
479
				$values[$key][2] = new awPoint(
480
					$old->x / 2, $old->y / 2
481
				);
482
			}
483
 
484
			$mainDriver->copyResizeImage(
485
				$image,
486
				new awPoint($x1 - $side->left / 2, $y1 - $side->top / 2),
487
				new awPoint($x1 - $side->left / 2 + $image->width / 2, $y1 - $side->top / 2 + $image->height/ 2),
488
				new awPoint(0, 0),
489
				new awPoint($image->width, $image->height),
490
				TRUE
491
			);
492
 
493
			$driver = $mainDriver;
494
 
495
		}
496
 
497
		// Get labels values
498
		$pc = array();
499
		foreach($this->values as $key => $value) {
500
			$pc[$key] = round($value / $sum * 100, $this->precision);
501
		}
502
		if($this->label->count() === 0) { // Check that there is no user defined values
503
			$this->label->set($pc);
504
		}
505
 
506
		$position = 0;
507
 
508
		foreach($pc as $key => $value) {
509
 
510
			// Limit number of labels to display
511
			if($position === $this->number) {
512
				break;
513
			}
514
 
515
			if(is_null($this->minimum) === FALSE and $value < $this->minimum) {
516
				continue;
517
			}
518
 
519
			$position++;
520
 
521
			list($from, $to, $explode) = $values[$key];
522
 
523
			$angle = $from + ($to - $from) / 2;
524
			$angleRad = (360 - $angle) * M_PI / 180;
525
 
526
			$point = new awPoint(
527
				$x + $explode->x + cos($angleRad) * ($width / 2 + $this->position),
528
				$y + $explode->y - sin($angleRad) * ($height / 2 + $this->position)
529
			);
530
 
531
			$angle %= 360;
532
 
533
			// We don't display labels on the 3D effect
534
			if($angle > 0 and $angle < 180) {
535
				$point = $point->move(0, -1 * sin($angleRad) * $this->size);
536
			}
537
 
538
			if($angle >= 45 and $angle < 135) {
539
				$this->label->setAlign(awLabel::CENTER, awLabel::BOTTOM);
540
			} else if($angle >= 135 and $angle < 225) {
541
				$this->label->setAlign(awLabel::RIGHT, awLabel::MIDDLE);
542
			} else if($angle >= 225 and $angle < 315) {
543
				$this->label->setAlign(awLabel::CENTER, awLabel::TOP);
544
			} else {
545
				$this->label->setAlign(awLabel::LEFT, awLabel::MIDDLE);
546
			}
547
 
548
			$this->label->draw(
549
				$driver,
550
				$point,
551
				$key
552
			);
553
 
554
		}
555
 
556
	}
557
 
558
	/**
559
	 * Return margins around the component
560
	 *
561
	 * @return array Left, right, top and bottom margins
562
	 */
563
	public function getMargin() {
564
 
565
		// Get axis informations
566
 
567
		$leftAxis = $this->padding->left;
568
		$rightAxis = $this->padding->right;
569
		$topAxis = $this->padding->top;
570
		$bottomAxis = $this->padding->bottom;
571
 
572
		return array($leftAxis, $rightAxis, $topAxis, $bottomAxis);
573
 
574
	}
575
 
576
 
577
	/**
578
	 * Change values of Y axis
579
	 * This method ignores not numeric values
580
	 *
581
	 * @param array $values
582
	 */
583
	public function setValues($values) {
584
 
585
		$this->checkArray($values);
586
		$this->values = $values;
587
 
588
	}
589
 
590
 
591
	/**
592
	 * Return values of Y axis
593
	 *
594
	 * @return array
595
	 */
596
	public function getValues() {
597
		return $this->values;
598
	}
599
 
600
	private function checkArray(&$array) {
601
 
602
		if(is_array($array) === FALSE) {
603
			awImage::drawError("Class Pie: You tried to set values that are not an array.");
604
		}
605
 
606
		foreach($array as $key => $value) {
607
			if(is_numeric($value) === FALSE) {
608
				unset($array[$key]);
609
			}
610
		}
611
 
612
		if(count($array) < 1) {
613
			awImage::drawError("Class Pie: Your graph must have at least 1 value.");
614
		}
615
 
616
	}
617
 
618
}
619
 
620
registerClass('Pie');
621
 
622
/**
623
 * Pie
624
 *
625
 * @package Artichow
626
 */
627
class awPiePart implements awLegendable {
628
 
629
	/**
630
	 * Pie part color
631
	 *
632
	 * @var Color
633
	 */
634
	protected $color;
635
 
636
	/**
637
	 * Build a new awPiePart
638
	 *
639
	 * @param awColor $color Pie part color
640
	 */
641
	public function __construct(awColor $color) {
642
 
643
		$this->color = $color;
644
 
645
	}
646
 
647
	/**
648
	 * Get the background color or gradient of an element of the component
649
	 *
650
	 * @return Color, Gradient
651
	 */
652
	public function getLegendBackground() {
653
		return $this->color;
654
	}
655
 
656
	/**
657
	 * Get the line thickness
658
	 *
659
	 * @return NULL
660
	 */
661
	public function getLegendLineThickness() {
662
	}
663
 
664
	/**
665
	 * Get the line type
666
	 *
667
	 * @return NULL
668
	 */
669
	public function getLegendLineStyle() {
670
	}
671
 
672
	/**
673
	 * Get the color of line
674
	 *
675
	 * @return NULL
676
	 */
677
	public function getLegendLineColor() {
678
	}
679
 
680
	/**
681
	 * Get a mark object
682
	 *
683
	 * @return NULL
684
	 */
685
	public function getLegendMark() {
686
	}
687
 
688
}
689
 
690
registerClass('PiePart');
691
 
692
function callbackPerCent($value) {
693
	return $value.'%';
694
}
695
?>