PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://github.com/fusenigk/mantisbt-1
PHP | 544 lines | 282 code | 35 blank | 227 comment | 19 complexity | de6800330199dd6d0bb9de0cfb603781 MD5 | raw file
  1. <?php
  2. /**
  3. * File containing the abstract ezcGraphChartElementAxis 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 an axis as a chart element
  12. *
  13. * Chart elements can be understood as widgets or layout container inside the
  14. * chart. The actual transformation to images happens inside the renderers.
  15. * They represent all elements inside the chart and contain mostly general
  16. * formatting options, while the renderer itself might define additional
  17. * formatting options for some chart elments. You can find more about the
  18. * general formatting options for chart elements in the base class
  19. * ezcGraphChartElement.
  20. *
  21. * The axis elements are special elements, as the border and background
  22. * settings do not apply directly as axis axis are not put inside any boxes.
  23. * The border value is reused for the color of the axis itself.
  24. *
  25. * Generally you should select the axis which matches your data best. By
  26. * default a labeled x axis and a numeric y axis are used. If you are using
  27. * date or time values on either axis, you should for example use a
  28. * ezcGraphChartElementDateAxis. The currently available axis types are:
  29. *
  30. * - ezcGraphChartElementDateAxis
  31. * - ezcGraphChartElementLabeledAxis
  32. * - ezcGraphChartElementLogarithmicalAxis
  33. * - ezcGraphChartElementNumericAxis
  34. *
  35. * Beside this there are several option to define the general layout of the
  36. * axis labels. The $formatString option may be used to add additional text to
  37. * each label on the axis, like a percent sign on the y axis:
  38. *
  39. * <code>
  40. * $chart->xAxis->formatString = '%s %%';
  41. * </code>
  42. *
  43. * For more complex formatting operations for the label you may assign a custom
  44. * formatter function to the property $labelCallback.
  45. *
  46. * The orientation of labels and their position relatively to the axis ticks is
  47. * calcualted and rendered by the ezcGraphAxisLabelRenderer classes. You can
  48. * choose between different axis label renderer, or create you own, and assign
  49. * an instance of one to the property $axisLabelRenderer. Currently the
  50. * available axis label renderers are:
  51. *
  52. * - ezcGraphAxisBoxedLabelRenderer
  53. *
  54. * Renders grid and labels like commonly used in bar charts, with the label
  55. * between two grid lines.
  56. *
  57. * - ezcGraphAxisCenteredLabelRenderer
  58. *
  59. * Centers the label right next to a tick. Commonly used for labeled axis.
  60. *
  61. * - ezcGraphAxisExactLabelRenderer
  62. *
  63. * Put the label next to each tick. Commonly used for numeric axis.
  64. *
  65. * - ezcGraphAxisNoLabelRenderer
  66. *
  67. * Renders no labels.
  68. *
  69. * - ezcGraphAxisRadarLabelRenderer
  70. *
  71. * Special label renderer for radar charts.
  72. *
  73. * - ezcGraphAxisRotatedLabelRenderer
  74. *
  75. * Accepts a rotation angle for the texts put at some axis, which might be
  76. * useful for longer textual labels on the axis.
  77. *
  78. * The label renderer used by default is different depending on the axis type.
  79. *
  80. * @property float $nullPosition
  81. * The position of the null value.
  82. * @property float $axisSpace
  83. * Percent of the chart space used to display axis labels and
  84. * arrowheads instead of data values.
  85. * @property float $outerAxisSpace
  86. * Percent of the chart space used to display axis arrow at the outer
  87. * side of the axis. If set to null, the axisSpace will be used here.
  88. * @property ezcGraphColor $majorGrid
  89. * Color of major majorGrid.
  90. * @property ezcGraphColor $minorGrid
  91. * Color of minor majorGrid.
  92. * @property mixed $majorStep
  93. * Labeled major steps displayed on the axis. @TODO: Should be moved
  94. * to numeric axis.
  95. * @property mixed $minorStep
  96. * Non labeled minor steps on the axis. @TODO: Should be moved to
  97. * numeric axis.
  98. * @property string $formatString
  99. * Formatstring to use for labeling of the axis.
  100. * @property string $label
  101. * Axis label
  102. * @property int $labelSize
  103. * Size of axis label
  104. * @property int $labelMargin
  105. * Distance between label an axis
  106. * @property int $minArrowHeadSize
  107. * Minimum Size used to draw arrow heads.
  108. * @property int $maxArrowHeadSize
  109. * Maximum Size used to draw arrow heads.
  110. * @property ezcGraphAxisLabelRenderer $axisLabelRenderer
  111. * AxisLabelRenderer used to render labels and grid on this axis.
  112. * @property callback $labelCallback
  113. * Callback function to format chart labels.
  114. * Function will receive two parameters and should return a
  115. * reformatted label.
  116. * string function( label, step )
  117. * @property float $chartPosition
  118. * Position of the axis in the chart. Only useful for additional
  119. * axis. The basic chart axis will be automatically positioned.
  120. * @property-read bool $initialized
  121. * Property indicating if some values were associated with axis, or a
  122. * scaling has been set manually.
  123. * @property float $labelRotation
  124. * Rotation of the axis label in degree
  125. *
  126. * @version 1.5
  127. * @package Graph
  128. */
  129. abstract class ezcGraphChartElementAxis extends ezcGraphChartElement
  130. {
  131. /**
  132. * Axis label renderer class
  133. *
  134. * @var ezcGraphAxisLabelRenderer
  135. */
  136. protected $axisLabelRenderer;
  137. /**
  138. * Optionally set inner boundings. May be null depending on the used chart
  139. * implementation.
  140. *
  141. * @var ezcGraphBoundings
  142. */
  143. protected $innerBoundings;
  144. /**
  145. * Constructor
  146. *
  147. * @param array $options Default option array
  148. * @return void
  149. * @ignore
  150. */
  151. public function __construct( array $options = array() )
  152. {
  153. $this->properties['nullPosition'] = false;
  154. $this->properties['axisSpace'] = .1;
  155. $this->properties['outerAxisSpace'] = null;
  156. $this->properties['majorGrid'] = false;
  157. $this->properties['minorGrid'] = false;
  158. $this->properties['majorStep'] = null;
  159. $this->properties['minorStep'] = null;
  160. $this->properties['formatString'] = '%s';
  161. $this->properties['label'] = false;
  162. $this->properties['labelSize'] = 14;
  163. $this->properties['labelMargin'] = 2;
  164. $this->properties['minArrowHeadSize'] = 4;
  165. $this->properties['maxArrowHeadSize'] = 8;
  166. $this->properties['labelCallback'] = null;
  167. $this->properties['chartPosition'] = null;
  168. $this->properties['initialized'] = false;
  169. $this->properties['labelRotation'] = 0.;
  170. parent::__construct( $options );
  171. if ( !isset( $this->axisLabelRenderer ) )
  172. {
  173. $this->axisLabelRenderer = new ezcGraphAxisExactLabelRenderer();
  174. }
  175. }
  176. /**
  177. * Set colors and border fro this element
  178. *
  179. * @param ezcGraphPalette $palette Palette
  180. * @return void
  181. */
  182. public function setFromPalette( ezcGraphPalette $palette )
  183. {
  184. $this->border = $palette->axisColor;
  185. $this->padding = $palette->padding;
  186. $this->margin = $palette->margin;
  187. $this->majorGrid = $palette->majorGridColor;
  188. $this->minorGrid = $palette->minorGridColor;
  189. }
  190. /**
  191. * __set
  192. *
  193. * @param mixed $propertyName
  194. * @param mixed $propertyValue
  195. * @throws ezcBaseValueException
  196. * If a submitted parameter was out of range or type.
  197. * @throws ezcBasePropertyNotFoundException
  198. * If a the value for the property options is not an instance of
  199. * @return void
  200. */
  201. public function __set( $propertyName, $propertyValue )
  202. {
  203. switch ( $propertyName )
  204. {
  205. case 'nullPosition':
  206. $this->properties['nullPosition'] = (float) $propertyValue;
  207. break;
  208. case 'axisSpace':
  209. if ( !is_numeric( $propertyValue ) ||
  210. ( $propertyValue < 0 ) ||
  211. ( $propertyValue >= 1 ) )
  212. {
  213. throw new ezcBaseValueException( $propertyName, $propertyValue, '0 <= float < 1' );
  214. }
  215. $this->properties['axisSpace'] = (float) $propertyValue;
  216. break;
  217. case 'outerAxisSpace':
  218. if ( !is_null( $propertyValue ) &&
  219. ( !is_numeric( $propertyValue ) ||
  220. ( $propertyValue < 0 ) ||
  221. ( $propertyValue >= 1 ) ) )
  222. {
  223. throw new ezcBaseValueException( $propertyName, $propertyValue, 'null, or 0 <= float < 1' );
  224. }
  225. $this->properties['outerAxisSpace'] = $propertyValue;
  226. break;
  227. case 'majorGrid':
  228. $this->properties['majorGrid'] = ezcGraphColor::create( $propertyValue );
  229. break;
  230. case 'minorGrid':
  231. $this->properties['minorGrid'] = ezcGraphColor::create( $propertyValue );
  232. break;
  233. case 'majorStep':
  234. if ( !is_numeric( $propertyValue ) ||
  235. ( $propertyValue <= 0 ) )
  236. {
  237. throw new ezcBaseValueException( $propertyName, $propertyValue, 'float > 0' );
  238. }
  239. $this->properties['majorStep'] = (float) $propertyValue;
  240. break;
  241. case 'minorStep':
  242. if ( !is_numeric( $propertyValue ) ||
  243. ( $propertyValue <= 0 ) )
  244. {
  245. throw new ezcBaseValueException( $propertyName, $propertyValue, 'float > 0' );
  246. }
  247. $this->properties['minorStep'] = (float) $propertyValue;
  248. break;
  249. case 'formatString':
  250. $this->properties['formatString'] = (string) $propertyValue;
  251. break;
  252. case 'label':
  253. $this->properties['label'] = (string) $propertyValue;
  254. break;
  255. case 'labelSize':
  256. if ( !is_numeric( $propertyValue ) ||
  257. ( $propertyValue <= 6 ) )
  258. {
  259. throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 6' );
  260. }
  261. $this->properties['labelSize'] = (int) $propertyValue;
  262. break;
  263. case 'labelMargin':
  264. if ( !is_numeric( $propertyValue ) ||
  265. ( $propertyValue <= 0 ) )
  266. {
  267. throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
  268. }
  269. $this->properties['labelMargin'] = (int) $propertyValue;
  270. break;
  271. case 'maxArrowHeadSize':
  272. if ( !is_numeric( $propertyValue ) ||
  273. ( $propertyValue <= 0 ) )
  274. {
  275. throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
  276. }
  277. $this->properties['maxArrowHeadSize'] = (int) $propertyValue;
  278. break;
  279. case 'minArrowHeadSize':
  280. if ( !is_numeric( $propertyValue ) ||
  281. ( $propertyValue <= 0 ) )
  282. {
  283. throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
  284. }
  285. $this->properties['minArrowHeadSize'] = (int) $propertyValue;
  286. break;
  287. case 'axisLabelRenderer':
  288. if ( $propertyValue instanceof ezcGraphAxisLabelRenderer )
  289. {
  290. $this->axisLabelRenderer = $propertyValue;
  291. }
  292. else
  293. {
  294. throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphAxisLabelRenderer' );
  295. }
  296. break;
  297. case 'labelCallback':
  298. if ( is_callable( $propertyValue ) )
  299. {
  300. $this->properties['labelCallback'] = $propertyValue;
  301. }
  302. else
  303. {
  304. throw new ezcBaseValueException( $propertyName, $propertyValue, 'callback function' );
  305. }
  306. break;
  307. case 'chartPosition':
  308. if ( !is_numeric( $propertyValue ) ||
  309. ( $propertyValue < 0 ) ||
  310. ( $propertyValue > 1 ) )
  311. {
  312. throw new ezcBaseValueException( $propertyName, $propertyValue, '0 <= float <= 1' );
  313. }
  314. $this->properties['chartPosition'] = (float) $propertyValue;
  315. break;
  316. case 'labelRotation':
  317. if ( !is_numeric( $propertyValue ) )
  318. {
  319. throw new ezcBaseValueException( $propertyName, $propertyValue, 'float' );
  320. }
  321. $this->properties['labelRotation'] = fmod( (float) $propertyValue, 360. );
  322. break;
  323. default:
  324. parent::__set( $propertyName, $propertyValue );
  325. break;
  326. }
  327. }
  328. /**
  329. * __get
  330. *
  331. * @param mixed $propertyName
  332. * @throws ezcBasePropertyNotFoundException
  333. * If a the value for the property options is not an instance of
  334. * @return mixed
  335. * @ignore
  336. */
  337. public function __get( $propertyName )
  338. {
  339. switch ( $propertyName )
  340. {
  341. case 'axisLabelRenderer':
  342. return $this->axisLabelRenderer;
  343. default:
  344. return parent::__get( $propertyName );
  345. }
  346. }
  347. /**
  348. * Get coordinate for a dedicated value on the chart
  349. *
  350. * @param float $value Value to determine position for
  351. * @return float Position on chart
  352. */
  353. abstract public function getCoordinate( $value );
  354. /**
  355. * Return count of minor steps
  356. *
  357. * @return integer Count of minor steps
  358. */
  359. abstract public function getMinorStepCount();
  360. /**
  361. * Return count of major steps
  362. *
  363. * @return integer Count of major steps
  364. */
  365. abstract public function getMajorStepCount();
  366. /**
  367. * Get label for a dedicated step on the axis
  368. *
  369. * @param integer $step Number of step
  370. * @return string label
  371. */
  372. abstract public function getLabel( $step );
  373. /**
  374. * Return array of steps on this axis
  375. *
  376. * @return array( ezcGraphAxisStep )
  377. */
  378. public function getSteps()
  379. {
  380. $majorSteps = $this->getMajorStepCount();
  381. $minorStepsPerMajorStepCount = ( $this->getMinorStepCount() / $majorSteps );
  382. $majorStepSize = 1 / $majorSteps;
  383. $minorStepSize = ( $minorStepsPerMajorStepCount > 0 ? $majorStepSize / $minorStepsPerMajorStepCount : 0 );
  384. $steps = array();
  385. for ( $major = 0; $major <= $majorSteps; ++$major )
  386. {
  387. $majorStep = new ezcGraphAxisStep(
  388. $majorStepSize * $major,
  389. $majorStepSize,
  390. $this->getLabel( $major ),
  391. array(),
  392. $this->isZeroStep( $major ),
  393. ( $major === $majorSteps )
  394. );
  395. if ( ( $minorStepsPerMajorStepCount > 0 ) &&
  396. ( $major < $majorSteps ) )
  397. {
  398. // Do not add minor steps at major steps positions
  399. for( $minor = 1; $minor < $minorStepsPerMajorStepCount; ++$minor )
  400. {
  401. $majorStep->childs[] = new ezcGraphAxisStep(
  402. ( $majorStepSize * $major ) + ( $minorStepSize * $minor ),
  403. $minorStepSize
  404. );
  405. }
  406. }
  407. $steps[] = $majorStep;
  408. }
  409. return $steps;
  410. }
  411. /**
  412. * Is zero step
  413. *
  414. * Returns true if the given step is the one on the initial axis position
  415. *
  416. * @param int $step Number of step
  417. * @return bool Status If given step is initial axis position
  418. */
  419. abstract public function isZeroStep( $step );
  420. /**
  421. * Add data for this axis
  422. *
  423. * @param array $values
  424. * @return void
  425. */
  426. abstract public function addData( array $values );
  427. /**
  428. * Calculate axis bounding values on base of the assigned values
  429. *
  430. * @abstract
  431. * @access public
  432. * @return void
  433. */
  434. abstract public function calculateAxisBoundings();
  435. /**
  436. * Render the axis
  437. *
  438. * @param ezcGraphRenderer $renderer Renderer
  439. * @param ezcGraphBoundings $boundings Boundings for the axis
  440. * @return ezcGraphBoundings Remaining boundings
  441. */
  442. public function render( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings, ezcGraphBoundings $innerBoundings = null )
  443. {
  444. $this->innerBoundings = $innerBoundings;
  445. $startSpace = $this->axisSpace;
  446. $endSpace = $this->outerAxisSpace === null ? $this->axisSpace : $this->outerAxisSpace;
  447. switch ( $this->position )
  448. {
  449. case ezcGraph::TOP:
  450. $start = new ezcGraphCoordinate(
  451. $boundings->width * $startSpace +
  452. $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
  453. 0
  454. );
  455. $end = new ezcGraphCoordinate(
  456. $boundings->width * $startSpace +
  457. $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
  458. $boundings->height
  459. );
  460. break;
  461. case ezcGraph::BOTTOM:
  462. $start = new ezcGraphCoordinate(
  463. $boundings->width * $startSpace +
  464. $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
  465. $boundings->height
  466. );
  467. $end = new ezcGraphCoordinate(
  468. $boundings->width * $startSpace +
  469. $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
  470. 0
  471. );
  472. break;
  473. case ezcGraph::LEFT:
  474. $start = new ezcGraphCoordinate(
  475. 0,
  476. $boundings->height * $endSpace +
  477. $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
  478. );
  479. $end = new ezcGraphCoordinate(
  480. $boundings->width,
  481. $boundings->height * $endSpace +
  482. $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
  483. );
  484. break;
  485. case ezcGraph::RIGHT:
  486. $start = new ezcGraphCoordinate(
  487. $boundings->width,
  488. $boundings->height * $endSpace +
  489. $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
  490. );
  491. $end = new ezcGraphCoordinate(
  492. 0,
  493. $boundings->height * $endSpace +
  494. $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
  495. );
  496. break;
  497. }
  498. $renderer->drawAxis(
  499. $boundings,
  500. $start,
  501. $end,
  502. $this,
  503. $this->axisLabelRenderer,
  504. $innerBoundings
  505. );
  506. return $boundings;
  507. }
  508. }
  509. ?>