fpspreadsheet: Fix chart data point labels

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9212 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-02-05 12:59:20 +00:00
parent 8176a4f3bf
commit 5c3be57541
5 changed files with 127 additions and 27 deletions

View File

@ -61,10 +61,13 @@ begin
// Individual sector colors, with white border
// Must be complete, otherwise will be ignored by Calc and replaced by default colors
line := TsChartline.CreateSolid(scWhite, 0.8);
fill := TsChartFill.CreateHatchFill(ch.Hatches.AddLineHatch('ltHorz', chsSingle, $00C0FF, 1, 0.1, 0), scWhite);
ser.DataPointStyles.AddSolidFill($C47244, line);
ser.DataPointStyles.AddSolidFill($317DED, line);
ser.DataPointStyles.AddSolidFill($A5A5A5, line);
ser.DataPointStyles.AddSolidFill($00C0FF, line);
ser.DataPointStyles.AddFillAndLine(fill, line);
// ser.DataPointStyles.AddSolidFill($00C0FF, line);
line.Color := scWhite;
ser.DataPointStyles.AddSolidFill($D69B5B, line);
line.Free;

View File

@ -69,6 +69,11 @@
<Debugging>
<DebugInfoType Value="dsDwarf3"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>

View File

@ -182,6 +182,8 @@ type
Hatch: Integer; // Index into chart's Hatches list
Image: Integer; // Index into chart's Images list
Transparency: Double; // 0.0 ... 1.0
constructor CreateSolidFill(AColor: TsColor);
constructor CreateHatchFill(AHatchIndex: Integer; ABkColor: TsColor = scTransparent);
procedure CopyFrom(AFill: TsChartFill);
end;
@ -1389,6 +1391,24 @@ end;
{ TsChartFill }
constructor TsChartFill.CreateSolidFill(AColor: TsColor);
begin
inherited Create;
Style := cfsSolid;
Color := AColor;
end;
constructor TsChartFill.CreateHatchFill(AHatchIndex: Integer; ABkColor: TsColor = scTransparent);
begin
inherited Create;
if aBkColor = scTransparent then
Style := cfsHatched
else
Style := cfsSolidHatched;
Hatch := AHatchIndex;
Color := ABkColor;
end;
procedure TsChartFill.CopyFrom(AFill: TsChartFill);
begin
if AFill <> nil then

View File

@ -104,6 +104,7 @@ type
procedure WriteChartPlotAreaNode(AStream: TStream; AIndent: Integer; AChart: TsChart);
procedure WriteChartRegression(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries);
procedure WriteChartSeriesDatapointLabels(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 WriteChartSeriesTitle(AStream: TStream; AIndent: Integer; ASeries: TsChartSeries);
procedure WriteChartTitleNode(AStream: TStream; AIndent: Integer; ATitle: TsChartText);
@ -1069,10 +1070,12 @@ begin
case nodeName of
'c:spPr':
begin
fill := TsChartFill.Create; // will be destroyed by the chart!
fill := TsChartFill.Create;
line := TsChartLine.Create;
ReadChartFillAndLineProps(ANode.FirstChild, ASeries.Chart, fill, line);
ASeries.DataPointStyles.AddFillAndLine(fill, line);
ASeries.DataPointStyles.AddFillAndLine(fill, line); // fill and line are copied here
line.Free;
fill.Free;
end;
'c:explosion':
; // in case of pie series: movement of individual sector away from center
@ -1758,7 +1761,6 @@ procedure TsSpreadOOXMLChartReader.ReadChartSeriesLabels(ANode: TDOMNode;
var
nodeName, s: String;
child1, child2, child3: TDOMNode;
dataLabels: TsChartDataLabels = [];
begin
if ANode = nil then
exit;
@ -1792,25 +1794,25 @@ begin
;
'c:showLegendKey':
if (s = '1') then
dataLabels := dataLabels + [cdlSymbol];
ASeries.DataLabels := ASeries.DataLabels + [cdlSymbol];
'c:showVal':
if (s = '1') then
dataLabels := dataLabels + [cdlValue];
ASeries.DataLabels := ASeries.DataLabels + [cdlValue];
'c:showCatName':
if (s = '1') then
dataLabels := dataLabels + [cdlCategory];
ASeries.DataLabels := ASeries.DataLabels + [cdlCategory];
'c:showSerName':
if (s = '1') then
dataLabels := dataLabels + [cdlSeriesName];
ASeries.DataLabels := ASeries.DataLabels + [cdlSeriesName];
'c:showPercent':
if (s = '1') then
dataLabels := dataLabels + [cdlPercentage];
ASeries.DataLabels := ASeries.DataLabels + [cdlPercentage];
'c:showBubbleSize':
if (s = '1') then
dataLabels := dataLabels + [cdlValue];
ASeries.DataLabels := ASeries.DataLabels + [cdlValue];
'c:showLeaderLines':
if (s = '1') then
dataLabels := dataLabels + [cdlLeaderLines];
ASeries.DataLabels := ASeries.DataLabels + [cdlLeaderLines];
'c:extLst':
begin
child1 := ANode.FirstChild;
@ -1859,8 +1861,6 @@ begin
end;
ANode := ANode.NextSibling;
end;
ASeries.DataLabels := dataLabels;
end;
procedure TsSpreadOOXMLChartReader.ReadChartSeriesProps(ANode: TDOMNode; ASeries: TsChartSeries);
@ -4071,6 +4071,35 @@ begin
));
end;
{@@ ----------------------------------------------------------------------------
Write individual data point formatting to the chartN.xml stream. The information
is written to <c:dPt> nodes underneath <c:ser>, one <c:dPt> node per data point.
-------------------------------------------------------------------------------}
procedure TsSpreadOOXMLChartWriter.WriteChartSeriesDataPointStyles(AStream: TStream;
AIndent: Integer; ASeries: TsChartSeries);
var
indent: String;
i: Integer;
dps: TsChartDatapointStyle;
explosionStr: String = '';
begin
indent := DupeString(' ', AIndent);
for i := 0 to ASeries.DataPointStyles.Count-1 do
begin
dps := ASeries.DataPointStyles[i];
if dps <> nil then
AppendToStream(AStream,
indent + '<c:dPt>' + LE +
indent + ' <c:idx val="' + IntToStr(i) + '"/>' + LE +
explosionStr + // to do: read explosion value from worksheet!
indent + ' <c:spPr>' + LE +
GetChartFillAndLineXML(AIndent + 4, ASeries.Chart, dps.Background, dps.Border) + LE +
indent + ' </c:spPr>' + LE +
indent + '</c:dPt>' + LE
);
end;
end;
{@@ ----------------------------------------------------------------------------
Writes the <c:ser> node for the specified chart series
Is called by all series types.
@ -4112,20 +4141,7 @@ begin
WriteChartSeriesTitle(AStream, AIndent + 2, ASeries);
// Individual data point formats
if ASeries.DataPointStyles.Count > 0 then
for i := 0 to ASeries.DataPointStyles.Count-1 do
begin
dps := ASeries.DataPointStyles[i];
AppendToStream(AStream,
indent + ' <c:dPt>' + LE +
indent + ' <c:idx val="' + IntToStr(i) + '"/>' + LE +
explosionStr + // to do: read explosion value from worksheet!
indent + ' <c:spPr>' + LE +
GetChartFillAndLineXML(AIndent + 6, chart, dps.Background, dps.Border) + LE +
indent + ' </c:spPr>' + LE +
indent + ' </c:dPt>' + LE
);
end;
WriteChartSeriesDatapointStyles(AStream, AIndent + 2, ASeries);
// Line & scatter series: symbol markers
if (ASeries is TsCustomLineSeries) then

View File

@ -34,6 +34,10 @@ uses
// FPSpreadsheet Visual
fpSpreadsheetCtrls, fpSpreadsheetGrid, fpsVisualUtils;
{$if LCL_FullVersion >= 3990000}
{$define DATAPOINT_STYLES}
{$ifend}
type
{@@ Chart data source designed to work together with TChart from Lazarus
@ -176,6 +180,10 @@ type
procedure UpdateScatterSeries(AWorkbookSeries: TsScatterSeries; AChartSeries: TLineSeries);
procedure UpdateStockSeries(AWorkbookSeries: TsStockSeries; AChartSeries: TStockSeries);
{$ifdef DATAPOINT_STYLES}
procedure UseDatapointStyles(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries);
{$endif}
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
@ -1234,8 +1242,12 @@ begin
src.SetColorRange(ASeries.FillColorRange);
src.SetTitleAddr(ASeries.TitleAddr);
{$ifdef DATAPOINT_STYLES}
UseDatapointStyles(ASeries, Result);
{$else}
// Copy individual data point colors to the chart series.
src.UseDataPointColors(ASeries);
{$endif}
if stackable then begin
calcSrc := TCalculatedChartSource.Create(self);
@ -1401,6 +1413,7 @@ begin
ABrush.Style := bsSolid; // Fall-back style
hatch := AWorkbookChart.Hatches[AFill.Hatch];
ABrush.Color := Convert_sColor_to_Color(hatch.PatternColor);
case hatch.Style of
chsSingle:
if InRange(hatch.PatternAngle mod 180, -22.5, 22.5) then // horizontal "approximation"
@ -2669,6 +2682,49 @@ begin
UpdateChartSeriesTrendline(AWorkbookSeries, AChartSeries);
end;
{$ifdef DATAPOINT_STYLES}
procedure TsWorkbookChartLink.UseDatapointStyles(AWorkbookSeries: TsChartSeries;
AChartSeries: TChartSeries);
var
styles: TChartStyles;
style: TChartStyle;
dps: TsChartDatapointStyle;
i: Integer;
begin
if AWorkbookSeries.DataPointStyles.Count = 0 then
exit;
if not ((AWorkbookSeries is TsPieSeries) or (AWorkbookSeries is TsBubbleSeries)) then
exit;
// TAChart cannot handle data point styles in case of layered bar series
if (AWorkbookSeries is TsBarSeries) and (AWorkbookSeries.Chart.Series.Count > 1) then
exit;
styles := TChartStyles.Create(AChartSeries);
for i := 0 to AWorkbookSeries.DatapointStyles.Count-1 do
begin
dps := AWorkbookSeries.DataPointStyles[i];
style := styles.Add;
if dps = nil then
begin
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.FILL, style.brush);
end else
begin
UpdateChartBrush(AWorkbookSeries.Chart, dps.Background, style.Brush);
UpdateChartPen(AWorkbookSeries.Chart, dps.Border, style.Pen);
end;
end;
if (AChartSeries is TPieSeries) then
TPieSeries(AChartSeries).Styles := styles
else if (AChartSeries is TBubbleSeries) then
TBubbleSeries(AChartSeries).Styles := styles
else if (AChartSeries is TBarSeries) then
TBarSeries(AChartSeries).Styles := styles;
end;
{$endif}
{$ENDIF}
end.