PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/MantisBT/library/ezc/Graph/src/charts/radar.php

https://bitbucket.org/crypticrod/sr_wp_code
PHP | 457 lines | 228 code | 41 blank | 188 comment | 13 complexity | 98cc6a67510f13d28639872e52ee1f62 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.1, GPL-3.0, LGPL-2.0, AGPL-3.0
  1. <?php
  2. /**
  3. * File containing the ezcGraphRadarChart 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 for radar charts.
  12. * Can make use of an unlimited amount of datasets and will display them as
  13. * lines by default.
  14. * Rotation axis:
  15. * - Labeled axis
  16. * - Centered axis label renderer
  17. * Axis:
  18. * - Numeric axis
  19. * - radar axis label renderer
  20. *
  21. * <code>
  22. * // Create a new radar chart
  23. * $chart = new ezcGraphRadarChart();
  24. *
  25. * // Add data to line chart
  26. * $chart->data['sample dataset'] = new ezcGraphArrayDataSet(
  27. * array(
  28. * '100' => 1.2,
  29. * '200' => 43.2,
  30. * '300' => -34.14,
  31. * '350' => 65,
  32. * '400' => 123,
  33. * )
  34. * );
  35. *
  36. * // Render chart with default 2d renderer and default SVG driver
  37. * $chart->render( 500, 200, 'radar_chart.svg' );
  38. * </code>
  39. *
  40. * Each chart consists of several chart elements which represents logical
  41. * parts of the chart and can be formatted independently. The line chart
  42. * consists of:
  43. * - title ( {@link ezcGraphChartElementText} )
  44. * - legend ( {@link ezcGraphChartElementLegend} )
  45. * - background ( {@link ezcGraphChartElementBackground} )
  46. * - axis ( {@link ezcGraphChartElementNumericAxis} )
  47. * - ratation axis ( {@link ezcGraphChartElementLabeledAxis} )
  48. *
  49. * The type of the axis may be changed and all elements can be configured by
  50. * accessing them as properties of the chart:
  51. *
  52. * The chart itself also offers several options to configure the appearance.
  53. * The extended configure options are available in
  54. * {@link ezcGraphRadarChartOptions} extending the
  55. * {@link ezcGraphChartOptions}.
  56. *
  57. * <code>
  58. * $chart->legend->position = ezcGraph::RIGHT;
  59. * </code>
  60. *
  61. * @property ezcGraphRadarChartOptions $options
  62. * Chart options class
  63. *
  64. * @version 1.5
  65. * @package Graph
  66. * @mainclass
  67. */
  68. class ezcGraphRadarChart extends ezcGraphChart
  69. {
  70. /**
  71. * Store major grid color for child axis.
  72. *
  73. * @var ezcGraphColor
  74. */
  75. protected $childAxisColor;
  76. /**
  77. * Constructor
  78. *
  79. * @param array $options Default option array
  80. * @return void
  81. * @ignore
  82. */
  83. public function __construct( array $options = array() )
  84. {
  85. $this->options = new ezcGraphRadarChartOptions( $options );
  86. $this->options->highlightFont = $this->options->font;
  87. parent::__construct();
  88. $this->elements['rotationAxis'] = new ezcGraphChartElementLabeledAxis();
  89. $this->addElement( 'axis', new ezcGraphChartElementNumericAxis() );
  90. $this->elements['axis']->position = ezcGraph::BOTTOM;
  91. $this->elements['axis']->axisLabelRenderer = new ezcGraphAxisRadarLabelRenderer();
  92. $this->elements['axis']->axisLabelRenderer->outerStep = true;
  93. $this->addElement( 'rotationAxis', new ezcGraphChartElementLabeledAxis() );
  94. // Do not render axis with default method, because we need an axis for
  95. // each label in dataset
  96. $this->renderElement['axis'] = false;
  97. $this->renderElement['rotationAxis'] = false;
  98. }
  99. /**
  100. * Set colors and border fro this element
  101. *
  102. * @param ezcGraphPalette $palette Palette
  103. * @return void
  104. */
  105. public function setFromPalette( ezcGraphPalette $palette )
  106. {
  107. $this->childAxisColor = $palette->majorGridColor;
  108. parent::setFromPalette( $palette );
  109. }
  110. /**
  111. * Property write access
  112. *
  113. * @throws ezcBasePropertyNotFoundException
  114. * If Option could not be found
  115. * @throws ezcBaseValueException
  116. * If value is out of range
  117. * @param string $propertyName Option name
  118. * @param mixed $propertyValue Option value;
  119. * @return void
  120. * @ignore
  121. */
  122. public function __set( $propertyName, $propertyValue )
  123. {
  124. switch ( $propertyName ) {
  125. case 'axis':
  126. if ( $propertyValue instanceof ezcGraphChartElementAxis )
  127. {
  128. $this->addElement( 'axis', $propertyValue );
  129. $this->elements['axis']->position = ezcGraph::BOTTOM;
  130. $this->elements['axis']->axisLabelRenderer = new ezcGraphAxisRadarLabelRenderer();
  131. $this->renderElement['axis'] = false;
  132. }
  133. else
  134. {
  135. throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
  136. }
  137. break;
  138. case 'rotationAxis':
  139. if ( $propertyValue instanceof ezcGraphChartElementAxis )
  140. {
  141. $this->addElement( 'rotationAxis', $propertyValue );
  142. $this->renderElement['rotationAxis'] = false;
  143. }
  144. else
  145. {
  146. throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
  147. }
  148. break;
  149. case 'renderer':
  150. if ( $propertyValue instanceof ezcGraphRadarRenderer )
  151. {
  152. parent::__set( $propertyName, $propertyValue );
  153. }
  154. else
  155. {
  156. throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphRadarRenderer' );
  157. }
  158. break;
  159. default:
  160. parent::__set( $propertyName, $propertyValue );
  161. }
  162. }
  163. /**
  164. * Draws a single rotated axis
  165. *
  166. * Sets the axis label position depending on the axis rotation.
  167. *
  168. * @param ezcGraphChartElementAxis $axis
  169. * @param ezcGraphBoundings $boundings
  170. * @param ezcGraphCoordinate $center
  171. * @param float $position
  172. * @param float $lastPosition
  173. * @return void
  174. */
  175. protected function drawRotatedAxis( ezcGraphChartElementAxis $axis, ezcGraphBoundings $boundings, ezcGraphCoordinate $center, $position, $lastPosition = null )
  176. {
  177. // Set axis position depending on angle for better axis label
  178. // positioning
  179. $angle = $position * 2 * M_PI;
  180. switch ( (int) ( ( $position + .125 ) * 4 ) )
  181. {
  182. case 0:
  183. case 4:
  184. $axis->position = ezcGraph::BOTTOM;
  185. break;
  186. case 1:
  187. $axis->position = ezcGraph::LEFT;
  188. break;
  189. case 2:
  190. $axis->position = ezcGraph::TOP;
  191. break;
  192. case 3:
  193. $axis->position = ezcGraph::RIGHT;
  194. break;
  195. }
  196. // Set last step to correctly draw grid
  197. if ( $axis->axisLabelRenderer instanceof ezcGraphAxisRadarLabelRenderer )
  198. {
  199. $axis->axisLabelRenderer->lastStep = $lastPosition;
  200. }
  201. // Do not draw axis label for last step
  202. if ( abs( $position - 1 ) <= .001 )
  203. {
  204. $axis->label = null;
  205. }
  206. $this->renderer->drawAxis(
  207. $boundings,
  208. clone $center,
  209. $dest = new ezcGraphCoordinate(
  210. $center->x + sin( $angle ) * ( $boundings->width / 2 ),
  211. $center->y - cos( $angle ) * ( $boundings->height / 2 )
  212. ),
  213. clone $axis,
  214. clone $axis->axisLabelRenderer
  215. );
  216. }
  217. /**
  218. * Render the assigned data
  219. *
  220. * Will renderer all charts data in the remaining boundings after drawing
  221. * all other chart elements. The data will be rendered depending on the
  222. * settings in the dataset.
  223. *
  224. * @param ezcGraphRenderer $renderer Renderer
  225. * @param ezcGraphBoundings $boundings Remaining boundings
  226. * @return void
  227. */
  228. protected function renderData( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings )
  229. {
  230. // Apply axis space
  231. $xAxisSpace = ( $boundings->x1 - $boundings->x0 ) * $this->axis->axisSpace;
  232. $yAxisSpace = ( $boundings->y1 - $boundings->y0 ) * $this->axis->axisSpace;
  233. $center = new ezcGraphCoordinate(
  234. ( $boundings->width / 2 ),
  235. ( $boundings->height / 2 )
  236. );
  237. // We do not differentiate between display types in radar charts.
  238. $nr = $count = count( $this->data );
  239. // Draw axis at major steps of virtual axis
  240. $steps = $this->elements['rotationAxis']->getSteps();
  241. $lastStepPosition = null;
  242. $axisColor = $this->elements['axis']->border;
  243. foreach ( $steps as $step )
  244. {
  245. $this->elements['axis']->label = $step->label;
  246. $this->drawRotatedAxis( $this->elements['axis'], $boundings, $center, $step->position, $lastStepPosition );
  247. $lastStepPosition = $step->position;
  248. if ( count( $step->childs ) )
  249. {
  250. foreach ( $step->childs as $childStep )
  251. {
  252. $this->elements['axis']->label = null;
  253. $this->elements['axis']->border = $this->childAxisColor;
  254. $this->drawRotatedAxis( $this->elements['axis'], $boundings, $center, $childStep->position, $lastStepPosition );
  255. $lastStepPosition = $childStep->position;
  256. }
  257. }
  258. $this->elements['axis']->border = $axisColor;
  259. }
  260. // Display data
  261. $this->elements['axis']->position = ezcGraph::TOP;
  262. foreach ( $this->data as $datasetName => $data )
  263. {
  264. --$nr;
  265. // Determine fill color for dataset
  266. if ( $this->options->fillLines !== false )
  267. {
  268. $fillColor = clone $data->color->default;
  269. $fillColor->alpha = (int) round( ( 255 - $fillColor->alpha ) * ( $this->options->fillLines / 255 ) );
  270. }
  271. else
  272. {
  273. $fillColor = null;
  274. }
  275. // Draw lines for dataset
  276. $lastPoint = false;
  277. foreach ( $data as $key => $value )
  278. {
  279. $point = new ezcGraphCoordinate(
  280. $this->elements['rotationAxis']->getCoordinate( $key ),
  281. $this->elements['axis']->getCoordinate( $value )
  282. );
  283. /* Transformation required for 3d like renderers ...
  284. * which axis should transform here?
  285. $point = $this->elements['xAxis']->axisLabelRenderer->modifyChartDataPosition(
  286. $this->elements['yAxis']->axisLabelRenderer->modifyChartDataPosition(
  287. new ezcGraphCoordinate(
  288. $this->elements['xAxis']->getCoordinate( $key ),
  289. $this->elements['yAxis']->getCoordinate( $value )
  290. )
  291. )
  292. );
  293. // */
  294. $renderer->drawRadarDataLine(
  295. $boundings,
  296. new ezcGraphContext( $datasetName, $key, $data->url[$key] ),
  297. $data->color->default,
  298. clone $center,
  299. ( $lastPoint === false ? $point : $lastPoint ),
  300. $point,
  301. $nr,
  302. $count,
  303. $data->symbol[$key],
  304. $data->color[$key],
  305. $fillColor,
  306. $this->options->lineThickness
  307. );
  308. $lastPoint = $point;
  309. }
  310. }
  311. }
  312. /**
  313. * Returns the default display type of the current chart type.
  314. *
  315. * @return int Display type
  316. */
  317. public function getDefaultDisplayType()
  318. {
  319. return ezcGraph::LINE;
  320. }
  321. /**
  322. * Renders the basic elements of this chart type
  323. *
  324. * @param int $width
  325. * @param int $height
  326. * @return void
  327. */
  328. protected function renderElements( $width, $height )
  329. {
  330. if ( !count( $this->data ) )
  331. {
  332. throw new ezcGraphNoDataException();
  333. }
  334. // Set image properties in driver
  335. $this->driver->options->width = $width;
  336. $this->driver->options->height = $height;
  337. // Calculate axis scaling and labeling
  338. foreach ( $this->data as $dataset )
  339. {
  340. $labels = array();
  341. $values = array();
  342. foreach ( $dataset as $label => $value )
  343. {
  344. $labels[] = $label;
  345. $values[] = $value;
  346. }
  347. $this->elements['axis']->addData( $values );
  348. $this->elements['rotationAxis']->addData( $labels );
  349. }
  350. $this->elements['axis']->calculateAxisBoundings();
  351. $this->elements['rotationAxis']->calculateAxisBoundings();
  352. // Generate legend
  353. $this->elements['legend']->generateFromDataSets( $this->data );
  354. // Get boundings from parameters
  355. $this->options->width = $width;
  356. $this->options->height = $height;
  357. // Render subelements
  358. $boundings = new ezcGraphBoundings();
  359. $boundings->x1 = $this->options->width;
  360. $boundings->y1 = $this->options->height;
  361. // Render subelements
  362. foreach ( $this->elements as $name => $element )
  363. {
  364. // Skip element, if it should not get rendered
  365. if ( $this->renderElement[$name] === false )
  366. {
  367. continue;
  368. }
  369. $this->driver->options->font = $element->font;
  370. $boundings = $element->render( $this->renderer, $boundings );
  371. }
  372. // Render graph
  373. $this->renderData( $this->renderer, $boundings );
  374. }
  375. /**
  376. * Render the line chart
  377. *
  378. * Renders the chart into a file or stream. The width and height are
  379. * needed to specify the dimensions of the resulting image. For direct
  380. * output use 'php://stdout' as output file.
  381. *
  382. * @param int $width Image width
  383. * @param int $height Image height
  384. * @param string $file Output file
  385. * @apichange
  386. * @return void
  387. */
  388. public function render( $width, $height, $file = null )
  389. {
  390. $this->renderElements( $width, $height );
  391. if ( !empty( $file ) )
  392. {
  393. $this->renderer->render( $file );
  394. }
  395. $this->renderedFile = $file;
  396. }
  397. /**
  398. * Renders this chart to direct output
  399. *
  400. * Does the same as ezcGraphChart::render(), but renders directly to
  401. * output and not into a file.
  402. *
  403. * @param int $width
  404. * @param int $height
  405. * @apichange
  406. * @return void
  407. */
  408. public function renderToOutput( $width, $height )
  409. {
  410. // @TODO: merge this function with render an deprecate ommit of third
  411. // argument in render() when API break is possible
  412. $this->renderElements( $width, $height );
  413. $this->renderer->render( null );
  414. }
  415. }
  416. ?>