PageRenderTime 53ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/artichow/inc/Legend.class.php

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