/apps/principal/lib/Graph/src/renderer/axis_label_rotated.php

https://github.com/proyectoalba/alba · PHP · 429 lines · 300 code · 30 blank · 99 comment · 20 complexity · 9f479947556548b8207b218f047a1fa0 MD5 · raw file

  1. <?php
  2. /**
  3. * File containing the ezcGraphAxisRotatedLabelRenderer class
  4. *
  5. * @package Graph
  6. * @version 1.2
  7. * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved.
  8. 2006 eZ systems as. All rights reserved.
  9. * @license http://ez.no/licenses/new_bsd New BSD License
  10. */
  11. /**
  12. * Can render axis labels rotated, so that more axis labels fir on one axis.
  13. * Produces best results if the axis space was increased, so that more spcae is
  14. * available below the axis.
  15. *
  16. * <code>
  17. * $chart->xAxis->axisLabelRenderer = new ezcGraphAxisRotatedLabelRenderer();
  18. *
  19. * // Define angle manually in degree
  20. * $chart->xAxis->axisLabelRenderer->angle = 45;
  21. *
  22. * // Increase axis space
  23. * $chart->xAxis->axisSpace = .2;
  24. * </code>
  25. *
  26. * @property float $angle
  27. * Angle of labels on axis in degrees.
  28. *
  29. * @version 1.2
  30. * @package Graph
  31. * @mainclass
  32. */
  33. class ezcGraphAxisRotatedLabelRenderer extends ezcGraphAxisLabelRenderer
  34. {
  35. /**
  36. * Store step array for later coordinate modifications
  37. *
  38. * @var array(ezcGraphStep)
  39. */
  40. protected $steps;
  41. /**
  42. * Store direction for later coordinate modifications
  43. *
  44. * @var ezcGraphVector
  45. */
  46. protected $direction;
  47. /**
  48. * Store coordinate width modifier for later coordinate modifications
  49. *
  50. * @var float
  51. */
  52. protected $widthModifier;
  53. /**
  54. * Store coordinate offset for later coordinate modifications
  55. *
  56. * @var float
  57. */
  58. protected $offset;
  59. /**
  60. * Constructor
  61. *
  62. * @param array $options Default option array
  63. * @return void
  64. * @ignore
  65. */
  66. public function __construct( array $options = array() )
  67. {
  68. parent::__construct( $options );
  69. $this->properties['angle'] = null;
  70. }
  71. /**
  72. * __set
  73. *
  74. * @param mixed $propertyName
  75. * @param mixed $propertyValue
  76. * @throws ezcBaseValueException
  77. * If a submitted parameter was out of range or type.
  78. * @throws ezcBasePropertyNotFoundException
  79. * If a the value for the property options is not an instance of
  80. * @return void
  81. * @ignore
  82. */
  83. public function __set( $propertyName, $propertyValue )
  84. {
  85. switch ( $propertyName )
  86. {
  87. case 'angle':
  88. if ( !is_numeric( $propertyValue ) )
  89. {
  90. throw new ezcBaseValueException( $propertyName, $propertyValue, '0 <= float < 360' );
  91. }
  92. $reducement = (int) ( $propertyValue - $propertyValue % 360 );
  93. $this->properties['angle'] = (float) $propertyValue - $reducement;
  94. break;
  95. default:
  96. return parent::__set( $propertyName, $propertyValue );
  97. }
  98. }
  99. /**
  100. * Render Axis labels
  101. *
  102. * Render labels for an axis.
  103. *
  104. * @param ezcGraphRenderer $renderer Renderer used to draw the chart
  105. * @param ezcGraphBoundings $boundings Boundings of the axis
  106. * @param ezcGraphCoordinate $start Axis starting point
  107. * @param ezcGraphCoordinate $end Axis ending point
  108. * @param ezcGraphChartElementAxis $axis Axis instance
  109. * @return void
  110. */
  111. public function renderLabels(
  112. ezcGraphRenderer $renderer,
  113. ezcGraphBoundings $boundings,
  114. ezcGraphCoordinate $start,
  115. ezcGraphCoordinate $end,
  116. ezcGraphChartElementAxis $axis )
  117. {
  118. // receive rendering parameters from axis
  119. $steps = $axis->getSteps();
  120. $this->steps = $steps;
  121. $axisBoundings = new ezcGraphBoundings(
  122. $start->x, $start->y,
  123. $end->x, $end->y
  124. );
  125. // Determine normalized axis direction
  126. $this->direction = new ezcGraphVector(
  127. $end->x - $start->x,
  128. $end->y - $start->y
  129. );
  130. $this->direction->unify();
  131. $axisAngle = -$this->direction->angle( new ezcGraphVector( 1, 0 ) );
  132. if ( $this->outerGrid )
  133. {
  134. $gridBoundings = $boundings;
  135. }
  136. else
  137. {
  138. $gridBoundings = new ezcGraphBoundings(
  139. $boundings->x0 + $renderer->xAxisSpace,
  140. $boundings->y0 + $renderer->yAxisSpace,
  141. $boundings->x1 - $renderer->xAxisSpace,
  142. $boundings->y1 - $renderer->yAxisSpace
  143. );
  144. }
  145. // Determine optimal angle if none specified
  146. if ( $this->angle === null )
  147. {
  148. $minimumStepWidth = null;
  149. foreach ( $steps as $nr => $step )
  150. {
  151. if ( ( $minimumStepWidth === null ) ||
  152. ( $step->width < $minimumStepWidth ) )
  153. {
  154. $minimumStepWidth = $step->width;
  155. }
  156. }
  157. $width = abs(
  158. $axisBoundings->width * $minimumStepWidth * $this->direction->x +
  159. $axisBoundings->height * $minimumStepWidth * $this->direction->y
  160. );
  161. $height = abs(
  162. $renderer->yAxisSpace * $this->direction->x +
  163. $renderer->xAxisSpace * $this->direction->y
  164. );
  165. $length = sqrt( pow( $width, 2 ) + pow( $height, 2 ) );
  166. $this->angle = rad2deg( acos( $height / $length ) );
  167. }
  168. // Determine additional required axis space by boxes
  169. $firstStep = reset( $steps );
  170. $lastStep = end( $steps );
  171. $textAngle = $axisAngle +
  172. deg2rad( $this->angle ) +
  173. ( $axis->position & ( ezcGraph::TOP | ezcGraph::BOTTOM ) ? deg2rad( 270 ) : deg2rad( 90 ) );
  174. // Ensure angle between 0 and 360 degrees
  175. $degTextAngle = rad2deg( $textAngle );
  176. while ( $degTextAngle < 0 )
  177. {
  178. $degTextAngle += 360.;
  179. }
  180. $this->offset =
  181. ( $this->angle < 0 ? -1 : 1 ) *
  182. ( $axis->position & ( ezcGraph::TOP | ezcGraph::LEFT ) ? 1 : -1 ) *
  183. ( 1 - cos( deg2rad( $this->angle * 2 ) ) );
  184. $axisSpaceFactor = abs(
  185. ( $this->direction->x == 0 ? 0 :
  186. $this->direction->x * $renderer->yAxisSpace / $axisBoundings->width ) +
  187. ( $this->direction->y == 0 ? 0 :
  188. $this->direction->y * $renderer->xAxisSpace / $axisBoundings->height )
  189. );
  190. $start = new ezcGraphCoordinate(
  191. $start->x + max( 0., $axisSpaceFactor * $this->offset ) * ( $end->x - $start->x ),
  192. $start->y + max( 0., $axisSpaceFactor * $this->offset ) * ( $end->y - $start->y )
  193. );
  194. $end = new ezcGraphCoordinate(
  195. $end->x + min( 0., $axisSpaceFactor * $this->offset ) * ( $end->x - $start->x ),
  196. $end->y + min( 0., $axisSpaceFactor * $this->offset ) * ( $end->y - $start->y )
  197. );
  198. $labelLength = sqrt(
  199. pow(
  200. $renderer->xAxisSpace * $this->direction->y +
  201. $axisSpaceFactor * $this->offset * ( $end->x - $start->x ),
  202. 2 ) +
  203. pow(
  204. $renderer->yAxisSpace * $this->direction->x +
  205. $axisSpaceFactor * $this->offset * ( $end->y - $start->y ),
  206. 2 )
  207. );
  208. $this->offset *= $axisSpaceFactor;
  209. // Draw steps and grid
  210. foreach ( $steps as $nr => $step )
  211. {
  212. $position = new ezcGraphCoordinate(
  213. $start->x + ( $end->x - $start->x ) * $step->position * abs( $this->direction->x ),
  214. $start->y + ( $end->y - $start->y ) * $step->position * abs( $this->direction->y )
  215. );
  216. $stepSize = new ezcGraphCoordinate(
  217. ( $end->x - $start->x ) * $step->width,
  218. ( $end->y - $start->y ) * $step->width
  219. );
  220. // Calculate label boundings
  221. switch ( true )
  222. {
  223. case ( $nr === 0 ):
  224. $labelSize = min(
  225. abs(
  226. $renderer->xAxisSpace * 2 * $this->direction->x +
  227. $renderer->yAxisSpace * 2 * $this->direction->y ),
  228. abs(
  229. $step->width * $axisBoundings->width * $this->direction->x +
  230. $step->width * $axisBoundings->height * $this->direction->y )
  231. );
  232. break;
  233. case ( $step->isLast ):
  234. $labelSize = min(
  235. abs(
  236. $renderer->xAxisSpace * 2 * $this->direction->x +
  237. $renderer->yAxisSpace * 2 * $this->direction->y ),
  238. abs(
  239. $steps[$nr - 1]->width * $axisBoundings->width * $this->direction->x +
  240. $steps[$nr - 1]->width * $axisBoundings->height * $this->direction->y )
  241. );
  242. break;
  243. default:
  244. $labelSize = min(
  245. abs(
  246. $step->width * $axisBoundings->width * $this->direction->x +
  247. $step->width * $axisBoundings->height * $this->direction->y ),
  248. abs(
  249. $steps[$nr - 1]->width * $axisBoundings->width * $this->direction->x +
  250. $steps[$nr - 1]->width * $axisBoundings->height * $this->direction->y )
  251. );
  252. break;
  253. }
  254. $labelSize = $labelSize * cos( deg2rad( $this->angle ) );
  255. $lengthReducement = min(
  256. abs( tan( deg2rad( $this->angle ) ) * ( $labelSize / 2 ) ),
  257. abs( $labelLength / 2 )
  258. );
  259. switch ( true )
  260. {
  261. case ( ( ( $degTextAngle >= 0 ) &&
  262. ( $degTextAngle < 90 ) &&
  263. ( ( $axis->position === ezcGraph::LEFT ) ||
  264. ( $axis->position === ezcGraph::RIGHT )
  265. )
  266. ) ||
  267. ( ( $degTextAngle >= 270 ) &&
  268. ( $degTextAngle < 360 ) &&
  269. ( ( $axis->position === ezcGraph::TOP ) ||
  270. ( $axis->position === ezcGraph::BOTTOM )
  271. )
  272. )
  273. ):
  274. $labelBoundings = new ezcGraphBoundings(
  275. $position->x,
  276. $position->y,
  277. $position->x + abs( $labelLength ) - $lengthReducement,
  278. $position->y + $labelSize
  279. );
  280. $labelAlignement = ezcGraph::LEFT | ezcGraph::TOP;
  281. $labelRotation = $degTextAngle;
  282. break;
  283. case ( ( ( $degTextAngle >= 90 ) &&
  284. ( $degTextAngle < 180 ) &&
  285. ( ( $axis->position === ezcGraph::LEFT ) ||
  286. ( $axis->position === ezcGraph::RIGHT )
  287. )
  288. ) ||
  289. ( ( $degTextAngle >= 180 ) &&
  290. ( $degTextAngle < 270 ) &&
  291. ( ( $axis->position === ezcGraph::TOP ) ||
  292. ( $axis->position === ezcGraph::BOTTOM )
  293. )
  294. )
  295. ):
  296. $labelBoundings = new ezcGraphBoundings(
  297. $position->x - abs( $labelLength ) + $lengthReducement,
  298. $position->y,
  299. $position->x,
  300. $position->y + $labelSize
  301. );
  302. $labelAlignement = ezcGraph::RIGHT | ezcGraph::TOP;
  303. $labelRotation = $degTextAngle - 180;
  304. break;
  305. case ( ( ( $degTextAngle >= 180 ) &&
  306. ( $degTextAngle < 270 ) &&
  307. ( ( $axis->position === ezcGraph::LEFT ) ||
  308. ( $axis->position === ezcGraph::RIGHT )
  309. )
  310. ) ||
  311. ( ( $degTextAngle >= 90 ) &&
  312. ( $degTextAngle < 180 ) &&
  313. ( ( $axis->position === ezcGraph::TOP ) ||
  314. ( $axis->position === ezcGraph::BOTTOM )
  315. )
  316. )
  317. ):
  318. $labelBoundings = new ezcGraphBoundings(
  319. $position->x - abs( $labelLength ) + $lengthReducement,
  320. $position->y - $labelSize,
  321. $position->x,
  322. $position->y
  323. );
  324. $labelAlignement = ezcGraph::RIGHT | ezcGraph::BOTTOM;
  325. $labelRotation = $degTextAngle - 180;
  326. break;
  327. case ( ( ( $degTextAngle >= 270 ) &&
  328. ( $degTextAngle < 360 ) &&
  329. ( ( $axis->position === ezcGraph::LEFT ) ||
  330. ( $axis->position === ezcGraph::RIGHT )
  331. )
  332. ) ||
  333. ( ( $degTextAngle >= 0 ) &&
  334. ( $degTextAngle < 90 ) &&
  335. ( ( $axis->position === ezcGraph::TOP ) ||
  336. ( $axis->position === ezcGraph::BOTTOM )
  337. )
  338. )
  339. ):
  340. $labelBoundings = new ezcGraphBoundings(
  341. $position->x,
  342. $position->y + $labelSize,
  343. $position->x + abs( $labelLength ) - $lengthReducement,
  344. $position->y
  345. );
  346. $labelAlignement = ezcGraph::LEFT | ezcGraph::BOTTOM;
  347. $labelRotation = $degTextAngle;
  348. break;
  349. }
  350. $renderer->drawText(
  351. $labelBoundings,
  352. $step->label,
  353. $labelAlignement,
  354. new ezcGraphRotation(
  355. $labelRotation,
  356. $position
  357. )
  358. );
  359. // major grid
  360. if ( $axis->majorGrid )
  361. {
  362. $this->drawGrid(
  363. $renderer,
  364. $gridBoundings,
  365. $position,
  366. $stepSize,
  367. $axis->majorGrid
  368. );
  369. }
  370. // major step
  371. $this->drawStep(
  372. $renderer,
  373. $position,
  374. $this->direction,
  375. $axis->position,
  376. $this->majorStepSize,
  377. $axis->border
  378. );
  379. }
  380. }
  381. /**
  382. * Modify chart data position
  383. *
  384. * Optionally additionally modify the coodinate of a data point
  385. *
  386. * @param ezcGraphCoordinate $coordinate Data point coordinate
  387. * @return ezcGraphCoordinate Modified coordinate
  388. */
  389. public function modifyChartDataPosition( ezcGraphCoordinate $coordinate )
  390. {
  391. return new ezcGraphCoordinate(
  392. $coordinate->x * abs( $this->direction->y ) +
  393. ( $coordinate->x * ( 1 - abs( $this->offset ) ) + max( 0, $this->offset ) ) * abs( $this->direction->x ),
  394. $coordinate->y * abs( $this->direction->x ) +
  395. ( $coordinate->y * ( 1 - abs( $this->offset ) ) + max( 0, $this->offset ) ) * abs( $this->direction->y )
  396. );
  397. }
  398. }
  399. ?>