fpspreadsheet: Complete primary and secondary axis support

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9068 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2023-12-04 18:53:04 +00:00
parent c47f53e62f
commit 157bb12de9
6 changed files with 116 additions and 44 deletions

View File

@ -44,6 +44,7 @@
<Filename Value="barchart_2axes_write_demo"/> <Filename Value="barchart_2axes_write_demo"/>
</Target> </Target>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
<Linking> <Linking>

View File

@ -57,7 +57,6 @@ begin
ser.SetYRange(3, 1, 8, 1); ser.SetYRange(3, 1, 8, 1);
ser.Fill.Style := cfsSolid; ser.Fill.Style := cfsSolid;
ser.Fill.Color := $0075ea; //597bff; ser.Fill.Color := $0075ea; //597bff;
ser.Fill.Color := scRed;
ser.Line.Style := clsNoLine; ser.Line.Style := clsNoLine;
// Add 2nd bar series ("Volume") // Add 2nd bar series ("Volume")

View File

@ -10,8 +10,7 @@ uses
athreads, athreads,
{$ENDIF} {$ENDIF}
Interfaces, // this includes the LCL widgetset Interfaces, // this includes the LCL widgetset
Forms, main, tachartlazaruspkg Forms, main;
{ you can add units after this };
{$R *.res} {$R *.res}

View File

@ -111,5 +111,6 @@ begin
sChartLink.WorkbookSource := sWorkbookSource1; sChartLink.WorkbookSource := sWorkbookSource1;
sChartLink.WorkbookChartIndex := 0; sChartLink.WorkbookChartIndex := 0;
end; end;
end. end.

View File

@ -2356,21 +2356,6 @@ begin
); );
end; end;
{ <style:style style:name="ch1400" style:family="chart" style:data-style-name="N0">
<style:chart-properties
chart:symbol-type="named-symbol"
chart:symbol-name="arrow-down"
chart:symbol-width="0.25cm"
chart:symbol-height="0.25cm"
chart:link-data-style-to-source="true"/>
<style:graphic-properties
svg:stroke-width="0.08cm"
svg:stroke-color="#ffd320"
draw:fill-color="#ffd320"
dr3d:edge-rounding="5%"/>
<style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
</style:style> }
function TsSpreadOpenDocChartWriter.GetChartSeriesStyleAsXML(AChart: TsChart; function TsSpreadOpenDocChartWriter.GetChartSeriesStyleAsXML(AChart: TsChart;
ASeriesIndex, AIndent, AStyleID: Integer): String; ASeriesIndex, AIndent, AStyleID: Integer): String;
var var

View File

@ -24,8 +24,8 @@ uses
// TAChart // TAChart
TATypes, TATextElements, TAChartUtils, TADrawUtils, TALegend, TATypes, TATextElements, TAChartUtils, TADrawUtils, TALegend,
TACustomSource, TASources, TACustomSeries, TASeries, TARadialSeries, TACustomSource, TASources, TACustomSeries, TASeries, TARadialSeries,
TAFitUtils, TAFuncSeries, TAMultiSeries, TAFitUtils, TAFuncSeries, TAMultiSeries, TATransformations,
TAChartAxisUtils, TAChartAxis, TAStyles, TAGraph, TAChartAxisUtils, TAChartAxis, TAStyles, TATools, TAGraph,
// FPSpreadsheet // FPSpreadsheet
fpsTypes, fpSpreadsheet, fpsUtils, fpsChart, fpsTypes, fpSpreadsheet, fpsUtils, fpsChart,
// FPSpreadsheet Visual // FPSpreadsheet Visual
@ -126,12 +126,14 @@ type
function ActiveChartSeries(ASeries: TsChartSeries): TChartSeries; function ActiveChartSeries(ASeries: TsChartSeries): TChartSeries;
procedure AddSeries(ASeries: TsChartSeries); procedure AddSeries(ASeries: TsChartSeries);
procedure FixAreaSeries(AWorkbookChart: TsChart); procedure FixAreaSeries({%H-}AWorkbookChart: TsChart);
procedure FixBarSeries(AWorkbookChart: TsChart);
procedure ClearChart; procedure ClearChart;
procedure ConstructHatchPattern(AWorkbookChart: TsChart; AFill: TsChartFill; ABrush: TBrush); procedure ConstructHatchPattern(AWorkbookChart: TsChart; AFill: TsChartFill; ABrush: TBrush);
procedure ConstructHatchPatternSolid(AWorkbookChart: TsChart; AFill: TsChartFill; ABrush: TBrush); procedure ConstructHatchPatternSolid(AWorkbookChart: TsChart; AFill: TsChartFill; ABrush: TBrush);
procedure ConstructSeriesMarks(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries); procedure ConstructSeriesMarks(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries);
function GetWorkbookChart: TsChart; function GetWorkbookChart: TsChart;
function IsSecondaryAxis(Axis: TsChartAxis): boolean;
function IsStackable(ASeries: TsChartSeries): Boolean; function IsStackable(ASeries: TsChartSeries): Boolean;
procedure UpdateChartAxis(AWorkbookAxis: TsChartAxis); procedure UpdateChartAxis(AWorkbookAxis: TsChartAxis);
@ -142,7 +144,7 @@ type
procedure UpdateChartLegend(AWorkbookLegend: TsChartLegend; ALegend: TChartLegend); procedure UpdateChartLegend(AWorkbookLegend: TsChartLegend; ALegend: TChartLegend);
procedure UpdateChartPen(AWorkbookChart: TsChart; AWorkbookLine: TsChartLine; APen: TPen); procedure UpdateChartPen(AWorkbookChart: TsChart; AWorkbookLine: TsChartLine; APen: TPen);
procedure UpdateChartSeriesMarks(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries); procedure UpdateChartSeriesMarks(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries);
procedure UpdateChartStyle(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries; AStyleIndex: Integer); procedure UpdateChartStyle(AWorkbookSeries: TsChartSeries; AStyleIndex: Integer);
procedure UpdateChartTitle(AWorkbookTitle: TsChartText; AChartTitle: TChartTitle); procedure UpdateChartTitle(AWorkbookTitle: TsChartText; AChartTitle: TChartTitle);
procedure UpdateAreaSeries(AWorkbookSeries: TsAreaSeries; AChartSeries: TAreaSeries); procedure UpdateAreaSeries(AWorkbookSeries: TsAreaSeries; AChartSeries: TAreaSeries);
@ -1129,7 +1131,7 @@ begin
UpdateChartSeriesMarks(ASeries, ser); UpdateChartSeriesMarks(ASeries, ser);
if IsStackable(ASeries) then if IsStackable(ASeries) then
begin begin
UpdateChartStyle(ASeries, ser, FChartStyles.Styles.Count-1); UpdateChartStyle(ASeries, FChartStyles.Styles.Count-1);
if ASeries.Chart.StackMode = csmStackedPercentage then if ASeries.Chart.StackMode = csmStackedPercentage then
FChart.LeftAxis.Marks.Format := Convert_NumFormatStr_to_FormatStr(axis.LabelFormatPercent) FChart.LeftAxis.Marks.Format := Convert_NumFormatStr_to_FormatStr(axis.LabelFormatPercent)
else else
@ -1207,6 +1209,9 @@ begin
// Clear the axes // Clear the axes
for i := FChart.AxisList.Count-1 downto 0 do for i := FChart.AxisList.Count-1 downto 0 do
begin begin
if FChart.AxisList[i].Transformations <> nil then
FChart.AxisList[i].Transformations.Free;
if FChart.AxisList[i].Minors <> nil then if FChart.AxisList[i].Minors <> nil then
for j := FChart.AxisList[i].Minors.Count-1 downto 0 do for j := FChart.AxisList[i].Minors.Count-1 downto 0 do
FChart.AxisList[i].Minors.Delete(j); FChart.AxisList[i].Minors.Delete(j);
@ -1389,14 +1394,18 @@ begin
end; end;
end; end;
} }
// Fix area series zero level not being clipped at chart's plotrect.
{@@ ----------------------------------------------------------------------------
Adjusts the area series zero level which, otherwise, is not clipped at the
chart's plotrect (in TAChart before v3.99)
-------------------------------------------------------------------------------}
procedure TsWorkbookChartLink.FixAreaSeries(AWorkbookChart: TsChart); procedure TsWorkbookChartLink.FixAreaSeries(AWorkbookChart: TsChart);
{$IF LCL_FullVersion < 3990000}
var var
i: Integer; i: Integer;
ser: TAreaSeries; ser: TAreaSeries;
ext: TDoubleRect; ext: TDoubleRect;
begin begin
{$IF LCL_FullVersion < 3990000}
if AWorkbookChart.GetChartType <> ctArea then if AWorkbookChart.GetChartType <> ctArea then
exit; exit;
@ -1411,7 +1420,43 @@ begin
ser.ZeroLevel := ext.b.y; ser.ZeroLevel := ext.b.y;
ser.UseZeroLevel := true; ser.UseZeroLevel := true;
end; end;
{$ENDIF} end;
{$ELSE}
begin
//
end;
{$ENDIF}
{@@ ----------------------------------------------------------------------------
Adjusts bar widths and offsets for side-by-side bar charts.
-------------------------------------------------------------------------------}
procedure TsWorkbookChartLink.FixBarSeries(AWorkbookChart: TsChart);
const
TOTAL_BARWIDTH = 75;
var
i, n: Integer;
wBar: Integer;
offs: Integer;
ser: TBarSeries;
begin
if AWorkbookChart.GetChartType <> ctBar then
exit;
// Count number of bar series
n := 0;
for i := 0 to FChart.SeriesCount - 1 do
if FChart.Series[i] is TBarSeries then inc(n);
// Calc bar width and adjust offset of each series within group
wBar := TOTAL_BARWIDTH div n;
offs := (wBar - TOTAL_BARWIDTH) div 2;
for i := 0 to FChart.SeriesCount - 1 do
if FChart.Series[i] is TBarSeries then
begin
ser := TBarSeries(FChart.Series[i]);
ser.BarWidthPercent := wBar;
ser.BarOffsetPercent := offs + wBar * i;
end;
end; end;
function TsWorkbookChartLink.GetWorkbookChart: TsChart; function TsWorkbookChartLink.GetWorkbookChart: TsChart;
@ -1422,30 +1467,37 @@ begin
Result := nil; Result := nil;
end; end;
function TsWorkbookChartLink.IsSecondaryAxis(Axis: TsChartAxis): Boolean;
begin
Result := (Axis = Axis.Chart.Y2Axis) or (Axis = Axis.Chart.X2Axis);
end;
{@@ ----------------------------------------------------------------------------
Bar, line and area series can be stacked if they are assigned to the same axis.
-------------------------------------------------------------------------------}
function TsWorkbookChartLink.IsStackable(ASeries: TsChartSeries): Boolean; function TsWorkbookChartLink.IsStackable(ASeries: TsChartSeries): Boolean;
var var
nextSeries: TsChartSeries; ch: TsChart;
firstSeries: TsChartSeries;
i, numSeries: Integer; i, numSeries: Integer;
begin begin
Result := (ASeries.ChartType in [ctBar, ctLine, ctArea]); Result := (ASeries.ChartType in [ctBar, ctLine, ctArea]);
if Result then if Result then
begin begin
numSeries := ASeries.Chart.Series.Count; ch := ASeries.Chart;
firstSeries := ASeries.Chart.Series[0]; numSeries := ch.Series.Count;
nextSeries := nil; if numSeries = 1 then
exit;
// Check whether all series are the same type and same y axis as ASeries.
// NOTE: Not perfect yet since there might abe two stackable groups,
// one for the left and one for the right axis...
for i := 0 to numSeries - 1 do for i := 0 to numSeries - 1 do
if (ASeries.Chart.Series[i] = ASeries) then if (ch.Series[i].ChartType <> ASeries.ChartType) or
(ch.Series[i].YAxis <> ASeries.YAxis) then
begin begin
if i < numSeries - 1 then Result := false;
nextSeries := ASeries.Chart.Series[i+1];
exit; exit;
end; end;
Result := (firstSeries.YAxis = ASeries.YAxis) and
(
((nextSeries <> nil) and (nextSeries.YAxis = ASeries.YAxis)) or
((nextSeries = nil) and (firstSeries = ASeries))
);
end; end;
end; end;
@ -1579,6 +1631,7 @@ begin
FChart.Prepare; FChart.Prepare;
UpdateChartAxisLabels(ch); UpdateChartAxisLabels(ch);
FixAreaSeries(ch); FixAreaSeries(ch);
FixBarSeries(ch);
end; end;
procedure TsWorkbookChartLink.UpdateChartAxis(AWorkbookAxis: TsChartAxis); procedure TsWorkbookChartLink.UpdateChartAxis(AWorkbookAxis: TsChartAxis);
@ -1586,9 +1639,12 @@ var
align: TChartAxisAlignment; align: TChartAxisAlignment;
axis: TChartAxis; axis: TChartAxis;
minorAxis: TChartMinorAxis; minorAxis: TChartMinorAxis;
T: TAxisTransform;
logTransf: TLogarithmAxisTransform;
begin begin
if AWorkbookAxis = nil then if AWorkbookAxis = nil then
exit; exit;
if AWorkbookAxis = AWorkbookAxis.Chart.XAxis then if AWorkbookAxis = AWorkbookAxis.Chart.XAxis then
align := calBottom align := calBottom
else if AWorkbookAxis = AWorkbookAxis.Chart.X2Axis then else if AWorkbookAxis = AWorkbookAxis.Chart.X2Axis then
@ -1617,6 +1673,7 @@ begin
axis.Title.Caption := AWorkbookAxis.Title.Caption; axis.Title.Caption := AWorkbookAxis.Title.Caption;
axis.Title.Visible := true; axis.Title.Visible := true;
Convert_sFont_to_Font(AWorkbookAxis.Title.Font, axis.Title.LabelFont); Convert_sFont_to_Font(AWorkbookAxis.Title.Font, axis.Title.LabelFont);
axis.Title.LabelFont.Orientation := round(AWorkbookAxis.Title.RotationAngle * 10);
// Labels // Labels
Convert_sFont_to_Font(AWorkbookAxis.LabelFont, axis.Marks.LabelFont); Convert_sFont_to_Font(AWorkbookAxis.LabelFont, axis.Marks.LabelFont);
@ -1628,7 +1685,7 @@ begin
// Major axis grid // Major axis grid
UpdateChartPen(AWorkbookAxis.Chart, AWorkbookAxis.MajorGridLines, axis.Grid); UpdateChartPen(AWorkbookAxis.Chart, AWorkbookAxis.MajorGridLines, axis.Grid);
axis.Grid.Visible := axis.Grid.Style <> psClear; axis.Grid.Visible := (axis.Grid.Style <> psClear) and not IsSecondaryAxis(AWorkbookAxis);
axis.TickLength := IfThen(catOutside in AWorkbookAxis.MajorTicks, 4, 0); axis.TickLength := IfThen(catOutside in AWorkbookAxis.MajorTicks, 4, 0);
axis.TickInnerLength := IfThen(catInside in AWorkbookAxis.MajorTicks, 4, 0); axis.TickInnerLength := IfThen(catInside in AWorkbookAxis.MajorTicks, 4, 0);
axis.TickColor := axis.AxisPen.Color; axis.TickColor := axis.AxisPen.Color;
@ -1639,7 +1696,7 @@ begin
begin begin
minorAxis := axis.Minors.Add; minorAxis := axis.Minors.Add;
UpdateChartPen(AWorkbookAxis.Chart, AWorkbookAxis.MinorGridLines, minorAxis.Grid); UpdateChartPen(AWorkbookAxis.Chart, AWorkbookAxis.MinorGridLines, minorAxis.Grid);
minorAxis.Grid.Visible := true; minorAxis.Grid.Visible := not IsSecondaryAxis(AWorkbookAxis);
minorAxis.Intervals.Count := AWorkbookAxis.MinorCount; minorAxis.Intervals.Count := AWorkbookAxis.MinorCount;
minorAxis.TickLength := IfThen(catOutside in AWorkbookAxis.MinorTicks, 2, 0); minorAxis.TickLength := IfThen(catOutside in AWorkbookAxis.MinorTicks, 2, 0);
minorAxis.TickInnerLength := IfThen(catInside in AWorkbookAxis.MinorTicks, 2, 0); minorAxis.TickInnerLength := IfThen(catInside in AWorkbookAxis.MinorTicks, 2, 0);
@ -1650,14 +1707,44 @@ begin
// Inverted? // Inverted?
axis.Inverted := AWorkbookAxis.Inverted; axis.Inverted := AWorkbookAxis.Inverted;
// Logarithmic? // Usually not needed, but axis handling is simplified when there is
// to do.... // an axis transformation at each axis.
if axis.Transformations = nil then
begin
axis.Transformations := TChartAxisTransformations.Create(FChart);
// Autoscale transformation for primary and secondary axes
T := TAutoScaleAxisTransform.Create(axis.Transformations);
T.Transformations := axis.Transformations;
if AWorkbookAxis.Chart.GetChartType in [ctRadar, ctFilledRadar] then
T.Enabled := false;
// Logarithmic
T := TLogarithmAxisTransform.Create(axis.Transformations);
T.Transformations := axis.Transformations;
TLogarithmAxisTransform(T).Base := 10;
TLogarithmAxisTransform(T).Enabled := AWorkbookAxis.Logarithmic;
end;
// Scaling // Scaling
axis.Range.UseMin := not AWorkbookAxis.AutomaticMin; axis.Range.UseMin := not AWorkbookAxis.AutomaticMin;
axis.Range.UseMax := not AWorkbookAxis.AutomaticMax; axis.Range.UseMax := not AWorkbookAxis.AutomaticMax;
axis.Range.Min := AWorkbookAxis.Min; axis.Range.Min := AWorkbookAxis.Min;
axis.Range.Max := AWorkbookAxis.Max; axis.Range.Max := AWorkbookAxis.Max;
// Logarithmic
logTransf := TLogarithmAxisTransform(axis.Transformations.List[1]);
logTransf.Enabled := AWorkbookAxis.Logarithmic;
if AWorkbookAxis.Logarithmic then
begin
// axis.Intervals.Options := axis.Intervals.Options + [aipInteger];;
axis.Intervals.MaxLength := 150;
axis.Intervals.MinLength := 30;
axis.Intervals.Tolerance := 30;
end else
begin
axis.Intervals.MaxLength := 100;
axis.Intervals.MinLength := 20;
axis.Intervals.Tolerance := 0;
end;
end; end;
procedure TsWorkbookChartLink.UpdateChartAxisLabels(AWorkbookChart: TsChart); procedure TsWorkbookChartLink.UpdateChartAxisLabels(AWorkbookChart: TsChart);
@ -1849,7 +1936,7 @@ begin
end; end;
procedure TsWorkbookChartLink.UpdateChartStyle(AWorkbookSeries: TsChartSeries; procedure TsWorkbookChartLink.UpdateChartStyle(AWorkbookSeries: TsChartSeries;
AChartSeries: TChartSeries; AStyleIndex: Integer); AStyleIndex: Integer);
var var
style: TChartStyle; style: TChartStyle;
begin begin