Chart.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. /**
  8. * PHPExcel_Reader_Excel2007_Chart
  9. *
  10. * @category PHPExcel
  11. * @package PHPExcel_Reader_Excel2007
  12. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  13. */
  14. class PHPExcel_Reader_Excel2007_Chart
  15. {
  16. private static function getAttribute($component, $name, $format)
  17. {
  18. $attributes = $component->attributes();
  19. if (isset($attributes[$name])) {
  20. if ($format == 'string') {
  21. return (string) $attributes[$name];
  22. } elseif ($format == 'integer') {
  23. return (integer) $attributes[$name];
  24. } elseif ($format == 'boolean') {
  25. return (boolean) ($attributes[$name] === '0' || $attributes[$name] !== 'true') ? false : true;
  26. } else {
  27. return (float) $attributes[$name];
  28. }
  29. }
  30. return null;
  31. }
  32. private static function readColor($color, $background = false)
  33. {
  34. if (isset($color["rgb"])) {
  35. return (string)$color["rgb"];
  36. } elseif (isset($color["indexed"])) {
  37. return PHPExcel_Style_Color::indexedColor($color["indexed"]-7, $background)->getARGB();
  38. }
  39. }
  40. public static function readChart($chartElements, $chartName)
  41. {
  42. $namespacesChartMeta = $chartElements->getNamespaces(true);
  43. $chartElementsC = $chartElements->children($namespacesChartMeta['c']);
  44. $XaxisLabel = $YaxisLabel = $legend = $title = null;
  45. $dispBlanksAs = $plotVisOnly = null;
  46. foreach ($chartElementsC as $chartElementKey => $chartElement) {
  47. switch ($chartElementKey) {
  48. case "chart":
  49. foreach ($chartElement as $chartDetailsKey => $chartDetails) {
  50. $chartDetailsC = $chartDetails->children($namespacesChartMeta['c']);
  51. switch ($chartDetailsKey) {
  52. case "plotArea":
  53. $plotAreaLayout = $XaxisLable = $YaxisLable = null;
  54. $plotSeries = $plotAttributes = array();
  55. foreach ($chartDetails as $chartDetailKey => $chartDetail) {
  56. switch ($chartDetailKey) {
  57. case "layout":
  58. $plotAreaLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta, 'plotArea');
  59. break;
  60. case "catAx":
  61. if (isset($chartDetail->title)) {
  62. $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
  63. }
  64. break;
  65. case "dateAx":
  66. if (isset($chartDetail->title)) {
  67. $XaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
  68. }
  69. break;
  70. case "valAx":
  71. if (isset($chartDetail->title)) {
  72. $YaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta, 'cat');
  73. }
  74. break;
  75. case "barChart":
  76. case "bar3DChart":
  77. $barDirection = self::getAttribute($chartDetail->barDir, 'val', 'string');
  78. $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  79. $plotSer->setPlotDirection($barDirection);
  80. $plotSeries[] = $plotSer;
  81. $plotAttributes = self::readChartAttributes($chartDetail);
  82. break;
  83. case "lineChart":
  84. case "line3DChart":
  85. $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  86. $plotAttributes = self::readChartAttributes($chartDetail);
  87. break;
  88. case "areaChart":
  89. case "area3DChart":
  90. $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  91. $plotAttributes = self::readChartAttributes($chartDetail);
  92. break;
  93. case "doughnutChart":
  94. case "pieChart":
  95. case "pie3DChart":
  96. $explosion = isset($chartDetail->ser->explosion);
  97. $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  98. $plotSer->setPlotStyle($explosion);
  99. $plotSeries[] = $plotSer;
  100. $plotAttributes = self::readChartAttributes($chartDetail);
  101. break;
  102. case "scatterChart":
  103. $scatterStyle = self::getAttribute($chartDetail->scatterStyle, 'val', 'string');
  104. $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  105. $plotSer->setPlotStyle($scatterStyle);
  106. $plotSeries[] = $plotSer;
  107. $plotAttributes = self::readChartAttributes($chartDetail);
  108. break;
  109. case "bubbleChart":
  110. $bubbleScale = self::getAttribute($chartDetail->bubbleScale, 'val', 'integer');
  111. $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  112. $plotSer->setPlotStyle($bubbleScale);
  113. $plotSeries[] = $plotSer;
  114. $plotAttributes = self::readChartAttributes($chartDetail);
  115. break;
  116. case "radarChart":
  117. $radarStyle = self::getAttribute($chartDetail->radarStyle, 'val', 'string');
  118. $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  119. $plotSer->setPlotStyle($radarStyle);
  120. $plotSeries[] = $plotSer;
  121. $plotAttributes = self::readChartAttributes($chartDetail);
  122. break;
  123. case "surfaceChart":
  124. case "surface3DChart":
  125. $wireFrame = self::getAttribute($chartDetail->wireframe, 'val', 'boolean');
  126. $plotSer = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  127. $plotSer->setPlotStyle($wireFrame);
  128. $plotSeries[] = $plotSer;
  129. $plotAttributes = self::readChartAttributes($chartDetail);
  130. break;
  131. case "stockChart":
  132. $plotSeries[] = self::chartDataSeries($chartDetail, $namespacesChartMeta, $chartDetailKey);
  133. $plotAttributes = self::readChartAttributes($plotAreaLayout);
  134. break;
  135. }
  136. }
  137. if ($plotAreaLayout == null) {
  138. $plotAreaLayout = new PHPExcel_Chart_Layout();
  139. }
  140. $plotArea = new PHPExcel_Chart_PlotArea($plotAreaLayout, $plotSeries);
  141. self::setChartAttributes($plotAreaLayout, $plotAttributes);
  142. break;
  143. case "plotVisOnly":
  144. $plotVisOnly = self::getAttribute($chartDetails, 'val', 'string');
  145. break;
  146. case "dispBlanksAs":
  147. $dispBlanksAs = self::getAttribute($chartDetails, 'val', 'string');
  148. break;
  149. case "title":
  150. $title = self::chartTitle($chartDetails, $namespacesChartMeta, 'title');
  151. break;
  152. case "legend":
  153. $legendPos = 'r';
  154. $legendLayout = null;
  155. $legendOverlay = false;
  156. foreach ($chartDetails as $chartDetailKey => $chartDetail) {
  157. switch ($chartDetailKey) {
  158. case "legendPos":
  159. $legendPos = self::getAttribute($chartDetail, 'val', 'string');
  160. break;
  161. case "overlay":
  162. $legendOverlay = self::getAttribute($chartDetail, 'val', 'boolean');
  163. break;
  164. case "layout":
  165. $legendLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta, 'legend');
  166. break;
  167. }
  168. }
  169. $legend = new PHPExcel_Chart_Legend($legendPos, $legendLayout, $legendOverlay);
  170. break;
  171. }
  172. }
  173. }
  174. }
  175. $chart = new PHPExcel_Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, $dispBlanksAs, $XaxisLabel, $YaxisLabel);
  176. return $chart;
  177. }
  178. private static function chartTitle($titleDetails, $namespacesChartMeta, $type)
  179. {
  180. $caption = array();
  181. $titleLayout = null;
  182. foreach ($titleDetails as $titleDetailKey => $chartDetail) {
  183. switch ($titleDetailKey) {
  184. case "tx":
  185. $titleDetails = $chartDetail->rich->children($namespacesChartMeta['a']);
  186. foreach ($titleDetails as $titleKey => $titleDetail) {
  187. switch ($titleKey) {
  188. case "p":
  189. $titleDetailPart = $titleDetail->children($namespacesChartMeta['a']);
  190. $caption[] = self::parseRichText($titleDetailPart);
  191. }
  192. }
  193. break;
  194. case "layout":
  195. $titleLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta);
  196. break;
  197. }
  198. }
  199. return new PHPExcel_Chart_Title($caption, $titleLayout);
  200. }
  201. private static function chartLayoutDetails($chartDetail, $namespacesChartMeta)
  202. {
  203. if (!isset($chartDetail->manualLayout)) {
  204. return null;
  205. }
  206. $details = $chartDetail->manualLayout->children($namespacesChartMeta['c']);
  207. if (is_null($details)) {
  208. return null;
  209. }
  210. $layout = array();
  211. foreach ($details as $detailKey => $detail) {
  212. // echo $detailKey, ' => ',self::getAttribute($detail, 'val', 'string'),PHP_EOL;
  213. $layout[$detailKey] = self::getAttribute($detail, 'val', 'string');
  214. }
  215. return new PHPExcel_Chart_Layout($layout);
  216. }
  217. private static function chartDataSeries($chartDetail, $namespacesChartMeta, $plotType)
  218. {
  219. $multiSeriesType = null;
  220. $smoothLine = false;
  221. $seriesLabel = $seriesCategory = $seriesValues = $plotOrder = array();
  222. $seriesDetailSet = $chartDetail->children($namespacesChartMeta['c']);
  223. foreach ($seriesDetailSet as $seriesDetailKey => $seriesDetails) {
  224. switch ($seriesDetailKey) {
  225. case "grouping":
  226. $multiSeriesType = self::getAttribute($chartDetail->grouping, 'val', 'string');
  227. break;
  228. case "ser":
  229. $marker = null;
  230. foreach ($seriesDetails as $seriesKey => $seriesDetail) {
  231. switch ($seriesKey) {
  232. case "idx":
  233. $seriesIndex = self::getAttribute($seriesDetail, 'val', 'integer');
  234. break;
  235. case "order":
  236. $seriesOrder = self::getAttribute($seriesDetail, 'val', 'integer');
  237. $plotOrder[$seriesIndex] = $seriesOrder;
  238. break;
  239. case "tx":
  240. $seriesLabel[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
  241. break;
  242. case "marker":
  243. $marker = self::getAttribute($seriesDetail->symbol, 'val', 'string');
  244. break;
  245. case "smooth":
  246. $smoothLine = self::getAttribute($seriesDetail, 'val', 'boolean');
  247. break;
  248. case "cat":
  249. $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta);
  250. break;
  251. case "val":
  252. $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
  253. break;
  254. case "xVal":
  255. $seriesCategory[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
  256. break;
  257. case "yVal":
  258. $seriesValues[$seriesIndex] = self::chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker);
  259. break;
  260. }
  261. }
  262. }
  263. }
  264. return new PHPExcel_Chart_DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $smoothLine);
  265. }
  266. private static function chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker = null, $smoothLine = false)
  267. {
  268. if (isset($seriesDetail->strRef)) {
  269. $seriesSource = (string) $seriesDetail->strRef->f;
  270. $seriesData = self::chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']), 's');
  271. return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
  272. } elseif (isset($seriesDetail->numRef)) {
  273. $seriesSource = (string) $seriesDetail->numRef->f;
  274. $seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c']));
  275. return new PHPExcel_Chart_DataSeriesValues('Number', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
  276. } elseif (isset($seriesDetail->multiLvlStrRef)) {
  277. $seriesSource = (string) $seriesDetail->multiLvlStrRef->f;
  278. $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']), 's');
  279. $seriesData['pointCount'] = count($seriesData['dataValues']);
  280. return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
  281. } elseif (isset($seriesDetail->multiLvlNumRef)) {
  282. $seriesSource = (string) $seriesDetail->multiLvlNumRef->f;
  283. $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']), 's');
  284. $seriesData['pointCount'] = count($seriesData['dataValues']);
  285. return new PHPExcel_Chart_DataSeriesValues('String', $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker, $smoothLine);
  286. }
  287. return null;
  288. }
  289. private static function chartDataSeriesValues($seriesValueSet, $dataType = 'n')
  290. {
  291. $seriesVal = array();
  292. $formatCode = '';
  293. $pointCount = 0;
  294. foreach ($seriesValueSet as $seriesValueIdx => $seriesValue) {
  295. switch ($seriesValueIdx) {
  296. case 'ptCount':
  297. $pointCount = self::getAttribute($seriesValue, 'val', 'integer');
  298. break;
  299. case 'formatCode':
  300. $formatCode = (string) $seriesValue;
  301. break;
  302. case 'pt':
  303. $pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
  304. if ($dataType == 's') {
  305. $seriesVal[$pointVal] = (string) $seriesValue->v;
  306. } else {
  307. $seriesVal[$pointVal] = (float) $seriesValue->v;
  308. }
  309. break;
  310. }
  311. }
  312. return array(
  313. 'formatCode' => $formatCode,
  314. 'pointCount' => $pointCount,
  315. 'dataValues' => $seriesVal
  316. );
  317. }
  318. private static function chartDataSeriesValuesMultiLevel($seriesValueSet, $dataType = 'n')
  319. {
  320. $seriesVal = array();
  321. $formatCode = '';
  322. $pointCount = 0;
  323. foreach ($seriesValueSet->lvl as $seriesLevelIdx => $seriesLevel) {
  324. foreach ($seriesLevel as $seriesValueIdx => $seriesValue) {
  325. switch ($seriesValueIdx) {
  326. case 'ptCount':
  327. $pointCount = self::getAttribute($seriesValue, 'val', 'integer');
  328. break;
  329. case 'formatCode':
  330. $formatCode = (string) $seriesValue;
  331. break;
  332. case 'pt':
  333. $pointVal = self::getAttribute($seriesValue, 'idx', 'integer');
  334. if ($dataType == 's') {
  335. $seriesVal[$pointVal][] = (string) $seriesValue->v;
  336. } else {
  337. $seriesVal[$pointVal][] = (float) $seriesValue->v;
  338. }
  339. break;
  340. }
  341. }
  342. }
  343. return array(
  344. 'formatCode' => $formatCode,
  345. 'pointCount' => $pointCount,
  346. 'dataValues' => $seriesVal
  347. );
  348. }
  349. private static function parseRichText($titleDetailPart = null)
  350. {
  351. $value = new PHPExcel_RichText();
  352. foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
  353. if (isset($titleDetailElement->t)) {
  354. $objText = $value->createTextRun((string) $titleDetailElement->t);
  355. }
  356. if (isset($titleDetailElement->rPr)) {
  357. if (isset($titleDetailElement->rPr->rFont["val"])) {
  358. $objText->getFont()->setName((string) $titleDetailElement->rPr->rFont["val"]);
  359. }
  360. $fontSize = (self::getAttribute($titleDetailElement->rPr, 'sz', 'integer'));
  361. if (!is_null($fontSize)) {
  362. $objText->getFont()->setSize(floor($fontSize / 100));
  363. }
  364. $fontColor = (self::getAttribute($titleDetailElement->rPr, 'color', 'string'));
  365. if (!is_null($fontColor)) {
  366. $objText->getFont()->setColor(new PHPExcel_Style_Color(self::readColor($fontColor)));
  367. }
  368. $bold = self::getAttribute($titleDetailElement->rPr, 'b', 'boolean');
  369. if (!is_null($bold)) {
  370. $objText->getFont()->setBold($bold);
  371. }
  372. $italic = self::getAttribute($titleDetailElement->rPr, 'i', 'boolean');
  373. if (!is_null($italic)) {
  374. $objText->getFont()->setItalic($italic);
  375. }
  376. $baseline = self::getAttribute($titleDetailElement->rPr, 'baseline', 'integer');
  377. if (!is_null($baseline)) {
  378. if ($baseline > 0) {
  379. $objText->getFont()->setSuperScript(true);
  380. } elseif ($baseline < 0) {
  381. $objText->getFont()->setSubScript(true);
  382. }
  383. }
  384. $underscore = (self::getAttribute($titleDetailElement->rPr, 'u', 'string'));
  385. if (!is_null($underscore)) {
  386. if ($underscore == 'sng') {
  387. $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_SINGLE);
  388. } elseif ($underscore == 'dbl') {
  389. $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_DOUBLE);
  390. } else {
  391. $objText->getFont()->setUnderline(PHPExcel_Style_Font::UNDERLINE_NONE);
  392. }
  393. }
  394. $strikethrough = (self::getAttribute($titleDetailElement->rPr, 's', 'string'));
  395. if (!is_null($strikethrough)) {
  396. if ($strikethrough == 'noStrike') {
  397. $objText->getFont()->setStrikethrough(false);
  398. } else {
  399. $objText->getFont()->setStrikethrough(true);
  400. }
  401. }
  402. }
  403. }
  404. return $value;
  405. }
  406. private static function readChartAttributes($chartDetail)
  407. {
  408. $plotAttributes = array();
  409. if (isset($chartDetail->dLbls)) {
  410. if (isset($chartDetail->dLbls->howLegendKey)) {
  411. $plotAttributes['showLegendKey'] = self::getAttribute($chartDetail->dLbls->showLegendKey, 'val', 'string');
  412. }
  413. if (isset($chartDetail->dLbls->showVal)) {
  414. $plotAttributes['showVal'] = self::getAttribute($chartDetail->dLbls->showVal, 'val', 'string');
  415. }
  416. if (isset($chartDetail->dLbls->showCatName)) {
  417. $plotAttributes['showCatName'] = self::getAttribute($chartDetail->dLbls->showCatName, 'val', 'string');
  418. }
  419. if (isset($chartDetail->dLbls->showSerName)) {
  420. $plotAttributes['showSerName'] = self::getAttribute($chartDetail->dLbls->showSerName, 'val', 'string');
  421. }
  422. if (isset($chartDetail->dLbls->showPercent)) {
  423. $plotAttributes['showPercent'] = self::getAttribute($chartDetail->dLbls->showPercent, 'val', 'string');
  424. }
  425. if (isset($chartDetail->dLbls->showBubbleSize)) {
  426. $plotAttributes['showBubbleSize'] = self::getAttribute($chartDetail->dLbls->showBubbleSize, 'val', 'string');
  427. }
  428. if (isset($chartDetail->dLbls->showLeaderLines)) {
  429. $plotAttributes['showLeaderLines'] = self::getAttribute($chartDetail->dLbls->showLeaderLines, 'val', 'string');
  430. }
  431. }
  432. return $plotAttributes;
  433. }
  434. private static function setChartAttributes($plotArea, $plotAttributes)
  435. {
  436. foreach ($plotAttributes as $plotAttributeKey => $plotAttributeValue) {
  437. switch ($plotAttributeKey) {
  438. case 'showLegendKey':
  439. $plotArea->setShowLegendKey($plotAttributeValue);
  440. break;
  441. case 'showVal':
  442. $plotArea->setShowVal($plotAttributeValue);
  443. break;
  444. case 'showCatName':
  445. $plotArea->setShowCatName($plotAttributeValue);
  446. break;
  447. case 'showSerName':
  448. $plotArea->setShowSerName($plotAttributeValue);
  449. break;
  450. case 'showPercent':
  451. $plotArea->setShowPercent($plotAttributeValue);
  452. break;
  453. case 'showBubbleSize':
  454. $plotArea->setShowBubbleSize($plotAttributeValue);
  455. break;
  456. case 'showLeaderLines':
  457. $plotArea->setShowLeaderLines($plotAttributeValue);
  458. break;
  459. }
  460. }
  461. }
  462. }