fpspreadsheet: Radar series support in xlsx chart reader/writer. Fix some issues with radar series in ods.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9222 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-02-07 17:36:41 +00:00
parent 45ec507997
commit 76c0221e9e
7 changed files with 196 additions and 112 deletions

View File

@ -51,11 +51,6 @@
<DebugInfoType Value="dsDwarf3"/> <DebugInfoType Value="dsDwarf3"/>
</Debugging> </Debugging>
</Linking> </Linking>
<Other>
<ConfigFile>
<WriteConfigFilePath Value=""/>
</ConfigFile>
</Other>
</CompilerOptions> </CompilerOptions>
<Debugging> <Debugging>
<Exceptions> <Exceptions>

View File

@ -12,8 +12,13 @@ var
book: TsWorkbook; book: TsWorkbook;
sheet: TsWorksheet; sheet: TsWorksheet;
ch: TsChart; ch: TsChart;
ser: TsChartSeries; ser: TsRadarSeries;
fn, dir: String;
begin begin
dir := ExtractFilePath(ParamStr(0)) + 'files/';
ForceDirectories(dir);
fn := dir + FILE_NAME;
book := TsWorkbook.Create; book := TsWorkbook.Create;
try try
// worksheet // worksheet
@ -51,25 +56,29 @@ begin
ser.SetLabelRange(3, 0, 10, 0); ser.SetLabelRange(3, 0, 10, 0);
ser.SetYRange(3, 1, 10, 1); ser.SetYRange(3, 1, 10, 1);
ser.Line.Color := scDarkRed; ser.Line.Color := scDarkRed;
ser.Fill.Color := scRed; //ser.Fill.Style := cfsNoFill; // --> non-filled radar chrt
ser.Fill.Transparency := 0.35; ser.ShowSymbols := true;
ser.Symbol := cssDiamond;
ser.SymbolFill.Style := cfsSolid;
ser.SymbolFill.Color := scYellow;
// in ods the symbol color is always equal to the line color
ser.SymbolWidth := 12; //3;
ser.SymbolHeight := 12; // 3;
// Add 2nd radar series ("Student 2") // Add 2nd radar series ("Student 2")
ser := TsRadarSeries.Create(ch); ser := TsFilledRadarSeries.Create(ch);
ser.SetTitleAddr(2, 2); ser.SetTitleAddr(2, 2);
ser.SetLabelRange(3, 0, 10, 0); ser.SetLabelRange(3, 0, 10, 0);
ser.SetYRange(3, 2, 10, 2); ser.SetYRange(3, 2, 10, 2);
ser.Line.Color := scDarkBlue; ser.Line.Color := scDarkBlue;
ser.Fill.Color := scBlue; ser.Fill.Color := $FFCC99;
ser.Fill.Transparency := 0.35; ser.Fill.Transparency := 0.35;
{ book.WriteToFile(fn + '.xlsx', true);
book.WriteToFile(FILE_NAME + '.xlsx', true); // Excel fails to open the file WriteLn('Data saved with chart in ', fn + '.xlsx');
WriteLn('Data saved with chart in ', FILE_NAME, '.xlsx');
}
book.WriteToFile(FILE_NAME + '.ods', true); book.WriteToFile(fn + '.ods', true);
WriteLn('Data saved with chart in ', FILE_NAME, '.ods'); WriteLn('Data saved with chart in ', fn + '.ods');
finally finally
book.Free; book.Free;
end; end;

View File

@ -6,7 +6,7 @@ interface
uses uses
Classes, SysUtils, Classes, SysUtils,
LCLVersion, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, LCLVersion, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, FileUtil,
TAGraph, TASources, TAGraph, TASources,
fpSpreadsheet, fpsTypes, fpsOpenDocument, xlsxOOXML, fpSpreadsheet, fpsTypes, fpsOpenDocument, xlsxOOXML,
fpSpreadsheetCtrls, fpSpreadsheetGrid, fpSpreadsheetChart; fpSpreadsheetCtrls, fpSpreadsheetGrid, fpSpreadsheetChart;
@ -35,6 +35,7 @@ type
procedure FormCreate(Sender: TObject); procedure FormCreate(Sender: TObject);
procedure sWorkbookSource1Error(Sender: TObject; const AMsg: String); procedure sWorkbookSource1Error(Sender: TObject; const AMsg: String);
private private
FDir: String;
sChartLink: TsWorkbookChartLink; sChartLink: TsWorkbookChartLink;
procedure LoadFile(AFileName: String); procedure LoadFile(AFileName: String);
@ -114,13 +115,27 @@ procedure TForm1.ComboBox1CloseUp(Sender: TObject);
begin begin
if ComboBox1.ItemIndex > -1 then if ComboBox1.ItemIndex > -1 then
begin begin
Combobox1.Text := Combobox1.Items[Combobox1.ItemIndex]; Combobox1.Text := FDir + Combobox1.Items[Combobox1.ItemIndex];
LoadFile(Combobox1.Text); LoadFile(Combobox1.Text);
end; end;
end; end;
procedure TForm1.FormCreate(Sender: TObject); procedure TForm1.FormCreate(Sender: TObject);
var
L: TStrings;
i: Integer;
begin begin
FDir := ExpandFileName(Application.Location + '../../../other/chart/files/');
L := TStringList.Create;
try
FindAllFiles(L, FDir, '*.xlsx;*.ods', false);
for i := 0 to L.Count-1 do
L[i] := ExtractFileName(L[i]);
Combobox1.Items.Assign(L);
finally
L.Free;
end;
{$IF LCL_FullVersion >= 2020000} {$IF LCL_FullVersion >= 2020000}
ComboBox1.TextHint := 'Enter or select file name'; ComboBox1.TextHint := 'Enter or select file name';
{$IFEND} {$IFEND}

View File

@ -619,13 +619,12 @@ type
FSymbolWidth: Double; // in mm FSymbolWidth: Double; // in mm
FShowLines: Boolean; FShowLines: Boolean;
FShowSymbols: Boolean; FShowSymbols: Boolean;
FBorder: TsChartLine; FSymbolBorder: TsChartLine;
function GetSymbolFill: TsChartFill; FSymbolFill: TsChartFill;
procedure SetSymbolFill(Value: TsChartFill);
protected protected
property Symbol: TsChartSeriesSymbol read FSymbol write FSymbol; property Symbol: TsChartSeriesSymbol read FSymbol write FSymbol;
property SymbolBorder: TsChartLine read FBorder write FBorder; property SymbolBorder: TsChartLine read FSymbolBorder write FSymbolBorder;
property SymbolFill: TsChartFill read GetSymbolFill write SetSymbolFill; property SymbolFill: TsChartFill read FSymbolFill write FSymbolFill;
property SymbolHeight: double read FSymbolHeight write FSymbolHeight; property SymbolHeight: double read FSymbolHeight write FSymbolHeight;
property SymbolWidth: double read FSymbolWidth write FSymbolWidth; property SymbolWidth: double read FSymbolWidth write FSymbolWidth;
property ShowLines: Boolean read FShowLines write FShowLines; property ShowLines: Boolean read FShowLines write FShowLines;
@ -666,18 +665,15 @@ type
end; end;
TsRadarSeries = class(TsLineSeries) TsRadarSeries = class(TsLineSeries)
protected
function GetChartType: TsChartType; override;
end;
{
TsRingSeries = class(TsPieSeries)
private
FInnerRadiusPercent: Integer;
public public
constructor Create(AChart: TsChart); override; constructor Create(AChart: TsChart); override;
property InnerRadiusPercent: Integer read FInnerRadiusPercent write FInnerRadiusPercent;
end; end;
}
TsFilledRadarSeries = class(TsRadarSeries)
public
constructor Create(AChart: TsChart); override;
end;
TsCustomScatterSeries = class(TsCustomLineSeries) TsCustomScatterSeries = class(TsCustomLineSeries)
public public
constructor Create(AChart: TsChart); override; constructor Create(AChart: TsChart); override;
@ -2490,27 +2486,22 @@ begin
FShowSymbols := false; FShowSymbols := false;
FShowLines := true; FShowLines := true;
FBorder := TsChartLine.Create; FSymbolBorder := TsChartLine.Create;
FBorder.Style := clsSolid; FSymbolBorder.Style := clsSolid;
FBorder.Width := PtsToMM(DEFAULT_CHART_LINEWIDTH); FSymbolBorder.Width := PtsToMM(DEFAULT_CHART_LINEWIDTH);
FBorder.Color := scBlack; FSymbolBorder.Color := scBlack;
FSymbolFill := TsChartFill.Create;
FSymbolFill.Style := cfsNoFill;
end; end;
destructor TsCustomLineSeries.Destroy; destructor TsCustomLineSeries.Destroy;
begin begin
FBorder.Free; FSymbolBorder.Free;
FSymbolFill.Free;
inherited; inherited;
end; end;
function TsCustomLineSeries.GetSymbolFill: TsChartFill;
begin
Result := FFill;
end;
procedure TsCustomLineSeries.SetSymbolFill(Value: TsChartFill);
begin
FFill := Value;
end;
{ TsPieSeries } { TsPieSeries }
constructor TsPieSeries.Create(AChart: TsChart); constructor TsPieSeries.Create(AChart: TsChart);
@ -2545,23 +2536,21 @@ end;
{ TsRadarSeries } { TsRadarSeries }
function TsRadarSeries.GetChartType: TsChartType; constructor TsRadarSeries.Create(AChart: TsChart);
begin
if Fill.Style <> cfsNoFill then
Result := ctFilledRadar
else
Result := ctRadar;
end;
(*
{ TsRingSeries }
constructor TsRingSeries.Create(AChart: TsChart);
begin begin
inherited Create(AChart); inherited Create(AChart);
FChartType := ctRing; FChartType := ctRadar;
FLine.Color := scBlack; FFill.Style := cfsNoFill; // to make the series default to ctRadar rather than ctFilledRadar
FInnerRadiusPercent := 50; end;
end; *)
{ TsFilledRadarSeries }
constructor TsFilledRadarSeries.Create(AChart: TsChart);
begin
inherited Create(AChart);
FChartType := ctFilledRadar;
Fill.Style := cfsSolid;
end;
{ TsTrendlineEquation } { TsTrendlineEquation }

View File

@ -1491,20 +1491,18 @@ begin
series := TsBarSeries.Create(AChart); series := TsBarSeries.Create(AChart);
'chart:bubble': 'chart:bubble':
series := TsBubbleSeries.Create(AChart); series := TsBubbleSeries.Create(AChart);
// 'chart:circle':
// series := TsPieSeries.Create(AChart);
'chart:filled-radar':
series := TsRadarSeries.Create(AChart);
'chart:line':
series := TsLineSeries.Create(AChart);
'chart:radar':
series := TsRadarSeries.Create(AChart);
'chart:circle': 'chart:circle':
begin begin
series := TsPieSeries.Create(AChart); series := TsPieSeries.Create(AChart);
if FChartType = ctRing then if FChartType = ctRing then
TsPieSeries(series).InnerRadiusPercent := 50; TsPieSeries(series).InnerRadiusPercent := 50;
end; end;
'chart:line':
series := TsLineSeries.Create(AChart);
'chart:radar':
series := TsRadarSeries.Create(AChart);
'chart:filled-radar':
series := TsFilledRadarSeries.Create(AChart);
'chart:scatter': 'chart:scatter':
series := TsScatterSeries.Create(AChart); series := TsScatterSeries.Create(AChart);
// 'chart:stock': --- has already been created // 'chart:stock': --- has already been created
@ -1650,6 +1648,13 @@ begin
if ASeries.ChartType in [ctBar] then if ASeries.ChartType in [ctBar] then
ASeries.Line.Style := clsSolid; ASeries.Line.Style := clsSolid;
GetChartLineProps(AStyleNode, AChart, ASeries.Line); GetChartLineProps(AStyleNode, AChart, ASeries.Line);
if ((ASeries is TsRadarSeries) and (ASeries.ChartType = ctRadar)) or (ASeries is TsCustomLineSeries) then
begin
// In ods, symbols and lines have the same color
TsRadarSeries(ASeries).SymbolFill.Style := cfsSolid;
TsRadarSeries(ASeries).SymbolFill.Color := ASeries.Line.Color;
TsRadarSeries(ASeries).SymbolBorder.Style := clsNoLine;
end else
GetChartFillProps(AStyleNode, AChart, ASeries.Fill); GetChartFillProps(AStyleNode, AChart, ASeries.Fill);
end; end;
'style:text-properties': 'style:text-properties':
@ -1739,10 +1744,10 @@ begin
TsOpenedCustomLineSeries(ASeries).Symbol := css; TsOpenedCustomLineSeries(ASeries).Symbol := css;
break; break;
end; end;
s := GetAttrValue(AStyleNode, 'symbol-width'); s := GetAttrValue(AStyleNode, 'chart:symbol-width');
if (s <> '') and EvalLengthStr(s, value, rel) then if (s <> '') and EvalLengthStr(s, value, rel) then
TsOpenedCustomLineSeries(ASeries).SymbolWidth := value; TsOpenedCustomLineSeries(ASeries).SymbolWidth := value;
s := GetAttrValue(AStyleNode, 'symbol-height'); s := GetAttrValue(AStyleNode, 'chart:symbol-height');
if (s <> '') and EvalLengthStr(s, value, rel) then if (s <> '') and EvalLengthStr(s, value, rel) then
TsOpenedCustomLineSeries(ASeries).SymbolHeight := value; TsOpenedCustomLineSeries(ASeries).SymbolHeight := value;
end else end else
@ -2607,7 +2612,7 @@ begin
ciStepCenterY: interpolationStr := 'chart:interpolation="step-center-y" '; ciStepCenterY: interpolationStr := 'chart:interpolation="step-center-y" ';
end; end;
if not (AChart.GetChartType in [ctRadar, ctPie]) then if not (AChart.GetChartType in [ctRadar, ctFilledRadar, ctPie]) then
rightAngledAxes := 'chart:right-angled-axes="true" '; rightAngledAxes := 'chart:right-angled-axes="true" ';
for i := 0 to AChart.Series.Count-1 do for i := 0 to AChart.Series.Count-1 do
@ -2784,7 +2789,7 @@ function TsSpreadOpenDocChartWriter.GetChartSeriesStyleAsXML(AChart: TsChart;
ASeriesIndex, AIndent, AStyleID: Integer): String; ASeriesIndex, AIndent, AStyleID: Integer): String;
var var
series: TsChartSeries; series: TsChartSeries;
lineser: TsLineSeries = nil; lineser: TsOpenedCustomLineSeries = nil;
indent: String; indent: String;
numStyle: String; numStyle: String;
forceNoLine: Boolean = false; forceNoLine: Boolean = false;
@ -2809,7 +2814,7 @@ begin
if ((series is TsLineSeries) and (series.ChartType <> ctFilledRadar)) or if ((series is TsLineSeries) and (series.ChartType <> ctFilledRadar)) or
(series is TsScatterSeries) then (series is TsScatterSeries) then
begin begin
lineser := TsLineSeries(series); lineser := TsOpenedCustomLineSeries(series);
if lineser.ShowSymbols then if lineser.ShowSymbols then
chartProps := Format( chartProps := Format(
'chart:symbol-type="named-symbol" chart:symbol-name="%s" chart:symbol-width="%.1fmm" chart:symbol-height="%.1fmm" ', 'chart:symbol-type="named-symbol" chart:symbol-name="%s" chart:symbol-width="%.1fmm" chart:symbol-height="%.1fmm" ',
@ -2870,9 +2875,10 @@ begin
// Graphic properties // Graphic properties
lineProps := GetChartLineStyleGraphicPropsAsXML(AChart, series.Line, forceNoLine); lineProps := GetChartLineStyleGraphicPropsAsXML(AChart, series.Line, forceNoLine);
fillProps := GetChartFillStyleGraphicPropsAsXML(AChart, series.Fill);
if (series is TsLineSeries) and (series.ChartType <> ctFilledRadar) then if (series is TsLineSeries) and (series.ChartType <> ctFilledRadar) then
begin begin
lineSer := TsOpenedCustomLineSeries(series);
fillProps := GetChartFillStyleGraphicPropsAsXML(AChart, lineser.SymbolFill);
if lineSer.ShowSymbols then if lineSer.ShowSymbols then
graphProps := graphProps + fillProps; graphProps := graphProps + fillProps;
if lineSer.ShowLines and (lineser.Line.Style <> clsNoLine) then if lineSer.ShowLines and (lineser.Line.Style <> clsNoLine) then
@ -2880,7 +2886,10 @@ begin
else else
graphProps := graphProps + 'draw:stroke="none" '; graphProps := graphProps + 'draw:stroke="none" ';
end else end else
begin
fillProps := GetChartFillStyleGraphicPropsAsXML(AChart, series.Fill);
graphProps := fillProps + lineProps; graphProps := fillProps + lineProps;
end;
// Text properties // Text properties
textProps := TsSpreadOpenDocWriter(Writer).WriteFontStyleXMLAsString(series.LabelFont); textProps := TsSpreadOpenDocWriter(Writer).WriteFontStyleXMLAsString(series.LabelFont);

View File

@ -102,7 +102,7 @@ type
procedure WriteChartAxisTitle(AStream: TStream; AIndent: Integer; Axis: TsChartAxis); procedure WriteChartAxisTitle(AStream: TStream; AIndent: Integer; Axis: TsChartAxis);
procedure WriteChartLegendNode(AStream: TStream; AIndent: Integer; ALegend: TsChartLegend); procedure WriteChartLegendNode(AStream: TStream; AIndent: Integer; ALegend: TsChartLegend);
procedure WriteChartPlotAreaNode(AStream: TStream; AIndent: Integer; AChart: TsChart); procedure WriteChartPlotAreaNode(AStream: TStream; AIndent: Integer; AChart: TsChart);
procedure WriteChartRegression(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries); procedure WriteChartTrendline(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries);
procedure WriteChartSeriesDatapointLabels(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries); procedure WriteChartSeriesDatapointLabels(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries);
procedure WriteChartSeriesDatapointStyles(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries); procedure WriteChartSeriesDatapointStyles(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries);
procedure WriteChartSeriesNode(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries; ASeriesIndex: Integer); procedure WriteChartSeriesNode(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries; ASeriesIndex: Integer);
@ -114,6 +114,7 @@ type
procedure WriteBarSeries(AStream: TStream; AIndent: Integer; ASeries: TsBarSeries; ASeriesIndex: Integer); procedure WriteBarSeries(AStream: TStream; AIndent: Integer; ASeries: TsBarSeries; ASeriesIndex: Integer);
procedure WriteBubbleSeries(AStream: TStream; AIndent: Integer; ASeries: TsBubbleSeries; ASeriesIndex: Integer); procedure WriteBubbleSeries(AStream: TStream; AIndent: Integer; ASeries: TsBubbleSeries; ASeriesIndex: Integer);
procedure WritePieSeries(AStream: TStream; AIndent: Integer; ASeries: TsPieSeries; ASeriesIndex: Integer); procedure WritePieSeries(AStream: TStream; AIndent: Integer; ASeries: TsPieSeries; ASeriesIndex: Integer);
procedure WriteRadarSeries(AStream: TStream; AIndent: Integer; ASeries: TsRadarSeries; ASeriesIndex: Integer);
procedure WriteScatterSeries(AStream: TStream; AIndent: Integer; ASeries: TsScatterSeries; ASeriesIndex: Integer); procedure WriteScatterSeries(AStream: TStream; AIndent: Integer; ASeries: TsScatterSeries; ASeriesIndex: Integer);
procedure WriteChartLabels(AStream: TStream; AIndent: Integer; AFont: TsFont); procedure WriteChartLabels(AStream: TStream; AIndent: Integer; AFont: TsFont);
@ -1395,7 +1396,7 @@ begin
if TryStrToInt(s, n) then if TryStrToInt(s, n) then
with TsOpenedCustomLineSeries(ASeries) do with TsOpenedCustomLineSeries(ASeries) do
begin begin
SymbolWidth := PtsToMM(n div 2); SymbolWidth := PtsToMM(n);
SymbolHeight := SymbolWidth; SymbolHeight := SymbolWidth;
end; end;
@ -1550,28 +1551,47 @@ end;
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsSpreadOOXMLChartReader.ReadChartRadarSeries(ANode: TDOMNode; AChart: TsChart); procedure TsSpreadOOXMLChartReader.ReadChartRadarSeries(ANode: TDOMNode; AChart: TsChart);
var var
nodeName: String; node: TDOMNode;
nodeName, s: String;
ser: TsRadarSeries; ser: TsRadarSeries;
radarStyle: String = ''; filled: Boolean = false;
begin begin
if ANode = nil then if ANode = nil then
exit; exit;
while Assigned(ANode) do // At first, we need the value of c:radarStyle because it determines the
// series class to be created.
node := ANode;
while Assigned(node) do
begin begin
nodeName := ANode.NodeName; nodeName := node.NodeName;
case nodeName of case nodeName of
'c:radarStyle': 'c:radarStyle':
radarStyle := GetAttrValue(ANode, 'val'); begin
s := GetAttrValue(node, 'val');
filled := s = 'filled';
end;
end;
node := node.NextSibling;
end;
// Search the series node. Then create the series and read its properties
// from the subnodes.
node := ANode;
while Assigned(node) do
begin
nodeName := node.NodeName;
case nodeName of
'c:ser': 'c:ser':
begin begin
if filled then
ser := TsFilledRadarSeries.Create(AChart)
else
ser := TsRadarSeries.Create(AChart); ser := TsRadarSeries.Create(AChart);
ReadChartSeriesProps(ANode.FirstChild, ser); ReadChartSeriesProps(node.FirstChild, ser);
if radarStyle <> 'filled' then
ser.Fill.Style := cfsNoFill;
end; end;
end; end;
ANode := ANode.NextSibling; node := node.NextSibling;
end; end;
end; end;
@ -3827,6 +3847,7 @@ var
markerStr: String; markerStr: String;
chart: TsChart; chart: TsChart;
ser: TsOpenedCustomLineSeries; ser: TsOpenedCustomLineSeries;
symbolSizePts: Integer;
begin begin
indent := DupeString(' ', AIndent); indent := DupeString(' ', AIndent);
chart := ASeries.Chart; chart := ASeries.Chart;
@ -3835,7 +3856,7 @@ begin
if ser.ShowSymbols then if ser.ShowSymbols then
case ser.Symbol of case ser.Symbol of
cssRect: markerStr := 'square'; cssRect: markerStr := 'square';
cssDiamond: markerStr := 'diamong'; cssDiamond: markerStr := 'diamond';
cssTriangle: markerStr := 'triangle'; cssTriangle: markerStr := 'triangle';
cssTriangleDown: markerStr := 'triangle'; // !!!! cssTriangleDown: markerStr := 'triangle'; // !!!!
cssTriangleLeft: markerStr := 'triangle'; // !!!! cssTriangleLeft: markerStr := 'triangle'; // !!!!
@ -3852,13 +3873,16 @@ begin
else else
markerStr := 'none'; markerStr := 'none';
symbolSizePts := round(mmToPts((ser.SymbolWidth + ser.SymbolHeight)/2));
if symbolSizePts > 72 then symbolSizePts := 72;
Result := Format( Result := Format(
indent + '<c:symbol val="%s"/>' + LE + indent + '<c:symbol val="%s"/>' + LE +
indent + '<c:size val="%.0f"/>' + LE + indent + '<c:size val="%d"/>' + LE +
indent + '<c:spPr>' + LE + indent + '<c:spPr>' + LE +
GetChartFillAndLineXML(AIndent + 2, chart, ser.SymbolFill, ser.SymbolBorder) + LE + GetChartFillAndLineXML(AIndent + 2, chart, ser.SymbolFill, ser.SymbolBorder) + LE +
indent + '</c:spPr>', indent + '</c:spPr>',
[ markerStr, mmToPts(ser.SymbolWidth + ser.SymbolHeight) ] [ markerStr, symbolSizePts ]
); );
end; end;
@ -3903,6 +3927,8 @@ begin
end; end;
ctPie, ctRing: ctPie, ctRing:
WritePieSeries(AStream, AIndent + 2, TsPieSeries(ser), i); WritePieSeries(AStream, AIndent + 2, TsPieSeries(ser), i);
ctRadar, ctFilledRadar:
WriteRadarSeries(AStream, AIndent + 2, TsRadarSeries(ser), i);
ctScatter: ctScatter:
begin begin
WriteScatterSeries(AStream, AIndent + 2, TsScatterSeries(ser), i); WriteScatterSeries(AStream, AIndent + 2, TsScatterSeries(ser), i);
@ -3972,6 +3998,39 @@ begin
); );
end; end;
procedure TsSpreadOOXMLChartWriter.WriteRadarSeries(AStream: TStream;
AIndent: Integer; ASeries: TsRadarSeries; ASeriesIndex: Integer);
var
indent: String;
chart: TsChart;
radarStyle: String;
begin
indent := DupeString(' ', AIndent);
chart := ASeries.Chart;
if ASeries.ChartType = ctFilledRadar then
radarStyle := 'filled'
else
radarStyle := 'marker';
AppendToStream(AStream,
indent + '<c:radarChart>' + LE +
indent + ' <c:radarStyle val="' + radarStyle + '"/>' + LE
);
WriteChartSeriesNode(AStream, AIndent + 4, ASeries, ASeriesIndex);
AppendToStream(AStream, Format(
indent + ' <c:axId val="%d"/>' + LE +
indent + ' <c:axId val="%d"/>' + LE +
indent + '</c:radarChart>' + LE,
[
FAxisID[chart.XAxis.Alignment], // <c:axId>
FAxisID[chart.YAxis.Alignment] // <c:axId>
]
));
end;
procedure TsSpreadOOXMLChartWriter.WriteScatterSeries(AStream: TStream; procedure TsSpreadOOXMLChartWriter.WriteScatterSeries(AStream: TStream;
AIndent: Integer; ASeries: TsScatterSeries; ASeriesIndex: Integer); AIndent: Integer; ASeries: TsScatterSeries; ASeriesIndex: Integer);
var var
@ -4015,7 +4074,7 @@ end;
Writes the <c:trendline> node for the specified chart series if a trendline Writes the <c:trendline> node for the specified chart series if a trendline
is activated. is activated.
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsSpreadOOXMLChartWriter.WriteChartRegression(AStream: TStream; procedure TsSpreadOOXMLChartWriter.WriteChartTrendline(AStream: TStream;
AIndent: Integer; ASeries: TsChartSeries); AIndent: Integer; ASeries: TsChartSeries);
var var
indent: String; indent: String;
@ -4182,9 +4241,6 @@ var
xRng, yRng: TsChartRange; xRng, yRng: TsChartRange;
forceNoLine: Boolean; forceNoLine: Boolean;
xValName, yValName, xRefName, yRefName: String; xValName, yValName, xRefName, yRefName: String;
explosionStr: String = '';
dps: TsChartDataPointStyle;
i: Integer;
begin begin
indent := DupeString(' ', AIndent); indent := DupeString(' ', AIndent);
chart := ASeries.Chart; chart := ASeries.Chart;
@ -4217,8 +4273,16 @@ begin
indent + ' </c:spPr>' + LE indent + ' </c:spPr>' + LE
); );
end else end else
// Line & scatter series: symbol markers // Line & scatter & radar series: symbol markers
if (ASeries is TsCustomLineSeries) then if (ASeries is TsCustomLineSeries) then
begin
if (ASeries.ChartType = ctFilledRadar) then
AppendToStream(AStream,
indent + ' <c:spPr>' + LE +
GetChartFillAndLineXML(AIndent + 4, chart, ASeries.Fill, ASeries.Line) + LE +
indent + ' </c:spPr>' + LE
)
else
begin begin
forceNoLine := not TsOpenedCustomLineSeries(ASeries).ShowLines; forceNoLine := not TsOpenedCustomLineSeries(ASeries).ShowLines;
AppendToStream(AStream, AppendToStream(AStream,
@ -4226,6 +4290,7 @@ begin
GetChartLineXML(AIndent + 4, chart, ASeries.Line, forceNoLine) + LE + GetChartLineXML(AIndent + 4, chart, ASeries.Line, forceNoLine) + LE +
indent + ' </c:spPr>' + LE indent + ' </c:spPr>' + LE
); );
end;
if TsOpenedCustomLineSeries(ASeries).ShowSymbols then if TsOpenedCustomLineSeries(ASeries).ShowSymbols then
AppendToStream(AStream, AppendToStream(AStream,
indent + ' <c:marker>' + LE + indent + ' <c:marker>' + LE +
@ -4242,7 +4307,7 @@ begin
// Trend line // Trend line
if ASeries.SupportsTrendline then if ASeries.SupportsTrendline then
WriteChartRegression(AStream, AIndent + 2, ASeries); WriteChartTrendline(AStream, AIndent + 2, ASeries);
// Data point labels // Data point labels
WriteChartSeriesDatapointLabels(AStream, AIndent + 2, ASeries); WriteChartSeriesDatapointLabels(AStream, AIndent + 2, ASeries);

View File

@ -550,10 +550,11 @@ begin
if FIntegerX then if FIntegerX then
value := trunc(value); value := trunc(value);
end else end else
if FCyclicX then
value := AIndex / FPointsNumber * TWO_PI
else
value := AIndex; value := AIndex;
// For polar series we rescale the x values to a full circle.
// And the angle begins at the 90° position.
if FCyclicX then
value := value / FPointsNumber * TWO_PI + pi/2;
FCurItem.SetX(i, value); FCurItem.SetX(i, value);
end; end;
@ -2651,8 +2652,8 @@ begin
UpdateChartBrush(AWorkbookSeries.Chart, openedWorkbookSeries.SymbolFill, seriesPointer.Brush); UpdateChartBrush(AWorkbookSeries.Chart, openedWorkbookSeries.SymbolFill, seriesPointer.Brush);
UpdateChartPen(AWorkbookSeries.Chart, openedWorkbookSeries.SymbolBorder, seriesPointer.Pen); UpdateChartPen(AWorkbookSeries.Chart, openedWorkbookSeries.SymbolBorder, seriesPointer.Pen);
seriesPointer.Style := POINTER_STYLES[openedWorkbookSeries.Symbol]; seriesPointer.Style := POINTER_STYLES[openedWorkbookSeries.Symbol];
seriesPointer.HorizSize := mmToPx(openedWorkbookSeries.SymbolWidth, ppi); seriesPointer.HorizSize := mmToPx(openedWorkbookSeries.SymbolWidth / 2, ppi);
seriesPointer.VertSize := mmToPx(openedWorkbookSeries.SymbolHeight, ppi); seriesPointer.VertSize := mmToPx(openedWorkbookSeries.SymbolHeight / 2, ppi);
// Error bars // Error bars
UpdateChartErrorBars(AWorkbookSeries, AChartSeries); UpdateChartErrorBars(AWorkbookSeries, AChartSeries);
@ -2694,14 +2695,15 @@ begin
(AChartSeries.Source as TsWorkbookChartSource).CyclicX := true; (AChartSeries.Source as TsWorkbookChartSource).CyclicX := true;
UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.Line, AChartSeries.LinePen); UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.Line, AChartSeries.LinePen);
if AWorkbookSeries.ChartType = ctFilledRadar then
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.Brush); UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, AChartSeries.Brush);
if AWorkbookSeries.ShowSymbols then if AWorkbookSeries.ShowSymbols then
begin begin
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.SymbolFill, AChartSeries.Pointer.Brush); UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.SymbolFill, AChartSeries.Pointer.Brush);
UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.SymbolBorder, AChartSeries.Pointer.Pen); UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.SymbolBorder, AChartSeries.Pointer.Pen);
AChartSeries.Pointer.Style := POINTER_STYLES[AWorkbookSeries.Symbol]; AChartSeries.Pointer.Style := POINTER_STYLES[AWorkbookSeries.Symbol];
AChartSeries.Pointer.HorizSize := mmToPx(AWorkbookSeries.SymbolWidth, ppi); AChartSeries.Pointer.HorizSize := mmToPx(AWorkbookSeries.SymbolWidth / 2, ppi);
AChartSeries.Pointer.VertSize := mmToPx(AWorkbookSeries.SymbolHeight, ppi); AChartSeries.Pointer.VertSize := mmToPx(AWorkbookSeries.SymbolHeight / 2, ppi);
end; end;
FChart.LeftAxis.Minors.Clear; FChart.LeftAxis.Minors.Clear;