PageRenderTime 25ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/phpmyvisites_1_9/libs/artichow/php4/inc/Axis.class.php

https://bitbucket.org/pombredanne/spip-zone-treemap
PHP | 760 lines | 354 code | 147 blank | 259 comment | 44 complexity | dea731fd33ebdf279372bd12879f0862 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. * Handle axis
  11. *
  12. * @package Artichow
  13. */
  14. class awAxis {
  15. /**
  16. * Axis line
  17. *
  18. * @var Line
  19. */
  20. var $line;
  21. /**
  22. * Axis labels
  23. *
  24. * @var Label
  25. */
  26. var $label;
  27. /**
  28. * Axis title
  29. *
  30. * @var Label
  31. */
  32. var $title;
  33. /**
  34. * Title position
  35. *
  36. * @var float
  37. */
  38. var $titlePosition = 0.5;
  39. /**
  40. * Labels number
  41. *
  42. * @var int
  43. */
  44. var $labelNumber;
  45. /**
  46. * Axis ticks
  47. *
  48. * @var array
  49. */
  50. var $ticks = array();
  51. /**
  52. * Axis and ticks color
  53. *
  54. * @var Color
  55. */
  56. var $color;
  57. /**
  58. * Axis left and right padding
  59. *
  60. * @var Side
  61. */
  62. var $padding;
  63. /**
  64. * Axis range
  65. *
  66. * @var array
  67. */
  68. var $range;
  69. /**
  70. * Hide axis
  71. *
  72. * @var bool
  73. */
  74. var $hide = FALSE;
  75. /**
  76. * Auto-scaling mode
  77. *
  78. * @var bool
  79. */
  80. var $auto = TRUE;
  81. /**
  82. * Axis range callback function
  83. *
  84. * @var array
  85. */
  86. var $rangeCallback = array(
  87. 'toValue' => 'toProportionalValue',
  88. 'toPosition' => 'toProportionalPosition'
  89. );
  90. /**
  91. * Build the axis
  92. *
  93. * @param float $min Begin of the range of the axis
  94. * @param float $max End of the range of the axis
  95. */
  96. function awAxis($min = NULL, $max = NULL) {
  97. $this->line = new awVector(
  98. new awPoint(0, 0),
  99. new awPoint(0, 0)
  100. );
  101. $this->label = new awLabel;
  102. $this->padding = new awSide;
  103. $this->title = new awLabel(
  104. NULL,
  105. NULL,
  106. NULL,
  107. 0
  108. );
  109. $this->setColor(new awBlack);
  110. if($min !== NULL and $max !== NULL) {
  111. $this->setRange($min, $max);
  112. }
  113. }
  114. /**
  115. * Enable/disable auto-scaling mode
  116. *
  117. * @param bool $auto
  118. */
  119. function auto($auto) {
  120. $this->auto = (bool)$auto;
  121. }
  122. /**
  123. * Get auto-scaling mode status
  124. *
  125. * @return bool
  126. */
  127. function isAuto() {
  128. return $this->auto;
  129. }
  130. /**
  131. * Hide axis
  132. *
  133. * @param bool $hide
  134. */
  135. function hide($hide = TRUE) {
  136. $this->hide = (bool)$hide;
  137. }
  138. /**
  139. * Show axis
  140. *
  141. * @param bool $show
  142. */
  143. function show($show = TRUE) {
  144. $this->hide = !(bool)$show;
  145. }
  146. /**
  147. * Return a tick object from its name
  148. *
  149. * @param string $name Tick object name
  150. * @return Tick
  151. */
  152. function tick($name) {
  153. if(array_key_exists($name, $this->ticks)) {
  154. return $tick = &$this->ticks[$name];
  155. } else {
  156. return NULL;
  157. }
  158. }
  159. /**
  160. * Add a tick object
  161. *
  162. * @param string $name Tick object name
  163. * @param &$tick Tick object
  164. */
  165. function addTick($name, &$tick) {
  166. $this->ticks[$name] = &$tick;
  167. }
  168. /**
  169. * Delete a tick object
  170. *
  171. * @param string $name Tick object name
  172. */
  173. function deleteTick($name) {
  174. if(array_key_exists($name, $this->ticks)) {
  175. unset($this->ticks[$name]);
  176. }
  177. }
  178. /**
  179. * Hide all ticks
  180. *
  181. * @param bool $hide Hide or not ?
  182. */
  183. function hideTicks($hide = TRUE) {
  184. foreach($this->ticks as $key => $tick) {
  185. $this->ticks[$key]->hide($hide);
  186. }
  187. }
  188. /**
  189. * Change ticks style
  190. *
  191. * @param int $style Ticks style
  192. */
  193. function setTickStyle($style) {
  194. foreach($this->ticks as $key => $tick) {
  195. $this->ticks[$key]->setStyle($style);
  196. }
  197. }
  198. /**
  199. * Change ticks interval
  200. *
  201. * @param int $interval Ticks interval
  202. */
  203. function setTickInterval($interval) {
  204. foreach($this->ticks as $key => $tick) {
  205. $this->ticks[$key]->setInterval($interval);
  206. }
  207. }
  208. /**
  209. * Change number of ticks relative to others ticks
  210. *
  211. * @param &$to Change number of theses ticks
  212. * @param &$from Ticks reference
  213. * @param float $number Number of ticks by the reference
  214. */
  215. function setNumberByTick($to, $from, $number) {
  216. $this->ticks[$to]->setNumberByTick($this->ticks[$from], $number);
  217. }
  218. /**
  219. * Reverse ticks style
  220. */
  221. function reverseTickStyle() {
  222. foreach($this->ticks as $key => $tick) {
  223. if($this->ticks[$key]->getStyle() === TICK_IN) {
  224. $this->ticks[$key]->setStyle(TICK_OUT);
  225. } else if($this->ticks[$key]->getStyle() === TICK_OUT) {
  226. $this->ticks[$key]->setStyle(TICK_IN);
  227. }
  228. }
  229. }
  230. /**
  231. * Change interval of labels
  232. *
  233. * @param int $interval Interval
  234. */
  235. function setLabelInterval($interval) {
  236. $this->auto(FALSE);
  237. $this->setTickInterval($interval);
  238. $this->label->setInterval($interval);
  239. }
  240. /**
  241. * Change number of labels
  242. *
  243. * @param int $number Number of labels to display (can be NULL)
  244. */
  245. function setLabelNumber($number) {
  246. $this->auto(FALSE);
  247. $this->labelNumber = is_null($number) ? NULL : (int)$number;
  248. }
  249. /**
  250. * Get number of labels
  251. *
  252. * @return int
  253. */
  254. function getLabelNumber() {
  255. return $this->labelNumber;
  256. }
  257. /**
  258. * Change precision of labels
  259. *
  260. * @param int $precision Precision
  261. */
  262. function setLabelPrecision($precision) {
  263. $this->auto(FALSE);
  264. $function = 'axis'.time().'_'.(microtime() * 1000000);
  265. eval('function '.$function.'($value) {
  266. return sprintf("%.'.(int)$precision.'f", $value);
  267. }');
  268. $this->label->setCallbackFunction($function);
  269. }
  270. /**
  271. * Change text of labels
  272. *
  273. * @param array $texts Some texts
  274. */
  275. function setLabelText($texts) {
  276. if(is_array($texts)) {
  277. $this->auto(FALSE);
  278. $function = 'axis'.time().'_'.(microtime() * 1000000);
  279. eval('function '.$function.'($value) {
  280. $texts = '.var_export($texts, TRUE).';
  281. return $texts[$value];
  282. }');
  283. $this->label->setCallbackFunction($function);
  284. }
  285. }
  286. /**
  287. * Get the position of a point
  288. *
  289. * @param &$xAxis X axis
  290. * @param &$yAxis Y axis
  291. * @param $p Position of the point
  292. * @return Point Position on the axis
  293. */
  294. function toPosition(&$xAxis, &$yAxis, $p) {
  295. $p1 = $xAxis->getPointFromValue($p->x);
  296. $p2 = $yAxis->getPointFromValue($p->y);
  297. return new awPoint(
  298. round($p1->x),
  299. round($p2->y)
  300. );
  301. }
  302. /**
  303. * Change title alignment
  304. *
  305. * @param int $alignment New Alignment
  306. */
  307. function setTitleAlignment($alignment) {
  308. switch($alignment) {
  309. case LABEL_TOP :
  310. $this->setTitlePosition(1);
  311. $this->title->setAlign(NULL, LABEL_BOTTOM);
  312. break;
  313. case LABEL_BOTTOM :
  314. $this->setTitlePosition(0);
  315. $this->title->setAlign(NULL, LABEL_TOP);
  316. break;
  317. case LABEL_LEFT :
  318. $this->setTitlePosition(0);
  319. $this->title->setAlign(LABEL_LEFT);
  320. break;
  321. case LABEL_RIGHT :
  322. $this->setTitlePosition(1);
  323. $this->title->setAlign(LABEL_RIGHT);
  324. break;
  325. }
  326. }
  327. /**
  328. * Change title position on the axis
  329. *
  330. * @param float $position A new awposition between 0 and 1
  331. */
  332. function setTitlePosition($position) {
  333. $this->titlePosition = (float)$position;
  334. }
  335. /**
  336. * Change axis and axis title color
  337. *
  338. * @param $color
  339. */
  340. function setColor($color) {
  341. $this->color = $color;
  342. $this->title->setColor($color);
  343. }
  344. /**
  345. * Change axis padding
  346. *
  347. * @param int $left Left padding in pixels
  348. * @param int $right Right padding in pixels
  349. */
  350. function setPadding($left, $right) {
  351. $this->padding->set($left, $right);
  352. }
  353. /**
  354. * Get axis padding
  355. *
  356. * @return Side
  357. */
  358. function getPadding() {
  359. return $this->padding;
  360. }
  361. /**
  362. * Change axis range
  363. *
  364. * @param float $min
  365. * @param float $max
  366. */
  367. function setRange($min, $max) {
  368. if($min !== NULL) {
  369. $this->range[0] = (float)$min;
  370. }
  371. if($max !== NULL) {
  372. $this->range[1] = (float)$max;
  373. }
  374. }
  375. /**
  376. * Get axis range
  377. *
  378. * @return array
  379. */
  380. function getRange() {
  381. return $this->range;
  382. }
  383. /**
  384. * Change axis range callback function
  385. *
  386. * @param string $toValue Transform a position between 0 and 1 to a value
  387. * @param string $toPosition Transform a value to a position between 0 and 1 on the axis
  388. */
  389. function setRangeCallback($toValue, $toPosition) {
  390. $this->rangeCallback = array(
  391. 'toValue' => (string)$toValue,
  392. 'toPosition' => (string)$toPosition
  393. );
  394. }
  395. /**
  396. * Center X values of the axis
  397. *
  398. * @param &$axis An axis
  399. * @param float $value The reference value on the axis
  400. */
  401. function setXCenter(&$axis, $value) {
  402. // Check vector angle
  403. if($this->line->isVertical() === FALSE) {
  404. trigger_error("setXCenter() can only be used on vertical axes", E_USER_ERROR);
  405. }
  406. $p = $axis->getPointFromValue($value);
  407. $this->line->setX(
  408. $p->x,
  409. $p->x
  410. );
  411. }
  412. /**
  413. * Center Y values of the axis
  414. *
  415. * @param &$axis An axis
  416. * @param float $value The reference value on the axis
  417. */
  418. function setYCenter(&$axis, $value) {
  419. // Check vector angle
  420. if($this->line->isHorizontal() === FALSE) {
  421. trigger_error("setYCenter() can only be used on horizontal axes", E_USER_ERROR);
  422. }
  423. $p = $axis->getPointFromValue($value);
  424. $this->line->setY(
  425. $p->y,
  426. $p->y
  427. );
  428. }
  429. /**
  430. * Get the distance between to values on the axis
  431. *
  432. * @param float $from The first value
  433. * @param float $to The last value
  434. * @return Point
  435. */
  436. function getDistance($from, $to) {
  437. $p1 = $this->getPointFromValue($from);
  438. $p2 = $this->getPointFromValue($to);
  439. return $p1->getDistance($p2);
  440. }
  441. /**
  442. * Get a point on the axis from a value
  443. *
  444. * @param float $value
  445. * @return Point
  446. */
  447. function getPointFromValue($value) {
  448. $callback = $this->rangeCallback['toPosition'];
  449. list($min, $max) = $this->range;
  450. $position = $callback($value, $min, $max);
  451. return $this->getPointFromPosition($position);
  452. }
  453. /**
  454. * Get a point on the axis from a position
  455. *
  456. * @param float $position A position between 0 and 1
  457. * @return Point
  458. */
  459. function getPointFromPosition($position) {
  460. $vector = $this->getVector();
  461. $angle = $vector->getAngle();
  462. $size = $vector->getSize();
  463. return $vector->p1->move(
  464. cos($angle) * $size * $position,
  465. -1 * sin($angle) * $size * $position
  466. );
  467. }
  468. /**
  469. * Draw axis
  470. *
  471. * @param $drawer A drawer
  472. */
  473. function draw($drawer) {
  474. if($this->hide) {
  475. return;
  476. }
  477. $vector = $this->getVector();
  478. // Draw axis ticks
  479. $this->drawTicks($drawer, $vector);
  480. // Draw axis line
  481. $this->line($drawer);
  482. // Draw labels
  483. $this->drawLabels($drawer);
  484. // Draw axis title
  485. $p = $this->getPointFromPosition($this->titlePosition);
  486. $this->title->draw($drawer, $p);
  487. }
  488. function autoScale() {
  489. if($this->isAuto() === FALSE) {
  490. return;
  491. }
  492. list($min, $max) = $this->getRange();
  493. $interval = $max - $min;
  494. $partMax = $max / $interval;
  495. $partMin = $min / $interval;
  496. $difference = log($interval) / log(10);
  497. $difference = floor($difference);
  498. $pow = pow(10, $difference);
  499. $intervalNormalize = $interval / $pow;
  500. if($difference <= 0) {
  501. $precision = $difference * -1 + 1;
  502. if($intervalNormalize > 2) {
  503. $precision--;
  504. }
  505. } else {
  506. $precision = 0;
  507. }
  508. if($min != 0 and $max != 0) {
  509. $precision++;
  510. }
  511. $this->setLabelPrecision($precision);
  512. if($intervalNormalize <= 1.5) {
  513. $intervalReal = 1.5;
  514. $labelNumber = 4;
  515. } else if($intervalNormalize <= 2) {
  516. $intervalReal = 2;
  517. $labelNumber = 5;
  518. } else if($intervalNormalize <= 3) {
  519. $intervalReal = 3;
  520. $labelNumber = 4;
  521. } else if($intervalNormalize <= 4) {
  522. $intervalReal = 4;
  523. $labelNumber = 5;
  524. } else if($intervalNormalize <= 5) {
  525. $intervalReal = 5;
  526. $labelNumber = 6;
  527. } else if($intervalNormalize <= 8) {
  528. $intervalReal = 8;
  529. $labelNumber = 5;
  530. } else if($intervalNormalize <= 10) {
  531. $intervalReal = 10;
  532. $labelNumber = 6;
  533. }
  534. if($min == 0) {
  535. $this->setRange(
  536. $min,
  537. $intervalReal * $pow
  538. );
  539. } else if($max == 0) {
  540. $this->setRange(
  541. $intervalReal * $pow * -1,
  542. 0
  543. );
  544. }
  545. $this->setLabelNumber($labelNumber);
  546. }
  547. function line($drawer) {
  548. $drawer->line(
  549. $this->color,
  550. $this->line
  551. );
  552. }
  553. function drawTicks($drawer, &$vector) {
  554. foreach($this->ticks as $tick) {
  555. $tick->setColor($this->color);
  556. $tick->draw($drawer, $vector);
  557. }
  558. }
  559. function drawLabels($drawer) {
  560. if($this->labelNumber !== NULL) {
  561. list($min, $max) = $this->range;
  562. $number = $this->labelNumber - 1;
  563. if($number < 1) {
  564. return;
  565. }
  566. $function = $this->rangeCallback['toValue'];
  567. $labels = array();
  568. for($i = 0; $i <= $number; $i++) {
  569. $labels[] = $function($i / $number, $min, $max);
  570. }
  571. $this->label->set($labels);
  572. }
  573. $labels = $this->label->count();
  574. for($i = 0; $i < $labels; $i++) {
  575. $p = $this->getPointFromValue($this->label->get($i));
  576. $this->label->draw($drawer, $p, $i);
  577. }
  578. }
  579. function getVector() {
  580. $angle = $this->line->getAngle();
  581. // Compute paddings
  582. $vector = new awVector(
  583. $this->line->p1->move(
  584. cos($angle) * $this->padding->left,
  585. -1 * sin($angle) * $this->padding->left
  586. ),
  587. $this->line->p2->move(
  588. -1 * cos($angle) * $this->padding->right,
  589. -1 * -1 * sin($angle) * $this->padding->right
  590. )
  591. );
  592. return $vector;
  593. }
  594. function __clone() {
  595. $this->label = $this->label;
  596. $this->line = $this->line;
  597. $this->title = $this->title;
  598. foreach($this->ticks as $name => $tick) {
  599. $this->ticks[$name] = $tick;
  600. }
  601. }
  602. }
  603. registerClass('Axis');
  604. function toProportionalValue($position, $min, $max) {
  605. return $min + ($max - $min) * $position;
  606. }
  607. function toProportionalPosition($value, $min, $max) {
  608. if($max - $min == 0) {
  609. return 0;
  610. }
  611. return ($value - $min) / ($max - $min);
  612. }
  613. ?>