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"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>

View File

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

View File

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

View File

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

View File

@ -2356,21 +2356,6 @@ begin
);
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;
ASeriesIndex, AIndent, AStyleID: Integer): String;
var

View File

@ -24,8 +24,8 @@ uses
// TAChart
TATypes, TATextElements, TAChartUtils, TADrawUtils, TALegend,
TACustomSource, TASources, TACustomSeries, TASeries, TARadialSeries,
TAFitUtils, TAFuncSeries, TAMultiSeries,
TAChartAxisUtils, TAChartAxis, TAStyles, TAGraph,
TAFitUtils, TAFuncSeries, TAMultiSeries, TATransformations,
TAChartAxisUtils, TAChartAxis, TAStyles, TATools, TAGraph,
// FPSpreadsheet
fpsTypes, fpSpreadsheet, fpsUtils, fpsChart,
// FPSpreadsheet Visual
@ -126,12 +126,14 @@ type
function ActiveChartSeries(ASeries: TsChartSeries): TChartSeries;
procedure AddSeries(ASeries: TsChartSeries);
procedure FixAreaSeries(AWorkbookChart: TsChart);
procedure FixAreaSeries({%H-}AWorkbookChart: TsChart);
procedure FixBarSeries(AWorkbookChart: TsChart);
procedure ClearChart;
procedure ConstructHatchPattern(AWorkbookChart: TsChart; AFill: TsChartFill; ABrush: TBrush);
procedure ConstructHatchPatternSolid(AWorkbookChart: TsChart; AFill: TsChartFill; ABrush: TBrush);
procedure ConstructSeriesMarks(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries);
function GetWorkbookChart: TsChart;
function IsSecondaryAxis(Axis: TsChartAxis): boolean;
function IsStackable(ASeries: TsChartSeries): Boolean;
procedure UpdateChartAxis(AWorkbookAxis: TsChartAxis);
@ -142,7 +144,7 @@ type
procedure UpdateChartLegend(AWorkbookLegend: TsChartLegend; ALegend: TChartLegend);
procedure UpdateChartPen(AWorkbookChart: TsChart; AWorkbookLine: TsChartLine; APen: TPen);
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 UpdateAreaSeries(AWorkbookSeries: TsAreaSeries; AChartSeries: TAreaSeries);
@ -1129,7 +1131,7 @@ begin
UpdateChartSeriesMarks(ASeries, ser);
if IsStackable(ASeries) then
begin
UpdateChartStyle(ASeries, ser, FChartStyles.Styles.Count-1);
UpdateChartStyle(ASeries, FChartStyles.Styles.Count-1);
if ASeries.Chart.StackMode = csmStackedPercentage then
FChart.LeftAxis.Marks.Format := Convert_NumFormatStr_to_FormatStr(axis.LabelFormatPercent)
else
@ -1207,6 +1209,9 @@ begin
// Clear the axes
for i := FChart.AxisList.Count-1 downto 0 do
begin
if FChart.AxisList[i].Transformations <> nil then
FChart.AxisList[i].Transformations.Free;
if FChart.AxisList[i].Minors <> nil then
for j := FChart.AxisList[i].Minors.Count-1 downto 0 do
FChart.AxisList[i].Minors.Delete(j);
@ -1389,14 +1394,18 @@ begin
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);
{$IF LCL_FullVersion < 3990000}
var
i: Integer;
ser: TAreaSeries;
ext: TDoubleRect;
begin
{$IF LCL_FullVersion < 3990000}
if AWorkbookChart.GetChartType <> ctArea then
exit;
@ -1411,7 +1420,43 @@ begin
ser.ZeroLevel := ext.b.y;
ser.UseZeroLevel := true;
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;
function TsWorkbookChartLink.GetWorkbookChart: TsChart;
@ -1422,30 +1467,37 @@ begin
Result := nil;
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;
var
nextSeries: TsChartSeries;
firstSeries: TsChartSeries;
ch: TsChart;
i, numSeries: Integer;
begin
Result := (ASeries.ChartType in [ctBar, ctLine, ctArea]);
if Result then
begin
numSeries := ASeries.Chart.Series.Count;
firstSeries := ASeries.Chart.Series[0];
nextSeries := nil;
ch := ASeries.Chart;
numSeries := ch.Series.Count;
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
if (ASeries.Chart.Series[i] = ASeries) then
if (ch.Series[i].ChartType <> ASeries.ChartType) or
(ch.Series[i].YAxis <> ASeries.YAxis) then
begin
if i < numSeries - 1 then
nextSeries := ASeries.Chart.Series[i+1];
Result := false;
exit;
end;
Result := (firstSeries.YAxis = ASeries.YAxis) and
(
((nextSeries <> nil) and (nextSeries.YAxis = ASeries.YAxis)) or
((nextSeries = nil) and (firstSeries = ASeries))
);
end;
end;
@ -1579,6 +1631,7 @@ begin
FChart.Prepare;
UpdateChartAxisLabels(ch);
FixAreaSeries(ch);
FixBarSeries(ch);
end;
procedure TsWorkbookChartLink.UpdateChartAxis(AWorkbookAxis: TsChartAxis);
@ -1586,9 +1639,12 @@ var
align: TChartAxisAlignment;
axis: TChartAxis;
minorAxis: TChartMinorAxis;
T: TAxisTransform;
logTransf: TLogarithmAxisTransform;
begin
if AWorkbookAxis = nil then
exit;
if AWorkbookAxis = AWorkbookAxis.Chart.XAxis then
align := calBottom
else if AWorkbookAxis = AWorkbookAxis.Chart.X2Axis then
@ -1617,6 +1673,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);
// Labels
Convert_sFont_to_Font(AWorkbookAxis.LabelFont, axis.Marks.LabelFont);
@ -1628,7 +1685,7 @@ begin
// Major 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.TickInnerLength := IfThen(catInside in AWorkbookAxis.MajorTicks, 4, 0);
axis.TickColor := axis.AxisPen.Color;
@ -1639,7 +1696,7 @@ begin
begin
minorAxis := axis.Minors.Add;
UpdateChartPen(AWorkbookAxis.Chart, AWorkbookAxis.MinorGridLines, minorAxis.Grid);
minorAxis.Grid.Visible := true;
minorAxis.Grid.Visible := not IsSecondaryAxis(AWorkbookAxis);
minorAxis.Intervals.Count := AWorkbookAxis.MinorCount;
minorAxis.TickLength := IfThen(catOutside in AWorkbookAxis.MinorTicks, 2, 0);
minorAxis.TickInnerLength := IfThen(catInside in AWorkbookAxis.MinorTicks, 2, 0);
@ -1650,14 +1707,44 @@ begin
// Inverted?
axis.Inverted := AWorkbookAxis.Inverted;
// Logarithmic?
// to do....
// Usually not needed, but axis handling is simplified when there is
// 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
axis.Range.UseMin := not AWorkbookAxis.AutomaticMin;
axis.Range.UseMax := not AWorkbookAxis.AutomaticMax;
axis.Range.Min := AWorkbookAxis.Min;
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;
procedure TsWorkbookChartLink.UpdateChartAxisLabels(AWorkbookChart: TsChart);
@ -1849,7 +1936,7 @@ begin
end;
procedure TsWorkbookChartLink.UpdateChartStyle(AWorkbookSeries: TsChartSeries;
AChartSeries: TChartSeries; AStyleIndex: Integer);
AStyleIndex: Integer);
var
style: TChartStyle;
begin