fpspreadsheet: xlsx chart writer supports trendline feature.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9204 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
289d74c7bb
commit
b81ce84311
@ -51,11 +51,6 @@
|
||||
<DebugInfoType Value="dsDwarf3"/>
|
||||
</Debugging>
|
||||
</Linking>
|
||||
<Other>
|
||||
<ConfigFile>
|
||||
<WriteConfigFilePath Value=""/>
|
||||
</ConfigFile>
|
||||
</Other>
|
||||
</CompilerOptions>
|
||||
<Debugging>
|
||||
<Exceptions>
|
||||
|
||||
@ -17,6 +17,7 @@ var
|
||||
rotated: Boolean;
|
||||
begin
|
||||
fn := FILE_NAME;
|
||||
|
||||
rotated := (ParamCount >= 1) and (lowercase(ParamStr(1)) = 'rotated');
|
||||
if rotated then
|
||||
fn := fn + '-rotated';
|
||||
@ -76,13 +77,11 @@ begin
|
||||
//ser.Regression.Equation.Top := 5;
|
||||
//ser.Regression.Equation.Left := 5;
|
||||
|
||||
{
|
||||
book.WriteToFile(fn + '.xlsx', true); // Excel fails to open the file
|
||||
WriteLn('Data saved with chart to ', fn, '.xlsx');
|
||||
}
|
||||
book.WriteToFile(fn + '.xlsx', true);
|
||||
WriteLn('Data saved with chart to ', fn + '.xlsx');
|
||||
|
||||
book.WriteToFile(fn + '.ods', true);
|
||||
WriteLn('Data saved with chart to ', fn, '.ods');
|
||||
WriteLn('Data saved with chart to ', fn + '.ods');
|
||||
finally
|
||||
book.Free;
|
||||
end;
|
||||
|
||||
@ -166,10 +166,11 @@ begin
|
||||
sChartLink.WorkbookSource := sWorkbookSource1;
|
||||
sChartLink.WorkbookChartIndex := 0;
|
||||
|
||||
|
||||
{
|
||||
// <<<<<<<<<<<<<<<<< to be removed again...
|
||||
Chart1.Invalidate;
|
||||
PrintChartInfo(Chart1);
|
||||
}
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
@ -100,7 +100,7 @@ type
|
||||
function GetChartLineStyleAsXML(AChart: TsChart;
|
||||
ALine: TsChartLine; AIndent, AStyleID: Integer): String;
|
||||
function GetChartLineStyleGraphicPropsAsXML(AChart: TsChart;
|
||||
ALine: TsChartLine): String;
|
||||
ALine: TsChartLine; ForceNoLine: Boolean = false): String;
|
||||
function GetChartPlotAreaStyleAsXML(AChart: TsChart;
|
||||
AIndent, AStyleID: Integer): String;
|
||||
function GetChartRegressionEquationStyleAsXML(AChart: TsChart;
|
||||
@ -2504,14 +2504,14 @@ end;
|
||||
|
||||
{ Constructs the xml for a line style to be used in the <style:graphic-properties> }
|
||||
function TsSpreadOpenDocChartWriter.GetChartLineStyleGraphicPropsAsXML(
|
||||
AChart: TsChart; ALine: TsChartLine): String;
|
||||
AChart: TsChart; ALine: TsChartLine; ForceNoLine: Boolean = false): String;
|
||||
var
|
||||
strokeStr: String = '';
|
||||
widthStr: String = '';
|
||||
colorStr: String = '';
|
||||
linestyle: TsChartLineStyle;
|
||||
begin
|
||||
if ALine.Style = clsNoLine then
|
||||
if (ALine.Style = clsNoLine) or ForceNoLine then
|
||||
begin
|
||||
Result := 'draw:stroke="none" ';
|
||||
exit;
|
||||
@ -2731,6 +2731,7 @@ var
|
||||
lineser: TsLineSeries = nil;
|
||||
indent: String;
|
||||
numStyle: String;
|
||||
forceNoLine: Boolean = false;
|
||||
chartProps: String = '';
|
||||
graphProps: String = '';
|
||||
textProps: String = '';
|
||||
@ -2759,6 +2760,7 @@ begin
|
||||
[SYMBOL_NAMES[lineSer.Symbol], lineSer.SymbolWidth, lineSer.SymbolHeight ],
|
||||
FPointSeparatorSettings
|
||||
);
|
||||
forceNoLine := not lineSer.ShowLines;
|
||||
end;
|
||||
|
||||
chartProps := chartProps + Format('chart:link-data-style-to-source="%s" ', [FALSE_TRUE[numStyle = 'N0']]);
|
||||
@ -2805,7 +2807,7 @@ begin
|
||||
chartProps := indent + ' <style:chart-properties ' + chartProps + '/>';
|
||||
|
||||
// Graphic properties
|
||||
lineProps := GetChartLineStyleGraphicPropsAsXML(AChart, series.Line);
|
||||
lineProps := GetChartLineStyleGraphicPropsAsXML(AChart, series.Line, forceNoLine);
|
||||
fillProps := GetChartFillStyleGraphicPropsAsXML(AChart, series.Fill);
|
||||
if (series is TsLineSeries) and (series.ChartType <> ctFilledRadar) then
|
||||
begin
|
||||
|
||||
@ -83,9 +83,9 @@ type
|
||||
function GetChartFillAndLineXML(AIndent: Integer; AChart: TsChart; AFill: TsChartFill; ALine: TsChartLine): String;
|
||||
function GetChartFillXML(AIndent: Integer; AChart: TsChart; AFill: TsChartFill): String;
|
||||
function GetChartFontXML(AIndent: Integer; AFont: TsFont; ANodeName: String): String;
|
||||
function GetChartLineXML(AIndent: Integer; AChart: TsChart; ALine: TsChartLine): String;
|
||||
function GetChartLineXML(AIndent: Integer; AChart: TsChart; ALine: TsChartLine; OverrideOff: Boolean = false): String;
|
||||
function GetChartRangeXML(AIndent: Integer; ARange: TsChartRange; ARefKind: String): String;
|
||||
function GetChartSeriesMarkerXML(AIndent: Integer; ASeries: TsScatterSeries): String;
|
||||
function GetChartSeriesMarkerXML(AIndent: Integer; ASeries: TsCustomLineSeries): String;
|
||||
|
||||
protected
|
||||
// Called by the public functions
|
||||
@ -102,6 +102,7 @@ type
|
||||
procedure WriteChartAxisTitle(AStream: TStream; AIndent: Integer; Axis: TsChartAxis);
|
||||
procedure WriteChartLegendNode(AStream: TStream; AIndent: Integer; ALegend: TsChartLegend);
|
||||
procedure WriteChartPlotAreaNode(AStream: TStream; AIndent: Integer; AChart: TsChart);
|
||||
procedure WriteChartRegression(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries);
|
||||
procedure WriteChartSeriesNode(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries; ASeriesIndex: Integer);
|
||||
procedure WriteChartSeriesTitle(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries);
|
||||
procedure WriteChartTitleNode(AStream: TStream; AIndent: Integer; ATitle: TsChartText);
|
||||
@ -160,6 +161,8 @@ const
|
||||
AX_POS: array[TsChartAxisAlignment] of string = ('l', 't', 'r', 'b');
|
||||
FALSE_TRUE: Array[boolean] of String = ('0', '1');
|
||||
LEGEND_POS: Array[TsChartLegendPosition] of string = ('r', 't', 'b', 'l');
|
||||
TRENDLINE_TYPES: Array[TsRegressionType] of string = ('', 'linear', 'log', 'exp', 'power', 'poly');
|
||||
// 'movingAvg' and 'log' not supported, so far
|
||||
|
||||
|
||||
{$INCLUDE xlsxooxmlchart_hatch.inc}
|
||||
@ -3252,7 +3255,7 @@ begin
|
||||
end;
|
||||
|
||||
function TsSpreadOOXMLChartWriter.GetChartLineXML(AIndent: Integer;
|
||||
AChart: TsChart; ALine: TsChartline): String;
|
||||
AChart: TsChart; ALine: TsChartline; OverrideOff: Boolean = false): String;
|
||||
var
|
||||
indent: String;
|
||||
noLine: Boolean;
|
||||
@ -3264,7 +3267,7 @@ var
|
||||
begin
|
||||
indent := DupeString(' ', AIndent);
|
||||
|
||||
if (ALine <> nil) and (ALine.Style <> clsNoLine) then
|
||||
if (ALine <> nil) and (ALine.Style <> clsNoLine) and not OverrideOff then
|
||||
begin
|
||||
Result := Format(
|
||||
indent + '<a:ln w="%.0f">' + LE +
|
||||
@ -3302,44 +3305,6 @@ begin
|
||||
Result := indent + '<a:ln>' + LE +
|
||||
indent + ' <a:noFill/>' + LE +
|
||||
indent + '</a:ln>';
|
||||
(*
|
||||
|
||||
|
||||
|
||||
Result := Format('<a:ln w="%.0f">', [ALine.Width * PTS_MULTIPLIER]);
|
||||
|
||||
Result := Result + LE + Format(
|
||||
indent + ' <a:solidFill>' + LE +
|
||||
indent + ' <a:srgbClr val="%s"/>' + LE +
|
||||
indent + ' </a:solidFill>' + LE +
|
||||
indent + ' <a:round/>' + LE, // must not be dropped!
|
||||
[ HtmlColorStr(ALine.Color) ]
|
||||
)
|
||||
|
||||
else
|
||||
Result := '<a:ln>';
|
||||
Result := indent + Result;
|
||||
|
||||
noLine := false;
|
||||
if (ALine <> nil) then
|
||||
begin
|
||||
if ALine.Style = clsSolid then
|
||||
Result := Result + LE + Format(
|
||||
indent + ' <a:solidFill>' + LE +
|
||||
indent + ' <a:srgbClr val="%s"/>' + LE +
|
||||
indent + ' </a:solidFill>' + LE +
|
||||
indent + ' <a:round/>' + LE, // must not be dropped!
|
||||
[ HtmlColorStr(ALine.Color) ]
|
||||
)
|
||||
else
|
||||
noLine := true;
|
||||
end;
|
||||
|
||||
if noLine then
|
||||
Result := Result + indent + ' <a:noFill/>';
|
||||
|
||||
Result := Result + indent + '</a:ln>';
|
||||
*)
|
||||
end;
|
||||
|
||||
function TsSpreadOOXMLChartWriter.GetChartRangeXML(AIndent: Integer;
|
||||
@ -3743,17 +3708,19 @@ end;
|
||||
Assembles the <c:marker> node of a scatter series as a string
|
||||
-------------------------------------------------------------------------------}
|
||||
function TsSpreadOOXMLChartWriter.GetChartSeriesMarkerXML(AIndent: Integer;
|
||||
ASeries: TsScatterSeries): String;
|
||||
ASeries: TsCustomLineSeries): String;
|
||||
var
|
||||
indent: String;
|
||||
markerStr: String;
|
||||
chart: TsChart;
|
||||
ser: TsOpenCustomLineSeries;
|
||||
begin
|
||||
indent := DupeString(' ', AIndent);
|
||||
chart := ASeries.Chart;
|
||||
ser := TsOpencustomLineseries(ASeries);
|
||||
|
||||
if ASeries.ShowSymbols then
|
||||
case ASeries.Symbol of
|
||||
if ser.ShowSymbols then
|
||||
case ser.Symbol of
|
||||
cssRect: markerStr := 'square';
|
||||
cssDiamond: markerStr := 'diamong';
|
||||
cssTriangle: markerStr := 'triangle';
|
||||
@ -3776,9 +3743,9 @@ begin
|
||||
indent + '<c:symbol val="%s"/>' + LE +
|
||||
indent + '<c:size val="%.0f"/>' + LE +
|
||||
indent + '<c:spPr>' + LE +
|
||||
GetChartFillAndLineXML(AIndent + 2, chart, ASeries.SymbolFill, ASeries.SymbolBorder) + LE +
|
||||
GetChartFillAndLineXML(AIndent + 2, chart, ser.SymbolFill, ser.SymbolBorder) + LE +
|
||||
indent + '</c:spPr>',
|
||||
[ markerStr, mmToPts(ASeries.SymbolWidth + ASeries.SymbolHeight) ]
|
||||
[ markerStr, mmToPts(ser.SymbolWidth + ser.SymbolHeight) ]
|
||||
);
|
||||
end;
|
||||
|
||||
@ -3872,6 +3839,65 @@ begin
|
||||
));
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes the <c:trendline> node for the specified chart series if a trendline
|
||||
is activated.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsSpreadOOXMLChartWriter.WriteChartRegression(AStream: TStream;
|
||||
AIndent: Integer; ASeries: TsChartSeries);
|
||||
var
|
||||
indent: String;
|
||||
regression: TsChartRegression;
|
||||
nameStr: String = '';
|
||||
orderStr: String = '';
|
||||
interceptStr: String = '';
|
||||
backwardStr: String = '';
|
||||
forwardStr: String = '';
|
||||
begin
|
||||
indent := DupeString(' ', AIndent);
|
||||
regression := TsOpenRegressionSeries(ASeries).Regression;
|
||||
|
||||
if regression.Title <> '' then
|
||||
nameStr := Format(
|
||||
indent + ' <c:name>%s</c:name>' + LE, [regression.Title]);
|
||||
|
||||
if regression.RegressionType = rtPolynomial then
|
||||
orderStr := Format(
|
||||
indent + ' <c:order val="%d"/>' + LE, [regression.PolynomialDegree]);
|
||||
|
||||
if regression.ForceYIntercept then
|
||||
interceptStr := Format(
|
||||
indent + ' <c:intercept val="%g"/>' + LE, [regression.YInterceptValue], FPointSeparatorSettings);
|
||||
|
||||
if regression.ExtrapolateForwardBy <> 0 then
|
||||
forwardStr := Format(
|
||||
indent + ' <c:forward val="%g"/>' + LE, [regression.ExtrapolateForwardBy], FPointSeparatorSettings);
|
||||
|
||||
if regression.ExtrapolateBackwardBy <> 0 then
|
||||
backwardStr := Format(
|
||||
indent + ' <c:backward val="%g"/>' + LE, [regression.ExtrapolateBackwardBy], FPointSeparatorSettings);
|
||||
|
||||
AppendToStream(AStream, Format(
|
||||
indent + '<c:trendline>' + LE +
|
||||
nameStr +
|
||||
indent + ' <c:spPr>' + LE +
|
||||
GetChartLineXML(AIndent + 4, ASeries.Chart, regression.Line) + LE +
|
||||
indent + ' </c:spPr>' + LE +
|
||||
indent + ' <c:trendlineType val="%s"/>' + LE +
|
||||
orderStr +
|
||||
interceptStr +
|
||||
forwardStr +
|
||||
backwardStr +
|
||||
indent + ' <c:dispRSqr val="%s"/>' + LE +
|
||||
indent + ' <c:dispEq val="%s"/>' + LE +
|
||||
indent + '</c:trendline>' + LE,
|
||||
[ TRENDLINE_TYPES[regression.RegressionType],
|
||||
FALSE_TRUE[regression.DisplayRSquare],
|
||||
FALSE_TRUE[regression.DisplayEquation]
|
||||
]
|
||||
));
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Writes the <c:ser> node for the specified chart series
|
||||
Is called by all series types.
|
||||
@ -3887,7 +3913,9 @@ var
|
||||
indent: string;
|
||||
chart: TsChart;
|
||||
xRng, yRng: TsChartRange;
|
||||
forceNoLine: Boolean;
|
||||
xValName, yValName, xRefName, yRefName: String;
|
||||
regression: TsChartRegression;
|
||||
begin
|
||||
indent := DupeString(' ', AIndent);
|
||||
chart := ASeries.Chart;
|
||||
@ -3908,20 +3936,32 @@ begin
|
||||
// Series title
|
||||
WriteChartSeriesTitle(AStream, AIndent + 2, ASeries);
|
||||
|
||||
// Series main formatting
|
||||
AppendToStream(AStream,
|
||||
indent + ' <c:spPr>' + LE +
|
||||
GetChartFillAndLineXML(AIndent + 4, chart, ASeries.Fill, ASeries.Line) + LE +
|
||||
indent + ' </c:spPr>' + LE
|
||||
);
|
||||
|
||||
// Scatter series: symbol markers
|
||||
if ASeries is TsScatterSeries then
|
||||
// Line & scatter series: symbol markers
|
||||
if (ASeries is TsCustomLineSeries) then
|
||||
begin
|
||||
forceNoLine := not TsOpenCustomLineSeries(ASeries).ShowLines;
|
||||
AppendToStream(AStream,
|
||||
indent + ' <c:marker>' + LE +
|
||||
GetChartSeriesMarkerXML(AIndent + 4, TsScatterSeries(ASeries)) + LE +
|
||||
indent + ' </c:marker>' + LE
|
||||
indent + ' <c:spPr>' + LE +
|
||||
GetChartLineXML(AIndent, chart, ASeries.Line, forceNoLine) + LE +
|
||||
indent + ' </c:spPr>' + LE
|
||||
);
|
||||
if TsOpenCustomLineSeries(ASeries).ShowSymbols then
|
||||
AppendToStream(AStream,
|
||||
indent + ' <c:marker>' + LE +
|
||||
GetChartSeriesMarkerXML(AIndent + 4, TsOpenCustomLineSeries(ASeries)) + LE +
|
||||
indent + ' </c:marker>' + LE
|
||||
);
|
||||
end else
|
||||
// Series main formatting
|
||||
AppendToStream(AStream,
|
||||
indent + ' <c:spPr>' + LE +
|
||||
GetChartFillAndLineXML(AIndent + 4, chart, ASeries.Fill, ASeries.Line) + LE +
|
||||
indent + ' </c:spPr>' + LE
|
||||
);
|
||||
|
||||
// Regression
|
||||
if ASeries.SupportsRegression then
|
||||
WriteChartRegression(AStream, AIndent + 2, ASeries);
|
||||
|
||||
// Cell ranges
|
||||
if (ASeries is TsScatterSeries) or (ASeries is TsBubbleSeries) then
|
||||
|
||||
Loading…
Reference in New Issue
Block a user