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__)."/../Graph.class.php";
11
 
12
 
13
/**
14
 * Some legends
15
 *
16
 * @package Artichow
17
 */
18
class awLegend implements awPositionable {
19
 
20
	/**
21
	 * Legends added
22
	 *
23
	 * @var array
24
	 */
25
	protected $legends = array();
26
 
27
	/**
28
	 * The current component
29
	 *
30
	 * @var Component
31
	 */
32
	protected $component;
33
 
34
	/**
35
	 * Background color or gradient
36
	 *
37
	 * @var Color, Gradient
38
	 */
39
	protected $background;
40
 
41
	/**
42
	 * Text color
43
	 *
44
	 * @var Color
45
	 */
46
	protected $textColor;
47
 
48
	/**
49
	 * Text font
50
	 *
51
	 * @var Font
52
	 */
53
	protected $textFont;
54
 
55
	/**
56
	 * Text margin
57
	 *
58
	 * @var Side
59
	 */
60
	protected $textMargin;
61
 
62
	/**
63
	 * Number of columns
64
	 *
65
	 * @var int
66
	 */
67
	protected $columns = NULL;
68
 
69
	/**
70
	 * Number of rows
71
	 *
72
	 * @var int
73
	 */
74
	protected $rows = NULL;
75
 
76
	/**
77
	 * Legend position
78
	 *
79
	 * @var Point
80
	 */
81
	protected $position;
82
 
83
	/**
84
	 * Hide legend ?
85
	 *
86
	 * @var bool
87
	 */
88
	protected $hide = FALSE;
89
 
90
	/**
91
	 * Space between each legend
92
	 *
93
	 * @var int
94
	 */
95
	protected $space = 4;
96
 
97
	/**
98
	 * Horizontal alignment
99
	 *
100
	 * @var int
101
	 */
102
	protected $hAlign;
103
 
104
	/**
105
	 * Vertical alignment
106
	 *
107
	 * @var int
108
	 */
109
	protected $vAlign;
110
 
111
	/**
112
	 * Margin
113
	 *
114
	 * @var array Array for left, right, top and bottom margins
115
	 */
116
	private $margin;
117
 
118
	/**
119
	 * Legend shadow
120
	 *
121
	 * @var Shadow
122
	 */
123
	public $shadow;
124
 
125
	/**
126
	 * Legend border
127
	 *
128
	 * @var Border
129
	 */
130
	public $border;
131
 
132
	/**
133
	 * Line legend
134
	 *
135
	 * @var int
136
	 */
137
	const LINE = 1;
138
 
139
	/**
140
	 * Color/Gradient background legend
141
	 *
142
	 * @var int
143
	 */
144
	const BACKGROUND = 2;
145
 
146
	/**
147
	 * Use marks and line as legend
148
	 *
149
	 * @var int
150
	 */
151
	const MARK = 3;
152
 
153
	/**
154
	 * Use marks as legend
155
	 *
156
	 * @var int
157
	 */
158
	const MARKONLY = 4;
159
 
160
	/**
161
	 * Right side model
162
	 *
163
	 * @var int
164
	 */
165
	const MODEL_RIGHT = 1;
166
 
167
	/**
168
	 * Bottom side model
169
	 *
170
	 * @var int
171
	 */
172
	const MODEL_BOTTOM = 2;
173
 
174
	/**
175
	 * Build the legend
176
	 *
177
	 * @param int $model Legend model
178
	 */
179
	public function __construct($model = awLegend::MODEL_RIGHT) {
180
 
181
		$this->shadow = new awShadow(awShadow::LEFT_BOTTOM);
182
		$this->border = new awBorder;
183
 
184
		$this->textMargin = new awSide(4);
185
		$this->setModel($model);
186
 
187
	}
188
 
189
	/**
190
	 * Set a predefined model for the legend
191
	 *
192
	 * @param int $model
193
	 */
194
	public function setModel($model) {
195
 
196
		$this->setBackgroundColor(new awColor(255, 255, 255, 15));
197
		$this->setPadding(8, 8, 8, 8);
198
		$this->setTextFont(new awFont2);
199
		$this->shadow->setSize(3);
200
 
201
		switch($model) {
202
 
203
			case awLegend::MODEL_RIGHT :
204
 
205
				$this->setColumns(1);
206
				$this->setAlign(awLegend::RIGHT, awLegend::MIDDLE);
207
				$this->setPosition(0.96, 0.50);
208
 
209
				break;
210
 
211
			case awLegend::MODEL_BOTTOM :
212
 
213
				$this->setRows(1);
214
				$this->setAlign(awLegend::CENTER, awLegend::TOP);
215
				$this->setPosition(0.50, 0.92);
216
 
217
				break;
218
 
219
			default :
220
 
221
				$this->setPosition(0.5, 0.5);
222
 
223
				break;
224
 
225
		}
226
 
227
	}
228
 
229
	/**
230
	 * Hide legend ?
231
	 *
232
	 * @param bool $hide TRUE to hide legend, FALSE otherwise
233
	 */
234
	public function hide($hide = TRUE) {
235
		$this->hide = (bool)$hide;
236
	}
237
 
238
	/**
239
	 * Show legend ?
240
	 *
241
	 * @param bool $show
242
	 */
243
	public function show($show = TRUE) {
244
		$this->hide = (bool)!$show;
245
	}
246
 
247
 
248
	/**
249
	 * Add a Legendable object to the legend
250
	 *
251
	 * @param awLegendable $legendable
252
	 * @param string $title Legend title
253
	 * @param int $type Legend type (default to awLegend::LINE)
254
	 */
255
	public function add(awLegendable $legendable, $title, $type = awLegend::LINE) {
256
 
257
		$legend = array($legendable, $title, $type);
258
 
259
		$this->legends[] = $legend;
260
 
261
	}
262
 
263
	/**
264
	 * Change legend padding
265
	 *
266
	 * @param int $left
267
	 * @param int $right
268
	 * @param int $top
269
	 * @param int $bottom
270
	 */
271
	public function setPadding($left, $right, $top, $bottom) {
272
		$this->padding = array((int)$left, (int)$right, (int)$top, (int)$bottom);
273
	}
274
 
275
	/**
276
	 * Change space between each legend
277
	 *
278
	 * @param int $space
279
	 */
280
	public function setSpace($space) {
281
		$this->space = (int)$space;
282
	}
283
 
284
	/**
285
	 * Change alignment
286
	 *
287
	 * @param int $h Horizontal alignment
288
	 * @param int $v Vertical alignment
289
	 */
290
	public function setAlign($h = NULL, $v = NULL) {
291
		if($h !== NULL) {
292
			$this->hAlign = (int)$h;
293
		}
294
		if($v !== NULL) {
295
			$this->vAlign = (int)$v;
296
		}
297
	}
298
 
299
	/**
300
	 * Change number of columns
301
	 *
302
	 * @param int $columns
303
	 */
304
	public function setColumns($columns) {
305
		$this->rows = NULL;
306
		$this->columns = (int)$columns;
307
	}
308
 
309
	/**
310
	 * Change number of rows
311
	 *
312
	 * @param int $rows
313
	 */
314
	public function setRows($rows) {
315
		$this->columns = NULL;
316
		$this->rows = (int)$rows;
317
	}
318
 
319
	/**
320
	 * Change legend position
321
	 * X and Y positions must be between 0 and 1.
322
	 *
323
	 * @param float $x
324
	 * @param float $y
325
	 */
326
	public function setPosition($x = NULL, $y = NULL) {
327
		$x = (is_null($x) and !is_null($this->position)) ? $this->position->x : $x;
328
		$y = (is_null($y) and !is_null($this->position)) ? $this->position->y : $y;
329
 
330
		$this->position = new awPoint($x, $y);
331
	}
332
 
333
	/**
334
	 * Get legend position
335
	 *
336
	 * @return Point
337
	 */
338
	public function getPosition() {
339
		return $this->position;
340
	}
341
 
342
	/**
343
	 * Change text font
344
	 *
345
	 * @param awFont $font
346
	 */
347
	public function setTextFont(awFont $font) {
348
		$this->textFont = $font;
349
	}
350
 
351
	/**
352
	 * Change text margin
353
	 *
354
	 * @param int $left
355
	 * @param int $right
356
	 */
357
	public function setTextMargin($left, $right) {
358
		$this->textMargin->set($left, $right);
359
	}
360
 
361
	/**
362
	 * Change text color
363
	 *
364
	 * @param awColor $color
365
	 */
366
	public function setTextColor(awColor $color) {
367
		$this->textColor = $color;
368
	}
369
 
370
	/**
371
	 * Change background
372
	 *
373
	 * @param mixed $background
374
	 */
375
	public function setBackground($background) {
376
		$this->background = $background;
377
	}
378
 
379
	/**
380
	 * Change background color
381
	 *
382
	 * @param awColor $color
383
	 */
384
	public function setBackgroundColor(awColor $color) {
385
		$this->background = $color;
386
	}
387
 
388
	/**
389
	 * Change background gradient
390
	 *
391
	 * @param awGradient $gradient
392
	 */
393
	public function setBackgroundGradient(awGradient $gradient) {
394
		$this->background = $gradient;
395
	}
396
 
397
	/**
398
	 * Count the number of Legendable objects in the legend
399
	 *
400
	 * @return int
401
	 */
402
	public function count() {
403
		return count($this->legends);
404
	}
405
 
406
	public function draw(awDriver $driver) {
407
 
408
		if($this->hide) {
409
			return;
410
		}
411
 
412
		$count = $this->count();
413
 
414
		// No legend to print
415
		if($count === 0) {
416
			return;
417
		}
418
 
419
		// Get text widths and heights of each element of the legend
420
		$widths = array();
421
		$heights = array();
422
		$texts = array();
423
		for($i = 0; $i < $count; $i++) {
424
			list(, $title, ) = $this->legends[$i];
425
			$text = new awText(
426
				$title,
427
				$this->textFont,
428
				$this->textColor,
429
 
430
			);
431
//			$font = $text->getFont();
432
			$widths[$i] = $driver->getTextWidth($text) + $this->textMargin->left + $this->textMargin->right;
433
			$heights[$i] = $driver->getTextHeight($text);
434
			$texts[$i] = $text;
435
		}
436
 
437
		// Maximum height of the font used
438
		$heightMax = array_max($heights);
439
 
440
		// Get number of columns
441
		if($this->columns !== NULL) {
442
			$columns = $this->columns;
443
		} else if($this->rows !== NULL) {
444
			$columns = ceil($count / $this->rows);
445
		} else {
446
			$columns = $count;
447
		}
448
 
449
		// Number of  rows
450
		$rows = (int)ceil($count / $columns);
451
 
452
		// Get maximum with of each column
453
		$widthMax = array();
454
		for($i = 0; $i < $count; $i++) {
455
			// Get column width
456
			$column = $i % $columns;
457
			if(array_key_exists($column, $widthMax) === FALSE) {
458
				$widthMax[$column] = $widths[$i];
459
			} else {
460
				$widthMax[$column] = max($widthMax[$column], $widths[$i]);
461
			}
462
		}
463
 
464
		$width = $this->padding[0] + $this->padding[1] - $this->space;
465
		for($i = 0; $i < $columns; $i++) {
466
			$width += $this->space + 5 + 10 + $widthMax[$i];
467
		}
468
 
469
		$height = ($heightMax + $this->space) * $rows - $this->space + $this->padding[2] + $this->padding[3];
470
 
471
		// Look for legends position
472
		list($x, $y) = $driver->getSize();
473
 
474
		$p = new awPoint(
475
			$this->position->x * $x,
476
			$this->position->y * $y
477
		);
478
 
479
		switch($this->hAlign) {
480
 
481
			case awLegend::CENTER :
482
				$p->x -= $width / 2;
483
				break;
484
 
485
			case awLegend::RIGHT :
486
				$p->x -= $width;
487
				break;
488
 
489
		}
490
 
491
		switch($this->vAlign) {
492
 
493
			case awLegend::MIDDLE :
494
				$p->y -= $height / 2;
495
				break;
496
 
497
			case awLegend::BOTTOM :
498
				$p->y -= $height;
499
				break;
500
 
501
		}
502
 
503
		// Draw legend shadow
504
		$this->shadow->draw(
505
			$driver,
506
			$p,
507
			$p->move($width, $height),
508
			awShadow::OUT
509
		);
510
 
511
		// Draw legends base
512
		$this->drawBase($driver, $p, $width, $height);
513
 
514
		// Draw each legend
515
		for($i = 0; $i < $count; $i++) {
516
 
517
			list($component, $title, $type) = $this->legends[$i];
518
 
519
			$column = $i % $columns;
520
			$row = (int)floor($i / $columns);
521
 
522
			// Get width of all previous columns
523
			$previousColumns = 0;
524
			for($j = 0; $j < $column; $j++) {
525
				$previousColumns += $this->space + 10 + 5 + $widthMax[$j];
526
			}
527
 
528
			// Draw legend text
529
			$driver->string(
530
				$texts[$i],
531
				$p->move(
532
					$this->padding[0] + $previousColumns + 10 + 5 + $this->textMargin->left,
533
					$this->padding[2] + $row * ($heightMax + $this->space) + $heightMax / 2 - $heights[$i] / 2
534
				)
535
			);
536
 
537
			// Draw legend icon
538
			switch($type) {
539
 
540
				case awLegend::LINE :
541
				case awLegend::MARK :
542
				case awLegend::MARKONLY :
543
 
544
					// Get vertical position
545
					$x = $this->padding[0] + $previousColumns;
546
					$y = $this->padding[2] + $row * ($heightMax + $this->space) + $heightMax / 2 - $component->getLegendLineThickness();
547
 
548
					// Draw two lines
549
					if($component->getLegendLineColor() !== NULL) {
550
 
551
						$color = $component->getLegendLineColor();
552
 
553
						if($color instanceof awColor and $type !== awLegend::MARKONLY) {
554
 
555
							$driver->line(
556
								$color,
557
								new awLine(
558
									$p->move(
559
										$x, // YaPB ??
560
										$y + $component->getLegendLineThickness() / 2
561
									),
562
									$p->move(
563
										$x + 10,
564
										$y + $component->getLegendLineThickness() / 2
565
									),
566
									$component->getLegendLineStyle(),
567
									$component->getLegendLineThickness()
568
								)
569
							);
570
 
571
							unset($color);
572
 
573
						}
574
 
575
					}
576
 
577
					if($type === awLegend::MARK or $type === awLegend::MARKONLY)  {
578
 
579
						$mark = $component->getLegendMark();
580
 
581
						if($mark !== NULL) {
582
							$mark->draw(
583
								$driver,
584
								$p->move(
585
									$x + 5.5,
586
									$y + $component->getLegendLineThickness() / 2
587
								)
588
							);
589
						}
590
 
591
						unset($mark);
592
 
593
					}
594
 
595
					break;
596
 
597
				case awLegend::BACKGROUND :
598
 
599
					// Get vertical position
600
					$x = $this->padding[0] + $previousColumns;
601
					$y = $this->padding[2] + $row * ($heightMax + $this->space) + $heightMax / 2 - 5;
602
 
603
					$from = $p->move(
604
						$x,
605
						$y
606
					);
607
 
608
					$to = $p->move(
609
						$x + 10,
610
						$y + 10
611
					);
612
 
613
					$background = $component->getLegendBackground();
614
 
615
					if($background !== NULL) {
616
 
617
						$driver->filledRectangle(
618
							$component->getLegendBackground(),
619
							new awLine($from, $to)
620
						);
621
 
622
						// Draw rectangle border
623
						$this->border->rectangle(
624
							$driver,
625
							$from->move(0, 0),
626
							$to->move(0, 0)
627
						);
628
 
629
					}
630
 
631
					unset($background, $from, $to);
632
 
633
					break;
634
 
635
			}
636
 
637
		}
638
 
639
	}
640
 
641
	private function drawBase(awDriver $driver, awPoint $p, $width, $height) {
642
 
643
		$this->border->rectangle(
644
			$driver,
645
			$p,
646
			$p->move($width, $height)
647
		);
648
 
649
		$size = $this->border->visible() ? 1 : 0;
650
 
651
		$driver->filledRectangle(
652
			$this->background,
653
			new awLine(
654
				$p->move($size, $size),
655
				$p->move($width - $size, $height - $size)
656
			)
657
		);
658
 
659
	}
660
 
661
}
662
 
663
registerClass('Legend');
664
 
665
/**
666
 * You can add a legend to components which implements this interface
667
 *
668
 * @package Artichow
669
 */
670
interface awLegendable {
671
 
672
	/**
673
	 * Get the line type
674
	 *
675
	 * @return int
676
	 */
677
	public function getLegendLineStyle();
678
 
679
	/**
680
	 * Get the line thickness
681
	 *
682
	 * @return int
683
	 */
684
	public function getLegendLineThickness();
685
 
686
	/**
687
	 * Get the color of line
688
	 *
689
	 * @return Color
690
	 */
691
	public function getLegendLineColor();
692
 
693
	/**
694
	 * Get the background color or gradient of an element of the component
695
	 *
696
	 * @return Color, Gradient
697
	 */
698
	public function getLegendBackground();
699
 
700
	/**
701
	 * Get a Mark object
702
	 *
703
	 * @return Mark
704
	 */
705
	public function getLegendMark();
706
 
707
}
708
 
709
registerInterface('Legendable');
710
?>