fpspreadsheet: Workbook chart link supports pie series offsets and data point styles.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9214 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
parent
1ebdbb15d8
commit
07ecb96d10
@ -63,10 +63,10 @@ begin
|
||||
line := TsChartline.CreateSolid(scWhite, 0.8);
|
||||
fill := TsChartFill.CreateHatchFill(ch.Hatches.AddLineHatch('ltHorz', chsSingle, $00C0FF, 1, 0.1, 0), scWhite);
|
||||
ser.DataPointStyles.AddSolidFill(0, $C47244, line);
|
||||
ser.DataPointStyles.AddSolidFill(1, $317DED, line, 10); // with explode offset, as percentage
|
||||
ser.DataPointStyles.AddSolidFill(1, $317DED, line, 20); // with explode offset, as percentage
|
||||
ser.DataPointStyles.AddSolidFill(2, $A5A5A5, line);
|
||||
ser.DataPointStyles.AddFillAndLine(3, fill, line);
|
||||
ser.DataPointStyles.AddSolidFill(4, $D69B5B, line, 20);
|
||||
ser.DataPointStyles.AddSolidFill(4, $D69B5B, line);
|
||||
line.Free;
|
||||
fill.Free;
|
||||
|
||||
|
@ -420,6 +420,7 @@ type
|
||||
constructor Create(AChart: TsChart);
|
||||
function AddFillAndLine(ADataPointIndex: Integer; AFill: TsChartFill; ALine: TsChartline; APieOffset: Integer = 0): Integer;
|
||||
function AddSolidFill(ADataPointIndex: Integer; AColor: TsColor; ALine: TsChartLine = nil; APieOffset: Integer = 0): Integer;
|
||||
function IndexOfDataPoint(ADataPointIndex: Integer): Integer;
|
||||
property Items[AIndex: Integer]: TsChartDataPointStyle read GetItem write SetItem; default;
|
||||
end;
|
||||
|
||||
@ -2010,6 +2011,14 @@ begin
|
||||
Result := TsChartDataPointStyle(inherited Items[AIndex]);
|
||||
end;
|
||||
|
||||
function TsChartDataPointStyleList.IndexOfDataPoint(ADataPointIndex: Integer): Integer;
|
||||
begin
|
||||
for Result := 0 to Count - 1 do
|
||||
if Items[Result].DataPointIndex = ADataPointIndex then
|
||||
exit;
|
||||
Result := -1;
|
||||
end;
|
||||
|
||||
procedure TsChartDataPointStyleList.SetItem(AIndex: Integer;
|
||||
AValue: TsChartDataPointStyle);
|
||||
begin
|
||||
|
@ -2733,8 +2733,7 @@ begin
|
||||
|
||||
if dataPointStyle = nil then
|
||||
begin
|
||||
// The series process by the caller has not individual style format.
|
||||
// We must write a node nevertheless...
|
||||
// No style information found. We write a node, nevertheless... (maybe can be dropped?)
|
||||
Result := Format(
|
||||
indent + '<style:style style:name="ch%d" style:family="chart">' + LE +
|
||||
indent + ' <style:chart-properties/>' + LE +
|
||||
@ -3744,7 +3743,7 @@ var
|
||||
trendlineEquation: String = '';
|
||||
trendline: TsChartTrendline = nil;
|
||||
titleAddr: String;
|
||||
i, j, idx, count: Integer;
|
||||
i, idx, count: Integer;
|
||||
nextStyleID, seriesStyleID, trendlineStyleID, trendlineEquStyleID: Integer;
|
||||
xErrStyleID, yErrStyleID, dataStyleID: Integer;
|
||||
datapointStyle: TsChartDataPointStyle;
|
||||
@ -3960,7 +3959,7 @@ begin
|
||||
for i := 0 to count - 1 do
|
||||
begin
|
||||
AppendToStream(AChartStream, Format(
|
||||
indent + ' <chart:data-point chart:style.name="ch%d"/>' + LE,
|
||||
indent + ' <chart:data-point chart:style-name="ch%d"/>' + LE,
|
||||
[ dataStyleID + i ]
|
||||
));
|
||||
inc(nextStyleID);
|
||||
@ -4028,17 +4027,7 @@ begin
|
||||
begin
|
||||
for i := 0 to count - 1 do
|
||||
begin
|
||||
idx := -1;
|
||||
for j := 0 to series.DataPointStyles.Count-1 do
|
||||
begin
|
||||
dataPointStyle := series.DataPointstyles[j];
|
||||
if (dataPointStyle <> nil) and (dataPointStyle.DataPointIndex = i) then
|
||||
begin
|
||||
idx := j;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
|
||||
idx := series.DataPointStyles.IndexOfDatapoint(i);
|
||||
AppendToStream(AStyleStream,
|
||||
GetChartSeriesDataPointStyleAsXML(AChart, ASeriesIndex, idx, AStyleIndent, dataStyleID)
|
||||
);
|
||||
|
@ -34,10 +34,6 @@ 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
|
||||
@ -62,6 +58,10 @@ type
|
||||
FCyclicX: Boolean;
|
||||
FIntegerX: Boolean; // only integers allowed for x values
|
||||
FDataPointColors: array of TsColor;
|
||||
FPieSeriesMode: boolean;
|
||||
FPieOffsets: Array of Double;
|
||||
FStyles: TChartStyles;
|
||||
|
||||
function GetRange(AIndex: TsXYLRange): String;
|
||||
function GetTitle: String;
|
||||
function GetWorkbook: TsWorkbook;
|
||||
@ -86,7 +86,7 @@ type
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
function RangeIsEmpty(ARange: TsCellRange): Boolean;
|
||||
procedure CheckPieSeriesMode(ASeries: TsChartSeries);
|
||||
procedure Reset;
|
||||
procedure SetColorRange(ARange: TsChartRange);
|
||||
procedure SetLabelRange(ARange: TsChartRange);
|
||||
@ -95,13 +95,17 @@ type
|
||||
procedure SetTitleAddr(Addr: TsChartCellAddr);
|
||||
procedure SetXErrorBarRange(APosRange, ANegRange: TsChartRange);
|
||||
procedure SetYErrorBarRange(APosRange, ANegRange: TsChartRange);
|
||||
procedure UseDataPointColors(ASeries: TsChartSeries);
|
||||
property PointsNumber: Cardinal read FPointsNumber;
|
||||
property Workbook: TsWorkbook read GetWorkbook;
|
||||
public
|
||||
// Interface to TsWorkbookSource
|
||||
procedure ListenerNotification(AChangedItems: TsNotificationItems; AData: Pointer = nil);
|
||||
procedure RemoveWorkbookSource;
|
||||
public
|
||||
// Special methods to be called by TsWorkbookChartLink
|
||||
function RangeIsEmpty(ARange: TsCellRange): Boolean;
|
||||
procedure UseDatapointColors(ASeries: TsChartSeries);
|
||||
property Styles: TChartStyles read FStyles;
|
||||
published
|
||||
property WorkbookSource: TsWorkbookSource read FWorkbookSource write SetWorkbookSource;
|
||||
property ColorRange: String index rngColor read GetRange write SetRange;
|
||||
@ -180,9 +184,7 @@ type
|
||||
procedure UpdateScatterSeries(AWorkbookSeries: TsScatterSeries; AChartSeries: TLineSeries);
|
||||
procedure UpdateStockSeries(AWorkbookSeries: TsStockSeries; AChartSeries: TStockSeries);
|
||||
|
||||
{$ifdef DATAPOINT_STYLES}
|
||||
procedure UseDatapointStyles(AWorkbookSeries: TsChartSeries; AChartSeries: TChartSeries);
|
||||
{$endif}
|
||||
procedure CreateChartStylesFromDatapoints(AWorkbookSeries: TsChartSeries; AChartStyles: TChartStyles);
|
||||
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
@ -377,6 +379,7 @@ end;
|
||||
constructor TsWorkbookChartSource.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited;
|
||||
FStyles := TChartStyles.Create(self);
|
||||
FCurItemIndex := -1;
|
||||
ClearRanges;
|
||||
end;
|
||||
@ -462,6 +465,9 @@ begin
|
||||
FRangeStr[rngY] := '';
|
||||
FRangeStr[rngLabel] := '';
|
||||
FRangeStr[rngColor] := '';
|
||||
|
||||
FStyles.Styles.Clear;
|
||||
SetLength(FPieOffsets, 0);
|
||||
end;
|
||||
|
||||
|
||||
@ -526,20 +532,30 @@ begin
|
||||
exit;
|
||||
end;
|
||||
|
||||
for i := 0 to XCount-1 do
|
||||
{ In PieSeriesMode, the x values are not taken from the worksheet, but
|
||||
have been made available in the separate array FPieOffsets. }
|
||||
if FPieSeriesMode then
|
||||
begin
|
||||
if (FRanges[rngX, i] <> nil) then
|
||||
begin
|
||||
GetXYItem(rngX, i, AIndex, value, tmpLabel);
|
||||
if FIntegerX then
|
||||
value := trunc(value);
|
||||
end else
|
||||
if FCyclicX then
|
||||
value := AIndex / FPointsNumber * TWO_PI
|
||||
if (AIndex >= 0) and (AIndex < Length(FPieOffsets)) then
|
||||
FCurItem.SetX(0, FPieOffsets[AIndex])
|
||||
else
|
||||
value := AIndex;
|
||||
FCurItem.SetX(i, value);
|
||||
end;
|
||||
FCurItem.SetX(0, 0.0);
|
||||
end
|
||||
else
|
||||
for i := 0 to XCount-1 do
|
||||
begin
|
||||
if (FRanges[rngX, i] <> nil) then
|
||||
begin
|
||||
GetXYItem(rngX, i, AIndex, value, tmpLabel);
|
||||
if FIntegerX then
|
||||
value := trunc(value);
|
||||
end else
|
||||
if FCyclicX then
|
||||
value := AIndex / FPointsNumber * TWO_PI
|
||||
else
|
||||
value := AIndex;
|
||||
FCurItem.SetX(i, value);
|
||||
end;
|
||||
|
||||
for i := 0 to YCount-1 do
|
||||
begin
|
||||
@ -556,6 +572,7 @@ begin
|
||||
FCurItem.Color := clTAColor; // = clDefault
|
||||
if AIndex <= High(FDataPointColors) then
|
||||
FCurItem.Color := FDataPointColors[AIndex];
|
||||
|
||||
if FRanges[rngColor] <> nil then
|
||||
begin
|
||||
GetXYItem(rngColor, 0, AIndex, dummyNumber, dummyString);
|
||||
@ -997,14 +1014,44 @@ begin
|
||||
SetRangeFromChart(rngY, YIndex, ARange);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
In case of a pie series, both xlsx and ods files do not provide the
|
||||
pie offsets as worksheet cell ranges but as attributes in the xml files.
|
||||
Therefore, we store these offsets separately in an array, FPieOffsets.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorkbookChartSource.CheckPieSeriesMode(ASeries: TsChartSeries);
|
||||
var
|
||||
i, j: Integer;
|
||||
datapointStyle: TsChartDataPointStyle;
|
||||
begin
|
||||
FPieSeriesMode := (ASeries is TsPieSeries);
|
||||
if FPieSeriesMode then
|
||||
begin
|
||||
SetLength(FPieOffsets, ASeries.Count);
|
||||
for i := 0 to ASeries.Count-1 do
|
||||
begin
|
||||
j := ASeries.DataPointStyles.IndexOfDataPoint(i);
|
||||
FPieOffsets[i] := 0;
|
||||
dataPointStyle := ASeries.DataPointStyles[j];
|
||||
if dataPointStyle <> nil then
|
||||
FPieOffsets[i] := dataPointStyle.PieOffset * 0.01;
|
||||
end;
|
||||
end else
|
||||
SetLength(FPieOffsets, 0);
|
||||
end;
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Extracts the fill color from the DataPointStyle items of the series. All the
|
||||
other elements are ignored because TAChart does not support them.
|
||||
|
||||
But note: Some series types allow to use chartstyles for individual data point
|
||||
formatting. In this case this method is not executed.
|
||||
-------------------------------------------------------------------------------}
|
||||
procedure TsWorkbookChartSource.UseDataPointColors(ASeries: TsChartSeries);
|
||||
var
|
||||
datapointStyle: TsChartDataPointStyle;
|
||||
i: Integer;
|
||||
style: TChartStyle;
|
||||
i, j: Integer;
|
||||
c: TsColor;
|
||||
g: TsChartGradient;
|
||||
begin
|
||||
@ -1037,7 +1084,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{@@ ----------------------------------------------------------------------------
|
||||
Setter method for the WorkbookSource
|
||||
-------------------------------------------------------------------------------}
|
||||
@ -1242,12 +1288,18 @@ 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}
|
||||
// Send pie offsets to chart soruce...
|
||||
src.CheckPieSeriesMode(ASeries);
|
||||
// ... as well as datapoint styles/colors
|
||||
CreateChartStylesFromDatapoints(ASeries, src.Styles);
|
||||
{$if LCL_FullVersion >= 3990000}
|
||||
if (Result is TPieSeries) then
|
||||
TPieSeries(Result).Styles := src.Styles
|
||||
else if (Result is TBubbleSeries) then
|
||||
TBubbleSeries(Result).Styles := src.Styles
|
||||
else if (Result is TBarSeries) then
|
||||
TBarSeries(Result).Styles := src.Styles;
|
||||
{$ifend}
|
||||
|
||||
if stackable then begin
|
||||
calcSrc := TCalculatedChartSource.Create(self);
|
||||
@ -2614,6 +2666,7 @@ begin
|
||||
if AWorkbookSeries is TsRingSeries then
|
||||
AChartSeries.InnerRadiusPercent := TsRingSeries(AWorkbookSeries).InnerRadiusPercent;
|
||||
{$IFEND}
|
||||
AChartSeries.Exploded := true;
|
||||
|
||||
FChart.BottomAxis.Visible := false;
|
||||
FChart.LeftAxis.Visible := false;
|
||||
@ -2682,6 +2735,41 @@ begin
|
||||
UpdateChartSeriesTrendline(AWorkbookSeries, AChartSeries);
|
||||
end;
|
||||
|
||||
procedure TsWorkbookChartLink.CreateChartStylesFromDatapoints(AWorkbookSeries: TsChartSeries;
|
||||
AChartStyles: TChartStyles);
|
||||
var
|
||||
style: TChartStyle;
|
||||
datapointStyle: TsChartDatapointStyle;
|
||||
i: Integer;
|
||||
begin
|
||||
AChartStyles.Styles.Clear;
|
||||
|
||||
if AWorkbookSeries.DataPointStyles.Count = 0 then
|
||||
exit;
|
||||
if not ((AWorkbookSeries is TsPieSeries) or (AWorkbookSeries is TsBubbleSeries)) then
|
||||
exit;
|
||||
if (AWorkbookSeries is TsBarSeries) and (AWorkbookSeries.Chart.Series.Count > 1) then
|
||||
exit; // TAChart cannot handle datapoint styles for layered bar series
|
||||
|
||||
for i := 0 to AWorkbookSeries.Count-1 do
|
||||
begin
|
||||
style := AChartStyles.Add;
|
||||
datapointStyle := AWorkbookSeries.DataPointStyles[i];
|
||||
if datapointstyle = nil then
|
||||
begin
|
||||
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, style.brush);
|
||||
UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.Line, style.Pen);
|
||||
end else
|
||||
begin
|
||||
UpdateChartBrush(AWorkbookSeries.Chart, datapointStyle.Background, style.Brush);
|
||||
UpdateChartPen(AWorkbookSeries.Chart, datapointStyle.Border, style.Pen);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
(*
|
||||
{$ifdef DATAPOINT_STYLES}
|
||||
procedure TsWorkbookChartLink.UseDatapointStyles(AWorkbookSeries: TsChartSeries;
|
||||
AChartSeries: TChartSeries);
|
||||
@ -2708,7 +2796,8 @@ begin
|
||||
style := styles.Add;
|
||||
if dps = nil then
|
||||
begin
|
||||
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.FILL, style.brush);
|
||||
UpdateChartBrush(AWorkbookSeries.Chart, AWorkbookSeries.Fill, style.brush);
|
||||
UpdateChartPen(AWorkbookSeries.Chart, AWorkbookSeries.Line, style.Pen);
|
||||
end else
|
||||
begin
|
||||
UpdateChartBrush(AWorkbookSeries.Chart, dps.Background, style.Brush);
|
||||
@ -2724,7 +2813,7 @@ begin
|
||||
TBarSeries(AChartSeries).Styles := styles;
|
||||
end;
|
||||
{$endif}
|
||||
|
||||
*)
|
||||
{$ENDIF}
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user