From 9c8682ff8bf908341b98960bb78bd0a7d6dbbcfb Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Wed, 14 Feb 2024 00:32:33 +0000 Subject: [PATCH] fpspreadsheet: Fix rotated axis titles. git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9239 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../fpspreadsheet/source/common/fpschart.pas | 47 ++++++++++--------- .../source/common/fpsopendocumentchart.pas | 16 ++++++- .../source/common/xlsxooxmlchart.pas | 32 +++++++++---- .../source/visual/fpspreadsheetchart.pas | 2 +- 4 files changed, 64 insertions(+), 33 deletions(-) diff --git a/components/fpspreadsheet/source/common/fpschart.pas b/components/fpspreadsheet/source/common/fpschart.pas index 47f133a8e..a5a99c481 100644 --- a/components/fpspreadsheet/source/common/fpschart.pas +++ b/components/fpspreadsheet/source/common/fpschart.pas @@ -302,6 +302,7 @@ type FAutomaticMinorSteps: Boolean; FAxisLine: TsChartLine; FCategoryRange: TsChartRange; + FDefaultTitleRotation: Boolean; FMajorGridLines: TsChartLine; FMinorGridLines: TsChartline; FInverted: Boolean; @@ -325,6 +326,7 @@ type FPositionValue: Double; FShowLabels: Boolean; FDateTime: Boolean; + function GetTitleRotationAngle: Single; procedure SetMax(AValue: Double); procedure SetMin(AValue: Double); procedure SetMinorCount(AValue: Integer); @@ -347,6 +349,7 @@ type property AxisLine: TsChartLine read FAxisLine write FAxisLine; property CategoryRange: TsChartRange read FCategoryRange write FCategoryRange; property DateTime: Boolean read FDateTime write FDateTime; + property DefaultTitleRotation: Boolean read FDefaultTitleRotation write FDefaultTitleRotation; property Inverted: Boolean read FInverted write FInverted; property LabelFont: TsFont read FLabelFont write FLabelFont; property LabelFormat: String read FLabelFormat write FLabelFormat; @@ -369,6 +372,7 @@ type property PositionValue: Double read FPositionValue write FPositionValue; property ShowLabels: Boolean read FShowLabels write FShowLabels; property Title: TsChartText read FTitle write FTitle; + property TitleRotationAngle: Single read GetTitleRotationAngle; property Visible; end; @@ -798,7 +802,6 @@ type FImages: TsChartImageList; function GetCategoryLabelRange: TsChartRange; - procedure SetRotatedAxes(AValue: Boolean); protected function AddSeries(ASeries: TsChartSeries): Integer; virtual; @@ -873,7 +876,7 @@ type { Connecting line between data points (for line and scatter series) } property Interpolation: TsChartInterpolation read FInterpolation write FInterpolation; { x and y axes exchanged (mainly for bar series, but works also for scatter and bubble series) } - property RotatedAxes: Boolean read FRotatedAxes write SetRotatedAxes; + property RotatedAxes: Boolean read FRotatedAxes write FRotatedAxes; { Stacking of series (for bar and area series ) } property StackMode: TsChartStackMode read FStackMode write FStackMode; @@ -1727,6 +1730,7 @@ begin FCategoryRange := TsChartRange.Create(AChart); FTitle := TsChartText.Create(AChart); + FDefaultTitleRotation := true; FLabelFont := TsFont.Create; FLabelFont.Size := 9; @@ -1842,6 +1846,26 @@ begin Result := Chart.X2Axis; end; +{@@ ---------------------------------------------------------------------------- + Returns the text rotation angle of the axis title. + When DefaultTitleRotation is true this is either 0 or 90, depending on the + axis direction. Otherwise it is the title's RotationAngle. +-------------------------------------------------------------------------------} +function TsChartAxis.GetTitleRotationAngle: Single; +var + rotated: Boolean; +begin + if FDefaultTitleRotation then + begin + rotated := FChart.RotatedAxes; + case FAlignment of + caaLeft, caaRight: if rotated then Result := 0 else Result := 90; + caaBottom, caaTop: if rotated then Result := 90 else Result := 0; + end; + end else + Result := FTitle.RotationAngle; +end; + procedure TsChartAxis.SetCategoryRange(ARow1, ACol1, ARow2, ACol2: Cardinal); begin SetCategoryRange('', ARow1, ACol1, '', ARow2, ACol2); @@ -2927,25 +2951,6 @@ begin Result := FLineStyles.Count; end; -procedure TsChart.SetRotatedAxes(AValue: Boolean); -begin - if FRotatedAxes = AValue then - exit; - FRotatedAxes := AValue; - if FRotatedAxes then - begin - FXAxis.Title.RotationAngle := FXAxis.Title.RotationAngle + 90; - FX2Axis.Title.RotationAngle := FX2Axis.Title.RotationAngle + 90; - FYAxis.Title.RotationAngle := FYAxis.Title.RotationAngle - 90; - FY2Axis.Title.RotationAngle := FY2Axis.Title.RotationAngle - 90; - end else - begin - FXAxis.Title.RotationAngle := FXAxis.Title.RotationAngle - 90; - FX2Axis.Title.RotationAngle := FX2Axis.Title.RotationAngle - 90; - FYAxis.Title.RotationAngle := FYAxis.Title.RotationAngle + 90; - FY2Axis.Title.RotationAngle := FY2Axis.Title.RotationAngle + 90; - end; -end; { TsChartList } diff --git a/components/fpspreadsheet/source/common/fpsopendocumentchart.pas b/components/fpspreadsheet/source/common/fpsopendocumentchart.pas index 242ed471d..14eadf8d3 100644 --- a/components/fpspreadsheet/source/common/fpsopendocumentchart.pas +++ b/components/fpspreadsheet/source/common/fpsopendocumentchart.pas @@ -1071,6 +1071,10 @@ begin AChart.YAxis.Visible := false; AChart.X2Axis.Visible := false; AChart.Y2Axis.Visible := false; + AChart.XAxis.DefaultTitleRotation := true; + AChart.YAxis.DefaultTitleRotation := true; + AChart.X2Axis.DefaultTitleRotation := true; + AChart.Y2Axis.DefaultTitleRotation := true; AChart.PlotArea.Border.Style := clsNoLine; AChart.Floor.Border.Style := clsNoLine; @@ -2346,6 +2350,7 @@ var font: TsFont; indent: String; rotAngle: Single; + rotAngleStr: String = ''; chartProps: String = ''; textProps: String = ''; begin @@ -2368,13 +2373,22 @@ begin end; font := axis.Title.Font; rotAngle := axis.Title.RotationAngle; + if not axis.DefaultTitleRotation then + begin + if AChart.RotatedAxes then + begin + if rotAngle = 0 then rotAngle := 90 else if rotAngle = 90 then rotAngle := 0; + end; + rotAngleStr := Format('%.1f', [rotangle], FPointSeparatorSettings); + end; end; else raise Exception.Create('[GetChartCaptionStyleAsXML] Unknown caption.'); end; chartProps := 'chart:auto-position="true" '; - chartProps := chartProps + Format('style:rotation-angle="%.1f" ', [rotAngle], FPointSeparatorSettings); + if rotAngleStr <> '' then + chartProps := chartProps + Format('style:rotation-angle="%s" ', [rotAngleStr]); textProps := TsSpreadOpenDocWriter(Writer).WriteFontStyleXMLAsString(font); diff --git a/components/fpspreadsheet/source/common/xlsxooxmlchart.pas b/components/fpspreadsheet/source/common/xlsxooxmlchart.pas index ffb7a128f..a4a319b33 100644 --- a/components/fpspreadsheet/source/common/xlsxooxmlchart.pas +++ b/components/fpspreadsheet/source/common/xlsxooxmlchart.pas @@ -119,7 +119,7 @@ type procedure WriteScatterSeries(AStream: TStream; AIndent: Integer; ASeries: TsScatterSeries; ASeriesIndex, APosInAxisGroup: Integer); procedure WriteChartLabels(AStream: TStream; AIndent: Integer; AFont: TsFont); - procedure WriteChartText(AStream: TStream; AIndent: Integer; AText: TsChartText); + procedure WriteChartText(AStream: TStream; AIndent: Integer; AText: TsChartText; ARotationAngle: Single); public constructor Create(AWriter: TsBasicSpreadWriter); override; @@ -2301,14 +2301,25 @@ begin s := GetAttrValue(child2, 'rot'); if (s <> '') and TryStrToInt(s, n) then begin - if n = 1000 then + if axis <> nil then begin - if axis <> nil then - n := DEFAULT_TEXT_DIR[axis.Chart.RotatedAxes, axis.Alignment] // not sure, but maybe 1000 means: default + if n = 1000 then + axis.DefaultTitleRotation := true else - n := 0; + begin + if n = 0 then + ATitle.RotationAngle := 0 + else + ATitle.RotationAngle := -n / ANGLE_MULTIPLIER; + axis.DefaultTitleRotation := false; + end; + end else + begin + if (n = 1000) or (n = 0) then + ATitle.RotationAngle := 0 + else + Atitle.RotationAngle := -n/ANGLE_MULTIPLIER; end; - ATitle.RotationAngle := -n / ANGLE_MULTIPLIER; end; end; 'a:lstStyle': @@ -2453,6 +2464,7 @@ end; procedure TsSpreadOOXMLChartReader.SetAxisDefaults(AWorkbookAxis: TsChartAxis); begin AWorkbookAxis.Title.Caption := ''; + AWorkbookAxis.DefaultTitleRotation := true; AWorkbookAxis.LabelRotation := 0; AWorkbookAxis.Visible := false; AWorkbookAxis.MajorGridLines.Style := clsNoLine; @@ -3842,7 +3854,7 @@ begin indent + '' + LE ); - WriteChartText(AStream, AIndent + 4, Axis.Title); + WriteChartText(AStream, AIndent + 4, Axis.Title, Axis.TitleRotationAngle); AppendToStream(AStream, indent + ' ' + LE + @@ -4636,7 +4648,7 @@ end; Writes a node containing either the chart title or axis title. -------------------------------------------------------------------------------} procedure TsSpreadOOXMLChartWriter.WriteChartText(AStream: TStream; - AIndent: Integer; AText: TsChartText); + AIndent: Integer; AText: TsChartText; ARotationAngle: Single); var indent: String; rotStr: String; @@ -4644,7 +4656,7 @@ begin if not AText.Visible then exit; - str(-AText.RotationAngle * ANGLE_MULTIPLIER:0:0, rotStr); + str(-ARotationAngle * ANGLE_MULTIPLIER:0:0, rotStr); indent := DupeString(' ', AIndent); AppendToStream(AStream, @@ -4685,7 +4697,7 @@ begin indent + '' + LE ); - WriteChartText(AStream, AIndent + 2, ATitle); + WriteChartText(AStream, AIndent + 2, ATitle, ATitle.RotationAngle); AppendToStream(AStream, indent + ' ' + LE + diff --git a/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas b/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas index 23ea257ac..e38955d7a 100644 --- a/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas +++ b/components/fpspreadsheet/source/visual/fpspreadsheetchart.pas @@ -2150,7 +2150,7 @@ begin axis.Title.Caption := AWorkbookAxis.Title.Caption; axis.Title.Visible := true; Convert_sFont_to_Font(AWorkbookAxis.Title.Font, axis.Title.LabelFont); - axis.Title.LabelFont.Orientation := round(AWorkbookAxis.Title.RotationAngle * 10); + axis.Title.LabelFont.Orientation := round(AWorkbookAxis.TitleRotationAngle * 10); // Labels Convert_sFont_to_Font(AWorkbookAxis.LabelFont, axis.Marks.LabelFont);