For God so loved the world, that He gave His only begotten Son, that all who believe in Him should not perish but have everlasting life
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

883 lines
33 KiB

  1. <?php
  2. require_once(PHPExcel_Settings::getChartRendererPath().'/jpgraph.php');
  3. /**
  4. * PHPExcel_Chart_Renderer_jpgraph
  5. *
  6. * Copyright (c) 2006 - 2015 PHPExcel
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * @category PHPExcel
  23. * @package PHPExcel_Chart_Renderer
  24. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  25. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  26. * @version ##VERSION##, ##DATE##
  27. */
  28. class PHPExcel_Chart_Renderer_jpgraph
  29. {
  30. private static $width = 640;
  31. private static $height = 480;
  32. private static $colourSet = array(
  33. 'mediumpurple1', 'palegreen3', 'gold1', 'cadetblue1',
  34. 'darkmagenta', 'coral', 'dodgerblue3', 'eggplant',
  35. 'mediumblue', 'magenta', 'sandybrown', 'cyan',
  36. 'firebrick1', 'forestgreen', 'deeppink4', 'darkolivegreen',
  37. 'goldenrod2'
  38. );
  39. private static $markSet = array(
  40. 'diamond' => MARK_DIAMOND,
  41. 'square' => MARK_SQUARE,
  42. 'triangle' => MARK_UTRIANGLE,
  43. 'x' => MARK_X,
  44. 'star' => MARK_STAR,
  45. 'dot' => MARK_FILLEDCIRCLE,
  46. 'dash' => MARK_DTRIANGLE,
  47. 'circle' => MARK_CIRCLE,
  48. 'plus' => MARK_CROSS
  49. );
  50. private $chart;
  51. private $graph;
  52. private static $plotColour = 0;
  53. private static $plotMark = 0;
  54. private function formatPointMarker($seriesPlot, $markerID)
  55. {
  56. $plotMarkKeys = array_keys(self::$markSet);
  57. if (is_null($markerID)) {
  58. // Use default plot marker (next marker in the series)
  59. self::$plotMark %= count(self::$markSet);
  60. $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
  61. } elseif ($markerID !== 'none') {
  62. // Use specified plot marker (if it exists)
  63. if (isset(self::$markSet[$markerID])) {
  64. $seriesPlot->mark->SetType(self::$markSet[$markerID]);
  65. } else {
  66. // If the specified plot marker doesn't exist, use default plot marker (next marker in the series)
  67. self::$plotMark %= count(self::$markSet);
  68. $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
  69. }
  70. } else {
  71. // Hide plot marker
  72. $seriesPlot->mark->Hide();
  73. }
  74. $seriesPlot->mark->SetColor(self::$colourSet[self::$plotColour]);
  75. $seriesPlot->mark->SetFillColor(self::$colourSet[self::$plotColour]);
  76. $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
  77. return $seriesPlot;
  78. }
  79. private function formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation = '')
  80. {
  81. $datasetLabelFormatCode = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getFormatCode();
  82. if (!is_null($datasetLabelFormatCode)) {
  83. // Retrieve any label formatting code
  84. $datasetLabelFormatCode = stripslashes($datasetLabelFormatCode);
  85. }
  86. $testCurrentIndex = 0;
  87. foreach ($datasetLabels as $i => $datasetLabel) {
  88. if (is_array($datasetLabel)) {
  89. if ($rotation == 'bar') {
  90. $datasetLabels[$i] = implode(" ", $datasetLabel);
  91. } else {
  92. $datasetLabel = array_reverse($datasetLabel);
  93. $datasetLabels[$i] = implode("\n", $datasetLabel);
  94. }
  95. } else {
  96. // Format labels according to any formatting code
  97. if (!is_null($datasetLabelFormatCode)) {
  98. $datasetLabels[$i] = PHPExcel_Style_NumberFormat::toFormattedString($datasetLabel, $datasetLabelFormatCode);
  99. }
  100. }
  101. ++$testCurrentIndex;
  102. }
  103. return $datasetLabels;
  104. }
  105. private function percentageSumCalculation($groupID, $seriesCount)
  106. {
  107. // Adjust our values to a percentage value across all series in the group
  108. for ($i = 0; $i < $seriesCount; ++$i) {
  109. if ($i == 0) {
  110. $sumValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
  111. } else {
  112. $nextValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
  113. foreach ($nextValues as $k => $value) {
  114. if (isset($sumValues[$k])) {
  115. $sumValues[$k] += $value;
  116. } else {
  117. $sumValues[$k] = $value;
  118. }
  119. }
  120. }
  121. }
  122. return $sumValues;
  123. }
  124. private function percentageAdjustValues($dataValues, $sumValues)
  125. {
  126. foreach ($dataValues as $k => $dataValue) {
  127. $dataValues[$k] = $dataValue / $sumValues[$k] * 100;
  128. }
  129. return $dataValues;
  130. }
  131. private function getCaption($captionElement)
  132. {
  133. // Read any caption
  134. $caption = (!is_null($captionElement)) ? $captionElement->getCaption() : null;
  135. // Test if we have a title caption to display
  136. if (!is_null($caption)) {
  137. // If we do, it could be a plain string or an array
  138. if (is_array($caption)) {
  139. // Implode an array to a plain string
  140. $caption = implode('', $caption);
  141. }
  142. }
  143. return $caption;
  144. }
  145. private function renderTitle()
  146. {
  147. $title = $this->getCaption($this->chart->getTitle());
  148. if (!is_null($title)) {
  149. $this->graph->title->Set($title);
  150. }
  151. }
  152. private function renderLegend()
  153. {
  154. $legend = $this->chart->getLegend();
  155. if (!is_null($legend)) {
  156. $legendPosition = $legend->getPosition();
  157. $legendOverlay = $legend->getOverlay();
  158. switch ($legendPosition) {
  159. case 'r':
  160. $this->graph->legend->SetPos(0.01, 0.5, 'right', 'center'); // right
  161. $this->graph->legend->SetColumns(1);
  162. break;
  163. case 'l':
  164. $this->graph->legend->SetPos(0.01, 0.5, 'left', 'center'); // left
  165. $this->graph->legend->SetColumns(1);
  166. break;
  167. case 't':
  168. $this->graph->legend->SetPos(0.5, 0.01, 'center', 'top'); // top
  169. break;
  170. case 'b':
  171. $this->graph->legend->SetPos(0.5, 0.99, 'center', 'bottom'); // bottom
  172. break;
  173. default:
  174. $this->graph->legend->SetPos(0.01, 0.01, 'right', 'top'); // top-right
  175. $this->graph->legend->SetColumns(1);
  176. break;
  177. }
  178. } else {
  179. $this->graph->legend->Hide();
  180. }
  181. }
  182. private function renderCartesianPlotArea($type = 'textlin')
  183. {
  184. $this->graph = new Graph(self::$width, self::$height);
  185. $this->graph->SetScale($type);
  186. $this->renderTitle();
  187. // Rotate for bar rather than column chart
  188. $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotDirection();
  189. $reverse = ($rotation == 'bar') ? true : false;
  190. $xAxisLabel = $this->chart->getXAxisLabel();
  191. if (!is_null($xAxisLabel)) {
  192. $title = $this->getCaption($xAxisLabel);
  193. if (!is_null($title)) {
  194. $this->graph->xaxis->SetTitle($title, 'center');
  195. $this->graph->xaxis->title->SetMargin(35);
  196. if ($reverse) {
  197. $this->graph->xaxis->title->SetAngle(90);
  198. $this->graph->xaxis->title->SetMargin(90);
  199. }
  200. }
  201. }
  202. $yAxisLabel = $this->chart->getYAxisLabel();
  203. if (!is_null($yAxisLabel)) {
  204. $title = $this->getCaption($yAxisLabel);
  205. if (!is_null($title)) {
  206. $this->graph->yaxis->SetTitle($title, 'center');
  207. if ($reverse) {
  208. $this->graph->yaxis->title->SetAngle(0);
  209. $this->graph->yaxis->title->SetMargin(-55);
  210. }
  211. }
  212. }
  213. }
  214. private function renderPiePlotArea($doughnut = false)
  215. {
  216. $this->graph = new PieGraph(self::$width, self::$height);
  217. $this->renderTitle();
  218. }
  219. private function renderRadarPlotArea()
  220. {
  221. $this->graph = new RadarGraph(self::$width, self::$height);
  222. $this->graph->SetScale('lin');
  223. $this->renderTitle();
  224. }
  225. private function renderPlotLine($groupID, $filled = false, $combination = false, $dimensions = '2d')
  226. {
  227. $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
  228. $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
  229. if ($labelCount > 0) {
  230. $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
  231. $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
  232. $this->graph->xaxis->SetTickLabels($datasetLabels);
  233. }
  234. $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
  235. $seriesPlots = array();
  236. if ($grouping == 'percentStacked') {
  237. $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
  238. }
  239. // Loop through each data series in turn
  240. for ($i = 0; $i < $seriesCount; ++$i) {
  241. $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
  242. $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
  243. if ($grouping == 'percentStacked') {
  244. $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
  245. }
  246. // Fill in any missing values in the $dataValues array
  247. $testCurrentIndex = 0;
  248. foreach ($dataValues as $k => $dataValue) {
  249. while ($k != $testCurrentIndex) {
  250. $dataValues[$testCurrentIndex] = null;
  251. ++$testCurrentIndex;
  252. }
  253. ++$testCurrentIndex;
  254. }
  255. $seriesPlot = new LinePlot($dataValues);
  256. if ($combination) {
  257. $seriesPlot->SetBarCenter();
  258. }
  259. if ($filled) {
  260. $seriesPlot->SetFilled(true);
  261. $seriesPlot->SetColor('black');
  262. $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
  263. } else {
  264. // Set the appropriate plot marker
  265. $this->formatPointMarker($seriesPlot, $marker);
  266. }
  267. $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
  268. $seriesPlot->SetLegend($dataLabel);
  269. $seriesPlots[] = $seriesPlot;
  270. }
  271. if ($grouping == 'standard') {
  272. $groupPlot = $seriesPlots;
  273. } else {
  274. $groupPlot = new AccLinePlot($seriesPlots);
  275. }
  276. $this->graph->Add($groupPlot);
  277. }
  278. private function renderPlotBar($groupID, $dimensions = '2d')
  279. {
  280. $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotDirection();
  281. // Rotate for bar rather than column chart
  282. if (($groupID == 0) && ($rotation == 'bar')) {
  283. $this->graph->Set90AndMargin();
  284. }
  285. $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
  286. $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
  287. if ($labelCount > 0) {
  288. $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
  289. $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation);
  290. // Rotate for bar rather than column chart
  291. if ($rotation == 'bar') {
  292. $datasetLabels = array_reverse($datasetLabels);
  293. $this->graph->yaxis->SetPos('max');
  294. $this->graph->yaxis->SetLabelAlign('center', 'top');
  295. $this->graph->yaxis->SetLabelSide(SIDE_RIGHT);
  296. }
  297. $this->graph->xaxis->SetTickLabels($datasetLabels);
  298. }
  299. $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
  300. $seriesPlots = array();
  301. if ($grouping == 'percentStacked') {
  302. $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
  303. }
  304. // Loop through each data series in turn
  305. for ($j = 0; $j < $seriesCount; ++$j) {
  306. $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
  307. if ($grouping == 'percentStacked') {
  308. $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
  309. }
  310. // Fill in any missing values in the $dataValues array
  311. $testCurrentIndex = 0;
  312. foreach ($dataValues as $k => $dataValue) {
  313. while ($k != $testCurrentIndex) {
  314. $dataValues[$testCurrentIndex] = null;
  315. ++$testCurrentIndex;
  316. }
  317. ++$testCurrentIndex;
  318. }
  319. // Reverse the $dataValues order for bar rather than column chart
  320. if ($rotation == 'bar') {
  321. $dataValues = array_reverse($dataValues);
  322. }
  323. $seriesPlot = new BarPlot($dataValues);
  324. $seriesPlot->SetColor('black');
  325. $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
  326. if ($dimensions == '3d') {
  327. $seriesPlot->SetShadow();
  328. }
  329. if (!$this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)) {
  330. $dataLabel = '';
  331. } else {
  332. $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)->getDataValue();
  333. }
  334. $seriesPlot->SetLegend($dataLabel);
  335. $seriesPlots[] = $seriesPlot;
  336. }
  337. // Reverse the plot order for bar rather than column chart
  338. if (($rotation == 'bar') && (!($grouping == 'percentStacked'))) {
  339. $seriesPlots = array_reverse($seriesPlots);
  340. }
  341. if ($grouping == 'clustered') {
  342. $groupPlot = new GroupBarPlot($seriesPlots);
  343. } elseif ($grouping == 'standard') {
  344. $groupPlot = new GroupBarPlot($seriesPlots);
  345. } else {
  346. $groupPlot = new AccBarPlot($seriesPlots);
  347. if ($dimensions == '3d') {
  348. $groupPlot->SetShadow();
  349. }
  350. }
  351. $this->graph->Add($groupPlot);
  352. }
  353. private function renderPlotScatter($groupID, $bubble)
  354. {
  355. $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
  356. $scatterStyle = $bubbleSize = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
  357. $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
  358. $seriesPlots = array();
  359. // Loop through each data series in turn
  360. for ($i = 0; $i < $seriesCount; ++$i) {
  361. $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
  362. $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
  363. foreach ($dataValuesY as $k => $dataValueY) {
  364. $dataValuesY[$k] = $k;
  365. }
  366. $seriesPlot = new ScatterPlot($dataValuesX, $dataValuesY);
  367. if ($scatterStyle == 'lineMarker') {
  368. $seriesPlot->SetLinkPoints();
  369. $seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
  370. } elseif ($scatterStyle == 'smoothMarker') {
  371. $spline = new Spline($dataValuesY, $dataValuesX);
  372. list($splineDataY, $splineDataX) = $spline->Get(count($dataValuesX) * self::$width / 20);
  373. $lplot = new LinePlot($splineDataX, $splineDataY);
  374. $lplot->SetColor(self::$colourSet[self::$plotColour]);
  375. $this->graph->Add($lplot);
  376. }
  377. if ($bubble) {
  378. $this->formatPointMarker($seriesPlot, 'dot');
  379. $seriesPlot->mark->SetColor('black');
  380. $seriesPlot->mark->SetSize($bubbleSize);
  381. } else {
  382. $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
  383. $this->formatPointMarker($seriesPlot, $marker);
  384. }
  385. $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
  386. $seriesPlot->SetLegend($dataLabel);
  387. $this->graph->Add($seriesPlot);
  388. }
  389. }
  390. private function renderPlotRadar($groupID)
  391. {
  392. $radarStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
  393. $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
  394. $seriesPlots = array();
  395. // Loop through each data series in turn
  396. for ($i = 0; $i < $seriesCount; ++$i) {
  397. $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
  398. $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
  399. $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
  400. $dataValues = array();
  401. foreach ($dataValuesY as $k => $dataValueY) {
  402. $dataValues[$k] = implode(' ', array_reverse($dataValueY));
  403. }
  404. $tmp = array_shift($dataValues);
  405. $dataValues[] = $tmp;
  406. $tmp = array_shift($dataValuesX);
  407. $dataValuesX[] = $tmp;
  408. $this->graph->SetTitles(array_reverse($dataValues));
  409. $seriesPlot = new RadarPlot(array_reverse($dataValuesX));
  410. $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
  411. $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
  412. if ($radarStyle == 'filled') {
  413. $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour]);
  414. }
  415. $this->formatPointMarker($seriesPlot, $marker);
  416. $seriesPlot->SetLegend($dataLabel);
  417. $this->graph->Add($seriesPlot);
  418. }
  419. }
  420. private function renderPlotContour($groupID)
  421. {
  422. $contourStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
  423. $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
  424. $seriesPlots = array();
  425. $dataValues = array();
  426. // Loop through each data series in turn
  427. for ($i = 0; $i < $seriesCount; ++$i) {
  428. $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
  429. $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
  430. $dataValues[$i] = $dataValuesX;
  431. }
  432. $seriesPlot = new ContourPlot($dataValues);
  433. $this->graph->Add($seriesPlot);
  434. }
  435. private function renderPlotStock($groupID)
  436. {
  437. $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
  438. $plotOrder = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder();
  439. $dataValues = array();
  440. // Loop through each data series in turn and build the plot arrays
  441. foreach ($plotOrder as $i => $v) {
  442. $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($v)->getDataValues();
  443. foreach ($dataValuesX as $j => $dataValueX) {
  444. $dataValues[$plotOrder[$i]][$j] = $dataValueX;
  445. }
  446. }
  447. if (empty($dataValues)) {
  448. return;
  449. }
  450. $dataValuesPlot = array();
  451. // Flatten the plot arrays to a single dimensional array to work with jpgraph
  452. for ($j = 0; $j < count($dataValues[0]); ++$j) {
  453. for ($i = 0; $i < $seriesCount; ++$i) {
  454. $dataValuesPlot[] = $dataValues[$i][$j];
  455. }
  456. }
  457. // Set the x-axis labels
  458. $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
  459. if ($labelCount > 0) {
  460. $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
  461. $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
  462. $this->graph->xaxis->SetTickLabels($datasetLabels);
  463. }
  464. $seriesPlot = new StockPlot($dataValuesPlot);
  465. $seriesPlot->SetWidth(20);
  466. $this->graph->Add($seriesPlot);
  467. }
  468. private function renderAreaChart($groupCount, $dimensions = '2d')
  469. {
  470. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
  471. $this->renderCartesianPlotArea();
  472. for ($i = 0; $i < $groupCount; ++$i) {
  473. $this->renderPlotLine($i, true, false, $dimensions);
  474. }
  475. }
  476. private function renderLineChart($groupCount, $dimensions = '2d')
  477. {
  478. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
  479. $this->renderCartesianPlotArea();
  480. for ($i = 0; $i < $groupCount; ++$i) {
  481. $this->renderPlotLine($i, false, false, $dimensions);
  482. }
  483. }
  484. private function renderBarChart($groupCount, $dimensions = '2d')
  485. {
  486. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_bar.php');
  487. $this->renderCartesianPlotArea();
  488. for ($i = 0; $i < $groupCount; ++$i) {
  489. $this->renderPlotBar($i, $dimensions);
  490. }
  491. }
  492. private function renderScatterChart($groupCount)
  493. {
  494. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
  495. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_regstat.php');
  496. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
  497. $this->renderCartesianPlotArea('linlin');
  498. for ($i = 0; $i < $groupCount; ++$i) {
  499. $this->renderPlotScatter($i, false);
  500. }
  501. }
  502. private function renderBubbleChart($groupCount)
  503. {
  504. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
  505. $this->renderCartesianPlotArea('linlin');
  506. for ($i = 0; $i < $groupCount; ++$i) {
  507. $this->renderPlotScatter($i, true);
  508. }
  509. }
  510. private function renderPieChart($groupCount, $dimensions = '2d', $doughnut = false, $multiplePlots = false)
  511. {
  512. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_pie.php');
  513. if ($dimensions == '3d') {
  514. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_pie3d.php');
  515. }
  516. $this->renderPiePlotArea($doughnut);
  517. $iLimit = ($multiplePlots) ? $groupCount : 1;
  518. for ($groupID = 0; $groupID < $iLimit; ++$groupID) {
  519. $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
  520. $exploded = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
  521. if ($groupID == 0) {
  522. $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
  523. if ($labelCount > 0) {
  524. $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
  525. $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
  526. }
  527. }
  528. $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
  529. $seriesPlots = array();
  530. // For pie charts, we only display the first series: doughnut charts generally display all series
  531. $jLimit = ($multiplePlots) ? $seriesCount : 1;
  532. // Loop through each data series in turn
  533. for ($j = 0; $j < $jLimit; ++$j) {
  534. $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
  535. // Fill in any missing values in the $dataValues array
  536. $testCurrentIndex = 0;
  537. foreach ($dataValues as $k => $dataValue) {
  538. while ($k != $testCurrentIndex) {
  539. $dataValues[$testCurrentIndex] = null;
  540. ++$testCurrentIndex;
  541. }
  542. ++$testCurrentIndex;
  543. }
  544. if ($dimensions == '3d') {
  545. $seriesPlot = new PiePlot3D($dataValues);
  546. } else {
  547. if ($doughnut) {
  548. $seriesPlot = new PiePlotC($dataValues);
  549. } else {
  550. $seriesPlot = new PiePlot($dataValues);
  551. }
  552. }
  553. if ($multiplePlots) {
  554. $seriesPlot->SetSize(($jLimit-$j) / ($jLimit * 4));
  555. }
  556. if ($doughnut) {
  557. $seriesPlot->SetMidColor('white');
  558. }
  559. $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
  560. if (count($datasetLabels) > 0) {
  561. $seriesPlot->SetLabels(array_fill(0, count($datasetLabels), ''));
  562. }
  563. if ($dimensions != '3d') {
  564. $seriesPlot->SetGuideLines(false);
  565. }
  566. if ($j == 0) {
  567. if ($exploded) {
  568. $seriesPlot->ExplodeAll();
  569. }
  570. $seriesPlot->SetLegends($datasetLabels);
  571. }
  572. $this->graph->Add($seriesPlot);
  573. }
  574. }
  575. }
  576. private function renderRadarChart($groupCount)
  577. {
  578. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_radar.php');
  579. $this->renderRadarPlotArea();
  580. for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
  581. $this->renderPlotRadar($groupID);
  582. }
  583. }
  584. private function renderStockChart($groupCount)
  585. {
  586. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_stock.php');
  587. $this->renderCartesianPlotArea('intint');
  588. for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
  589. $this->renderPlotStock($groupID);
  590. }
  591. }
  592. private function renderContourChart($groupCount, $dimensions)
  593. {
  594. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_contour.php');
  595. $this->renderCartesianPlotArea('intint');
  596. for ($i = 0; $i < $groupCount; ++$i) {
  597. $this->renderPlotContour($i);
  598. }
  599. }
  600. private function renderCombinationChart($groupCount, $dimensions, $outputDestination)
  601. {
  602. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
  603. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_bar.php');
  604. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_scatter.php');
  605. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_regstat.php');
  606. require_once(PHPExcel_Settings::getChartRendererPath().'jpgraph_line.php');
  607. $this->renderCartesianPlotArea();
  608. for ($i = 0; $i < $groupCount; ++$i) {
  609. $dimensions = null;
  610. $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
  611. switch ($chartType) {
  612. case 'area3DChart':
  613. $dimensions = '3d';
  614. // no break
  615. case 'areaChart':
  616. $this->renderPlotLine($i, true, true, $dimensions);
  617. break;
  618. case 'bar3DChart':
  619. $dimensions = '3d';
  620. // no break
  621. case 'barChart':
  622. $this->renderPlotBar($i, $dimensions);
  623. break;
  624. case 'line3DChart':
  625. $dimensions = '3d';
  626. // no break
  627. case 'lineChart':
  628. $this->renderPlotLine($i, false, true, $dimensions);
  629. break;
  630. case 'scatterChart':
  631. $this->renderPlotScatter($i, false);
  632. break;
  633. case 'bubbleChart':
  634. $this->renderPlotScatter($i, true);
  635. break;
  636. default:
  637. $this->graph = null;
  638. return false;
  639. }
  640. }
  641. $this->renderLegend();
  642. $this->graph->Stroke($outputDestination);
  643. return true;
  644. }
  645. public function render($outputDestination)
  646. {
  647. self::$plotColour = 0;
  648. $groupCount = $this->chart->getPlotArea()->getPlotGroupCount();
  649. $dimensions = null;
  650. if ($groupCount == 1) {
  651. $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType();
  652. } else {
  653. $chartTypes = array();
  654. for ($i = 0; $i < $groupCount; ++$i) {
  655. $chartTypes[] = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
  656. }
  657. $chartTypes = array_unique($chartTypes);
  658. if (count($chartTypes) == 1) {
  659. $chartType = array_pop($chartTypes);
  660. } elseif (count($chartTypes) == 0) {
  661. echo 'Chart is not yet implemented<br />';
  662. return false;
  663. } else {
  664. return $this->renderCombinationChart($groupCount, $dimensions, $outputDestination);
  665. }
  666. }
  667. switch ($chartType) {
  668. case 'area3DChart':
  669. $dimensions = '3d';
  670. // no break
  671. case 'areaChart':
  672. $this->renderAreaChart($groupCount, $dimensions);
  673. break;
  674. case 'bar3DChart':
  675. $dimensions = '3d';
  676. // no break
  677. case 'barChart':
  678. $this->renderBarChart($groupCount, $dimensions);
  679. break;
  680. case 'line3DChart':
  681. $dimensions = '3d';
  682. // no break
  683. case 'lineChart':
  684. $this->renderLineChart($groupCount, $dimensions);
  685. break;
  686. case 'pie3DChart':
  687. $dimensions = '3d';
  688. // no break
  689. case 'pieChart':
  690. $this->renderPieChart($groupCount, $dimensions, false, false);
  691. break;
  692. case 'doughnut3DChart':
  693. $dimensions = '3d';
  694. // no break
  695. case 'doughnutChart':
  696. $this->renderPieChart($groupCount, $dimensions, true, true);
  697. break;
  698. case 'scatterChart':
  699. $this->renderScatterChart($groupCount);
  700. break;
  701. case 'bubbleChart':
  702. $this->renderBubbleChart($groupCount);
  703. break;
  704. case 'radarChart':
  705. $this->renderRadarChart($groupCount);
  706. break;
  707. case 'surface3DChart':
  708. $dimensions = '3d';
  709. // no break
  710. case 'surfaceChart':
  711. $this->renderContourChart($groupCount, $dimensions);
  712. break;
  713. case 'stockChart':
  714. $this->renderStockChart($groupCount, $dimensions);
  715. break;
  716. default:
  717. echo $chartType.' is not yet implemented<br />';
  718. return false;
  719. }
  720. $this->renderLegend();
  721. $this->graph->Stroke($outputDestination);
  722. return true;
  723. }
  724. /**
  725. * Create a new PHPExcel_Chart_Renderer_jpgraph
  726. */
  727. public function __construct(PHPExcel_Chart $chart)
  728. {
  729. $this->graph = null;
  730. $this->chart = $chart;
  731. }
  732. }