You've already forked lazarus-ccr
fpspreadsheet: Support number formatting in charts.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9008 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -49,6 +49,7 @@ begin
|
|||||||
ser.LabelSeparator := '\n'; // this is the symbol for a line-break
|
ser.LabelSeparator := '\n'; // this is the symbol for a line-break
|
||||||
ser.LabelPosition := lpOutside;
|
ser.LabelPosition := lpOutside;
|
||||||
ser.Line.Color := scWhite;
|
ser.Line.Color := scWhite;
|
||||||
|
ser.LabelFormat := '#,##0';
|
||||||
//ser.SetFillColorRange(4, 2, 8, 2);
|
//ser.SetFillColorRange(4, 2, 8, 2);
|
||||||
|
|
||||||
b.WriteToFile('world-population.xlsx', true); // Excel fails to open the file
|
b.WriteToFile('world-population.xlsx', true); // Excel fails to open the file
|
||||||
|
@ -61,6 +61,7 @@ begin
|
|||||||
ser.Regression.Equation.Border.Color := scRed;
|
ser.Regression.Equation.Border.Color := scRed;
|
||||||
ser.Regression.Equation.Fill.Style := fsSolidFill;
|
ser.Regression.Equation.Fill.Style := fsSolidFill;
|
||||||
ser.Regression.Equation.Fill.FgColor := scSilver;
|
ser.Regression.Equation.Fill.FgColor := scSilver;
|
||||||
|
ser.Regression.Equation.NumberFormat := '0.000';
|
||||||
//ser.Regression.Equation.Top := 5;
|
//ser.Regression.Equation.Top := 5;
|
||||||
//ser.Regression.Equation.Left := 5;
|
//ser.Regression.Equation.Left := 5;
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@ type
|
|||||||
FCaptionRotation: Integer;
|
FCaptionRotation: Integer;
|
||||||
FLabelFont: TsFont;
|
FLabelFont: TsFont;
|
||||||
FLabelFormat: String;
|
FLabelFormat: String;
|
||||||
|
FLabelFormatPercent: String;
|
||||||
FLabelRotation: Integer;
|
FLabelRotation: Integer;
|
||||||
FLogarithmic: Boolean;
|
FLogarithmic: Boolean;
|
||||||
FMajorInterval: Double;
|
FMajorInterval: Double;
|
||||||
@ -158,6 +159,7 @@ type
|
|||||||
property Inverted: Boolean read FInverted write FInverted;
|
property Inverted: Boolean read FInverted write FInverted;
|
||||||
property LabelFont: TsFont read FLabelFont write FLabelFont;
|
property LabelFont: TsFont read FLabelFont write FLabelFont;
|
||||||
property LabelFormat: String read FLabelFormat write FLabelFormat;
|
property LabelFormat: String read FLabelFormat write FLabelFormat;
|
||||||
|
property LabelFormatPercent: String read FLabelFormatPercent write FLabelFormatPercent;
|
||||||
property LabelRotation: Integer read FLabelRotation write FLabelRotation;
|
property LabelRotation: Integer read FLabelRotation write FLabelRotation;
|
||||||
property Logarithmic: Boolean read FLogarithmic write FLogarithmic;
|
property Logarithmic: Boolean read FLogarithmic write FLogarithmic;
|
||||||
property MajorGridLines: TsChartLine read FMajorGridLines write FMajorGridLines;
|
property MajorGridLines: TsChartLine read FMajorGridLines write FMajorGridLines;
|
||||||
@ -593,6 +595,8 @@ begin
|
|||||||
FLabelFont.Style := [];
|
FLabelFont.Style := [];
|
||||||
FLabelFont.Color := scBlack;
|
FLabelFont.Color := scBlack;
|
||||||
|
|
||||||
|
FLabelFormatPercent := '0%';
|
||||||
|
|
||||||
FCaptionRotation := 0;
|
FCaptionRotation := 0;
|
||||||
FLabelRotation := 0;
|
FLabelRotation := 0;
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ type
|
|||||||
private
|
private
|
||||||
FSCharts: array of TStream;
|
FSCharts: array of TStream;
|
||||||
FSObjectStyles: array of TStream;
|
FSObjectStyles: array of TStream;
|
||||||
|
FNumberFormatList: TStrings;
|
||||||
FPointSeparatorSettings: TFormatSettings;
|
FPointSeparatorSettings: TFormatSettings;
|
||||||
|
|
||||||
function GetChartAxisStyleAsXML(Axis: TsChartAxis; AIndent, AStyleID: Integer): String;
|
function GetChartAxisStyleAsXML(Axis: TsChartAxis; AIndent, AStyleID: Integer): String;
|
||||||
function GetChartBackgroundStyleAsXML(AChart: TsChart; AFill: TsChartFill;
|
function GetChartBackgroundStyleAsXML(AChart: TsChart; AFill: TsChartFill;
|
||||||
ABorder: TsChartLine; AIndent: Integer; AStyleID: Integer): String;
|
ABorder: TsChartLine; AIndent: Integer; AStyleID: Integer): String;
|
||||||
@ -38,6 +40,9 @@ type
|
|||||||
function GetChartRegressionStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: Integer): String;
|
function GetChartRegressionStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: Integer): String;
|
||||||
function GetChartSeriesStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: integer): String;
|
function GetChartSeriesStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: integer): String;
|
||||||
// function GetChartTitleStyleAsXML(AChart: TsChart; AStyleIndex, AIndent: Integer): String;
|
// function GetChartTitleStyleAsXML(AChart: TsChart; AStyleIndex, AIndent: Integer): String;
|
||||||
|
|
||||||
|
function GetNumberFormatID(ANumFormat: String): String;
|
||||||
|
procedure ListAllNumberFormats(AChart: TsChart);
|
||||||
procedure PrepareChartTable(AChart: TsChart; AWorksheet: TsBasicWorksheet);
|
procedure PrepareChartTable(AChart: TsChart; AWorksheet: TsBasicWorksheet);
|
||||||
|
|
||||||
protected
|
protected
|
||||||
@ -63,6 +68,7 @@ type
|
|||||||
|
|
||||||
public
|
public
|
||||||
constructor Create(AWriter: TsBasicSpreadWriter); override;
|
constructor Create(AWriter: TsBasicSpreadWriter); override;
|
||||||
|
destructor Destroy; override;
|
||||||
procedure AddChartsToZip(AZip: TZipper);
|
procedure AddChartsToZip(AZip: TZipper);
|
||||||
procedure AddToMetaInfManifest(AStream: TStream);
|
procedure AddToMetaInfManifest(AStream: TStream);
|
||||||
procedure CreateStreams; override;
|
procedure CreateStreams; override;
|
||||||
@ -119,6 +125,36 @@ begin
|
|||||||
Result := Result + Format('_%.2x_', [ord(AName[i])]);
|
Result := Result + Format('_%.2x_', [ord(AName[i])]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
{ internal number formats }
|
||||||
|
{------------------------------------------------------------------------------}
|
||||||
|
|
||||||
|
type
|
||||||
|
TsChartNumberFormatList = class(TStringList)
|
||||||
|
public
|
||||||
|
constructor Create;
|
||||||
|
function Add(const ANumFormat: String): Integer; override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TsChartNumberFormatList.Create;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
Add(''); // default number format
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Adds a new format, but make sure to avoid duplicates.
|
||||||
|
function TsChartNumberFormatList.Add(const ANumFormat: String): Integer;
|
||||||
|
begin
|
||||||
|
if (ANumFormat = '') and (Count > 0) then
|
||||||
|
Result := 0
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result := IndexOf(ANumFormat);
|
||||||
|
if Result = -1 then
|
||||||
|
Result := inherited Add(ANumFormat);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{------------------------------------------------------------------------------}
|
{------------------------------------------------------------------------------}
|
||||||
{ TsSpreadOpenDocChartWriter }
|
{ TsSpreadOpenDocChartWriter }
|
||||||
@ -127,8 +163,17 @@ end;
|
|||||||
constructor TsSpreadOpenDocChartWriter.Create(AWriter: TsBasicSpreadWriter);
|
constructor TsSpreadOpenDocChartWriter.Create(AWriter: TsBasicSpreadWriter);
|
||||||
begin
|
begin
|
||||||
inherited Create(AWriter);
|
inherited Create(AWriter);
|
||||||
|
|
||||||
FPointSeparatorSettings := SysUtils.DefaultFormatSettings;
|
FPointSeparatorSettings := SysUtils.DefaultFormatSettings;
|
||||||
FPointSeparatorSettings.DecimalSeparator:='.';
|
FPointSeparatorSettings.DecimalSeparator:='.';
|
||||||
|
|
||||||
|
FNumberFormatList := TsChartNumberFormatList.Create;
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TsSpreadOpenDocChartWriter.Destroy;
|
||||||
|
begin
|
||||||
|
FNumberFormatList.Free;
|
||||||
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TsSpreadOpenDocChartWriter.AddChartsToZip(AZip: TZipper);
|
procedure TsSpreadOpenDocChartWriter.AddChartsToZip(AZip: TZipper);
|
||||||
@ -201,6 +246,7 @@ var
|
|||||||
chart: TsChart;
|
chart: TsChart;
|
||||||
indent: String;
|
indent: String;
|
||||||
angle: Integer;
|
angle: Integer;
|
||||||
|
idx: Integer;
|
||||||
textProps: String = '';
|
textProps: String = '';
|
||||||
graphProps: String = '';
|
graphProps: String = '';
|
||||||
chartProps: String = '';
|
chartProps: String = '';
|
||||||
@ -212,9 +258,11 @@ begin
|
|||||||
|
|
||||||
chart := Axis.Chart;
|
chart := Axis.Chart;
|
||||||
|
|
||||||
// Special number format for numerical axis labels
|
// Get number format, use percent format for stacked percentage axis
|
||||||
if (Axis = chart.YAxis) and (chart.StackMode = csmStackedPercentage) then
|
if (Axis = chart.YAxis) and (chart.StackMode = csmStackedPercentage) then
|
||||||
numStyle := 'N10010';
|
numStyle := GetNumberFormatID(Axis.LabelFormatPercent)
|
||||||
|
else
|
||||||
|
numStyle := GetNumberFormatID(Axis.LabelFormat);
|
||||||
|
|
||||||
// Show axis labels
|
// Show axis labels
|
||||||
if Axis.ShowLabels then
|
if Axis.ShowLabels then
|
||||||
@ -537,6 +585,7 @@ function TsSpreadOpenDocChartWriter.GetChartRegressionEquationStyleAsXML(
|
|||||||
AChart: TsChart; AEquation: TsRegressionEquation; AIndent, AStyleID: Integer): String;
|
AChart: TsChart; AEquation: TsRegressionEquation; AIndent, AStyleID: Integer): String;
|
||||||
var
|
var
|
||||||
indent: String;
|
indent: String;
|
||||||
|
idx: Integer;
|
||||||
numStyle: String = 'N0';
|
numStyle: String = 'N0';
|
||||||
chartprops: String = '';
|
chartprops: String = '';
|
||||||
lineprops: String = '';
|
lineprops: String = '';
|
||||||
@ -547,9 +596,7 @@ begin
|
|||||||
|
|
||||||
indent := DupeString(' ', AIndent);
|
indent := DupeString(' ', AIndent);
|
||||||
|
|
||||||
// TO DO: Create chart number style list and find the current style there!
|
numStyle := GetNumberFormatID(AEquation.NumberFormat);
|
||||||
if not AEquation.DefaultNumberFormat then
|
|
||||||
numStyle := 'N0';
|
|
||||||
|
|
||||||
if not AEquation.DefaultXName then
|
if not AEquation.DefaultXName then
|
||||||
chartprops := chartprops + Format('loext:regression-x-name="%s" ', [AEquation.XName]);
|
chartprops := chartprops + Format('loext:regression-x-name="%s" ', [AEquation.XName]);
|
||||||
@ -647,6 +694,7 @@ var
|
|||||||
series: TsChartSeries;
|
series: TsChartSeries;
|
||||||
lineser: TsLineSeries = nil;
|
lineser: TsLineSeries = nil;
|
||||||
indent: String;
|
indent: String;
|
||||||
|
numStyle: String;
|
||||||
chartProps: String = '';
|
chartProps: String = '';
|
||||||
graphProps: String = '';
|
graphProps: String = '';
|
||||||
textProps: String = '';
|
textProps: String = '';
|
||||||
@ -659,8 +707,12 @@ begin
|
|||||||
indent := DupeString(' ', AIndent);
|
indent := DupeString(' ', AIndent);
|
||||||
series := AChart.Series[ASeriesIndex];
|
series := AChart.Series[ASeriesIndex];
|
||||||
|
|
||||||
|
// Number format
|
||||||
|
numStyle := GetNumberFormatID(series.LabelFormat);
|
||||||
|
|
||||||
// Chart properties
|
// Chart properties
|
||||||
chartProps := 'chart:symbol-type="none" ';
|
chartProps := 'chart:symbol-type="none" ';
|
||||||
|
|
||||||
if (series is TsLineSeries) and (series.ChartType <> ctFilledRadar) then
|
if (series is TsLineSeries) and (series.ChartType <> ctFilledRadar) then
|
||||||
begin
|
begin
|
||||||
lineser := TsLineSeries(series);
|
lineser := TsLineSeries(series);
|
||||||
@ -672,9 +724,7 @@ begin
|
|||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
chartProps := chartProps + 'chart:link-data-style-to-source="true" ';
|
chartProps := chartProps + Format('chart:link-data-style-to-source="%s" ', [FALSE_TRUE[numStyle = 'N0']]);
|
||||||
// to do: link-data-style-to-source must go to "false" in case of a specific
|
|
||||||
// numeric label format. But that requires a number-style in the Object/style.xml
|
|
||||||
|
|
||||||
if ([cdlValue, cdlPercentage] * series.DataLabels = [cdlValue]) then
|
if ([cdlValue, cdlPercentage] * series.DataLabels = [cdlValue]) then
|
||||||
chartProps := chartProps + 'chart:data-label-number="value" '
|
chartProps := chartProps + 'chart:data-label-number="value" '
|
||||||
@ -729,15 +779,63 @@ begin
|
|||||||
textProps := TsSpreadOpenDocWriter(Writer).WriteFontStyleXMLAsString(series.LabelFont);
|
textProps := TsSpreadOpenDocWriter(Writer).WriteFontStyleXMLAsString(series.LabelFont);
|
||||||
|
|
||||||
Result := Format(
|
Result := Format(
|
||||||
indent + '<style:style style:name="ch%d" style:family="chart" style:data-style-name="N0">' + LE +
|
indent + '<style:style style:name="ch%d" style:family="chart" style:data-style-name="%s">' + LE +
|
||||||
indent + chartProps + LE +
|
indent + chartProps + LE +
|
||||||
indent + ' <style:graphic-properties %s/>' + LE +
|
indent + ' <style:graphic-properties %s/>' + LE +
|
||||||
indent + ' <style:text-properties %s/>' + LE +
|
indent + ' <style:text-properties %s/>' + LE +
|
||||||
indent + '</style:style>' + LE,
|
indent + '</style:style>' + LE,
|
||||||
[ AStyleID, graphProps, textProps ]
|
[ AStyleID, numstyle, graphProps, textProps ]
|
||||||
);
|
);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TsSpreadOpenDocChartWriter.GetNumberFormatID(ANumFormat: String): String;
|
||||||
|
var
|
||||||
|
idx: Integer;
|
||||||
|
begin
|
||||||
|
idx := FNumberFormatList.IndexOf(ANumFormat);
|
||||||
|
if idx > -1 then
|
||||||
|
Result := Format('N%d', [idx])
|
||||||
|
else
|
||||||
|
Result := 'N0';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TsSpreadOpenDocChartWriter.ListAllNumberFormats(AChart: TsChart);
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
series: TsChartSeries;
|
||||||
|
regression: TsChartRegression;
|
||||||
|
begin
|
||||||
|
FNumberFormatList.Clear;
|
||||||
|
|
||||||
|
// Formats of axis labels
|
||||||
|
FNumberFormatList.Add(AChart.XAxis.LabelFormat);
|
||||||
|
FNumberFormatList.Add(AChart.YAxis.LabelFormat);
|
||||||
|
FNumberFormatList.Add(AChart.X2Axis.LabelFormat);
|
||||||
|
FNumberFormatList.Add(AChart.Y2Axis.LabelFormat);
|
||||||
|
if AChart.StackMode = csmStackedPercentage then
|
||||||
|
begin
|
||||||
|
FNumberFormatList.Add(AChart.YAxis.LabelFormatPercent);
|
||||||
|
FNumberFormatList.Add(AChart.Y2Axis.LabelFormatPercent);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Formats of series labels
|
||||||
|
for i := 0 to AChart.Series.Count-1 do
|
||||||
|
begin
|
||||||
|
series := AChart.Series[i];
|
||||||
|
FNumberFormatList.Add(series.LabelFormat);
|
||||||
|
// Format of fit equation
|
||||||
|
if (series is TsScatterSeries) then begin
|
||||||
|
regression := TsScatterSeries(series).Regression;
|
||||||
|
if (regression.RegressionType <> rtNone) and
|
||||||
|
(regression.DisplayEquation or regression.DisplayRSquare) then
|
||||||
|
begin
|
||||||
|
FNumberFormatList.Add(regression.Equation.NumberFormat);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ Extracts the cells needed by the given chart from the chart's worksheet and
|
{ Extracts the cells needed by the given chart from the chart's worksheet and
|
||||||
copies their values into a temporary worksheet, AWorksheet, so that these
|
copies their values into a temporary worksheet, AWorksheet, so that these
|
||||||
data can be written to the xml immediately.
|
data can be written to the xml immediately.
|
||||||
@ -936,11 +1034,10 @@ var
|
|||||||
styleStream: TMemoryStream;
|
styleStream: TMemoryStream;
|
||||||
styleID: Integer;
|
styleID: Integer;
|
||||||
begin
|
begin
|
||||||
// FChartStyleList.Clear;
|
|
||||||
|
|
||||||
chartStream := TMemoryStream.Create;
|
chartStream := TMemoryStream.Create;
|
||||||
styleStream := TMemoryStream.Create;
|
styleStream := TMemoryStream.Create;
|
||||||
try
|
try
|
||||||
|
ListAllNumberFormats(AChart);
|
||||||
WriteChartNumberStyles(styleStream, 4, AChart);
|
WriteChartNumberStyles(styleStream, 4, AChart);
|
||||||
|
|
||||||
styleID := 1;
|
styleID := 1;
|
||||||
@ -1210,9 +1307,28 @@ procedure TsSpreadOpenDocChartWriter.WriteChartNumberStyles(AStream: TStream;
|
|||||||
AIndent: Integer; AChart: TsChart);
|
AIndent: Integer; AChart: TsChart);
|
||||||
var
|
var
|
||||||
indent: String;
|
indent: String;
|
||||||
|
numFmtName: String;
|
||||||
|
numFmtStr: String;
|
||||||
|
numFmtXML: String;
|
||||||
|
i: Integer;
|
||||||
|
parser: TsSpreadOpenDocNumFormatParser;
|
||||||
begin
|
begin
|
||||||
indent := DupeString(' ', AIndent);
|
indent := DupeString(' ', AIndent);
|
||||||
|
|
||||||
|
for i := 0 to FNumberFormatList.Count-1 do begin
|
||||||
|
numFmtName := Format('N%d', [i]);
|
||||||
|
numFmtStr := FNumberFormatList[i];
|
||||||
|
parser := TsSpreadOpenDocNumFormatParser.Create(numFmtStr, FWriter.Workbook.FormatSettings);
|
||||||
|
try
|
||||||
|
numFmtXML := parser.BuildXMLAsString(numFmtName);
|
||||||
|
if numFmtXML <> '' then
|
||||||
|
AppendToStream(AStream, indent + numFmtXML);
|
||||||
|
finally
|
||||||
|
parser.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{
|
||||||
|
|
||||||
AppendToStream(AStream,
|
AppendToStream(AStream,
|
||||||
indent + '<number:number-style style:name="N0">' + LE +
|
indent + '<number:number-style style:name="N0">' + LE +
|
||||||
indent + ' <number:number number:min-integer-digits="1"/>' + LE +
|
indent + ' <number:number number:min-integer-digits="1"/>' + LE +
|
||||||
@ -1226,6 +1342,7 @@ begin
|
|||||||
indent + ' <number:text>%</number:text>' + LE +
|
indent + ' <number:text>%</number:text>' + LE +
|
||||||
indent + '</number:percentage-style>' + LE
|
indent + '</number:percentage-style>' + LE
|
||||||
);
|
);
|
||||||
|
}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Writes the file "Object N/styles.xml" (N = 1, 2, ...) which is needed by the
|
{ Writes the file "Object N/styles.xml" (N = 1, 2, ...) which is needed by the
|
||||||
|
Reference in New Issue
Block a user