PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/library/ezc/Graph/src/axis/labeled.php

https://github.com/fusenigk/mantisbt-1
PHP | 520 lines | 287 code | 43 blank | 190 comment | 25 complexity | cb765a5c9c241416d392c195678a282d MD5 | raw file
  1. <?php
  2. /**
  3. * File containing the ezcGraphChartElementLabeledAxis class
  4. *
  5. * @package Graph
  6. * @version 1.5
  7. * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
  8. * @license http://ez.no/licenses/new_bsd New BSD License
  9. */
  10. /**
  11. * Class to represent a labeled axis.
  12. *
  13. * Axis elements represent the axis in a bar, line or radar chart. They are
  14. * chart elements (ezcGraphChartElement) extending from
  15. * ezcGraphChartElementAxis, where additional formatting options can be found.
  16. * You should generally use the axis, which matches your input data best, so
  17. * that the automatic chart layouting works best. Aavailable axis types are:
  18. *
  19. * - ezcGraphChartElementDateAxis
  20. * - ezcGraphChartElementLabeledAxis
  21. * - ezcGraphChartElementLogarithmicalAxis
  22. * - ezcGraphChartElementNumericAxis
  23. *
  24. * The labeled axis will accept any values and converts them to strings. The
  25. * labeled axis does not know about any special meanings of values and
  26. * maintains the order of the given labels with equidistant spaces between all
  27. * values. If your data has a special meaning, like a set of numbers or dates,
  28. * use one of the other more appropriate axis.
  29. *
  30. * Because it is not always possible to fit all labels in a chart you may
  31. * define the count of labels drawn using the $labelCount option. For all other
  32. * labels only a small step will be rendered.
  33. *
  34. * The labeled axis may be used like:
  35. *
  36. * <code>
  37. * $graph = new ezcGraphLineChart();
  38. * $graph->options->fillLines = 210;
  39. * $graph->options->font->maxFontSize = 10;
  40. * $graph->title = 'Error level colors';
  41. * $graph->legend = false;
  42. *
  43. * $graph->yAxis = new ezcGraphChartElementLabeledAxis();
  44. * $graph->yAxis->axisLabelRenderer->showZeroValue = true;
  45. *
  46. * $graph->yAxis->label = 'Color';
  47. * $graph->xAxis->label = 'Error level';
  48. *
  49. * // Add data
  50. * $graph->data['colors'] = new ezcGraphArrayDataSet(
  51. * array(
  52. * 'info' => 'blue',
  53. * 'notice' => 'green',
  54. * 'warning' => 'orange',
  55. * 'error' => 'red',
  56. * 'fatal' => 'red',
  57. * )
  58. * );
  59. *
  60. * $graph->render( 400, 150, 'tutorial_axis_labeled.svg' );
  61. * </code>
  62. *
  63. * @property float $labelCount
  64. * Define count of displayed labels on the axis
  65. *
  66. * @version 1.5
  67. * @package Graph
  68. * @mainclass
  69. */
  70. class ezcGraphChartElementLabeledAxis extends ezcGraphChartElementAxis
  71. {
  72. /**
  73. * Array with labeles for data
  74. *
  75. * @var array
  76. */
  77. protected $labels = array();
  78. /**
  79. * Labels indexed by their name as key for faster lookups
  80. *
  81. * @var array
  82. */
  83. protected $labelsIndexed = array();
  84. /**
  85. * Reduced amount of labels which will be displayed in the chart
  86. *
  87. * @var array
  88. */
  89. protected $displayedLabels = array();
  90. /**
  91. * Maximum count of labels which can be displayed on one axis
  92. * @todo Perhaps base this on the chart size
  93. */
  94. const MAX_LABEL_COUNT = 10;
  95. /**
  96. * Precalculated steps on the axis
  97. *
  98. * @var array(ezcGraphAxisStep)
  99. */
  100. protected $steps;
  101. /**
  102. * Constructor
  103. *
  104. * @param array $options Default option array
  105. * @return void
  106. * @ignore
  107. */
  108. public function __construct( array $options = array() )
  109. {
  110. $this->properties['labelCount'] = null;
  111. $this->axisLabelRenderer = new ezcGraphAxisCenteredLabelRenderer();
  112. parent::__construct( $options );
  113. }
  114. /**
  115. * __set
  116. *
  117. * @param mixed $propertyName
  118. * @param mixed $propertyValue
  119. * @throws ezcBaseValueException
  120. * If a submitted parameter was out of range or type.
  121. * @throws ezcBasePropertyNotFoundException
  122. * If a the value for the property options is not an instance of
  123. * @return void
  124. * @ignore
  125. */
  126. public function __set( $propertyName, $propertyValue )
  127. {
  128. switch ( $propertyName )
  129. {
  130. case 'labelCount':
  131. if ( !is_numeric( $propertyValue ) ||
  132. ( $propertyValue <= 1 ) )
  133. {
  134. throw new ezcBaseValueException( $propertyName, $propertyValue, 'int > 1' );
  135. }
  136. $this->properties['labelCount'] = (int) $propertyValue;
  137. break;
  138. default:
  139. parent::__set( $propertyName, $propertyValue );
  140. break;
  141. }
  142. }
  143. /**
  144. * Increase the keys of all elements in the array up from the start key, to
  145. * insert an additional element at the correct position.
  146. *
  147. * @param array $array Array
  148. * @param int $startKey Key to increase keys from
  149. * @return array Updated array
  150. */
  151. protected function increaseKeys( array $array, $startKey )
  152. {
  153. foreach ( $array as $key => $value )
  154. {
  155. if ( $key === $startKey )
  156. {
  157. // Recursive check, if next key should be increased, too
  158. if ( isset ( $array[$key + 1] ) )
  159. {
  160. $array = $this->increaseKeys( $array, $key + 1 );
  161. }
  162. // Increase key
  163. $array[$key + 1] = $array[$key];
  164. unset( $array[$key] );
  165. }
  166. }
  167. return $array;
  168. }
  169. /**
  170. * Provide initial set of labels
  171. *
  172. * This method may be used to provide an ordered set of labels, containing
  173. * labels, which are not available in the datasets or to provide a label
  174. * order different to the one in the given dataset.
  175. *
  176. * @param array $labels
  177. * @return void
  178. */
  179. public function provideLabels( array $labels )
  180. {
  181. $this->addData( $labels );
  182. }
  183. /**
  184. * Add data for this axis
  185. *
  186. * @param array $values Value which will be displayed on this axis
  187. * @return void
  188. */
  189. public function addData( array $values )
  190. {
  191. $position = 0;
  192. foreach ( $values as $label )
  193. {
  194. $label = (string) $label;
  195. if ( !in_array( $label, $this->labels, true ) )
  196. {
  197. if ( isset( $this->labels[$position] ) )
  198. {
  199. $this->labels = $this->increaseKeys( $this->labels, $position );
  200. $this->labels[$position++] = $label;
  201. }
  202. else
  203. {
  204. $this->labels[$position++] = $label;
  205. }
  206. }
  207. else
  208. {
  209. $position = array_search( $label, $this->labels, true ) + 1;
  210. }
  211. }
  212. ksort( $this->labels );
  213. $this->labelsIndexed = array_flip( $this->labels );
  214. $this->properties['initialized'] = true;
  215. }
  216. /**
  217. * Calculate axis bounding values on base of the assigned values
  218. *
  219. * @abstract
  220. * @access public
  221. * @return void
  222. */
  223. public function calculateAxisBoundings()
  224. {
  225. $this->steps = array();
  226. // Apply label format callback function
  227. if ( $this->properties['labelCallback'] !== null )
  228. {
  229. foreach ( $this->labels as $nr => $label )
  230. {
  231. $this->labels[$nr] = call_user_func_array(
  232. $this->properties['labelCallback'],
  233. array(
  234. $label,
  235. $nr
  236. )
  237. );
  238. }
  239. }
  240. $labelCount = count( $this->labels ) - 1;
  241. if ( $labelCount === 0 )
  242. {
  243. // Create single only step
  244. $this->steps = array(
  245. new ezcGraphAxisStep(
  246. 0,
  247. 1,
  248. reset( $this->labels ),
  249. array(),
  250. true,
  251. true
  252. ),
  253. );
  254. return true;
  255. }
  256. if ( $this->properties['labelCount'] === null )
  257. {
  258. if ( $labelCount <= self::MAX_LABEL_COUNT )
  259. {
  260. $stepSize = 1 / $labelCount;
  261. foreach ( $this->labels as $nr => $label )
  262. {
  263. $this->steps[] = new ezcGraphAxisStep(
  264. $stepSize * $nr,
  265. $stepSize,
  266. $label,
  267. array(),
  268. $nr === 0,
  269. $nr === $labelCount
  270. );
  271. }
  272. // @TODO: This line is deprecated and only build for
  273. // deprecated getLabel()
  274. $this->displayedLabels = $this->labels;
  275. return true;
  276. }
  277. for ( $div = self::MAX_LABEL_COUNT; $div > 1; --$div )
  278. {
  279. if ( ( $labelCount % $div ) === 0 )
  280. {
  281. // @TODO: This part is deprecated and only build for
  282. // deprecated getLabel()
  283. $step = $labelCount / $div;
  284. foreach ( $this->labels as $nr => $label )
  285. {
  286. if ( ( $nr % $step ) === 0 )
  287. {
  288. $this->displayedLabels[] = $label;
  289. }
  290. }
  291. // End of deprecated part
  292. break;
  293. }
  294. }
  295. }
  296. else
  297. {
  298. $div = false;
  299. }
  300. // Build up step array
  301. if ( $div > 2 )
  302. {
  303. $step = $labelCount / $div;
  304. $stepSize = 1 / $div;
  305. $minorStepSize = $stepSize / $step;
  306. foreach ( $this->labels as $nr => $label )
  307. {
  308. if ( ( $nr % $step ) === 0 )
  309. {
  310. $mainstep = new ezcGraphAxisStep(
  311. $stepSize * ( $nr / $step ),
  312. $stepSize,
  313. $label,
  314. array(),
  315. $nr === 0,
  316. $nr === $labelCount
  317. );
  318. $this->steps[] = $mainstep;
  319. }
  320. else
  321. {
  322. $mainstep->childs[] = new ezcGraphAxisStep(
  323. $mainstep->position + $minorStepSize * ( $nr % $step ),
  324. $minorStepSize
  325. );
  326. }
  327. }
  328. }
  329. else
  330. {
  331. if ( $this->properties['labelCount'] === null )
  332. {
  333. $floatStep = $labelCount / ( self::MAX_LABEL_COUNT - 1 );
  334. }
  335. else
  336. {
  337. $floatStep = $labelCount / min( $labelCount, $this->properties['labelCount'] - 1 );
  338. }
  339. $position = 0;
  340. $minorStepSize = 1 / $labelCount;
  341. foreach ( $this->labels as $nr => $label )
  342. {
  343. if ( $nr >= $position )
  344. {
  345. $position += $floatStep;
  346. // Add as major step
  347. $mainstep = new ezcGraphAxisStep(
  348. $minorStepSize * $nr,
  349. ceil( $position - $nr ) * $minorStepSize,
  350. $label,
  351. array(),
  352. $nr === 0,
  353. $nr === $labelCount
  354. );
  355. // @TODO: This line is deprecated and only build for
  356. // deprecated getLabel()
  357. $this->displayedLabels[] = $label;
  358. $this->steps[] = $mainstep;
  359. }
  360. else
  361. {
  362. $mainstep->childs[] = new ezcGraphAxisStep(
  363. $minorStepSize * $nr,
  364. $minorStepSize
  365. );
  366. }
  367. }
  368. }
  369. }
  370. /**
  371. * Return array of steps on this axis
  372. *
  373. * @return array( ezcGraphAxisStep )
  374. */
  375. public function getSteps()
  376. {
  377. return $this->steps;
  378. }
  379. /**
  380. * Get coordinate for a dedicated value on the chart
  381. *
  382. * @param string $value Value to determine position for
  383. * @return float Position on chart
  384. */
  385. public function getCoordinate( $value )
  386. {
  387. if ( ( $value === false ) ||
  388. ( $value === null ) ||
  389. ( !isset( $this->labelsIndexed[$value] ) ) )
  390. {
  391. switch ( $this->position )
  392. {
  393. case ezcGraph::LEFT:
  394. case ezcGraph::TOP:
  395. return 0.;
  396. case ezcGraph::RIGHT:
  397. case ezcGraph::BOTTOM:
  398. return 1.;
  399. }
  400. }
  401. else
  402. {
  403. $key = $this->labelsIndexed[$value];
  404. switch ( $this->position )
  405. {
  406. case ezcGraph::LEFT:
  407. case ezcGraph::TOP:
  408. if ( count( $this->labels ) > 1 )
  409. {
  410. return (float) $key / ( count ( $this->labels ) - 1 );
  411. }
  412. else
  413. {
  414. return 0;
  415. }
  416. case ezcGraph::BOTTOM:
  417. case ezcGraph::RIGHT:
  418. if ( count( $this->labels ) > 1 )
  419. {
  420. return (float) 1 - $key / ( count ( $this->labels ) - 1 );
  421. }
  422. else
  423. {
  424. return 1;
  425. }
  426. }
  427. }
  428. }
  429. /**
  430. * Return count of minor steps
  431. *
  432. * @return integer Count of minor steps
  433. */
  434. public function getMinorStepCount()
  435. {
  436. return 0;
  437. }
  438. /**
  439. * Return count of major steps
  440. *
  441. * @return integer Count of major steps
  442. */
  443. public function getMajorStepCount()
  444. {
  445. return max( count( $this->displayedLabels ) - 1, 1 );
  446. }
  447. /**
  448. * Get label for a dedicated step on the axis
  449. *
  450. * @param integer $step Number of step
  451. * @return string label
  452. */
  453. public function getLabel( $step )
  454. {
  455. if ( isset( $this->displayedLabels[$step] ) )
  456. {
  457. return $this->displayedLabels[$step];
  458. }
  459. else
  460. {
  461. return false;
  462. }
  463. }
  464. /**
  465. * Is zero step
  466. *
  467. * Returns true if the given step is the one on the initial axis position
  468. *
  469. * @param int $step Number of step
  470. * @return bool Status If given step is initial axis position
  471. */
  472. public function isZeroStep( $step )
  473. {
  474. return !$step;
  475. }
  476. }
  477. ?>