summaryrefslogtreecommitdiffstats
path: root/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart')
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php556
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php663
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeries.php394
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeriesValues.php397
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Exception.php9
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/GridLines.php454
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php481
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php157
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php111
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Properties.php369
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/IRenderer.php22
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php870
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/PHP Charting Libraries.txt20
-rw-r--r--vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Title.php65
14 files changed, 4568 insertions, 0 deletions
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php
new file mode 100644
index 0000000..6b852f0
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Axis.php
@@ -0,0 +1,556 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+/**
+ * Created by PhpStorm.
+ * User: Wiktor Trzonkowski
+ * Date: 6/17/14
+ * Time: 12:11 PM.
+ */
+class Axis extends Properties
+{
+ /**
+ * Axis Number.
+ *
+ * @var array of mixed
+ */
+ private $axisNumber = [
+ 'format' => self::FORMAT_CODE_GENERAL,
+ 'source_linked' => 1,
+ ];
+
+ /**
+ * Axis Options.
+ *
+ * @var array of mixed
+ */
+ private $axisOptions = [
+ 'minimum' => null,
+ 'maximum' => null,
+ 'major_unit' => null,
+ 'minor_unit' => null,
+ 'orientation' => self::ORIENTATION_NORMAL,
+ 'minor_tick_mark' => self::TICK_MARK_NONE,
+ 'major_tick_mark' => self::TICK_MARK_NONE,
+ 'axis_labels' => self::AXIS_LABELS_NEXT_TO,
+ 'horizontal_crosses' => self::HORIZONTAL_CROSSES_AUTOZERO,
+ 'horizontal_crosses_value' => null,
+ ];
+
+ /**
+ * Fill Properties.
+ *
+ * @var array of mixed
+ */
+ private $fillProperties = [
+ 'type' => self::EXCEL_COLOR_TYPE_ARGB,
+ 'value' => null,
+ 'alpha' => 0,
+ ];
+
+ /**
+ * Line Properties.
+ *
+ * @var array of mixed
+ */
+ private $lineProperties = [
+ 'type' => self::EXCEL_COLOR_TYPE_ARGB,
+ 'value' => null,
+ 'alpha' => 0,
+ ];
+
+ /**
+ * Line Style Properties.
+ *
+ * @var array of mixed
+ */
+ private $lineStyleProperties = [
+ 'width' => '9525',
+ 'compound' => self::LINE_STYLE_COMPOUND_SIMPLE,
+ 'dash' => self::LINE_STYLE_DASH_SOLID,
+ 'cap' => self::LINE_STYLE_CAP_FLAT,
+ 'join' => self::LINE_STYLE_JOIN_BEVEL,
+ 'arrow' => [
+ 'head' => [
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_5,
+ ],
+ 'end' => [
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_8,
+ ],
+ ],
+ ];
+
+ /**
+ * Shadow Properties.
+ *
+ * @var array of mixed
+ */
+ private $shadowProperties = [
+ 'presets' => self::SHADOW_PRESETS_NOSHADOW,
+ 'effect' => null,
+ 'color' => [
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 40,
+ ],
+ 'size' => [
+ 'sx' => null,
+ 'sy' => null,
+ 'kx' => null,
+ ],
+ 'blur' => null,
+ 'direction' => null,
+ 'distance' => null,
+ 'algn' => null,
+ 'rotWithShape' => null,
+ ];
+
+ /**
+ * Glow Properties.
+ *
+ * @var array of mixed
+ */
+ private $glowProperties = [
+ 'size' => null,
+ 'color' => [
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 40,
+ ],
+ ];
+
+ /**
+ * Soft Edge Properties.
+ *
+ * @var array of mixed
+ */
+ private $softEdges = [
+ 'size' => null,
+ ];
+
+ /**
+ * Get Series Data Type.
+ *
+ * @param mixed $format_code
+ *
+ * @return string
+ */
+ public function setAxisNumberProperties($format_code)
+ {
+ $this->axisNumber['format'] = (string) $format_code;
+ $this->axisNumber['source_linked'] = 0;
+ }
+
+ /**
+ * Get Axis Number Format Data Type.
+ *
+ * @return string
+ */
+ public function getAxisNumberFormat()
+ {
+ return $this->axisNumber['format'];
+ }
+
+ /**
+ * Get Axis Number Source Linked.
+ *
+ * @return string
+ */
+ public function getAxisNumberSourceLinked()
+ {
+ return (string) $this->axisNumber['source_linked'];
+ }
+
+ /**
+ * Set Axis Options Properties.
+ *
+ * @param string $axis_labels
+ * @param string $horizontal_crosses_value
+ * @param string $horizontal_crosses
+ * @param string $axis_orientation
+ * @param string $major_tmt
+ * @param string $minor_tmt
+ * @param string $minimum
+ * @param string $maximum
+ * @param string $major_unit
+ * @param string $minor_unit
+ */
+ public function setAxisOptionsProperties($axis_labels, $horizontal_crosses_value = null, $horizontal_crosses = null, $axis_orientation = null, $major_tmt = null, $minor_tmt = null, $minimum = null, $maximum = null, $major_unit = null, $minor_unit = null): void
+ {
+ $this->axisOptions['axis_labels'] = (string) $axis_labels;
+ ($horizontal_crosses_value !== null) ? $this->axisOptions['horizontal_crosses_value'] = (string) $horizontal_crosses_value : null;
+ ($horizontal_crosses !== null) ? $this->axisOptions['horizontal_crosses'] = (string) $horizontal_crosses : null;
+ ($axis_orientation !== null) ? $this->axisOptions['orientation'] = (string) $axis_orientation : null;
+ ($major_tmt !== null) ? $this->axisOptions['major_tick_mark'] = (string) $major_tmt : null;
+ ($minor_tmt !== null) ? $this->axisOptions['minor_tick_mark'] = (string) $minor_tmt : null;
+ ($minor_tmt !== null) ? $this->axisOptions['minor_tick_mark'] = (string) $minor_tmt : null;
+ ($minimum !== null) ? $this->axisOptions['minimum'] = (string) $minimum : null;
+ ($maximum !== null) ? $this->axisOptions['maximum'] = (string) $maximum : null;
+ ($major_unit !== null) ? $this->axisOptions['major_unit'] = (string) $major_unit : null;
+ ($minor_unit !== null) ? $this->axisOptions['minor_unit'] = (string) $minor_unit : null;
+ }
+
+ /**
+ * Get Axis Options Property.
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+ public function getAxisOptionsProperty($property)
+ {
+ return $this->axisOptions[$property];
+ }
+
+ /**
+ * Set Axis Orientation Property.
+ *
+ * @param string $orientation
+ */
+ public function setAxisOrientation($orientation): void
+ {
+ $this->axisOptions['orientation'] = (string) $orientation;
+ }
+
+ /**
+ * Set Fill Property.
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ */
+ public function setFillParameters($color, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_ARGB): void
+ {
+ $this->fillProperties = $this->setColorProperties($color, $alpha, $type);
+ }
+
+ /**
+ * Set Line Property.
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ */
+ public function setLineParameters($color, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_ARGB): void
+ {
+ $this->lineProperties = $this->setColorProperties($color, $alpha, $type);
+ }
+
+ /**
+ * Get Fill Property.
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+ public function getFillProperty($property)
+ {
+ return $this->fillProperties[$property];
+ }
+
+ /**
+ * Get Line Property.
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+ public function getLineProperty($property)
+ {
+ return $this->lineProperties[$property];
+ }
+
+ /**
+ * Set Line Style Properties.
+ *
+ * @param float $line_width
+ * @param string $compound_type
+ * @param string $dash_type
+ * @param string $cap_type
+ * @param string $join_type
+ * @param string $head_arrow_type
+ * @param string $head_arrow_size
+ * @param string $end_arrow_type
+ * @param string $end_arrow_size
+ */
+ public function setLineStyleProperties($line_width = null, $compound_type = null, $dash_type = null, $cap_type = null, $join_type = null, $head_arrow_type = null, $head_arrow_size = null, $end_arrow_type = null, $end_arrow_size = null): void
+ {
+ ($line_width !== null) ? $this->lineStyleProperties['width'] = $this->getExcelPointsWidth((float) $line_width) : null;
+ ($compound_type !== null) ? $this->lineStyleProperties['compound'] = (string) $compound_type : null;
+ ($dash_type !== null) ? $this->lineStyleProperties['dash'] = (string) $dash_type : null;
+ ($cap_type !== null) ? $this->lineStyleProperties['cap'] = (string) $cap_type : null;
+ ($join_type !== null) ? $this->lineStyleProperties['join'] = (string) $join_type : null;
+ ($head_arrow_type !== null) ? $this->lineStyleProperties['arrow']['head']['type'] = (string) $head_arrow_type : null;
+ ($head_arrow_size !== null) ? $this->lineStyleProperties['arrow']['head']['size'] = (string) $head_arrow_size : null;
+ ($end_arrow_type !== null) ? $this->lineStyleProperties['arrow']['end']['type'] = (string) $end_arrow_type : null;
+ ($end_arrow_size !== null) ? $this->lineStyleProperties['arrow']['end']['size'] = (string) $end_arrow_size : null;
+ }
+
+ /**
+ * Get Line Style Property.
+ *
+ * @param array|string $elements
+ *
+ * @return string
+ */
+ public function getLineStyleProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->lineStyleProperties, $elements);
+ }
+
+ /**
+ * Get Line Style Arrow Excel Width.
+ *
+ * @param string $arrow
+ *
+ * @return string
+ */
+ public function getLineStyleArrowWidth($arrow)
+ {
+ return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'w');
+ }
+
+ /**
+ * Get Line Style Arrow Excel Length.
+ *
+ * @param string $arrow
+ *
+ * @return string
+ */
+ public function getLineStyleArrowLength($arrow)
+ {
+ return $this->getLineStyleArrowSize($this->lineStyleProperties['arrow'][$arrow]['size'], 'len');
+ }
+
+ /**
+ * Set Shadow Properties.
+ *
+ * @param int $sh_presets
+ * @param string $sh_color_value
+ * @param string $sh_color_type
+ * @param string $sh_color_alpha
+ * @param float $sh_blur
+ * @param int $sh_angle
+ * @param float $sh_distance
+ */
+ public function setShadowProperties($sh_presets, $sh_color_value = null, $sh_color_type = null, $sh_color_alpha = null, $sh_blur = null, $sh_angle = null, $sh_distance = null): void
+ {
+ $this->setShadowPresetsProperties((int) $sh_presets)
+ ->setShadowColor(
+ $sh_color_value === null ? $this->shadowProperties['color']['value'] : $sh_color_value,
+ $sh_color_alpha === null ? (int) $this->shadowProperties['color']['alpha'] : $sh_color_alpha,
+ $sh_color_type === null ? $this->shadowProperties['color']['type'] : $sh_color_type
+ )
+ ->setShadowBlur($sh_blur)
+ ->setShadowAngle($sh_angle)
+ ->setShadowDistance($sh_distance);
+ }
+
+ /**
+ * Set Shadow Color.
+ *
+ * @param int $shadow_presets
+ *
+ * @return $this
+ */
+ private function setShadowPresetsProperties($shadow_presets)
+ {
+ $this->shadowProperties['presets'] = $shadow_presets;
+ $this->setShadowProperiesMapValues($this->getShadowPresetsMap($shadow_presets));
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Properties from Mapped Values.
+ *
+ * @param mixed &$reference
+ *
+ * @return $this
+ */
+ private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
+ {
+ $base_reference = $reference;
+ foreach ($properties_map as $property_key => $property_val) {
+ if (is_array($property_val)) {
+ if ($reference === null) {
+ $reference = &$this->shadowProperties[$property_key];
+ } else {
+ $reference = &$reference[$property_key];
+ }
+ $this->setShadowProperiesMapValues($property_val, $reference);
+ } else {
+ if ($base_reference === null) {
+ $this->shadowProperties[$property_key] = $property_val;
+ } else {
+ $reference[$property_key] = $property_val;
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Color.
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ * @return $this
+ */
+ private function setShadowColor($color, $alpha, $type)
+ {
+ $this->shadowProperties['color'] = $this->setColorProperties($color, $alpha, $type);
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Blur.
+ *
+ * @param float $blur
+ *
+ * @return $this
+ */
+ private function setShadowBlur($blur)
+ {
+ if ($blur !== null) {
+ $this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Angle.
+ *
+ * @param int $angle
+ *
+ * @return $this
+ */
+ private function setShadowAngle($angle)
+ {
+ if ($angle !== null) {
+ $this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Distance.
+ *
+ * @param float $distance
+ *
+ * @return $this
+ */
+ private function setShadowDistance($distance)
+ {
+ if ($distance !== null) {
+ $this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Shadow Property.
+ *
+ * @param string|string[] $elements
+ *
+ * @return null|array|int|string
+ */
+ public function getShadowProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->shadowProperties, $elements);
+ }
+
+ /**
+ * Set Glow Properties.
+ *
+ * @param float $size
+ * @param string $color_value
+ * @param int $color_alpha
+ * @param string $color_type
+ */
+ public function setGlowProperties($size, $color_value = null, $color_alpha = null, $color_type = null): void
+ {
+ $this->setGlowSize($size)
+ ->setGlowColor(
+ $color_value === null ? $this->glowProperties['color']['value'] : $color_value,
+ $color_alpha === null ? (int) $this->glowProperties['color']['alpha'] : $color_alpha,
+ $color_type === null ? $this->glowProperties['color']['type'] : $color_type
+ );
+ }
+
+ /**
+ * Get Glow Property.
+ *
+ * @param array|string $property
+ *
+ * @return string
+ */
+ public function getGlowProperty($property)
+ {
+ return $this->getArrayElementsValue($this->glowProperties, $property);
+ }
+
+ /**
+ * Set Glow Color.
+ *
+ * @param float $size
+ *
+ * @return $this
+ */
+ private function setGlowSize($size)
+ {
+ if ($size !== null) {
+ $this->glowProperties['size'] = $this->getExcelPointsWidth($size);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Glow Color.
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ * @return $this
+ */
+ private function setGlowColor($color, $alpha, $type)
+ {
+ $this->glowProperties['color'] = $this->setColorProperties($color, $alpha, $type);
+
+ return $this;
+ }
+
+ /**
+ * Set Soft Edges Size.
+ *
+ * @param float $size
+ */
+ public function setSoftEdges($size): void
+ {
+ if ($size !== null) {
+ $softEdges['size'] = (string) $this->getExcelPointsWidth($size);
+ }
+ }
+
+ /**
+ * Get Soft Edges Size.
+ *
+ * @return string
+ */
+ public function getSoftEdgesSize()
+ {
+ return $this->softEdges['size'];
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php
new file mode 100644
index 0000000..6b8af57
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Chart.php
@@ -0,0 +1,663 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+use PhpOffice\PhpSpreadsheet\Settings;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class Chart
+{
+ /**
+ * Chart Name.
+ *
+ * @var string
+ */
+ private $name = '';
+
+ /**
+ * Worksheet.
+ *
+ * @var Worksheet
+ */
+ private $worksheet;
+
+ /**
+ * Chart Title.
+ *
+ * @var Title
+ */
+ private $title;
+
+ /**
+ * Chart Legend.
+ *
+ * @var Legend
+ */
+ private $legend;
+
+ /**
+ * X-Axis Label.
+ *
+ * @var Title
+ */
+ private $xAxisLabel;
+
+ /**
+ * Y-Axis Label.
+ *
+ * @var Title
+ */
+ private $yAxisLabel;
+
+ /**
+ * Chart Plot Area.
+ *
+ * @var PlotArea
+ */
+ private $plotArea;
+
+ /**
+ * Plot Visible Only.
+ *
+ * @var bool
+ */
+ private $plotVisibleOnly = true;
+
+ /**
+ * Display Blanks as.
+ *
+ * @var string
+ */
+ private $displayBlanksAs = DataSeries::EMPTY_AS_GAP;
+
+ /**
+ * Chart Asix Y as.
+ *
+ * @var Axis
+ */
+ private $yAxis;
+
+ /**
+ * Chart Asix X as.
+ *
+ * @var Axis
+ */
+ private $xAxis;
+
+ /**
+ * Chart Major Gridlines as.
+ *
+ * @var GridLines
+ */
+ private $majorGridlines;
+
+ /**
+ * Chart Minor Gridlines as.
+ *
+ * @var GridLines
+ */
+ private $minorGridlines;
+
+ /**
+ * Top-Left Cell Position.
+ *
+ * @var string
+ */
+ private $topLeftCellRef = 'A1';
+
+ /**
+ * Top-Left X-Offset.
+ *
+ * @var int
+ */
+ private $topLeftXOffset = 0;
+
+ /**
+ * Top-Left Y-Offset.
+ *
+ * @var int
+ */
+ private $topLeftYOffset = 0;
+
+ /**
+ * Bottom-Right Cell Position.
+ *
+ * @var string
+ */
+ private $bottomRightCellRef = 'A1';
+
+ /**
+ * Bottom-Right X-Offset.
+ *
+ * @var int
+ */
+ private $bottomRightXOffset = 10;
+
+ /**
+ * Bottom-Right Y-Offset.
+ *
+ * @var int
+ */
+ private $bottomRightYOffset = 10;
+
+ /**
+ * Create a new Chart.
+ *
+ * @param mixed $name
+ * @param mixed $plotVisibleOnly
+ * @param string $displayBlanksAs
+ */
+ public function __construct($name, ?Title $title = null, ?Legend $legend = null, ?PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = DataSeries::EMPTY_AS_GAP, ?Title $xAxisLabel = null, ?Title $yAxisLabel = null, ?Axis $xAxis = null, ?Axis $yAxis = null, ?GridLines $majorGridlines = null, ?GridLines $minorGridlines = null)
+ {
+ $this->name = $name;
+ $this->title = $title;
+ $this->legend = $legend;
+ $this->xAxisLabel = $xAxisLabel;
+ $this->yAxisLabel = $yAxisLabel;
+ $this->plotArea = $plotArea;
+ $this->plotVisibleOnly = $plotVisibleOnly;
+ $this->displayBlanksAs = $displayBlanksAs;
+ $this->xAxis = $xAxis;
+ $this->yAxis = $yAxis;
+ $this->majorGridlines = $majorGridlines;
+ $this->minorGridlines = $minorGridlines;
+ }
+
+ /**
+ * Get Name.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Get Worksheet.
+ *
+ * @return Worksheet
+ */
+ public function getWorksheet()
+ {
+ return $this->worksheet;
+ }
+
+ /**
+ * Set Worksheet.
+ *
+ * @param Worksheet $pValue
+ *
+ * @return $this
+ */
+ public function setWorksheet(?Worksheet $pValue = null)
+ {
+ $this->worksheet = $pValue;
+
+ return $this;
+ }
+
+ /**
+ * Get Title.
+ *
+ * @return Title
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+ /**
+ * Set Title.
+ *
+ * @return $this
+ */
+ public function setTitle(Title $title)
+ {
+ $this->title = $title;
+
+ return $this;
+ }
+
+ /**
+ * Get Legend.
+ *
+ * @return Legend
+ */
+ public function getLegend()
+ {
+ return $this->legend;
+ }
+
+ /**
+ * Set Legend.
+ *
+ * @return $this
+ */
+ public function setLegend(Legend $legend)
+ {
+ $this->legend = $legend;
+
+ return $this;
+ }
+
+ /**
+ * Get X-Axis Label.
+ *
+ * @return Title
+ */
+ public function getXAxisLabel()
+ {
+ return $this->xAxisLabel;
+ }
+
+ /**
+ * Set X-Axis Label.
+ *
+ * @return $this
+ */
+ public function setXAxisLabel(Title $label)
+ {
+ $this->xAxisLabel = $label;
+
+ return $this;
+ }
+
+ /**
+ * Get Y-Axis Label.
+ *
+ * @return Title
+ */
+ public function getYAxisLabel()
+ {
+ return $this->yAxisLabel;
+ }
+
+ /**
+ * Set Y-Axis Label.
+ *
+ * @return $this
+ */
+ public function setYAxisLabel(Title $label)
+ {
+ $this->yAxisLabel = $label;
+
+ return $this;
+ }
+
+ /**
+ * Get Plot Area.
+ *
+ * @return PlotArea
+ */
+ public function getPlotArea()
+ {
+ return $this->plotArea;
+ }
+
+ /**
+ * Get Plot Visible Only.
+ *
+ * @return bool
+ */
+ public function getPlotVisibleOnly()
+ {
+ return $this->plotVisibleOnly;
+ }
+
+ /**
+ * Set Plot Visible Only.
+ *
+ * @param bool $plotVisibleOnly
+ *
+ * @return $this
+ */
+ public function setPlotVisibleOnly($plotVisibleOnly)
+ {
+ $this->plotVisibleOnly = $plotVisibleOnly;
+
+ return $this;
+ }
+
+ /**
+ * Get Display Blanks as.
+ *
+ * @return string
+ */
+ public function getDisplayBlanksAs()
+ {
+ return $this->displayBlanksAs;
+ }
+
+ /**
+ * Set Display Blanks as.
+ *
+ * @param string $displayBlanksAs
+ *
+ * @return $this
+ */
+ public function setDisplayBlanksAs($displayBlanksAs)
+ {
+ $this->displayBlanksAs = $displayBlanksAs;
+
+ return $this;
+ }
+
+ /**
+ * Get yAxis.
+ *
+ * @return Axis
+ */
+ public function getChartAxisY()
+ {
+ if ($this->yAxis !== null) {
+ return $this->yAxis;
+ }
+
+ return new Axis();
+ }
+
+ /**
+ * Get xAxis.
+ *
+ * @return Axis
+ */
+ public function getChartAxisX()
+ {
+ if ($this->xAxis !== null) {
+ return $this->xAxis;
+ }
+
+ return new Axis();
+ }
+
+ /**
+ * Get Major Gridlines.
+ *
+ * @return GridLines
+ */
+ public function getMajorGridlines()
+ {
+ if ($this->majorGridlines !== null) {
+ return $this->majorGridlines;
+ }
+
+ return new GridLines();
+ }
+
+ /**
+ * Get Minor Gridlines.
+ *
+ * @return GridLines
+ */
+ public function getMinorGridlines()
+ {
+ if ($this->minorGridlines !== null) {
+ return $this->minorGridlines;
+ }
+
+ return new GridLines();
+ }
+
+ /**
+ * Set the Top Left position for the chart.
+ *
+ * @param string $cell
+ * @param int $xOffset
+ * @param int $yOffset
+ *
+ * @return $this
+ */
+ public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
+ {
+ $this->topLeftCellRef = $cell;
+ if ($xOffset !== null) {
+ $this->setTopLeftXOffset($xOffset);
+ }
+ if ($yOffset !== null) {
+ $this->setTopLeftYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the top left position of the chart.
+ *
+ * @return array an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+ */
+ public function getTopLeftPosition()
+ {
+ return [
+ 'cell' => $this->topLeftCellRef,
+ 'xOffset' => $this->topLeftXOffset,
+ 'yOffset' => $this->topLeftYOffset,
+ ];
+ }
+
+ /**
+ * Get the cell address where the top left of the chart is fixed.
+ *
+ * @return string
+ */
+ public function getTopLeftCell()
+ {
+ return $this->topLeftCellRef;
+ }
+
+ /**
+ * Set the Top Left cell position for the chart.
+ *
+ * @param string $cell
+ *
+ * @return $this
+ */
+ public function setTopLeftCell($cell)
+ {
+ $this->topLeftCellRef = $cell;
+
+ return $this;
+ }
+
+ /**
+ * Set the offset position within the Top Left cell for the chart.
+ *
+ * @param int $xOffset
+ * @param int $yOffset
+ *
+ * @return $this
+ */
+ public function setTopLeftOffset($xOffset, $yOffset)
+ {
+ if ($xOffset !== null) {
+ $this->setTopLeftXOffset($xOffset);
+ }
+
+ if ($yOffset !== null) {
+ $this->setTopLeftYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the offset position within the Top Left cell for the chart.
+ *
+ * @return int[]
+ */
+ public function getTopLeftOffset()
+ {
+ return [
+ 'X' => $this->topLeftXOffset,
+ 'Y' => $this->topLeftYOffset,
+ ];
+ }
+
+ public function setTopLeftXOffset($xOffset)
+ {
+ $this->topLeftXOffset = $xOffset;
+
+ return $this;
+ }
+
+ public function getTopLeftXOffset()
+ {
+ return $this->topLeftXOffset;
+ }
+
+ public function setTopLeftYOffset($yOffset)
+ {
+ $this->topLeftYOffset = $yOffset;
+
+ return $this;
+ }
+
+ public function getTopLeftYOffset()
+ {
+ return $this->topLeftYOffset;
+ }
+
+ /**
+ * Set the Bottom Right position of the chart.
+ *
+ * @param string $cell
+ * @param int $xOffset
+ * @param int $yOffset
+ *
+ * @return $this
+ */
+ public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
+ {
+ $this->bottomRightCellRef = $cell;
+ if ($xOffset !== null) {
+ $this->setBottomRightXOffset($xOffset);
+ }
+ if ($yOffset !== null) {
+ $this->setBottomRightYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the bottom right position of the chart.
+ *
+ * @return array an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
+ */
+ public function getBottomRightPosition()
+ {
+ return [
+ 'cell' => $this->bottomRightCellRef,
+ 'xOffset' => $this->bottomRightXOffset,
+ 'yOffset' => $this->bottomRightYOffset,
+ ];
+ }
+
+ public function setBottomRightCell($cell)
+ {
+ $this->bottomRightCellRef = $cell;
+
+ return $this;
+ }
+
+ /**
+ * Get the cell address where the bottom right of the chart is fixed.
+ *
+ * @return string
+ */
+ public function getBottomRightCell()
+ {
+ return $this->bottomRightCellRef;
+ }
+
+ /**
+ * Set the offset position within the Bottom Right cell for the chart.
+ *
+ * @param int $xOffset
+ * @param int $yOffset
+ *
+ * @return $this
+ */
+ public function setBottomRightOffset($xOffset, $yOffset)
+ {
+ if ($xOffset !== null) {
+ $this->setBottomRightXOffset($xOffset);
+ }
+
+ if ($yOffset !== null) {
+ $this->setBottomRightYOffset($yOffset);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the offset position within the Bottom Right cell for the chart.
+ *
+ * @return int[]
+ */
+ public function getBottomRightOffset()
+ {
+ return [
+ 'X' => $this->bottomRightXOffset,
+ 'Y' => $this->bottomRightYOffset,
+ ];
+ }
+
+ public function setBottomRightXOffset($xOffset)
+ {
+ $this->bottomRightXOffset = $xOffset;
+
+ return $this;
+ }
+
+ public function getBottomRightXOffset()
+ {
+ return $this->bottomRightXOffset;
+ }
+
+ public function setBottomRightYOffset($yOffset)
+ {
+ $this->bottomRightYOffset = $yOffset;
+
+ return $this;
+ }
+
+ public function getBottomRightYOffset()
+ {
+ return $this->bottomRightYOffset;
+ }
+
+ public function refresh(): void
+ {
+ if ($this->worksheet !== null) {
+ $this->plotArea->refresh($this->worksheet);
+ }
+ }
+
+ /**
+ * Render the chart to given file (or stream).
+ *
+ * @param string $outputDestination Name of the file render to
+ *
+ * @return bool true on success
+ */
+ public function render($outputDestination = null)
+ {
+ if ($outputDestination == 'php://output') {
+ $outputDestination = null;
+ }
+
+ $libraryName = Settings::getChartRenderer();
+ if ($libraryName === null) {
+ return false;
+ }
+
+ // Ensure that data series values are up-to-date before we render
+ $this->refresh();
+
+ $renderer = new $libraryName($this);
+
+ return $renderer->render($outputDestination);
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeries.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeries.php
new file mode 100644
index 0000000..eb8af62
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeries.php
@@ -0,0 +1,394 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class DataSeries
+{
+ const TYPE_BARCHART = 'barChart';
+ const TYPE_BARCHART_3D = 'bar3DChart';
+ const TYPE_LINECHART = 'lineChart';
+ const TYPE_LINECHART_3D = 'line3DChart';
+ const TYPE_AREACHART = 'areaChart';
+ const TYPE_AREACHART_3D = 'area3DChart';
+ const TYPE_PIECHART = 'pieChart';
+ const TYPE_PIECHART_3D = 'pie3DChart';
+ const TYPE_DOUGHNUTCHART = 'doughnutChart';
+ const TYPE_DONUTCHART = self::TYPE_DOUGHNUTCHART; // Synonym
+ const TYPE_SCATTERCHART = 'scatterChart';
+ const TYPE_SURFACECHART = 'surfaceChart';
+ const TYPE_SURFACECHART_3D = 'surface3DChart';
+ const TYPE_RADARCHART = 'radarChart';
+ const TYPE_BUBBLECHART = 'bubbleChart';
+ const TYPE_STOCKCHART = 'stockChart';
+ const TYPE_CANDLECHART = self::TYPE_STOCKCHART; // Synonym
+
+ const GROUPING_CLUSTERED = 'clustered';
+ const GROUPING_STACKED = 'stacked';
+ const GROUPING_PERCENT_STACKED = 'percentStacked';
+ const GROUPING_STANDARD = 'standard';
+
+ const DIRECTION_BAR = 'bar';
+ const DIRECTION_HORIZONTAL = self::DIRECTION_BAR;
+ const DIRECTION_COL = 'col';
+ const DIRECTION_COLUMN = self::DIRECTION_COL;
+ const DIRECTION_VERTICAL = self::DIRECTION_COL;
+
+ const STYLE_LINEMARKER = 'lineMarker';
+ const STYLE_SMOOTHMARKER = 'smoothMarker';
+ const STYLE_MARKER = 'marker';
+ const STYLE_FILLED = 'filled';
+
+ const EMPTY_AS_GAP = 'gap';
+ const EMPTY_AS_ZERO = 'zero';
+ const EMPTY_AS_SPAN = 'span';
+
+ /**
+ * Series Plot Type.
+ *
+ * @var string
+ */
+ private $plotType;
+
+ /**
+ * Plot Grouping Type.
+ *
+ * @var string
+ */
+ private $plotGrouping;
+
+ /**
+ * Plot Direction.
+ *
+ * @var string
+ */
+ private $plotDirection;
+
+ /**
+ * Plot Style.
+ *
+ * @var null|string
+ */
+ private $plotStyle;
+
+ /**
+ * Order of plots in Series.
+ *
+ * @var array of integer
+ */
+ private $plotOrder = [];
+
+ /**
+ * Plot Label.
+ *
+ * @var array of DataSeriesValues
+ */
+ private $plotLabel = [];
+
+ /**
+ * Plot Category.
+ *
+ * @var array of DataSeriesValues
+ */
+ private $plotCategory = [];
+
+ /**
+ * Smooth Line.
+ *
+ * @var bool
+ */
+ private $smoothLine;
+
+ /**
+ * Plot Values.
+ *
+ * @var array of DataSeriesValues
+ */
+ private $plotValues = [];
+
+ /**
+ * Create a new DataSeries.
+ *
+ * @param null|mixed $plotType
+ * @param null|mixed $plotGrouping
+ * @param int[] $plotOrder
+ * @param DataSeriesValues[] $plotLabel
+ * @param DataSeriesValues[] $plotCategory
+ * @param DataSeriesValues[] $plotValues
+ * @param null|string $plotDirection
+ * @param bool $smoothLine
+ * @param null|string $plotStyle
+ */
+ public function __construct($plotType = null, $plotGrouping = null, array $plotOrder = [], array $plotLabel = [], array $plotCategory = [], array $plotValues = [], $plotDirection = null, $smoothLine = false, $plotStyle = null)
+ {
+ $this->plotType = $plotType;
+ $this->plotGrouping = $plotGrouping;
+ $this->plotOrder = $plotOrder;
+ $keys = array_keys($plotValues);
+ $this->plotValues = $plotValues;
+ if ((count($plotLabel) == 0) || ($plotLabel[$keys[0]] === null)) {
+ $plotLabel[$keys[0]] = new DataSeriesValues();
+ }
+ $this->plotLabel = $plotLabel;
+
+ if ((count($plotCategory) == 0) || ($plotCategory[$keys[0]] === null)) {
+ $plotCategory[$keys[0]] = new DataSeriesValues();
+ }
+ $this->plotCategory = $plotCategory;
+
+ $this->smoothLine = $smoothLine;
+ $this->plotStyle = $plotStyle;
+
+ if ($plotDirection === null) {
+ $plotDirection = self::DIRECTION_COL;
+ }
+ $this->plotDirection = $plotDirection;
+ }
+
+ /**
+ * Get Plot Type.
+ *
+ * @return string
+ */
+ public function getPlotType()
+ {
+ return $this->plotType;
+ }
+
+ /**
+ * Set Plot Type.
+ *
+ * @param string $plotType
+ *
+ * @return $this
+ */
+ public function setPlotType($plotType)
+ {
+ $this->plotType = $plotType;
+
+ return $this;
+ }
+
+ /**
+ * Get Plot Grouping Type.
+ *
+ * @return string
+ */
+ public function getPlotGrouping()
+ {
+ return $this->plotGrouping;
+ }
+
+ /**
+ * Set Plot Grouping Type.
+ *
+ * @param string $groupingType
+ *
+ * @return $this
+ */
+ public function setPlotGrouping($groupingType)
+ {
+ $this->plotGrouping = $groupingType;
+
+ return $this;
+ }
+
+ /**
+ * Get Plot Direction.
+ *
+ * @return string
+ */
+ public function getPlotDirection()
+ {
+ return $this->plotDirection;
+ }
+
+ /**
+ * Set Plot Direction.
+ *
+ * @param string $plotDirection
+ *
+ * @return $this
+ */
+ public function setPlotDirection($plotDirection)
+ {
+ $this->plotDirection = $plotDirection;
+
+ return $this;
+ }
+
+ /**
+ * Get Plot Order.
+ *
+ * @return int[]
+ */
+ public function getPlotOrder()
+ {
+ return $this->plotOrder;
+ }
+
+ /**
+ * Get Plot Labels.
+ *
+ * @return array of DataSeriesValues
+ */
+ public function getPlotLabels()
+ {
+ return $this->plotLabel;
+ }
+
+ /**
+ * Get Plot Label by Index.
+ *
+ * @param mixed $index
+ *
+ * @return DataSeriesValues
+ */
+ public function getPlotLabelByIndex($index)
+ {
+ $keys = array_keys($this->plotLabel);
+ if (in_array($index, $keys)) {
+ return $this->plotLabel[$index];
+ } elseif (isset($keys[$index])) {
+ return $this->plotLabel[$keys[$index]];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get Plot Categories.
+ *
+ * @return array of DataSeriesValues
+ */
+ public function getPlotCategories()
+ {
+ return $this->plotCategory;
+ }
+
+ /**
+ * Get Plot Category by Index.
+ *
+ * @param mixed $index
+ *
+ * @return DataSeriesValues
+ */
+ public function getPlotCategoryByIndex($index)
+ {
+ $keys = array_keys($this->plotCategory);
+ if (in_array($index, $keys)) {
+ return $this->plotCategory[$index];
+ } elseif (isset($keys[$index])) {
+ return $this->plotCategory[$keys[$index]];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get Plot Style.
+ *
+ * @return null|string
+ */
+ public function getPlotStyle()
+ {
+ return $this->plotStyle;
+ }
+
+ /**
+ * Set Plot Style.
+ *
+ * @param null|string $plotStyle
+ *
+ * @return $this
+ */
+ public function setPlotStyle($plotStyle)
+ {
+ $this->plotStyle = $plotStyle;
+
+ return $this;
+ }
+
+ /**
+ * Get Plot Values.
+ *
+ * @return array of DataSeriesValues
+ */
+ public function getPlotValues()
+ {
+ return $this->plotValues;
+ }
+
+ /**
+ * Get Plot Values by Index.
+ *
+ * @param mixed $index
+ *
+ * @return DataSeriesValues
+ */
+ public function getPlotValuesByIndex($index)
+ {
+ $keys = array_keys($this->plotValues);
+ if (in_array($index, $keys)) {
+ return $this->plotValues[$index];
+ } elseif (isset($keys[$index])) {
+ return $this->plotValues[$keys[$index]];
+ }
+
+ return false;
+ }
+
+ /**
+ * Get Number of Plot Series.
+ *
+ * @return int
+ */
+ public function getPlotSeriesCount()
+ {
+ return count($this->plotValues);
+ }
+
+ /**
+ * Get Smooth Line.
+ *
+ * @return bool
+ */
+ public function getSmoothLine()
+ {
+ return $this->smoothLine;
+ }
+
+ /**
+ * Set Smooth Line.
+ *
+ * @param bool $smoothLine
+ *
+ * @return $this
+ */
+ public function setSmoothLine($smoothLine)
+ {
+ $this->smoothLine = $smoothLine;
+
+ return $this;
+ }
+
+ public function refresh(Worksheet $worksheet): void
+ {
+ foreach ($this->plotValues as $plotValues) {
+ if ($plotValues !== null) {
+ $plotValues->refresh($worksheet, true);
+ }
+ }
+ foreach ($this->plotLabel as $plotValues) {
+ if ($plotValues !== null) {
+ $plotValues->refresh($worksheet, true);
+ }
+ }
+ foreach ($this->plotCategory as $plotValues) {
+ if ($plotValues !== null) {
+ $plotValues->refresh($worksheet, false);
+ }
+ }
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeriesValues.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeriesValues.php
new file mode 100644
index 0000000..7aa7957
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/DataSeriesValues.php
@@ -0,0 +1,397 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
+use PhpOffice\PhpSpreadsheet\Calculation\Functions;
+use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class DataSeriesValues
+{
+ const DATASERIES_TYPE_STRING = 'String';
+ const DATASERIES_TYPE_NUMBER = 'Number';
+
+ private static $dataTypeValues = [
+ self::DATASERIES_TYPE_STRING,
+ self::DATASERIES_TYPE_NUMBER,
+ ];
+
+ /**
+ * Series Data Type.
+ *
+ * @var string
+ */
+ private $dataType;
+
+ /**
+ * Series Data Source.
+ *
+ * @var string
+ */
+ private $dataSource;
+
+ /**
+ * Format Code.
+ *
+ * @var string
+ */
+ private $formatCode;
+
+ /**
+ * Series Point Marker.
+ *
+ * @var string
+ */
+ private $pointMarker;
+
+ /**
+ * Point Count (The number of datapoints in the dataseries).
+ *
+ * @var int
+ */
+ private $pointCount = 0;
+
+ /**
+ * Data Values.
+ *
+ * @var array of mixed
+ */
+ private $dataValues = [];
+
+ /**
+ * Fill color (can be array with colors if dataseries have custom colors).
+ *
+ * @var string|string[]
+ */
+ private $fillColor;
+
+ /**
+ * Line Width.
+ *
+ * @var int
+ */
+ private $lineWidth = 12700;
+
+ /**
+ * Create a new DataSeriesValues object.
+ *
+ * @param string $dataType
+ * @param string $dataSource
+ * @param null|mixed $formatCode
+ * @param int $pointCount
+ * @param mixed $dataValues
+ * @param null|mixed $marker
+ * @param null|string|string[] $fillColor
+ */
+ public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null)
+ {
+ $this->setDataType($dataType);
+ $this->dataSource = $dataSource;
+ $this->formatCode = $formatCode;
+ $this->pointCount = $pointCount;
+ $this->dataValues = $dataValues;
+ $this->pointMarker = $marker;
+ $this->fillColor = $fillColor;
+ }
+
+ /**
+ * Get Series Data Type.
+ *
+ * @return string
+ */
+ public function getDataType()
+ {
+ return $this->dataType;
+ }
+
+ /**
+ * Set Series Data Type.
+ *
+ * @param string $dataType Datatype of this data series
+ * Typical values are:
+ * DataSeriesValues::DATASERIES_TYPE_STRING
+ * Normally used for axis point values
+ * DataSeriesValues::DATASERIES_TYPE_NUMBER
+ * Normally used for chart data values
+ *
+ * @return $this
+ */
+ public function setDataType($dataType)
+ {
+ if (!in_array($dataType, self::$dataTypeValues)) {
+ throw new Exception('Invalid datatype for chart data series values');
+ }
+ $this->dataType = $dataType;
+
+ return $this;
+ }
+
+ /**
+ * Get Series Data Source (formula).
+ *
+ * @return string
+ */
+ public function getDataSource()
+ {
+ return $this->dataSource;
+ }
+
+ /**
+ * Set Series Data Source (formula).
+ *
+ * @param string $dataSource
+ *
+ * @return $this
+ */
+ public function setDataSource($dataSource)
+ {
+ $this->dataSource = $dataSource;
+
+ return $this;
+ }
+
+ /**
+ * Get Point Marker.
+ *
+ * @return string
+ */
+ public function getPointMarker()
+ {
+ return $this->pointMarker;
+ }
+
+ /**
+ * Set Point Marker.
+ *
+ * @param string $marker
+ *
+ * @return $this
+ */
+ public function setPointMarker($marker)
+ {
+ $this->pointMarker = $marker;
+
+ return $this;
+ }
+
+ /**
+ * Get Series Format Code.
+ *
+ * @return string
+ */
+ public function getFormatCode()
+ {
+ return $this->formatCode;
+ }
+
+ /**
+ * Set Series Format Code.
+ *
+ * @param string $formatCode
+ *
+ * @return $this
+ */
+ public function setFormatCode($formatCode)
+ {
+ $this->formatCode = $formatCode;
+
+ return $this;
+ }
+
+ /**
+ * Get Series Point Count.
+ *
+ * @return int
+ */
+ public function getPointCount()
+ {
+ return $this->pointCount;
+ }
+
+ /**
+ * Get fill color.
+ *
+ * @return string|string[] HEX color or array with HEX colors
+ */
+ public function getFillColor()
+ {
+ return $this->fillColor;
+ }
+
+ /**
+ * Set fill color for series.
+ *
+ * @param string|string[] $color HEX color or array with HEX colors
+ *
+ * @return DataSeriesValues
+ */
+ public function setFillColor($color)
+ {
+ if (is_array($color)) {
+ foreach ($color as $colorValue) {
+ $this->validateColor($colorValue);
+ }
+ } else {
+ $this->validateColor($color);
+ }
+ $this->fillColor = $color;
+
+ return $this;
+ }
+
+ /**
+ * Method for validating hex color.
+ *
+ * @param string $color value for color
+ *
+ * @return bool true if validation was successful
+ */
+ private function validateColor($color)
+ {
+ if (!preg_match('/^[a-f0-9]{6}$/i', $color)) {
+ throw new Exception(sprintf('Invalid hex color for chart series (color: "%s")', $color));
+ }
+
+ return true;
+ }
+
+ /**
+ * Get line width for series.
+ *
+ * @return int
+ */
+ public function getLineWidth()
+ {
+ return $this->lineWidth;
+ }
+
+ /**
+ * Set line width for the series.
+ *
+ * @param int $width
+ *
+ * @return $this
+ */
+ public function setLineWidth($width)
+ {
+ $minWidth = 12700;
+ $this->lineWidth = max($minWidth, $width);
+
+ return $this;
+ }
+
+ /**
+ * Identify if the Data Series is a multi-level or a simple series.
+ *
+ * @return null|bool
+ */
+ public function isMultiLevelSeries()
+ {
+ if (count($this->dataValues) > 0) {
+ return is_array(array_values($this->dataValues)[0]);
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the level count of a multi-level Data Series.
+ *
+ * @return int
+ */
+ public function multiLevelCount()
+ {
+ $levelCount = 0;
+ foreach ($this->dataValues as $dataValueSet) {
+ $levelCount = max($levelCount, count($dataValueSet));
+ }
+
+ return $levelCount;
+ }
+
+ /**
+ * Get Series Data Values.
+ *
+ * @return array of mixed
+ */
+ public function getDataValues()
+ {
+ return $this->dataValues;
+ }
+
+ /**
+ * Get the first Series Data value.
+ *
+ * @return mixed
+ */
+ public function getDataValue()
+ {
+ $count = count($this->dataValues);
+ if ($count == 0) {
+ return null;
+ } elseif ($count == 1) {
+ return $this->dataValues[0];
+ }
+
+ return $this->dataValues;
+ }
+
+ /**
+ * Set Series Data Values.
+ *
+ * @param array $dataValues
+ *
+ * @return $this
+ */
+ public function setDataValues($dataValues)
+ {
+ $this->dataValues = Functions::flattenArray($dataValues);
+ $this->pointCount = count($dataValues);
+
+ return $this;
+ }
+
+ public function refresh(Worksheet $worksheet, $flatten = true): void
+ {
+ if ($this->dataSource !== null) {
+ $calcEngine = Calculation::getInstance($worksheet->getParent());
+ $newDataValues = Calculation::unwrapResult(
+ $calcEngine->_calculateFormulaValue(
+ '=' . $this->dataSource,
+ null,
+ $worksheet->getCell('A1')
+ )
+ );
+ if ($flatten) {
+ $this->dataValues = Functions::flattenArray($newDataValues);
+ foreach ($this->dataValues as &$dataValue) {
+ if (is_string($dataValue) && !empty($dataValue) && $dataValue[0] == '#') {
+ $dataValue = 0.0;
+ }
+ }
+ unset($dataValue);
+ } else {
+ [$worksheet, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true);
+ $dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange));
+ if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
+ $this->dataValues = Functions::flattenArray($newDataValues);
+ } else {
+ $newArray = array_values(array_shift($newDataValues));
+ foreach ($newArray as $i => $newDataSet) {
+ $newArray[$i] = [$newDataSet];
+ }
+
+ foreach ($newDataValues as $newDataSet) {
+ $i = 0;
+ foreach ($newDataSet as $newDataVal) {
+ array_unshift($newArray[$i++], $newDataVal);
+ }
+ }
+ $this->dataValues = $newArray;
+ }
+ }
+ $this->pointCount = count($this->dataValues);
+ }
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Exception.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Exception.php
new file mode 100644
index 0000000..98229a5
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Exception.php
@@ -0,0 +1,9 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
+
+class Exception extends PhpSpreadsheetException
+{
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/GridLines.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/GridLines.php
new file mode 100644
index 0000000..3b704ec
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/GridLines.php
@@ -0,0 +1,454 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+/**
+ * Created by PhpStorm.
+ * User: Wiktor Trzonkowski
+ * Date: 7/2/14
+ * Time: 2:36 PM.
+ */
+class GridLines extends Properties
+{
+ /**
+ * Properties of Class:
+ * Object State (State for Minor Tick Mark) @var bool
+ * Line Properties @var array of mixed
+ * Shadow Properties @var array of mixed
+ * Glow Properties @var array of mixed
+ * Soft Properties @var array of mixed.
+ */
+ private $objectState = false;
+
+ private $lineProperties = [
+ 'color' => [
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => null,
+ 'alpha' => 0,
+ ],
+ 'style' => [
+ 'width' => '9525',
+ 'compound' => self::LINE_STYLE_COMPOUND_SIMPLE,
+ 'dash' => self::LINE_STYLE_DASH_SOLID,
+ 'cap' => self::LINE_STYLE_CAP_FLAT,
+ 'join' => self::LINE_STYLE_JOIN_BEVEL,
+ 'arrow' => [
+ 'head' => [
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_5,
+ ],
+ 'end' => [
+ 'type' => self::LINE_STYLE_ARROW_TYPE_NOARROW,
+ 'size' => self::LINE_STYLE_ARROW_SIZE_8,
+ ],
+ ],
+ ],
+ ];
+
+ private $shadowProperties = [
+ 'presets' => self::SHADOW_PRESETS_NOSHADOW,
+ 'effect' => null,
+ 'color' => [
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 85,
+ ],
+ 'size' => [
+ 'sx' => null,
+ 'sy' => null,
+ 'kx' => null,
+ ],
+ 'blur' => null,
+ 'direction' => null,
+ 'distance' => null,
+ 'algn' => null,
+ 'rotWithShape' => null,
+ ];
+
+ private $glowProperties = [
+ 'size' => null,
+ 'color' => [
+ 'type' => self::EXCEL_COLOR_TYPE_STANDARD,
+ 'value' => 'black',
+ 'alpha' => 40,
+ ],
+ ];
+
+ private $softEdges = [
+ 'size' => null,
+ ];
+
+ /**
+ * Get Object State.
+ *
+ * @return bool
+ */
+ public function getObjectState()
+ {
+ return $this->objectState;
+ }
+
+ /**
+ * Change Object State to True.
+ *
+ * @return $this
+ */
+ private function activateObject()
+ {
+ $this->objectState = true;
+
+ return $this;
+ }
+
+ /**
+ * Set Line Color Properties.
+ *
+ * @param string $value
+ * @param int $alpha
+ * @param string $type
+ */
+ public function setLineColorProperties($value, $alpha = 0, $type = self::EXCEL_COLOR_TYPE_STANDARD): void
+ {
+ $this->activateObject()
+ ->lineProperties['color'] = $this->setColorProperties(
+ $value,
+ $alpha,
+ $type
+ );
+ }
+
+ /**
+ * Set Line Color Properties.
+ *
+ * @param float $line_width
+ * @param string $compound_type
+ * @param string $dash_type
+ * @param string $cap_type
+ * @param string $join_type
+ * @param string $head_arrow_type
+ * @param string $head_arrow_size
+ * @param string $end_arrow_type
+ * @param string $end_arrow_size
+ */
+ public function setLineStyleProperties($line_width = null, $compound_type = null, $dash_type = null, $cap_type = null, $join_type = null, $head_arrow_type = null, $head_arrow_size = null, $end_arrow_type = null, $end_arrow_size = null): void
+ {
+ $this->activateObject();
+ ($line_width !== null)
+ ? $this->lineProperties['style']['width'] = $this->getExcelPointsWidth((float) $line_width)
+ : null;
+ ($compound_type !== null)
+ ? $this->lineProperties['style']['compound'] = (string) $compound_type
+ : null;
+ ($dash_type !== null)
+ ? $this->lineProperties['style']['dash'] = (string) $dash_type
+ : null;
+ ($cap_type !== null)
+ ? $this->lineProperties['style']['cap'] = (string) $cap_type
+ : null;
+ ($join_type !== null)
+ ? $this->lineProperties['style']['join'] = (string) $join_type
+ : null;
+ ($head_arrow_type !== null)
+ ? $this->lineProperties['style']['arrow']['head']['type'] = (string) $head_arrow_type
+ : null;
+ ($head_arrow_size !== null)
+ ? $this->lineProperties['style']['arrow']['head']['size'] = (string) $head_arrow_size
+ : null;
+ ($end_arrow_type !== null)
+ ? $this->lineProperties['style']['arrow']['end']['type'] = (string) $end_arrow_type
+ : null;
+ ($end_arrow_size !== null)
+ ? $this->lineProperties['style']['arrow']['end']['size'] = (string) $end_arrow_size
+ : null;
+ }
+
+ /**
+ * Get Line Color Property.
+ *
+ * @param string $parameter
+ *
+ * @return string
+ */
+ public function getLineColorProperty($parameter)
+ {
+ return $this->lineProperties['color'][$parameter];
+ }
+
+ /**
+ * Get Line Style Property.
+ *
+ * @param array|string $elements
+ *
+ * @return string
+ */
+ public function getLineStyleProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->lineProperties['style'], $elements);
+ }
+
+ /**
+ * Set Glow Properties.
+ *
+ * @param float $size
+ * @param string $color_value
+ * @param int $color_alpha
+ * @param string $color_type
+ */
+ public function setGlowProperties($size, $color_value = null, $color_alpha = null, $color_type = null): void
+ {
+ $this
+ ->activateObject()
+ ->setGlowSize($size)
+ ->setGlowColor($color_value, $color_alpha, $color_type);
+ }
+
+ /**
+ * Get Glow Color Property.
+ *
+ * @param string $property
+ *
+ * @return string
+ */
+ public function getGlowColor($property)
+ {
+ return $this->glowProperties['color'][$property];
+ }
+
+ /**
+ * Get Glow Size.
+ *
+ * @return string
+ */
+ public function getGlowSize()
+ {
+ return $this->glowProperties['size'];
+ }
+
+ /**
+ * Set Glow Size.
+ *
+ * @param float $size
+ *
+ * @return $this
+ */
+ private function setGlowSize($size)
+ {
+ $this->glowProperties['size'] = $this->getExcelPointsWidth((float) $size);
+
+ return $this;
+ }
+
+ /**
+ * Set Glow Color.
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ * @return $this
+ */
+ private function setGlowColor($color, $alpha, $type)
+ {
+ if ($color !== null) {
+ $this->glowProperties['color']['value'] = (string) $color;
+ }
+ if ($alpha !== null) {
+ $this->glowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha);
+ }
+ if ($type !== null) {
+ $this->glowProperties['color']['type'] = (string) $type;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Line Style Arrow Parameters.
+ *
+ * @param string $arrow_selector
+ * @param string $property_selector
+ *
+ * @return string
+ */
+ public function getLineStyleArrowParameters($arrow_selector, $property_selector)
+ {
+ return $this->getLineStyleArrowSize($this->lineProperties['style']['arrow'][$arrow_selector]['size'], $property_selector);
+ }
+
+ /**
+ * Set Shadow Properties.
+ *
+ * @param int $sh_presets
+ * @param string $sh_color_value
+ * @param string $sh_color_type
+ * @param int $sh_color_alpha
+ * @param string $sh_blur
+ * @param int $sh_angle
+ * @param float $sh_distance
+ */
+ public function setShadowProperties($sh_presets, $sh_color_value = null, $sh_color_type = null, $sh_color_alpha = null, $sh_blur = null, $sh_angle = null, $sh_distance = null): void
+ {
+ $this->activateObject()
+ ->setShadowPresetsProperties((int) $sh_presets)
+ ->setShadowColor(
+ $sh_color_value === null ? $this->shadowProperties['color']['value'] : $sh_color_value,
+ $sh_color_alpha === null ? (int) $this->shadowProperties['color']['alpha'] : $this->getTrueAlpha($sh_color_alpha),
+ $sh_color_type === null ? $this->shadowProperties['color']['type'] : $sh_color_type
+ )
+ ->setShadowBlur($sh_blur)
+ ->setShadowAngle($sh_angle)
+ ->setShadowDistance($sh_distance);
+ }
+
+ /**
+ * Set Shadow Presets Properties.
+ *
+ * @param int $shadow_presets
+ *
+ * @return $this
+ */
+ private function setShadowPresetsProperties($shadow_presets)
+ {
+ $this->shadowProperties['presets'] = $shadow_presets;
+ $this->setShadowProperiesMapValues($this->getShadowPresetsMap($shadow_presets));
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Properties Values.
+ *
+ * @param mixed &$reference
+ *
+ * @return $this
+ */
+ private function setShadowProperiesMapValues(array $properties_map, &$reference = null)
+ {
+ $base_reference = $reference;
+ foreach ($properties_map as $property_key => $property_val) {
+ if (is_array($property_val)) {
+ if ($reference === null) {
+ $reference = &$this->shadowProperties[$property_key];
+ } else {
+ $reference = &$reference[$property_key];
+ }
+ $this->setShadowProperiesMapValues($property_val, $reference);
+ } else {
+ if ($base_reference === null) {
+ $this->shadowProperties[$property_key] = $property_val;
+ } else {
+ $reference[$property_key] = $property_val;
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Color.
+ *
+ * @param string $color
+ * @param int $alpha
+ * @param string $type
+ *
+ * @return $this
+ */
+ private function setShadowColor($color, $alpha, $type)
+ {
+ if ($color !== null) {
+ $this->shadowProperties['color']['value'] = (string) $color;
+ }
+ if ($alpha !== null) {
+ $this->shadowProperties['color']['alpha'] = $this->getTrueAlpha((int) $alpha);
+ }
+ if ($type !== null) {
+ $this->shadowProperties['color']['type'] = (string) $type;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Blur.
+ *
+ * @param float $blur
+ *
+ * @return $this
+ */
+ private function setShadowBlur($blur)
+ {
+ if ($blur !== null) {
+ $this->shadowProperties['blur'] = (string) $this->getExcelPointsWidth($blur);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Angle.
+ *
+ * @param int $angle
+ *
+ * @return $this
+ */
+ private function setShadowAngle($angle)
+ {
+ if ($angle !== null) {
+ $this->shadowProperties['direction'] = (string) $this->getExcelPointsAngle($angle);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set Shadow Distance.
+ *
+ * @param float $distance
+ *
+ * @return $this
+ */
+ private function setShadowDistance($distance)
+ {
+ if ($distance !== null) {
+ $this->shadowProperties['distance'] = (string) $this->getExcelPointsWidth($distance);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get Shadow Property.
+ *
+ * @param string|string[] $elements
+ *
+ * @return string
+ */
+ public function getShadowProperty($elements)
+ {
+ return $this->getArrayElementsValue($this->shadowProperties, $elements);
+ }
+
+ /**
+ * Set Soft Edges Size.
+ *
+ * @param float $size
+ */
+ public function setSoftEdgesSize($size): void
+ {
+ if ($size !== null) {
+ $this->activateObject();
+ $this->softEdges['size'] = (string) $this->getExcelPointsWidth($size);
+ }
+ }
+
+ /**
+ * Get Soft Edges Size.
+ *
+ * @return string
+ */
+ public function getSoftEdgesSize()
+ {
+ return $this->softEdges['size'];
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php
new file mode 100644
index 0000000..4ac86df
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Layout.php
@@ -0,0 +1,481 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+class Layout
+{
+ /**
+ * layoutTarget.
+ *
+ * @var string
+ */
+ private $layoutTarget;
+
+ /**
+ * X Mode.
+ *
+ * @var string
+ */
+ private $xMode;
+
+ /**
+ * Y Mode.
+ *
+ * @var string
+ */
+ private $yMode;
+
+ /**
+ * X-Position.
+ *
+ * @var float
+ */
+ private $xPos;
+
+ /**
+ * Y-Position.
+ *
+ * @var float
+ */
+ private $yPos;
+
+ /**
+ * width.
+ *
+ * @var float
+ */
+ private $width;
+
+ /**
+ * height.
+ *
+ * @var float
+ */
+ private $height;
+
+ /**
+ * show legend key
+ * Specifies that legend keys should be shown in data labels.
+ *
+ * @var bool
+ */
+ private $showLegendKey;
+
+ /**
+ * show value
+ * Specifies that the value should be shown in a data label.
+ *
+ * @var bool
+ */
+ private $showVal;
+
+ /**
+ * show category name
+ * Specifies that the category name should be shown in the data label.
+ *
+ * @var bool
+ */
+ private $showCatName;
+
+ /**
+ * show data series name
+ * Specifies that the series name should be shown in the data label.
+ *
+ * @var bool
+ */
+ private $showSerName;
+
+ /**
+ * show percentage
+ * Specifies that the percentage should be shown in the data label.
+ *
+ * @var bool
+ */
+ private $showPercent;
+
+ /**
+ * show bubble size.
+ *
+ * @var bool
+ */
+ private $showBubbleSize;
+
+ /**
+ * show leader lines
+ * Specifies that leader lines should be shown for the data label.
+ *
+ * @var bool
+ */
+ private $showLeaderLines;
+
+ /**
+ * Create a new Layout.
+ */
+ public function __construct(array $layout = [])
+ {
+ if (isset($layout['layoutTarget'])) {
+ $this->layoutTarget = $layout['layoutTarget'];
+ }
+ if (isset($layout['xMode'])) {
+ $this->xMode = $layout['xMode'];
+ }
+ if (isset($layout['yMode'])) {
+ $this->yMode = $layout['yMode'];
+ }
+ if (isset($layout['x'])) {
+ $this->xPos = (float) $layout['x'];
+ }
+ if (isset($layout['y'])) {
+ $this->yPos = (float) $layout['y'];
+ }
+ if (isset($layout['w'])) {
+ $this->width = (float) $layout['w'];
+ }
+ if (isset($layout['h'])) {
+ $this->height = (float) $layout['h'];
+ }
+ }
+
+ /**
+ * Get Layout Target.
+ *
+ * @return string
+ */
+ public function getLayoutTarget()
+ {
+ return $this->layoutTarget;
+ }
+
+ /**
+ * Set Layout Target.
+ *
+ * @param string $value
+ *
+ * @return $this
+ */
+ public function setLayoutTarget($value)
+ {
+ $this->layoutTarget = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get X-Mode.
+ *
+ * @return string
+ */
+ public function getXMode()
+ {
+ return $this->xMode;
+ }
+
+ /**
+ * Set X-Mode.
+ *
+ * @param string $value
+ *
+ * @return $this
+ */
+ public function setXMode($value)
+ {
+ $this->xMode = (string) $value;
+
+ return $this;
+ }
+
+ /**
+ * Get Y-Mode.
+ *
+ * @return string
+ */
+ public function getYMode()
+ {
+ return $this->yMode;
+ }
+
+ /**
+ * Set Y-Mode.
+ *
+ * @param string $value
+ *
+ * @return $this
+ */
+ public function setYMode($value)
+ {
+ $this->yMode = (string) $value;
+
+ return $this;
+ }
+
+ /**
+ * Get X-Position.
+ *
+ * @return number
+ */
+ public function getXPosition()
+ {
+ return $this->xPos;
+ }
+
+ /**
+ * Set X-Position.
+ *
+ * @param float $value
+ *
+ * @return $this
+ */
+ public function setXPosition($value)
+ {
+ $this->xPos = (float) $value;
+
+ return $this;
+ }
+
+ /**
+ * Get Y-Position.
+ *
+ * @return number
+ */
+ public function getYPosition()
+ {
+ return $this->yPos;
+ }
+
+ /**
+ * Set Y-Position.
+ *
+ * @param float $value
+ *
+ * @return $this
+ */
+ public function setYPosition($value)
+ {
+ $this->yPos = (float) $value;
+
+ return $this;
+ }
+
+ /**
+ * Get Width.
+ *
+ * @return number
+ */
+ public function getWidth()
+ {
+ return $this->width;
+ }
+
+ /**
+ * Set Width.
+ *
+ * @param float $value
+ *
+ * @return $this
+ */
+ public function setWidth($value)
+ {
+ $this->width = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get Height.
+ *
+ * @return number
+ */
+ public function getHeight()
+ {
+ return $this->height;
+ }
+
+ /**
+ * Set Height.
+ *
+ * @param float $value
+ *
+ * @return $this
+ */
+ public function setHeight($value)
+ {
+ $this->height = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get show legend key.
+ *
+ * @return bool
+ */
+ public function getShowLegendKey()
+ {
+ return $this->showLegendKey;
+ }
+
+ /**
+ * Set show legend key
+ * Specifies that legend keys should be shown in data labels.
+ *
+ * @param bool $value Show legend key
+ *
+ * @return $this
+ */
+ public function setShowLegendKey($value)
+ {
+ $this->showLegendKey = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get show value.
+ *
+ * @return bool
+ */
+ public function getShowVal()
+ {
+ return $this->showVal;
+ }
+
+ /**
+ * Set show val
+ * Specifies that the value should be shown in data labels.
+ *
+ * @param bool $value Show val
+ *
+ * @return $this
+ */
+ public function setShowVal($value)
+ {
+ $this->showVal = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get show category name.
+ *
+ * @return bool
+ */
+ public function getShowCatName()
+ {
+ return $this->showCatName;
+ }
+
+ /**
+ * Set show cat name
+ * Specifies that the category name should be shown in data labels.
+ *
+ * @param bool $value Show cat name
+ *
+ * @return $this
+ */
+ public function setShowCatName($value)
+ {
+ $this->showCatName = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get show data series name.
+ *
+ * @return bool
+ */
+ public function getShowSerName()
+ {
+ return $this->showSerName;
+ }
+
+ /**
+ * Set show ser name
+ * Specifies that the series name should be shown in data labels.
+ *
+ * @param bool $value Show series name
+ *
+ * @return $this
+ */
+ public function setShowSerName($value)
+ {
+ $this->showSerName = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get show percentage.
+ *
+ * @return bool
+ */
+ public function getShowPercent()
+ {
+ return $this->showPercent;
+ }
+
+ /**
+ * Set show percentage
+ * Specifies that the percentage should be shown in data labels.
+ *
+ * @param bool $value Show percentage
+ *
+ * @return $this
+ */
+ public function setShowPercent($value)
+ {
+ $this->showPercent = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get show bubble size.
+ *
+ * @return bool
+ */
+ public function getShowBubbleSize()
+ {
+ return $this->showBubbleSize;
+ }
+
+ /**
+ * Set show bubble size
+ * Specifies that the bubble size should be shown in data labels.
+ *
+ * @param bool $value Show bubble size
+ *
+ * @return $this
+ */
+ public function setShowBubbleSize($value)
+ {
+ $this->showBubbleSize = $value;
+
+ return $this;
+ }
+
+ /**
+ * Get show leader lines.
+ *
+ * @return bool
+ */
+ public function getShowLeaderLines()
+ {
+ return $this->showLeaderLines;
+ }
+
+ /**
+ * Set show leader lines
+ * Specifies that leader lines should be shown in data labels.
+ *
+ * @param bool $value Show leader lines
+ *
+ * @return $this
+ */
+ public function setShowLeaderLines($value)
+ {
+ $this->showLeaderLines = $value;
+
+ return $this;
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php
new file mode 100644
index 0000000..9af5c5b
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Legend.php
@@ -0,0 +1,157 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+class Legend
+{
+ /** Legend positions */
+ const XL_LEGEND_POSITION_BOTTOM = -4107; // Below the chart.
+ const XL_LEGEND_POSITION_CORNER = 2; // In the upper right-hand corner of the chart border.
+ const XL_LEGEND_POSITION_CUSTOM = -4161; // A custom position.
+ const XL_LEGEND_POSITION_LEFT = -4131; // Left of the chart.
+ const XL_LEGEND_POSITION_RIGHT = -4152; // Right of the chart.
+ const XL_LEGEND_POSITION_TOP = -4160; // Above the chart.
+
+ const POSITION_RIGHT = 'r';
+ const POSITION_LEFT = 'l';
+ const POSITION_BOTTOM = 'b';
+ const POSITION_TOP = 't';
+ const POSITION_TOPRIGHT = 'tr';
+
+ private static $positionXLref = [
+ self::XL_LEGEND_POSITION_BOTTOM => self::POSITION_BOTTOM,
+ self::XL_LEGEND_POSITION_CORNER => self::POSITION_TOPRIGHT,
+ self::XL_LEGEND_POSITION_CUSTOM => '??',
+ self::XL_LEGEND_POSITION_LEFT => self::POSITION_LEFT,
+ self::XL_LEGEND_POSITION_RIGHT => self::POSITION_RIGHT,
+ self::XL_LEGEND_POSITION_TOP => self::POSITION_TOP,
+ ];
+
+ /**
+ * Legend position.
+ *
+ * @var string
+ */
+ private $position = self::POSITION_RIGHT;
+
+ /**
+ * Allow overlay of other elements?
+ *
+ * @var bool
+ */
+ private $overlay = true;
+
+ /**
+ * Legend Layout.
+ *
+ * @var Layout
+ */
+ private $layout;
+
+ /**
+ * Create a new Legend.
+ *
+ * @param string $position
+ * @param bool $overlay
+ */
+ public function __construct($position = self::POSITION_RIGHT, ?Layout $layout = null, $overlay = false)
+ {
+ $this->setPosition($position);
+ $this->layout = $layout;
+ $this->setOverlay($overlay);
+ }
+
+ /**
+ * Get legend position as an excel string value.
+ *
+ * @return string
+ */
+ public function getPosition()
+ {
+ return $this->position;
+ }
+
+ /**
+ * Get legend position using an excel string value.
+ *
+ * @param string $position see self::POSITION_*
+ *
+ * @return bool
+ */
+ public function setPosition($position)
+ {
+ if (!in_array($position, self::$positionXLref)) {
+ return false;
+ }
+
+ $this->position = $position;
+
+ return true;
+ }
+
+ /**
+ * Get legend position as an Excel internal numeric value.
+ *
+ * @return int
+ */
+ public function getPositionXL()
+ {
+ return array_search($this->position, self::$positionXLref);
+ }
+
+ /**
+ * Set legend position using an Excel internal numeric value.
+ *
+ * @param int $positionXL see self::XL_LEGEND_POSITION_*
+ *
+ * @return bool
+ */
+ public function setPositionXL($positionXL)
+ {
+ if (!isset(self::$positionXLref[$positionXL])) {
+ return false;
+ }
+
+ $this->position = self::$positionXLref[$positionXL];
+
+ return true;
+ }
+
+ /**
+ * Get allow overlay of other elements?
+ *
+ * @return bool
+ */
+ public function getOverlay()
+ {
+ return $this->overlay;
+ }
+
+ /**
+ * Set allow overlay of other elements?
+ *
+ * @param bool $overlay
+ *
+ * @return bool
+ */
+ public function setOverlay($overlay)
+ {
+ if (!is_bool($overlay)) {
+ return false;
+ }
+
+ $this->overlay = $overlay;
+
+ return true;
+ }
+
+ /**
+ * Get Layout.
+ *
+ * @return Layout
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php
new file mode 100644
index 0000000..03939d3
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/PlotArea.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
+
+class PlotArea
+{
+ /**
+ * PlotArea Layout.
+ *
+ * @var Layout
+ */
+ private $layout;
+
+ /**
+ * Plot Series.
+ *
+ * @var DataSeries[]
+ */
+ private $plotSeries = [];
+
+ /**
+ * Create a new PlotArea.
+ *
+ * @param DataSeries[] $plotSeries
+ */
+ public function __construct(?Layout $layout = null, array $plotSeries = [])
+ {
+ $this->layout = $layout;
+ $this->plotSeries = $plotSeries;
+ }
+
+ /**
+ * Get Layout.
+ *
+ * @return Layout
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+
+ /**
+ * Get Number of Plot Groups.
+ *
+ * @return array of DataSeries
+ */
+ public function getPlotGroupCount()
+ {
+ return count($this->plotSeries);
+ }
+
+ /**
+ * Get Number of Plot Series.
+ *
+ * @return int
+ */
+ public function getPlotSeriesCount()
+ {
+ $seriesCount = 0;
+ foreach ($this->plotSeries as $plot) {
+ $seriesCount += $plot->getPlotSeriesCount();
+ }
+
+ return $seriesCount;
+ }
+
+ /**
+ * Get Plot Series.
+ *
+ * @return array of DataSeries
+ */
+ public function getPlotGroup()
+ {
+ return $this->plotSeries;
+ }
+
+ /**
+ * Get Plot Series by Index.
+ *
+ * @param mixed $index
+ *
+ * @return DataSeries
+ */
+ public function getPlotGroupByIndex($index)
+ {
+ return $this->plotSeries[$index];
+ }
+
+ /**
+ * Set Plot Series.
+ *
+ * @param DataSeries[] $plotSeries
+ *
+ * @return $this
+ */
+ public function setPlotSeries(array $plotSeries)
+ {
+ $this->plotSeries = $plotSeries;
+
+ return $this;
+ }
+
+ public function refresh(Worksheet $worksheet): void
+ {
+ foreach ($this->plotSeries as $plotSeries) {
+ $plotSeries->refresh($worksheet);
+ }
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Properties.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Properties.php
new file mode 100644
index 0000000..8749a0d
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Properties.php
@@ -0,0 +1,369 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+/**
+ * Created by PhpStorm.
+ * User: nhw2h8s
+ * Date: 7/2/14
+ * Time: 5:45 PM.
+ */
+abstract class Properties
+{
+ const
+ EXCEL_COLOR_TYPE_STANDARD = 'prstClr';
+ const EXCEL_COLOR_TYPE_SCHEME = 'schemeClr';
+ const EXCEL_COLOR_TYPE_ARGB = 'srgbClr';
+
+ const
+ AXIS_LABELS_LOW = 'low';
+ const AXIS_LABELS_HIGH = 'high';
+ const AXIS_LABELS_NEXT_TO = 'nextTo';
+ const AXIS_LABELS_NONE = 'none';
+
+ const
+ TICK_MARK_NONE = 'none';
+ const TICK_MARK_INSIDE = 'in';
+ const TICK_MARK_OUTSIDE = 'out';
+ const TICK_MARK_CROSS = 'cross';
+
+ const
+ HORIZONTAL_CROSSES_AUTOZERO = 'autoZero';
+ const HORIZONTAL_CROSSES_MAXIMUM = 'max';
+
+ const
+ FORMAT_CODE_GENERAL = 'General';
+ const FORMAT_CODE_NUMBER = '#,##0.00';
+ const FORMAT_CODE_CURRENCY = '$#,##0.00';
+ const FORMAT_CODE_ACCOUNTING = '_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_)';
+ const FORMAT_CODE_DATE = 'm/d/yyyy';
+ const FORMAT_CODE_TIME = '[$-F400]h:mm:ss AM/PM';
+ const FORMAT_CODE_PERCENTAGE = '0.00%';
+ const FORMAT_CODE_FRACTION = '# ?/?';
+ const FORMAT_CODE_SCIENTIFIC = '0.00E+00';
+ const FORMAT_CODE_TEXT = '@';
+ const FORMAT_CODE_SPECIAL = '00000';
+
+ const
+ ORIENTATION_NORMAL = 'minMax';
+ const ORIENTATION_REVERSED = 'maxMin';
+
+ const
+ LINE_STYLE_COMPOUND_SIMPLE = 'sng';
+ const LINE_STYLE_COMPOUND_DOUBLE = 'dbl';
+ const LINE_STYLE_COMPOUND_THICKTHIN = 'thickThin';
+ const LINE_STYLE_COMPOUND_THINTHICK = 'thinThick';
+ const LINE_STYLE_COMPOUND_TRIPLE = 'tri';
+ const LINE_STYLE_DASH_SOLID = 'solid';
+ const LINE_STYLE_DASH_ROUND_DOT = 'sysDot';
+ const LINE_STYLE_DASH_SQUERE_DOT = 'sysDash';
+ const LINE_STYPE_DASH_DASH = 'dash';
+ const LINE_STYLE_DASH_DASH_DOT = 'dashDot';
+ const LINE_STYLE_DASH_LONG_DASH = 'lgDash';
+ const LINE_STYLE_DASH_LONG_DASH_DOT = 'lgDashDot';
+ const LINE_STYLE_DASH_LONG_DASH_DOT_DOT = 'lgDashDotDot';
+ const LINE_STYLE_CAP_SQUARE = 'sq';
+ const LINE_STYLE_CAP_ROUND = 'rnd';
+ const LINE_STYLE_CAP_FLAT = 'flat';
+ const LINE_STYLE_JOIN_ROUND = 'bevel';
+ const LINE_STYLE_JOIN_MITER = 'miter';
+ const LINE_STYLE_JOIN_BEVEL = 'bevel';
+ const LINE_STYLE_ARROW_TYPE_NOARROW = null;
+ const LINE_STYLE_ARROW_TYPE_ARROW = 'triangle';
+ const LINE_STYLE_ARROW_TYPE_OPEN = 'arrow';
+ const LINE_STYLE_ARROW_TYPE_STEALTH = 'stealth';
+ const LINE_STYLE_ARROW_TYPE_DIAMOND = 'diamond';
+ const LINE_STYLE_ARROW_TYPE_OVAL = 'oval';
+ const LINE_STYLE_ARROW_SIZE_1 = 1;
+ const LINE_STYLE_ARROW_SIZE_2 = 2;
+ const LINE_STYLE_ARROW_SIZE_3 = 3;
+ const LINE_STYLE_ARROW_SIZE_4 = 4;
+ const LINE_STYLE_ARROW_SIZE_5 = 5;
+ const LINE_STYLE_ARROW_SIZE_6 = 6;
+ const LINE_STYLE_ARROW_SIZE_7 = 7;
+ const LINE_STYLE_ARROW_SIZE_8 = 8;
+ const LINE_STYLE_ARROW_SIZE_9 = 9;
+
+ const
+ SHADOW_PRESETS_NOSHADOW = null;
+ const SHADOW_PRESETS_OUTER_BOTTTOM_RIGHT = 1;
+ const SHADOW_PRESETS_OUTER_BOTTOM = 2;
+ const SHADOW_PRESETS_OUTER_BOTTOM_LEFT = 3;
+ const SHADOW_PRESETS_OUTER_RIGHT = 4;
+ const SHADOW_PRESETS_OUTER_CENTER = 5;
+ const SHADOW_PRESETS_OUTER_LEFT = 6;
+ const SHADOW_PRESETS_OUTER_TOP_RIGHT = 7;
+ const SHADOW_PRESETS_OUTER_TOP = 8;
+ const SHADOW_PRESETS_OUTER_TOP_LEFT = 9;
+ const SHADOW_PRESETS_INNER_BOTTTOM_RIGHT = 10;
+ const SHADOW_PRESETS_INNER_BOTTOM = 11;
+ const SHADOW_PRESETS_INNER_BOTTOM_LEFT = 12;
+ const SHADOW_PRESETS_INNER_RIGHT = 13;
+ const SHADOW_PRESETS_INNER_CENTER = 14;
+ const SHADOW_PRESETS_INNER_LEFT = 15;
+ const SHADOW_PRESETS_INNER_TOP_RIGHT = 16;
+ const SHADOW_PRESETS_INNER_TOP = 17;
+ const SHADOW_PRESETS_INNER_TOP_LEFT = 18;
+ const SHADOW_PRESETS_PERSPECTIVE_BELOW = 19;
+ const SHADOW_PRESETS_PERSPECTIVE_UPPER_RIGHT = 20;
+ const SHADOW_PRESETS_PERSPECTIVE_UPPER_LEFT = 21;
+ const SHADOW_PRESETS_PERSPECTIVE_LOWER_RIGHT = 22;
+ const SHADOW_PRESETS_PERSPECTIVE_LOWER_LEFT = 23;
+
+ /**
+ * @param float $width
+ *
+ * @return float
+ */
+ protected function getExcelPointsWidth($width)
+ {
+ return $width * 12700;
+ }
+
+ /**
+ * @param float $angle
+ *
+ * @return float
+ */
+ protected function getExcelPointsAngle($angle)
+ {
+ return $angle * 60000;
+ }
+
+ protected function getTrueAlpha($alpha)
+ {
+ return (string) 100 - $alpha . '000';
+ }
+
+ protected function setColorProperties($color, $alpha, $type)
+ {
+ return [
+ 'type' => (string) $type,
+ 'value' => (string) $color,
+ 'alpha' => (string) $this->getTrueAlpha($alpha),
+ ];
+ }
+
+ protected function getLineStyleArrowSize($array_selector, $array_kay_selector)
+ {
+ $sizes = [
+ 1 => ['w' => 'sm', 'len' => 'sm'],
+ 2 => ['w' => 'sm', 'len' => 'med'],
+ 3 => ['w' => 'sm', 'len' => 'lg'],
+ 4 => ['w' => 'med', 'len' => 'sm'],
+ 5 => ['w' => 'med', 'len' => 'med'],
+ 6 => ['w' => 'med', 'len' => 'lg'],
+ 7 => ['w' => 'lg', 'len' => 'sm'],
+ 8 => ['w' => 'lg', 'len' => 'med'],
+ 9 => ['w' => 'lg', 'len' => 'lg'],
+ ];
+
+ return $sizes[$array_selector][$array_kay_selector];
+ }
+
+ protected function getShadowPresetsMap($shadow_presets_option)
+ {
+ $presets_options = [
+ //OUTER
+ 1 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '2700000',
+ 'algn' => 'tl',
+ 'rotWithShape' => '0',
+ ],
+ 2 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '5400000',
+ 'algn' => 't',
+ 'rotWithShape' => '0',
+ ],
+ 3 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '8100000',
+ 'algn' => 'tr',
+ 'rotWithShape' => '0',
+ ],
+ 4 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'algn' => 'l',
+ 'rotWithShape' => '0',
+ ],
+ 5 => [
+ 'effect' => 'outerShdw',
+ 'size' => [
+ 'sx' => '102000',
+ 'sy' => '102000',
+ ],
+ 'blur' => '63500',
+ 'distance' => '38100',
+ 'algn' => 'ctr',
+ 'rotWithShape' => '0',
+ ],
+ 6 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '10800000',
+ 'algn' => 'r',
+ 'rotWithShape' => '0',
+ ],
+ 7 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '18900000',
+ 'algn' => 'bl',
+ 'rotWithShape' => '0',
+ ],
+ 8 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '16200000',
+ 'rotWithShape' => '0',
+ ],
+ 9 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '50800',
+ 'distance' => '38100',
+ 'direction' => '13500000',
+ 'algn' => 'br',
+ 'rotWithShape' => '0',
+ ],
+ //INNER
+ 10 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '2700000',
+ ],
+ 11 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '5400000',
+ ],
+ 12 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '8100000',
+ ],
+ 13 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ ],
+ 14 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '114300',
+ ],
+ 15 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '10800000',
+ ],
+ 16 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '18900000',
+ ],
+ 17 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '16200000',
+ ],
+ 18 => [
+ 'effect' => 'innerShdw',
+ 'blur' => '63500',
+ 'distance' => '50800',
+ 'direction' => '13500000',
+ ],
+ //perspective
+ 19 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '152400',
+ 'distance' => '317500',
+ 'size' => [
+ 'sx' => '90000',
+ 'sy' => '-19000',
+ ],
+ 'direction' => '5400000',
+ 'rotWithShape' => '0',
+ ],
+ 20 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'direction' => '18900000',
+ 'size' => [
+ 'sy' => '23000',
+ 'kx' => '-1200000',
+ ],
+ 'algn' => 'bl',
+ 'rotWithShape' => '0',
+ ],
+ 21 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'direction' => '13500000',
+ 'size' => [
+ 'sy' => '23000',
+ 'kx' => '1200000',
+ ],
+ 'algn' => 'br',
+ 'rotWithShape' => '0',
+ ],
+ 22 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'distance' => '12700',
+ 'direction' => '2700000',
+ 'size' => [
+ 'sy' => '-23000',
+ 'kx' => '-800400',
+ ],
+ 'algn' => 'bl',
+ 'rotWithShape' => '0',
+ ],
+ 23 => [
+ 'effect' => 'outerShdw',
+ 'blur' => '76200',
+ 'distance' => '12700',
+ 'direction' => '8100000',
+ 'size' => [
+ 'sy' => '-23000',
+ 'kx' => '800400',
+ ],
+ 'algn' => 'br',
+ 'rotWithShape' => '0',
+ ],
+ ];
+
+ return $presets_options[$shadow_presets_option];
+ }
+
+ protected function getArrayElementsValue($properties, $elements)
+ {
+ $reference = &$properties;
+ if (!is_array($elements)) {
+ return $reference[$elements];
+ }
+
+ foreach ($elements as $keys) {
+ $reference = &$reference[$keys];
+ }
+
+ return $reference;
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/IRenderer.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/IRenderer.php
new file mode 100644
index 0000000..3ef5f16
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/IRenderer.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart\Renderer;
+
+use PhpOffice\PhpSpreadsheet\Chart\Chart;
+
+interface IRenderer
+{
+ /**
+ * IRenderer constructor.
+ */
+ public function __construct(Chart $chart);
+
+ /**
+ * Render the chart to given file (or stream).
+ *
+ * @param string $filename Name of the file render to
+ *
+ * @return bool true on success
+ */
+ public function render($filename);
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php
new file mode 100644
index 0000000..559357e
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php
@@ -0,0 +1,870 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart\Renderer;
+
+use AccBarPlot;
+use AccLinePlot;
+use BarPlot;
+use ContourPlot;
+use Graph;
+use GroupBarPlot;
+use LinePlot;
+use PhpOffice\PhpSpreadsheet\Chart\Chart;
+use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
+use PieGraph;
+use PiePlot;
+use PiePlot3D;
+use PiePlotC;
+use RadarGraph;
+use RadarPlot;
+use ScatterPlot;
+use Spline;
+use StockPlot;
+
+class JpGraph implements IRenderer
+{
+ private static $width = 640;
+
+ private static $height = 480;
+
+ private static $colourSet = [
+ 'mediumpurple1', 'palegreen3', 'gold1', 'cadetblue1',
+ 'darkmagenta', 'coral', 'dodgerblue3', 'eggplant',
+ 'mediumblue', 'magenta', 'sandybrown', 'cyan',
+ 'firebrick1', 'forestgreen', 'deeppink4', 'darkolivegreen',
+ 'goldenrod2',
+ ];
+
+ private static $markSet;
+
+ private $chart;
+
+ private $graph;
+
+ private static $plotColour = 0;
+
+ private static $plotMark = 0;
+
+ /**
+ * Create a new jpgraph.
+ */
+ public function __construct(Chart $chart)
+ {
+ self::init();
+ $this->graph = null;
+ $this->chart = $chart;
+ }
+
+ private static function init(): void
+ {
+ static $loaded = false;
+ if ($loaded) {
+ return;
+ }
+
+ \JpGraph\JpGraph::load();
+ \JpGraph\JpGraph::module('bar');
+ \JpGraph\JpGraph::module('contour');
+ \JpGraph\JpGraph::module('line');
+ \JpGraph\JpGraph::module('pie');
+ \JpGraph\JpGraph::module('pie3d');
+ \JpGraph\JpGraph::module('radar');
+ \JpGraph\JpGraph::module('regstat');
+ \JpGraph\JpGraph::module('scatter');
+ \JpGraph\JpGraph::module('stock');
+
+ self::$markSet = [
+ 'diamond' => MARK_DIAMOND,
+ 'square' => MARK_SQUARE,
+ 'triangle' => MARK_UTRIANGLE,
+ 'x' => MARK_X,
+ 'star' => MARK_STAR,
+ 'dot' => MARK_FILLEDCIRCLE,
+ 'dash' => MARK_DTRIANGLE,
+ 'circle' => MARK_CIRCLE,
+ 'plus' => MARK_CROSS,
+ ];
+
+ $loaded = true;
+ }
+
+ private function formatPointMarker($seriesPlot, $markerID)
+ {
+ $plotMarkKeys = array_keys(self::$markSet);
+ if ($markerID === null) {
+ // Use default plot marker (next marker in the series)
+ self::$plotMark %= count(self::$markSet);
+ $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
+ } elseif ($markerID !== 'none') {
+ // Use specified plot marker (if it exists)
+ if (isset(self::$markSet[$markerID])) {
+ $seriesPlot->mark->SetType(self::$markSet[$markerID]);
+ } else {
+ // If the specified plot marker doesn't exist, use default plot marker (next marker in the series)
+ self::$plotMark %= count(self::$markSet);
+ $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
+ }
+ } else {
+ // Hide plot marker
+ $seriesPlot->mark->Hide();
+ }
+ $seriesPlot->mark->SetColor(self::$colourSet[self::$plotColour]);
+ $seriesPlot->mark->SetFillColor(self::$colourSet[self::$plotColour]);
+ $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+
+ return $seriesPlot;
+ }
+
+ private function formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation = '')
+ {
+ $datasetLabelFormatCode = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getFormatCode();
+ if ($datasetLabelFormatCode !== null) {
+ // Retrieve any label formatting code
+ $datasetLabelFormatCode = stripslashes($datasetLabelFormatCode);
+ }
+
+ $testCurrentIndex = 0;
+ foreach ($datasetLabels as $i => $datasetLabel) {
+ if (is_array($datasetLabel)) {
+ if ($rotation == 'bar') {
+ $datasetLabels[$i] = implode(' ', $datasetLabel);
+ } else {
+ $datasetLabel = array_reverse($datasetLabel);
+ $datasetLabels[$i] = implode("\n", $datasetLabel);
+ }
+ } else {
+ // Format labels according to any formatting code
+ if ($datasetLabelFormatCode !== null) {
+ $datasetLabels[$i] = NumberFormat::toFormattedString($datasetLabel, $datasetLabelFormatCode);
+ }
+ }
+ ++$testCurrentIndex;
+ }
+
+ return $datasetLabels;
+ }
+
+ private function percentageSumCalculation($groupID, $seriesCount)
+ {
+ $sumValues = [];
+ // Adjust our values to a percentage value across all series in the group
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ if ($i == 0) {
+ $sumValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ } else {
+ $nextValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ foreach ($nextValues as $k => $value) {
+ if (isset($sumValues[$k])) {
+ $sumValues[$k] += $value;
+ } else {
+ $sumValues[$k] = $value;
+ }
+ }
+ }
+ }
+
+ return $sumValues;
+ }
+
+ private function percentageAdjustValues($dataValues, $sumValues)
+ {
+ foreach ($dataValues as $k => $dataValue) {
+ $dataValues[$k] = $dataValue / $sumValues[$k] * 100;
+ }
+
+ return $dataValues;
+ }
+
+ private function getCaption($captionElement)
+ {
+ // Read any caption
+ $caption = ($captionElement !== null) ? $captionElement->getCaption() : null;
+ // Test if we have a title caption to display
+ if ($caption !== null) {
+ // If we do, it could be a plain string or an array
+ if (is_array($caption)) {
+ // Implode an array to a plain string
+ $caption = implode('', $caption);
+ }
+ }
+
+ return $caption;
+ }
+
+ private function renderTitle(): void
+ {
+ $title = $this->getCaption($this->chart->getTitle());
+ if ($title !== null) {
+ $this->graph->title->Set($title);
+ }
+ }
+
+ private function renderLegend(): void
+ {
+ $legend = $this->chart->getLegend();
+ if ($legend !== null) {
+ $legendPosition = $legend->getPosition();
+ switch ($legendPosition) {
+ case 'r':
+ $this->graph->legend->SetPos(0.01, 0.5, 'right', 'center'); // right
+ $this->graph->legend->SetColumns(1);
+
+ break;
+ case 'l':
+ $this->graph->legend->SetPos(0.01, 0.5, 'left', 'center'); // left
+ $this->graph->legend->SetColumns(1);
+
+ break;
+ case 't':
+ $this->graph->legend->SetPos(0.5, 0.01, 'center', 'top'); // top
+
+ break;
+ case 'b':
+ $this->graph->legend->SetPos(0.5, 0.99, 'center', 'bottom'); // bottom
+
+ break;
+ default:
+ $this->graph->legend->SetPos(0.01, 0.01, 'right', 'top'); // top-right
+ $this->graph->legend->SetColumns(1);
+
+ break;
+ }
+ } else {
+ $this->graph->legend->Hide();
+ }
+ }
+
+ private function renderCartesianPlotArea($type = 'textlin'): void
+ {
+ $this->graph = new Graph(self::$width, self::$height);
+ $this->graph->SetScale($type);
+
+ $this->renderTitle();
+
+ // Rotate for bar rather than column chart
+ $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotDirection();
+ $reverse = $rotation == 'bar';
+
+ $xAxisLabel = $this->chart->getXAxisLabel();
+ if ($xAxisLabel !== null) {
+ $title = $this->getCaption($xAxisLabel);
+ if ($title !== null) {
+ $this->graph->xaxis->SetTitle($title, 'center');
+ $this->graph->xaxis->title->SetMargin(35);
+ if ($reverse) {
+ $this->graph->xaxis->title->SetAngle(90);
+ $this->graph->xaxis->title->SetMargin(90);
+ }
+ }
+ }
+
+ $yAxisLabel = $this->chart->getYAxisLabel();
+ if ($yAxisLabel !== null) {
+ $title = $this->getCaption($yAxisLabel);
+ if ($title !== null) {
+ $this->graph->yaxis->SetTitle($title, 'center');
+ if ($reverse) {
+ $this->graph->yaxis->title->SetAngle(0);
+ $this->graph->yaxis->title->SetMargin(-55);
+ }
+ }
+ }
+ }
+
+ private function renderPiePlotArea(): void
+ {
+ $this->graph = new PieGraph(self::$width, self::$height);
+
+ $this->renderTitle();
+ }
+
+ private function renderRadarPlotArea(): void
+ {
+ $this->graph = new RadarGraph(self::$width, self::$height);
+ $this->graph->SetScale('lin');
+
+ $this->renderTitle();
+ }
+
+ private function renderPlotLine($groupID, $filled = false, $combination = false, $dimensions = '2d'): void
+ {
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+ $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount();
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+ $this->graph->xaxis->SetTickLabels($datasetLabels);
+ }
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = [];
+ if ($grouping == 'percentStacked') {
+ $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
+ }
+
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+ if ($grouping == 'percentStacked') {
+ $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
+ }
+
+ // Fill in any missing values in the $dataValues array
+ $testCurrentIndex = 0;
+ foreach ($dataValues as $k => $dataValue) {
+ while ($k != $testCurrentIndex) {
+ $dataValues[$testCurrentIndex] = null;
+ ++$testCurrentIndex;
+ }
+ ++$testCurrentIndex;
+ }
+
+ $seriesPlot = new LinePlot($dataValues);
+ if ($combination) {
+ $seriesPlot->SetBarCenter();
+ }
+
+ if ($filled) {
+ $seriesPlot->SetFilled(true);
+ $seriesPlot->SetColor('black');
+ $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
+ } else {
+ // Set the appropriate plot marker
+ $this->formatPointMarker($seriesPlot, $marker);
+ }
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+ $seriesPlot->SetLegend($dataLabel);
+
+ $seriesPlots[] = $seriesPlot;
+ }
+
+ if ($grouping == 'standard') {
+ $groupPlot = $seriesPlots;
+ } else {
+ $groupPlot = new AccLinePlot($seriesPlots);
+ }
+ $this->graph->Add($groupPlot);
+ }
+
+ private function renderPlotBar($groupID, $dimensions = '2d'): void
+ {
+ $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotDirection();
+ // Rotate for bar rather than column chart
+ if (($groupID == 0) && ($rotation == 'bar')) {
+ $this->graph->Set90AndMargin();
+ }
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+
+ $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount();
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation);
+ // Rotate for bar rather than column chart
+ if ($rotation == 'bar') {
+ $datasetLabels = array_reverse($datasetLabels);
+ $this->graph->yaxis->SetPos('max');
+ $this->graph->yaxis->SetLabelAlign('center', 'top');
+ $this->graph->yaxis->SetLabelSide(SIDE_RIGHT);
+ }
+ $this->graph->xaxis->SetTickLabels($datasetLabels);
+ }
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = [];
+ if ($grouping == 'percentStacked') {
+ $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
+ }
+
+ // Loop through each data series in turn
+ for ($j = 0; $j < $seriesCount; ++$j) {
+ $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+ if ($grouping == 'percentStacked') {
+ $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
+ }
+
+ // Fill in any missing values in the $dataValues array
+ $testCurrentIndex = 0;
+ foreach ($dataValues as $k => $dataValue) {
+ while ($k != $testCurrentIndex) {
+ $dataValues[$testCurrentIndex] = null;
+ ++$testCurrentIndex;
+ }
+ ++$testCurrentIndex;
+ }
+
+ // Reverse the $dataValues order for bar rather than column chart
+ if ($rotation == 'bar') {
+ $dataValues = array_reverse($dataValues);
+ }
+ $seriesPlot = new BarPlot($dataValues);
+ $seriesPlot->SetColor('black');
+ $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
+ if ($dimensions == '3d') {
+ $seriesPlot->SetShadow();
+ }
+ if (!$this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)) {
+ $dataLabel = '';
+ } else {
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)->getDataValue();
+ }
+ $seriesPlot->SetLegend($dataLabel);
+
+ $seriesPlots[] = $seriesPlot;
+ }
+ // Reverse the plot order for bar rather than column chart
+ if (($rotation == 'bar') && ($grouping != 'percentStacked')) {
+ $seriesPlots = array_reverse($seriesPlots);
+ }
+
+ if ($grouping == 'clustered') {
+ $groupPlot = new GroupBarPlot($seriesPlots);
+ } elseif ($grouping == 'standard') {
+ $groupPlot = new GroupBarPlot($seriesPlots);
+ } else {
+ $groupPlot = new AccBarPlot($seriesPlots);
+ if ($dimensions == '3d') {
+ $groupPlot->SetShadow();
+ }
+ }
+
+ $this->graph->Add($groupPlot);
+ }
+
+ private function renderPlotScatter($groupID, $bubble): void
+ {
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+ $scatterStyle = $bubbleSize = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = [];
+
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+ foreach ($dataValuesY as $k => $dataValueY) {
+ $dataValuesY[$k] = $k;
+ }
+
+ $seriesPlot = new ScatterPlot($dataValuesX, $dataValuesY);
+ if ($scatterStyle == 'lineMarker') {
+ $seriesPlot->SetLinkPoints();
+ $seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
+ } elseif ($scatterStyle == 'smoothMarker') {
+ $spline = new Spline($dataValuesY, $dataValuesX);
+ [$splineDataY, $splineDataX] = $spline->Get(count($dataValuesX) * self::$width / 20);
+ $lplot = new LinePlot($splineDataX, $splineDataY);
+ $lplot->SetColor(self::$colourSet[self::$plotColour]);
+
+ $this->graph->Add($lplot);
+ }
+
+ if ($bubble) {
+ $this->formatPointMarker($seriesPlot, 'dot');
+ $seriesPlot->mark->SetColor('black');
+ $seriesPlot->mark->SetSize($bubbleSize);
+ } else {
+ $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+ $this->formatPointMarker($seriesPlot, $marker);
+ }
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+ $seriesPlot->SetLegend($dataLabel);
+
+ $this->graph->Add($seriesPlot);
+ }
+ }
+
+ private function renderPlotRadar($groupID): void
+ {
+ $radarStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = [];
+
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+ $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
+
+ $dataValues = [];
+ foreach ($dataValuesY as $k => $dataValueY) {
+ $dataValues[$k] = implode(' ', array_reverse($dataValueY));
+ }
+ $tmp = array_shift($dataValues);
+ $dataValues[] = $tmp;
+ $tmp = array_shift($dataValuesX);
+ $dataValuesX[] = $tmp;
+
+ $this->graph->SetTitles(array_reverse($dataValues));
+
+ $seriesPlot = new RadarPlot(array_reverse($dataValuesX));
+
+ $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
+ $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+ if ($radarStyle == 'filled') {
+ $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour]);
+ }
+ $this->formatPointMarker($seriesPlot, $marker);
+ $seriesPlot->SetLegend($dataLabel);
+
+ $this->graph->Add($seriesPlot);
+ }
+ }
+
+ private function renderPlotContour($groupID): void
+ {
+ $contourStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = [];
+
+ $dataValues = [];
+ // Loop through each data series in turn
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
+
+ $dataValues[$i] = $dataValuesX;
+ }
+ $seriesPlot = new ContourPlot($dataValues);
+
+ $this->graph->Add($seriesPlot);
+ }
+
+ private function renderPlotStock($groupID): void
+ {
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $plotOrder = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder();
+
+ $dataValues = [];
+ // Loop through each data series in turn and build the plot arrays
+ foreach ($plotOrder as $i => $v) {
+ $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($v)->getDataValues();
+ foreach ($dataValuesX as $j => $dataValueX) {
+ $dataValues[$plotOrder[$i]][$j] = $dataValueX;
+ }
+ }
+ if (empty($dataValues)) {
+ return;
+ }
+
+ $dataValuesPlot = [];
+ // Flatten the plot arrays to a single dimensional array to work with jpgraph
+ $jMax = count($dataValues[0]);
+ for ($j = 0; $j < $jMax; ++$j) {
+ for ($i = 0; $i < $seriesCount; ++$i) {
+ $dataValuesPlot[] = $dataValues[$i][$j];
+ }
+ }
+
+ // Set the x-axis labels
+ $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount();
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+ $this->graph->xaxis->SetTickLabels($datasetLabels);
+ }
+
+ $seriesPlot = new StockPlot($dataValuesPlot);
+ $seriesPlot->SetWidth(20);
+
+ $this->graph->Add($seriesPlot);
+ }
+
+ private function renderAreaChart($groupCount, $dimensions = '2d'): void
+ {
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotLine($i, true, false, $dimensions);
+ }
+ }
+
+ private function renderLineChart($groupCount, $dimensions = '2d'): void
+ {
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotLine($i, false, false, $dimensions);
+ }
+ }
+
+ private function renderBarChart($groupCount, $dimensions = '2d'): void
+ {
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotBar($i, $dimensions);
+ }
+ }
+
+ private function renderScatterChart($groupCount): void
+ {
+ $this->renderCartesianPlotArea('linlin');
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotScatter($i, false);
+ }
+ }
+
+ private function renderBubbleChart($groupCount): void
+ {
+ $this->renderCartesianPlotArea('linlin');
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotScatter($i, true);
+ }
+ }
+
+ private function renderPieChart($groupCount, $dimensions = '2d', $doughnut = false, $multiplePlots = false): void
+ {
+ $this->renderPiePlotArea();
+
+ $iLimit = ($multiplePlots) ? $groupCount : 1;
+ for ($groupID = 0; $groupID < $iLimit; ++$groupID) {
+ $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
+ $exploded = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
+ $datasetLabels = [];
+ if ($groupID == 0) {
+ $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount();
+ if ($labelCount > 0) {
+ $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
+ $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
+ }
+ }
+
+ $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
+ $seriesPlots = [];
+ // For pie charts, we only display the first series: doughnut charts generally display all series
+ $jLimit = ($multiplePlots) ? $seriesCount : 1;
+ // Loop through each data series in turn
+ for ($j = 0; $j < $jLimit; ++$j) {
+ $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
+
+ // Fill in any missing values in the $dataValues array
+ $testCurrentIndex = 0;
+ foreach ($dataValues as $k => $dataValue) {
+ while ($k != $testCurrentIndex) {
+ $dataValues[$testCurrentIndex] = null;
+ ++$testCurrentIndex;
+ }
+ ++$testCurrentIndex;
+ }
+
+ if ($dimensions == '3d') {
+ $seriesPlot = new PiePlot3D($dataValues);
+ } else {
+ if ($doughnut) {
+ $seriesPlot = new PiePlotC($dataValues);
+ } else {
+ $seriesPlot = new PiePlot($dataValues);
+ }
+ }
+
+ if ($multiplePlots) {
+ $seriesPlot->SetSize(($jLimit - $j) / ($jLimit * 4));
+ }
+
+ if ($doughnut) {
+ $seriesPlot->SetMidColor('white');
+ }
+
+ $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
+ if (count($datasetLabels) > 0) {
+ $seriesPlot->SetLabels(array_fill(0, count($datasetLabels), ''));
+ }
+ if ($dimensions != '3d') {
+ $seriesPlot->SetGuideLines(false);
+ }
+ if ($j == 0) {
+ if ($exploded) {
+ $seriesPlot->ExplodeAll();
+ }
+ $seriesPlot->SetLegends($datasetLabels);
+ }
+
+ $this->graph->Add($seriesPlot);
+ }
+ }
+ }
+
+ private function renderRadarChart($groupCount): void
+ {
+ $this->renderRadarPlotArea();
+
+ for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
+ $this->renderPlotRadar($groupID);
+ }
+ }
+
+ private function renderStockChart($groupCount): void
+ {
+ $this->renderCartesianPlotArea('intint');
+
+ for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
+ $this->renderPlotStock($groupID);
+ }
+ }
+
+ private function renderContourChart($groupCount, $dimensions): void
+ {
+ $this->renderCartesianPlotArea('intint');
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $this->renderPlotContour($i);
+ }
+ }
+
+ private function renderCombinationChart($groupCount, $dimensions, $outputDestination)
+ {
+ $this->renderCartesianPlotArea();
+
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $dimensions = null;
+ $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+ switch ($chartType) {
+ case 'area3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'areaChart':
+ $this->renderPlotLine($i, true, true, $dimensions);
+
+ break;
+ case 'bar3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'barChart':
+ $this->renderPlotBar($i, $dimensions);
+
+ break;
+ case 'line3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'lineChart':
+ $this->renderPlotLine($i, false, true, $dimensions);
+
+ break;
+ case 'scatterChart':
+ $this->renderPlotScatter($i, false);
+
+ break;
+ case 'bubbleChart':
+ $this->renderPlotScatter($i, true);
+
+ break;
+ default:
+ $this->graph = null;
+
+ return false;
+ }
+ }
+
+ $this->renderLegend();
+
+ $this->graph->Stroke($outputDestination);
+
+ return true;
+ }
+
+ public function render($outputDestination)
+ {
+ self::$plotColour = 0;
+
+ $groupCount = $this->chart->getPlotArea()->getPlotGroupCount();
+
+ $dimensions = null;
+ if ($groupCount == 1) {
+ $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType();
+ } else {
+ $chartTypes = [];
+ for ($i = 0; $i < $groupCount; ++$i) {
+ $chartTypes[] = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
+ }
+ $chartTypes = array_unique($chartTypes);
+ if (count($chartTypes) == 1) {
+ $chartType = array_pop($chartTypes);
+ } elseif (count($chartTypes) == 0) {
+ echo 'Chart is not yet implemented<br />';
+
+ return false;
+ } else {
+ return $this->renderCombinationChart($groupCount, $dimensions, $outputDestination);
+ }
+ }
+
+ switch ($chartType) {
+ case 'area3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'areaChart':
+ $this->renderAreaChart($groupCount, $dimensions);
+
+ break;
+ case 'bar3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'barChart':
+ $this->renderBarChart($groupCount, $dimensions);
+
+ break;
+ case 'line3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'lineChart':
+ $this->renderLineChart($groupCount, $dimensions);
+
+ break;
+ case 'pie3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'pieChart':
+ $this->renderPieChart($groupCount, $dimensions, false, false);
+
+ break;
+ case 'doughnut3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'doughnutChart':
+ $this->renderPieChart($groupCount, $dimensions, true, true);
+
+ break;
+ case 'scatterChart':
+ $this->renderScatterChart($groupCount);
+
+ break;
+ case 'bubbleChart':
+ $this->renderBubbleChart($groupCount);
+
+ break;
+ case 'radarChart':
+ $this->renderRadarChart($groupCount);
+
+ break;
+ case 'surface3DChart':
+ $dimensions = '3d';
+ // no break
+ case 'surfaceChart':
+ $this->renderContourChart($groupCount, $dimensions);
+
+ break;
+ case 'stockChart':
+ $this->renderStockChart($groupCount);
+
+ break;
+ default:
+ echo $chartType . ' is not yet implemented<br />';
+
+ return false;
+ }
+ $this->renderLegend();
+
+ $this->graph->Stroke($outputDestination);
+
+ return true;
+ }
+}
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/PHP Charting Libraries.txt b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/PHP Charting Libraries.txt
new file mode 100644
index 0000000..1ead22a
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/PHP Charting Libraries.txt
@@ -0,0 +1,20 @@
+ChartDirector
+ https://www.advsofteng.com/cdphp.html
+
+GraPHPite
+ http://graphpite.sourceforge.net/
+
+JpGraph
+ http://www.aditus.nu/jpgraph/
+
+LibChart
+ https://naku.dohcrew.com/libchart/pages/introduction/
+
+pChart
+ http://pchart.sourceforge.net/
+
+TeeChart
+ https://www.steema.com/
+
+PHPGraphLib
+ http://www.ebrueggeman.com/phpgraphlib \ No newline at end of file
diff --git a/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Title.php b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Title.php
new file mode 100644
index 0000000..b4c1f03
--- /dev/null
+++ b/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Title.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace PhpOffice\PhpSpreadsheet\Chart;
+
+class Title
+{
+ /**
+ * Title Caption.
+ *
+ * @var string
+ */
+ private $caption;
+
+ /**
+ * Title Layout.
+ *
+ * @var Layout
+ */
+ private $layout;
+
+ /**
+ * Create a new Title.
+ *
+ * @param null|mixed $caption
+ */
+ public function __construct($caption = null, ?Layout $layout = null)
+ {
+ $this->caption = $caption;
+ $this->layout = $layout;
+ }
+
+ /**
+ * Get caption.
+ *
+ * @return string
+ */
+ public function getCaption()
+ {
+ return $this->caption;
+ }
+
+ /**
+ * Set caption.
+ *
+ * @param string $caption
+ *
+ * @return $this
+ */
+ public function setCaption($caption)
+ {
+ $this->caption = $caption;
+
+ return $this;
+ }
+
+ /**
+ * Get Layout.
+ *
+ * @return Layout
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+}