diff --git a/samples/Chart/33_Chart_create_line_dateaxis.php b/samples/Chart/33_Chart_create_line_dateaxis.php
new file mode 100644
index 00000000..1a47e5aa
--- /dev/null
+++ b/samples/Chart/33_Chart_create_line_dateaxis.php
@@ -0,0 +1,375 @@
+getActiveSheet();
+$dataSheet->setTitle('Data');
+// changed data to simulate a trend chart - Xaxis are dates; Yaxis are 3 meausurements from each date
+// Dates changed not to fall on exact quarter start
+$dataSheet->fromArray(
+ [
+ ['', 'date', 'metric1', 'metric2', 'metric3'],
+ ['=DATEVALUE(B2)', '2021-01-10', 12.1, 15.1, 21.1],
+ ['=DATEVALUE(B3)', '2021-04-21', 56.2, 73.2, 86.2],
+ ['=DATEVALUE(B4)', '2021-07-31', 52.2, 61.2, 69.2],
+ ['=DATEVALUE(B5)', '2021-10-11', 30.2, 22.2, 0.2],
+ ['=DATEVALUE(B6)', '2022-01-21', 40.1, 38.1, 65.1],
+ ['=DATEVALUE(B7)', '2022-04-11', 45.2, 44.2, 96.2],
+ ['=DATEVALUE(B8)', '2022-07-01', 52.2, 51.2, 55.2],
+ ['=DATEVALUE(B9)', '2022-10-31', 41.2, 72.2, 56.2],
+ ]
+);
+
+$dataSheet->getStyle('A2:A9')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601);
+$dataSheet->getColumnDimension('A')->setAutoSize(true);
+$dataSheet->getColumnDimension('B')->setAutoSize(true);
+$dataSheet->setSelectedCells('A1');
+
+// Set the Labels for each data series we want to plot
+// Datatype
+// Cell reference for data
+// Format Code
+// Number of datapoints in series
+$dataSeriesLabels = [
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Data!$C$1', null, 1),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Data!$D$1', null, 1),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Data!$E$1', null, 1),
+];
+// Set the X-Axis Labels
+// NUMBER, not STRING
+// added x-axis values for each of the 3 metrics
+// added FORMATE_CODE_NUMBER
+// Number of datapoints in series
+$xAxisTickValues = [
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Data!$A$2:$A$9', Properties::FORMAT_CODE_DATE_ISO8601, 8),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Data!$A$2:$A$9', Properties::FORMAT_CODE_DATE_ISO8601, 8),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Data!$A$2:$A$9', Properties::FORMAT_CODE_DATE_ISO8601, 8),
+];
+// Set the Data values for each data series we want to plot
+// Datatype
+// Cell reference for data
+// Format Code
+// Number of datapoints in series
+// Data values
+// Data Marker
+// Data Marker Color fill/[fill,Border]
+// Data Marker size
+// Color(s) added
+// added FORMAT_CODE_NUMBER
+$dataSeriesValues = [
+ new DataSeriesValues(
+ DataSeriesValues::DATASERIES_TYPE_NUMBER,
+ 'Data!$C$2:$C$9',
+ Properties::FORMAT_CODE_NUMBER,
+ 8,
+ null,
+ 'diamond',
+ null,
+ 5
+ ),
+ new DataSeriesValues(
+ DataSeriesValues::DATASERIES_TYPE_NUMBER,
+ 'Data!$D$2:$D$9',
+ Properties::FORMAT_CODE_NUMBER,
+ 8,
+ null,
+ 'square',
+ '*accent1',
+ 6
+ ),
+ new DataSeriesValues(
+ DataSeriesValues::DATASERIES_TYPE_NUMBER,
+ 'Data!$E$2:$E$9',
+ Properties::FORMAT_CODE_NUMBER,
+ 8,
+ null,
+ null,
+ null,
+ 7
+ ), // let Excel choose marker shape
+];
+// series 1 - metric1
+// marker details
+$dataSeriesValues[0]
+ ->getMarkerFillColor()
+ ->setColorProperties('0070C0', null, ChartColor::EXCEL_COLOR_TYPE_ARGB);
+$dataSeriesValues[0]
+ ->getMarkerBorderColor()
+ ->setColorProperties('002060', null, ChartColor::EXCEL_COLOR_TYPE_ARGB);
+
+// line details - dashed, smooth line (Bezier) with arrows, 40% transparent
+$dataSeriesValues[0]
+ ->setSmoothLine(true)
+ ->setScatterLines(true)
+ ->setLineColorProperties('accent1', 40, ChartColor::EXCEL_COLOR_TYPE_SCHEME); // value, alpha, type
+$dataSeriesValues[0]->setLineStyleProperties(
+ 2.5, // width in points
+ Properties::LINE_STYLE_COMPOUND_TRIPLE, // compound
+ Properties::LINE_STYLE_DASH_SQUARE_DOT, // dash
+ Properties::LINE_STYLE_CAP_SQUARE, // cap
+ Properties::LINE_STYLE_JOIN_MITER, // join
+ Properties::LINE_STYLE_ARROW_TYPE_OPEN, // head type
+ Properties::LINE_STYLE_ARROW_SIZE_4, // head size preset index
+ Properties::LINE_STYLE_ARROW_TYPE_ARROW, // end type
+ Properties::LINE_STYLE_ARROW_SIZE_6 // end size preset index
+);
+
+// series 2 - metric2, straight line - no special effects, connected
+$dataSeriesValues[1] // square marker border color
+ ->getMarkerBorderColor()
+ ->setColorProperties('accent6', 3, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
+$dataSeriesValues[1] // square marker fill color
+ ->getMarkerFillColor()
+ ->setColorProperties('0FFF00', null, ChartColor::EXCEL_COLOR_TYPE_ARGB);
+$dataSeriesValues[1]
+ ->setScatterLines(true)
+ ->setSmoothLine(false)
+ ->setLineColorProperties('FF0000', 80, ChartColor::EXCEL_COLOR_TYPE_ARGB);
+$dataSeriesValues[1]->setLineWidth(2.0);
+
+// series 3 - metric3, markers, no line
+$dataSeriesValues[2] // triangle? fill
+ //->setPointMarker('triangle') // let Excel choose shape, which is predicted to be a triangle
+ ->getMarkerFillColor()
+ ->setColorProperties('FFFF00', null, ChartColor::EXCEL_COLOR_TYPE_ARGB);
+$dataSeriesValues[2] // triangle border
+ ->getMarkerBorderColor()
+ ->setColorProperties('accent4', null, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
+$dataSeriesValues[2]->setScatterLines(false); // points not connected
+// Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers
+$xAxis = new Axis();
+$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601);
+
+// Build the dataseries
+$series = new DataSeries(
+ DataSeries::TYPE_SCATTERCHART, // plotType
+ null, // plotGrouping (Scatter charts don't have grouping)
+ range(0, count($dataSeriesValues) - 1), // plotOrder
+ $dataSeriesLabels, // plotLabel
+ $xAxisTickValues, // plotCategory
+ $dataSeriesValues, // plotValues
+ null, // plotDirection
+ null, // smooth line
+ DataSeries::STYLE_SMOOTHMARKER // plotStyle
+);
+
+// Set the series in the plot area
+$plotArea = new PlotArea(null, [$series]);
+// Set the chart legend
+$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
+
+$title = new Title('Test Scatter Chart');
+$yAxisLabel = new Title('Value ($k)');
+$yAxis = new Axis();
+$yAxis->setMajorGridlines(new GridLines());
+
+// Create the chart
+$chart = new Chart(
+ 'chart1', // name
+ $title, // title
+ $legend, // legend
+ $plotArea, // plotArea
+ true, // plotVisibleOnly
+ DataSeries::EMPTY_AS_GAP, // displayBlanksAs
+ null, // xAxisLabel
+ $yAxisLabel, // yAxisLabel
+ // added xAxis for correct date display
+ $xAxis, // xAxis
+ $yAxis, // yAxis
+);
+
+// Set the position of the chart in the chart sheet
+$chart->setTopLeftPosition('A1');
+$chart->setBottomRightPosition('P12');
+
+// create a 'Chart' worksheet, add $chart to it
+$spreadsheet->createSheet();
+$chartSheet = $spreadsheet->getSheet(1);
+$chartSheet->setTitle('Scatter+Line Chart');
+
+$chartSheet = $spreadsheet->getSheetByName('Scatter+Line Chart');
+// Add the chart to the worksheet
+$chartSheet->addChart($chart);
+
+// ------- Demonstrate Date Xaxis in Line Chart, not possible using Scatter Chart ------------
+
+// Set the Labels (Column header) for each data series we want to plot
+$dataSeriesLabels = [
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Data!$E$1', null, 1),
+];
+
+// Set the X-Axis Labels - dates, N.B. 01/10/2021 === Jan 10, NOT Oct 1 !!
+// x-axis values are the Excel numeric representation of the date - so set
+// formatCode=General for the xAxis VALUES, but we want the labels to be
+// DISPLAYED as 'yyyy-mm-dd' That is, read a number, display a date.
+$xAxisTickValues = [
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Data!$A$2:$A$9', Properties::FORMAT_CODE_DATE_ISO8601, 8),
+];
+
+// X axis (date) settings
+$xAxisLabel = new Title('Date');
+$xAxis = new Axis();
+$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601); // yyyy-mm-dd
+
+// Set the Data values for each data series we want to plot
+$dataSeriesValues = [
+ new DataSeriesValues(
+ DataSeriesValues::DATASERIES_TYPE_NUMBER,
+ 'Data!$E$2:$E$9',
+ Properties::FORMAT_CODE_NUMBER,
+ 8,
+ null,
+ 'triangle',
+ null,
+ 7
+ ),
+];
+
+// series - metric3, markers, no line
+$dataSeriesValues[0]
+ ->setScatterlines(false); // disable connecting lines
+$dataSeriesValues[0]
+ ->getMarkerFillColor()
+ ->setColorProperties('FFFF00', null, ChartColor::EXCEL_COLOR_TYPE_ARGB);
+$dataSeriesValues[0]
+ ->getMarkerBorderColor()
+ ->setColorProperties('accent4', null, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
+
+// Build the dataseries
+// must now use LineChart instead of ScatterChart, since ScatterChart does not
+// support "dateAx" axis type.
+$series = new DataSeries(
+ DataSeries::TYPE_LINECHART, // plotType
+ 'standard', // plotGrouping
+ range(0, count($dataSeriesValues) - 1), // plotOrder
+ $dataSeriesLabels, // plotLabel
+ $xAxisTickValues, // plotCategory
+ $dataSeriesValues, // plotValues
+ null, // plotDirection
+ false, // smooth line
+ DataSeries::STYLE_LINEMARKER // plotStyle
+ // DataSeries::STYLE_SMOOTHMARKER // plotStyle
+);
+
+// Set the series in the plot area
+$plotArea = new PlotArea(null, [$series]);
+// Set the chart legend
+$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false);
+
+$title = new Title('Test Line-Chart with Date Axis - metric3 values');
+
+// X axis (date) settings
+$xAxisLabel = new Title('Game Date');
+$xAxis = new Axis();
+// date axis values are Excel numbers, not yyyy-mm-dd Date strings
+$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601);
+
+$xAxis->setAxisType('dateAx'); // dateAx available ONLY for LINECHART, not SCATTERCHART
+
+// measure the time span in Quarters, of data.
+$dateMinMax = dateRange(8, $spreadsheet); // array 'min'=>earliest date of first Q, 'max'=>latest date of final Q
+// change xAxis tick marks to match Qtr boundaries
+
+$nQtrs = sprintf('%3.2f', (($dateMinMax['max'] - $dateMinMax['min']) / 30.5) / 4);
+$tickMarkInterval = ($nQtrs > 20) ? 6 : 3; // tick marks every ? months
+
+$xAxis->setAxisOptionsProperties(
+ Properties::AXIS_LABELS_NEXT_TO, // axis_label pos
+ null, // horizontalCrossesValue
+ null, // horizontalCrosses
+ null, // axisOrientation
+ 'in', // major_tick_mark
+ null, // minor_tick_mark
+ $dateMinMax['min'], // minimum calculate this from the earliest data: 'Data!$A$2'
+ $dateMinMax['max'], // maximum calculate this from the last data: 'Data!$A$'.($nrows+1)
+ $tickMarkInterval, // majorUnit determines tickmarks & Gridlines ?
+ null, // minorUnit
+ null, // textRotation
+ null, // hidden
+ 'days', // baseTimeUnit
+ 'months', // majorTimeUnit,
+ 'months', // minorTimeUnit
+);
+
+$yAxisLabel = new Title('Value ($k)');
+$yAxis = new Axis();
+$yAxis->setMajorGridlines(new GridLines());
+$xAxis->setMajorGridlines(new GridLines());
+$minorGridLines = new GridLines();
+$minorGridLines->activateObject();
+$xAxis->setMinorGridlines($minorGridLines);
+
+// Create the chart
+$chart = new Chart(
+ 'chart2', // name
+ $title, // title
+ $legend, // legend
+ $plotArea, // plotArea
+ true, // plotVisibleOnly
+ DataSeries::EMPTY_AS_GAP, // displayBlanksAs
+ null, // xAxisLabel
+ $yAxisLabel, // yAxisLabel
+ // added xAxis for correct date display
+ $xAxis, // xAxis
+ $yAxis, // yAxis
+);
+
+// Set the position of the chart in the chart sheet below the first chart
+$chart->setTopLeftPosition('A13');
+$chart->setBottomRightPosition('P25');
+$chart->setRoundedCorners('true'); // Rounded corners in Chart Outline
+
+// Add the chart to the worksheet $chartSheet
+$chartSheet->addChart($chart);
+$spreadsheet->setActiveSheetIndex(1);
+
+// Save Excel 2007 file
+$filename = $helper->getFilename(__FILE__);
+$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
+$writer->setIncludeCharts(true);
+$callStartTime = microtime(true);
+$writer->save($filename);
+$helper->logWrite($writer, $filename, $callStartTime);
+$spreadsheet->disconnectWorksheets();
+
+function dateRange(int $nrows, Spreadsheet $wrkbk): array
+{
+ $dataSheet = $wrkbk->getSheetByName('Data');
+
+ // start the xaxis at the beginning of the quarter of the first date
+ $startDateStr = $dataSheet->getCell('B2')->getValue(); // yyyy-mm-dd date string
+ $startDate = DateTime::createFromFormat('Y-m-d', $startDateStr); // php date obj
+
+ // get date of first day of the quarter of the start date
+ $startMonth = $startDate->format('n'); // suppress leading zero
+ $startYr = $startDate->format('Y');
+ $qtr = intdiv($startMonth, 3) + (($startMonth % 3 > 0) ? 1 : 0);
+ $qtrStartMonth = sprintf('%02d', 1 + (($qtr - 1) * 3));
+ $qtrStartStr = "$startYr-$qtrStartMonth-01";
+ $ExcelQtrStartDateVal = SharedDate::convertIsoDate($qtrStartStr);
+
+ // end the xaxis at the end of the quarter of the last date
+ $lastDateStr = $dataSheet->getCellByColumnAndRow(2, $nrows + 1)->getValue();
+ $lastDate = DateTime::createFromFormat('Y-m-d', $lastDateStr);
+ $lastMonth = $lastDate->format('n');
+ $lastYr = $lastDate->format('Y');
+ $qtr = intdiv($lastMonth, 3) + (($lastMonth % 3 > 0) ? 1 : 0);
+ $qtrEndMonth = 3 + (($qtr - 1) * 3);
+ $lastDOM = cal_days_in_month(CAL_GREGORIAN, $qtrEndMonth, $lastYr);
+ $qtrEndMonth = sprintf('%02d', $qtrEndMonth);
+ $qtrEndStr = "$lastYr-$qtrEndMonth-$lastDOM";
+ $ExcelQtrEndDateVal = SharedDate::convertIsoDate($qtrEndStr);
+
+ $minMaxDates = ['min' => $ExcelQtrStartDateVal, 'max' => $ExcelQtrEndDateVal];
+
+ return $minMaxDates;
+}
diff --git a/samples/Chart/33_Chart_create_scatter5_trendlines.php b/samples/Chart/33_Chart_create_scatter5_trendlines.php
index da831fa9..a640f735 100644
--- a/samples/Chart/33_Chart_create_scatter5_trendlines.php
+++ b/samples/Chart/33_Chart_create_scatter5_trendlines.php
@@ -263,6 +263,7 @@ $chart->setBottomRightPosition('P25');
// Add the chart to the worksheet $chartSheet
$chartSheet->addChart($chart);
+$spreadsheet->setActiveSheetIndex(1);
// Save Excel 2007 file
$filename = $helper->getFilename(__FILE__);
diff --git a/samples/templates/32readwriteLineDateAxisChart1.xlsx b/samples/templates/32readwriteLineDateAxisChart1.xlsx
new file mode 100644
index 00000000..42470303
Binary files /dev/null and b/samples/templates/32readwriteLineDateAxisChart1.xlsx differ
diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php
index bd7082ff..3ac5c3cd 100644
--- a/src/PhpSpreadsheet/Chart/Axis.php
+++ b/src/PhpSpreadsheet/Chart/Axis.php
@@ -10,6 +10,14 @@ namespace PhpOffice\PhpSpreadsheet\Chart;
*/
class Axis extends Properties
{
+ const AXIS_TYPE_CATEGORY = 'catAx';
+ const AXIS_TYPE_DATE = 'dateAx';
+ const AXIS_TYPE_VALUE = 'valAx';
+
+ const TIME_UNIT_DAYS = 'days';
+ const TIME_UNIT_MONTHS = 'months';
+ const TIME_UNIT_YEARS = 'years';
+
public function __construct()
{
parent::__construct();
@@ -62,6 +70,9 @@ class Axis extends Properties
'horizontal_crosses_value' => null,
'textRotation' => null,
'hidden' => null,
+ 'majorTimeUnit' => self::TIME_UNIT_YEARS,
+ 'minorTimeUnit' => self::TIME_UNIT_MONTHS,
+ 'baseTimeUnit' => self::TIME_UNIT_DAYS,
];
/**
@@ -74,6 +85,7 @@ class Axis extends Properties
private const NUMERIC_FORMAT = [
Properties::FORMAT_CODE_NUMBER,
Properties::FORMAT_CODE_DATE,
+ Properties::FORMAT_CODE_DATE_ISO8601,
];
/**
@@ -115,12 +127,12 @@ class Axis extends Properties
public function getAxisIsNumericFormat(): bool
{
- return (bool) $this->axisNumber['numeric'];
+ return $this->axisType === self::AXIS_TYPE_DATE || (bool) $this->axisNumber['numeric'];
}
public function setAxisOption(string $key, ?string $value): void
{
- if (!empty($value)) {
+ if ($value !== null && $value !== '') {
$this->axisOptions[$key] = $value;
}
}
@@ -140,7 +152,10 @@ class Axis extends Properties
?string $majorUnit = null,
?string $minorUnit = null,
?string $textRotation = null,
- ?string $hidden = null
+ ?string $hidden = null,
+ ?string $baseTimeUnit = null,
+ ?string $majorTimeUnit = null,
+ ?string $minorTimeUnit = null
): void {
$this->axisOptions['axis_labels'] = $axisLabels;
$this->setAxisOption('horizontal_crosses_value', $horizontalCrossesValue);
@@ -154,6 +169,9 @@ class Axis extends Properties
$this->setAxisOption('minor_unit', $minorUnit);
$this->setAxisOption('textRotation', $textRotation);
$this->setAxisOption('hidden', $hidden);
+ $this->setAxisOption('baseTimeUnit', $baseTimeUnit);
+ $this->setAxisOption('majorTimeUnit', $majorTimeUnit);
+ $this->setAxisOption('minorTimeUnit', $minorTimeUnit);
}
/**
@@ -185,7 +203,7 @@ class Axis extends Properties
public function setAxisType(string $type): self
{
- if ($type === 'catAx' || $type === 'valAx') {
+ if ($type === self::AXIS_TYPE_CATEGORY || $type === self::AXIS_TYPE_VALUE || $type === self::AXIS_TYPE_DATE) {
$this->axisType = $type;
} else {
$this->axisType = '';
diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
index dab2b410..76316db9 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
@@ -139,12 +139,13 @@ class Chart
$plotAreaLayout = $this->chartLayoutDetails($chartDetail);
break;
- case 'catAx':
+ case Axis::AXIS_TYPE_CATEGORY:
+ case Axis::AXIS_TYPE_DATE:
$catAxRead = true;
if (isset($chartDetail->title)) {
$XaxisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
}
- $xAxis->setAxisType('catAx');
+ $xAxis->setAxisType($chartDetailKey);
$this->readEffects($chartDetail, $xAxis);
if (isset($chartDetail->spPr)) {
$sppr = $chartDetail->spPr->children($this->aNamespace);
@@ -173,13 +174,7 @@ class Chart
$this->setAxisProperties($chartDetail, $xAxis);
break;
- case 'dateAx':
- if (isset($chartDetail->title)) {
- $XaxisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
- }
-
- break;
- case 'valAx':
+ case Axis::AXIS_TYPE_VALUE:
$whichAxis = null;
$axPos = null;
if (isset($chartDetail->axPos)) {
@@ -1375,6 +1370,15 @@ class Chart
if (isset($chartDetail->minorUnit)) {
$whichAxis->setAxisOption('minor_unit', (string) self::getAttribute($chartDetail->minorUnit, 'val', 'string'));
}
+ if (isset($chartDetail->baseTimeUnit)) {
+ $whichAxis->setAxisOption('baseTimeUnit', (string) self::getAttribute($chartDetail->baseTimeUnit, 'val', 'string'));
+ }
+ if (isset($chartDetail->majorTimeUnit)) {
+ $whichAxis->setAxisOption('majorTimeUnit', (string) self::getAttribute($chartDetail->majorTimeUnit, 'val', 'string'));
+ }
+ if (isset($chartDetail->minorTimeUnit)) {
+ $whichAxis->setAxisOption('minorTimeUnit', (string) self::getAttribute($chartDetail->minorTimeUnit, 'val', 'string'));
+ }
if (isset($chartDetail->txPr)) {
$children = $chartDetail->txPr->children($this->aNamespace);
if (isset($children->bodyPr)) {
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
index ad746a0a..48f7d255 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
@@ -490,13 +490,14 @@ class Chart extends WriterPart
private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id1, $id2, $isMultiLevelSeries, Axis $yAxis): void
{
// N.B. writeCategoryAxis may be invoked with the last parameter($yAxis) using $xAxis for ScatterChart, etc
- // In that case, xAxis is NOT a category.
- if ($yAxis->getAxisType() !== '') {
- $objWriter->startElement('c:' . $yAxis->getAxisType());
+ // In that case, xAxis may contain values like the yAxis, or it may be a date axis (LINECHART).
+ $axisType = $yAxis->getAxisType();
+ if ($axisType !== '') {
+ $objWriter->startElement("c:$axisType");
} elseif ($yAxis->getAxisIsNumericFormat()) {
- $objWriter->startElement('c:valAx');
+ $objWriter->startElement('c:' . Axis::AXIS_TYPE_VALUE);
} else {
- $objWriter->startElement('c:catAx');
+ $objWriter->startElement('c:' . Axis::AXIS_TYPE_CATEGORY);
}
$majorGridlines = $yAxis->getMajorGridlines();
$minorGridlines = $yAxis->getMinorGridlines();
@@ -654,7 +655,8 @@ class Chart extends WriterPart
}
$objWriter->startElement('c:auto');
- $objWriter->writeAttribute('val', '1');
+ // LineChart with dateAx wants '0'
+ $objWriter->writeAttribute('val', ($axisType === Axis::AXIS_TYPE_DATE) ? '0' : '1');
$objWriter->endElement();
$objWriter->startElement('c:lblAlgn');
@@ -665,6 +667,30 @@ class Chart extends WriterPart
$objWriter->writeAttribute('val', '100');
$objWriter->endElement();
+ if ($axisType === Axis::AXIS_TYPE_DATE) {
+ $property = 'baseTimeUnit';
+ $propertyVal = $yAxis->getAxisOptionsProperty($property);
+ if (!empty($propertyVal)) {
+ $objWriter->startElement("c:$property");
+ $objWriter->writeAttribute('val', $propertyVal);
+ $objWriter->endElement();
+ }
+ $property = 'majorTimeUnit';
+ $propertyVal = $yAxis->getAxisOptionsProperty($property);
+ if (!empty($propertyVal)) {
+ $objWriter->startElement("c:$property");
+ $objWriter->writeAttribute('val', $propertyVal);
+ $objWriter->endElement();
+ }
+ $property = 'minorTimeUnit';
+ $propertyVal = $yAxis->getAxisOptionsProperty($property);
+ if (!empty($propertyVal)) {
+ $objWriter->startElement("c:$property");
+ $objWriter->writeAttribute('val', $propertyVal);
+ $objWriter->endElement();
+ }
+ }
+
if ($isMultiLevelSeries) {
$objWriter->startElement('c:noMultiLvlLbl');
$objWriter->writeAttribute('val', '0');
@@ -683,7 +709,7 @@ class Chart extends WriterPart
*/
private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $groupType, $id1, $id2, $isMultiLevelSeries, Axis $xAxis): void
{
- $objWriter->startElement('c:valAx');
+ $objWriter->startElement('c:' . Axis::AXIS_TYPE_VALUE);
$majorGridlines = $xAxis->getMajorGridlines();
$minorGridlines = $xAxis->getMinorGridlines();
@@ -1079,7 +1105,7 @@ class Chart extends WriterPart
$objWriter->endElement(); // a:ln
}
}
- $nofill = $groupType == DataSeries::TYPE_STOCKCHART || ($groupType === DataSeries::TYPE_SCATTERCHART && !$plotSeriesValues->getScatterLines());
+ $nofill = $groupType === DataSeries::TYPE_STOCKCHART || (($groupType === DataSeries::TYPE_SCATTERCHART || $groupType === DataSeries::TYPE_LINECHART) && !$plotSeriesValues->getScatterLines());
if ($callLineStyles) {
$this->writeLineStyles($objWriter, $plotSeriesValues, $nofill);
$this->writeEffects($objWriter, $plotSeriesValues);
diff --git a/tests/PhpSpreadsheetTests/Chart/AxisPropertiesTest.php b/tests/PhpSpreadsheetTests/Chart/AxisPropertiesTest.php
index 91df25cb..0bfc2966 100644
--- a/tests/PhpSpreadsheetTests/Chart/AxisPropertiesTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/AxisPropertiesTest.php
@@ -109,7 +109,9 @@ class AxisPropertiesTest extends AbstractFunctional
'8', //minimum
'68', //maximum
'20', //majorUnit
- '5' //minorUnit
+ '5', //minorUnit
+ '6', //textRotation
+ '0', //hidden
);
self::assertSame(Properties::AXIS_LABELS_HIGH, $xAxis->getAxisOptionsProperty('axis_labels'));
self::assertNull($xAxis->getAxisOptionsProperty('horizontal_crosses_value'));
@@ -121,6 +123,8 @@ class AxisPropertiesTest extends AbstractFunctional
self::assertSame('68', $xAxis->getAxisOptionsProperty('maximum'));
self::assertSame('20', $xAxis->getAxisOptionsProperty('major_unit'));
self::assertSame('5', $xAxis->getAxisOptionsProperty('minor_unit'));
+ self::assertSame('6', $xAxis->getAxisOptionsProperty('textRotation'));
+ self::assertSame('0', $xAxis->getAxisOptionsProperty('hidden'));
$yAxis = new Axis();
$yAxis->setFillParameters('accent1', 30, 'schemeClr');
@@ -158,6 +162,8 @@ class AxisPropertiesTest extends AbstractFunctional
self::assertSame('68', $xAxis2->getAxisOptionsProperty('maximum'));
self::assertSame('20', $xAxis2->getAxisOptionsProperty('major_unit'));
self::assertSame('5', $xAxis2->getAxisOptionsProperty('minor_unit'));
+ self::assertSame('6', $xAxis2->getAxisOptionsProperty('textRotation'));
+ self::assertSame('0', $xAxis2->getAxisOptionsProperty('hidden'));
$yAxis2 = $chart->getChartAxisY();
self::assertSame('accent1', $yAxis2->getFillProperty('value'));
@@ -198,6 +204,8 @@ class AxisPropertiesTest extends AbstractFunctional
self::assertSame('68', $xAxis3->getAxisOptionsProperty('maximum'));
self::assertSame('20', $xAxis3->getAxisOptionsProperty('major_unit'));
self::assertSame('5', $xAxis3->getAxisOptionsProperty('minor_unit'));
+ self::assertSame('6', $xAxis3->getAxisOptionsProperty('textRotation'));
+ self::assertSame('0', $xAxis3->getAxisOptionsProperty('hidden'));
$yAxis3 = $chart2->getChartAxisY();
self::assertSame('accent1', $yAxis3->getFillProperty('value'));
diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32CatAxValAxTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32CatAxValAxTest.php
index 268ee094..1f046af9 100644
--- a/tests/PhpSpreadsheetTests/Chart/Charts32CatAxValAxTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/Charts32CatAxValAxTest.php
@@ -23,6 +23,8 @@ class Charts32CatAxValAxTest extends TestCase
/** @var string */
private $outputFileName = '';
+ private const FORMAT_CODE_DATE_ISO8601_SLASH = 'yyyy/mm/dd'; // not automatically treated as numeric
+
protected function tearDown(): void
{
if ($this->outputFileName !== '') {
@@ -48,7 +50,7 @@ class Charts32CatAxValAxTest extends TestCase
['=DATEVALUE("2021-01-10")', 30.2, 32.2, 0.2],
]
);
- $worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601);
+ $worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(self::FORMAT_CODE_DATE_ISO8601_SLASH);
$worksheet->getColumnDimension('A')->setAutoSize(true);
$worksheet->setSelectedCells('A1');
@@ -91,9 +93,9 @@ class Charts32CatAxValAxTest extends TestCase
$xAxis = new Axis();
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
if (is_bool($numeric)) {
- $xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, $numeric);
+ $xAxis->setAxisNumberProperties(self::FORMAT_CODE_DATE_ISO8601_SLASH, $numeric);
} else {
- $xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601);
+ $xAxis->setAxisNumberProperties(self::FORMAT_CODE_DATE_ISO8601_SLASH);
}
// Build the dataseries
diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php
index 6a4673fd..4cc62360 100644
--- a/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php
@@ -177,4 +177,45 @@ class Charts32XmlTest extends TestCase
)
);
}
+
+ public function testDateAx(): void
+ {
+ $file = self::DIRECTORY . '32readwriteLineDateAxisChart1.xlsx';
+ $reader = new XlsxReader();
+ $reader->setIncludeCharts(true);
+ $spreadsheet = $reader->load($file);
+ $sheet = $spreadsheet->getActiveSheet();
+ $charts = $sheet->getChartCollection();
+ self::assertCount(2, $charts);
+ $chart = $charts[1];
+ self::assertNotNull($chart);
+
+ $writer = new XlsxWriter($spreadsheet);
+ $writer->setIncludeCharts(true);
+ $writerChart = new XlsxWriter\Chart($writer);
+ $data = $writerChart->writeChart($chart);
+ $spreadsheet->disconnectWorksheets();
+
+ self::assertSame(
+ 1,
+ substr_count(
+ $data,
+ ''
+ )
+ );
+ self::assertSame(
+ 1,
+ substr_count(
+ $data,
+ ''
+ )
+ );
+ self::assertSame(
+ 1,
+ substr_count(
+ $data,
+ ''
+ )
+ );
+ }
}