jpgraph.php 28 KB

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