PageRenderTime 67ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/phpmyvisites_1_9/libs/artichow/php4/Pie.class.php

https://bitbucket.org/pombredanne/spip-zone-treemap
PHP | 680 lines | 325 code | 148 blank | 207 comment | 29 complexity | abe1635b27bd654a1d5222945f479801 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. require_once dirname(__FILE__)."/Component.class.php";
  10. /* <php4> */
  11. define("PIE_DARK", 1);
  12. define("PIE_COLORED", 2);
  13. define("PIE_AQUA", 3);
  14. define("PIE_EARTH", 4);
  15. /* </php4> */
  16. /**
  17. * Pie
  18. *
  19. * @package Artichow
  20. */
  21. class awPie extends awComponent {
  22. /**
  23. * A dark theme for pies
  24. *
  25. *
  26. * @var int
  27. */
  28. /**
  29. * A colored theme for pies
  30. *
  31. * @var int
  32. */
  33. /**
  34. * A water theme for pies
  35. *
  36. * @var int
  37. */
  38. /**
  39. * A earth theme for pies
  40. *
  41. * @var int
  42. */
  43. /**
  44. * Pie values
  45. *
  46. * @var array
  47. */
  48. var $values;
  49. /**
  50. * Pie colors
  51. *
  52. * @var array
  53. */
  54. var $colors;
  55. /**
  56. * Pie legend
  57. *
  58. * @var array
  59. */
  60. var $legendValues = array();
  61. /**
  62. * Intensity of the 3D effect
  63. *
  64. * @var int
  65. */
  66. var $size;
  67. /**
  68. * Border color
  69. *
  70. * @var Color
  71. */
  72. var $border;
  73. /**
  74. * Pie explode
  75. *
  76. * @var array
  77. */
  78. var $explode = array();
  79. /**
  80. * Initial angle
  81. *
  82. * @var int
  83. */
  84. var $angle = 0;
  85. /**
  86. * Labels precision
  87. *
  88. * @var int
  89. */
  90. var $precision;
  91. /**
  92. * Labels number
  93. *
  94. * @var int
  95. */
  96. var $number;
  97. /**
  98. * Labels minimum
  99. *
  100. * @var int
  101. */
  102. var $minimum;
  103. /**
  104. * Labels position
  105. *
  106. * @var int
  107. */
  108. var $position = 15;
  109. /**
  110. * Labels of your pie
  111. *
  112. * @var Label
  113. */
  114. var $label;
  115. /**
  116. * Build the plot
  117. *
  118. * @param array $values Pie values
  119. */
  120. function awPie($values, $colors = PIE_COLORED) {
  121. $this->setValues($values);
  122. if(is_array($colors)) {
  123. $this->colors = $colors;
  124. } else {
  125. switch($colors) {
  126. case PIE_AQUA :
  127. $this->colors = array(
  128. new awColor(131, 220, 215),
  129. new awColor(131, 190, 215),
  130. new awColor(131, 160, 215),
  131. new awColor(160, 140, 215),
  132. new awColor(190, 131, 215),
  133. new awColor(220, 131, 215)
  134. );
  135. break;
  136. case PIE_EARTH :
  137. $this->colors = array(
  138. new awColor(97, 179, 110),
  139. new awColor(130, 179, 97),
  140. new awColor(168, 179, 97),
  141. new awColor(179, 147, 97),
  142. new awColor(179, 108, 97),
  143. new awColor(99, 107, 189),
  144. new awColor(99, 165, 189)
  145. );
  146. break;
  147. case PIE_DARK :
  148. $this->colors = array(
  149. new awColor(140, 100, 170),
  150. new awColor(130, 170, 100),
  151. new awColor(160, 160, 120),
  152. new awColor(150, 110, 140),
  153. new awColor(130, 150, 160),
  154. new awColor(90, 170, 140)
  155. );
  156. break;
  157. default :
  158. $this->colors = array(
  159. new awColor(187, 213, 151),
  160. new awColor(223, 177, 151),
  161. new awColor(111, 186, 132),
  162. new awColor(197, 160, 230),
  163. new awColor(165, 169, 63),
  164. new awColor(218, 177, 89),
  165. new awColor(116, 205, 121),
  166. new awColor(200, 201, 78),
  167. new awColor(127, 205, 177),
  168. new awColor(205, 160, 160),
  169. new awColor(190, 190, 190)
  170. );
  171. break;
  172. }
  173. }
  174. parent::awComponent();
  175. $this->label = new awLabel;
  176. $this->label->setCallbackFunction('callbackPerCent');
  177. }
  178. /**
  179. * Change legend values
  180. *
  181. * @param array $legend An array of values for each part of the pie
  182. */
  183. function setLegend($legend) {
  184. $this->legendValues = (array)$legend;
  185. }
  186. /**
  187. * Set a border all around the pie
  188. *
  189. * @param $color A color for the border
  190. */
  191. function setBorder($color) {
  192. $this->border = $color;
  193. }
  194. /**
  195. * Change 3D effect intensity
  196. *
  197. * @param int $size Effect size
  198. */
  199. function set3D($size) {
  200. $this->size = (int)$size;
  201. }
  202. /**
  203. * Change initial angle
  204. *
  205. * @param int $angle New angle in degrees
  206. */
  207. function setStartAngle($angle) {
  208. $this->angle = (int)$angle;
  209. }
  210. /**
  211. * Change label precision
  212. *
  213. * @param int $precision New precision
  214. */
  215. function setLabelPrecision($precision) {
  216. $this->precision = (int)$precision;
  217. }
  218. /**
  219. * Change label position
  220. *
  221. * @param int $position New position in pixels
  222. */
  223. function setLabelPosition($position) {
  224. $this->position = (int)$position;
  225. }
  226. /**
  227. * Change label number
  228. *
  229. * @param int $number New number
  230. */
  231. function setLabelNumber($number) {
  232. $this->number = is_null($number) ? $number : (int)$number;
  233. }
  234. /**
  235. * Change label minimum
  236. *
  237. * @param int $minimum New minimum
  238. */
  239. function setLabelMinimum($minimum) {
  240. $this->minimum = is_null($minimum) ? $minimum : (int)$minimum;
  241. }
  242. /**
  243. * Change Pie explode
  244. *
  245. * @param array $explode
  246. */
  247. function explode($explode) {
  248. $this->explode = (array)$explode;
  249. }
  250. function drawEnvelope($drawer) {
  251. }
  252. function drawComponent($drawer, $x1, $y1, $x2, $y2, $aliasing) {
  253. $count = count($this->values);
  254. $sum = array_sum($this->values);
  255. $width = $x2 - $x1;
  256. $height = $y2 - $y1;
  257. if($aliasing) {
  258. $x = $width / 2;
  259. $y = $height / 2;
  260. } else {
  261. $x = $width / 2 + $x1;
  262. $y = $height / 2 + $y1;
  263. }
  264. $position = $this->angle;
  265. $values = array();
  266. $parts = array();
  267. $angles = 0;
  268. if($aliasing) {
  269. $side = new awSide(0, 0, 0, 0);
  270. }
  271. foreach($this->values as $key => $value) {
  272. $angle = ($value / $sum * 360);
  273. if($key === $count - 1) {
  274. $angle = 360 - $angles;
  275. }
  276. $angles += $angle;
  277. if(array_key_exists($key, $this->explode)) {
  278. $middle = 360 - ($position + $angle / 2);
  279. $posX = $this->explode[$key] * cos($middle * M_PI / 180);
  280. $posY = $this->explode[$key] * sin($middle * M_PI / 180) * -1;
  281. if($aliasing) {
  282. $explode = new awPoint(
  283. $posX * 2,
  284. $posY * 2
  285. );
  286. $side->set(
  287. max($side->left, $posX * -2),
  288. max($side->right, $posX * 2),
  289. max($side->top, $posY * -2),
  290. max($side->bottom, $posY * 2)
  291. );
  292. } else {
  293. $explode = new awPoint(
  294. $posX,
  295. $posY
  296. );
  297. }
  298. } else {
  299. $explode = new awPoint(0, 0);
  300. }
  301. $values[$key] = array(
  302. $position, ($position + $angle), $explode
  303. );
  304. $color = $this->colors[$key % count($this->colors)];
  305. $parts[$key] = new awPiePart($color);
  306. // Add part to the legend
  307. $legend = array_key_exists($key, $this->legendValues) ? $this->legendValues[$key] : $key;
  308. $this->legend->add($parts[$key], $legend, LEGEND_BACKGROUND);
  309. $position += $angle;
  310. }
  311. if($aliasing) {
  312. $mainDrawer = $drawer;
  313. $x *= 2;
  314. $y *= 2;
  315. $width *= 2;
  316. $height *= 2;
  317. $this->size *= 2;
  318. $image = new awImage;
  319. $image->border->hide();
  320. $image->setSize(
  321. $width + $side->left + $side->right,
  322. $height + $side->top + $side->bottom + $this->size + 1 /* bugs.php.net ! */
  323. );
  324. $drawer = $image->getDrawer(
  325. $width / $image->width,
  326. $height / $image->height,
  327. ($width / 2 + $side->left) / $image->width,
  328. ($height / 2 + $side->top) / $image->height
  329. );
  330. }
  331. // Draw 3D effect
  332. for($i = $this->size; $i > 0; $i--) {
  333. foreach($values as $key => $value) {
  334. $color = $this->colors[$key % count($this->colors)];
  335. $color->brightness(-50);
  336. list($from, $to, $explode) = $value;
  337. $drawer->filledArc($color, $explode->move($x, $y + $i), $width, $height, $from, $to);
  338. $color->free();
  339. unset($color);
  340. if(is_a($this->border, 'awColor')) {
  341. $point = $explode->move($x, $y);
  342. if($i === $this->size) {
  343. $drawer->arc($this->border, $point->move(0, $this->size), $width, $height, $from, $to);
  344. }
  345. }
  346. }
  347. }
  348. foreach($values as $key => $value) {
  349. $color = $this->colors[$key % count($this->colors)];
  350. list($from, $to, $explode) = $value;
  351. $drawer->filledArc($color, $explode->move($x, $y), $width, $height, $from, $to);
  352. if(is_a($this->border, 'awColor')) {
  353. $point = $explode->move($x, $y);
  354. $drawer->arc($this->border, $point, $width, $height, $from, $to);
  355. }
  356. }
  357. if($aliasing) {
  358. $x = $x / 2 + $x1;
  359. $y = $y / 2 + $y1;
  360. $width /= 2;
  361. $height /= 2;
  362. $this->size /= 2;
  363. foreach($values as $key => $value) {
  364. $old = $values[$key][2];
  365. $values[$key][2] = new awPoint(
  366. $old->x / 2, $old->y / 2
  367. );
  368. }
  369. $mainDrawer->copyResizeImage(
  370. $image,
  371. new awPoint($x1 - $side->left / 2, $y1 - $side->top / 2),
  372. new awPoint($x1 - $side->left / 2 + $image->width / 2, $y1 - $side->top / 2 + $image->height/ 2),
  373. new awPoint(0, 0),
  374. new awPoint($image->width, $image->height),
  375. TRUE
  376. );
  377. $drawer = $mainDrawer;
  378. }
  379. // Get labels values
  380. $pc = array();
  381. foreach($this->values as $key => $value) {
  382. $pc[$key] = round($value / $sum * 100, $this->precision);
  383. }
  384. if($this->label->count() === 0) { // Check that there is no user defined values
  385. $this->label->set($pc);
  386. }
  387. $position = 0;
  388. foreach($pc as $key => $value) {
  389. // Limit number of labels to display
  390. if($position === $this->number) {
  391. break;
  392. }
  393. if(is_null($this->minimum) === FALSE and $value < $this->minimum) {
  394. continue;
  395. }
  396. $position++;
  397. list($from, $to, $explode) = $values[$key];
  398. $angle = $from + ($to - $from) / 2;
  399. $angleRad = (360 - $angle) * M_PI / 180;
  400. $point = new awPoint(
  401. $x + $explode->x + cos($angleRad) * ($width / 2 + $this->position),
  402. $y + $explode->y - sin($angleRad) * ($height / 2 + $this->position)
  403. );
  404. $angle %= 360;
  405. // We don't display labels on the 3D effect
  406. if($angle > 0 and $angle < 180) {
  407. $point = $point->move(0, -1 * sin($angleRad) * $this->size);
  408. }
  409. if($angle >= 45 and $angle < 135) {
  410. $this->label->setAlign(LABEL_CENTER, LABEL_BOTTOM);
  411. } else if($angle >= 135 and $angle < 225) {
  412. $this->label->setAlign(LABEL_RIGHT, LABEL_MIDDLE);
  413. } else if($angle >= 225 and $angle < 315) {
  414. $this->label->setAlign(LABEL_CENTER, LABEL_TOP);
  415. } else {
  416. $this->label->setAlign(LABEL_LEFT, LABEL_MIDDLE);
  417. }
  418. $this->label->draw(
  419. $drawer,
  420. $point,
  421. $key
  422. );
  423. }
  424. }
  425. /**
  426. * Return margins around the component
  427. *
  428. * @return array Left, right, top and bottom margins
  429. */
  430. function getMargin() {
  431. // Get axis informations
  432. $leftAxis = $this->padding->left;
  433. $rightAxis = $this->padding->right;
  434. $topAxis = $this->padding->top;
  435. $bottomAxis = $this->padding->bottom;
  436. return array($leftAxis, $rightAxis, $topAxis, $bottomAxis);
  437. }
  438. /**
  439. * Change values of Y axis
  440. * This method ignores not numeric values
  441. *
  442. * @param array $values
  443. */
  444. function setValues($values) {
  445. $this->checkArray($values);
  446. $this->values = $values;
  447. }
  448. /**
  449. * Return values of Y axis
  450. *
  451. * @return array
  452. */
  453. function getValues() {
  454. return $this->values;
  455. }
  456. function checkArray(&$array) {
  457. if(is_array($array) === FALSE) {
  458. trigger_error("You tried to set values that are not an array");
  459. }
  460. foreach($array as $key => $value) {
  461. if(is_numeric($value) === FALSE) {
  462. unset($array[$key]);
  463. }
  464. }
  465. if(count($array) < 1) {
  466. trigger_error("Your graph must have at least 1 value");
  467. }
  468. }
  469. }
  470. registerClass('Pie');
  471. /**
  472. * Pie
  473. *
  474. * @package Artichow
  475. */
  476. class awPiePart {
  477. /**
  478. * Pie part color
  479. *
  480. * @var Color
  481. */
  482. var $color;
  483. /**
  484. * Build a new awPiePart
  485. *
  486. * @param $color Pie part color
  487. */
  488. function awPiePart($color) {
  489. $this->color = $color;
  490. }
  491. /**
  492. * Get the background color or gradient of an element of the component
  493. *
  494. * @return Color, Gradient
  495. */
  496. function getLegendBackground() {
  497. return $this->color;
  498. }
  499. /**
  500. * Get the line thickness
  501. *
  502. * @return NULL
  503. */
  504. function getLegendLineThickness() {
  505. }
  506. /**
  507. * Get the line type
  508. *
  509. * @return NULL
  510. */
  511. function getLegendLineStyle() {
  512. }
  513. /**
  514. * Get the color of line
  515. *
  516. * @return NULL
  517. */
  518. function getLegendLineColor() {
  519. }
  520. /**
  521. * Get a mark object
  522. *
  523. * @return NULL
  524. */
  525. function getLegendMark() {
  526. }
  527. }
  528. registerClass('PiePart');
  529. function callbackPerCent($value) {
  530. return $value.'%';
  531. }
  532. ?>