fpspreadsheet: Chart link as well as ods reader/writer support individual data point colors

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9063 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2023-12-01 23:54:16 +00:00
parent fb4abdab4d
commit 8919da735c
4 changed files with 265 additions and 24 deletions

View File

@ -25,6 +25,7 @@ begin
sheet.WriteText(1, 0, 'https://en.wikipedia.org/wiki/World_population'); sheet.WriteText(1, 0, 'https://en.wikipedia.org/wiki/World_population');
sheet.WriteHyperlink(1, 0, 'https://en.wikipedia.org/wiki/World_population'); sheet.WriteHyperlink(1, 0, 'https://en.wikipedia.org/wiki/World_population');
sheet.WriteText(3, 0, 'Continent'); sheet.WriteText (3, 1, 'Population (millions)'); sheet.WriteText(3, 0, 'Continent'); sheet.WriteText (3, 1, 'Population (millions)');
sheet.WriteFontStyle(3, 0, [fssBold]); sheet.WriteFontStyle(3, 1, [fssBold]);
sheet.WriteText(4, 0, 'Asia'); sheet.WriteNumber(4, 1, 4641); // sheet.WriteChartColor(4, 2, scYellow); sheet.WriteText(4, 0, 'Asia'); sheet.WriteNumber(4, 1, 4641); // sheet.WriteChartColor(4, 2, scYellow);
sheet.WriteText(5, 0, 'Africa'); sheet.WriteNumber(5, 1, 1340); // sheet.WriteChartColor(5, 2, scBrown); sheet.WriteText(5, 0, 'Africa'); sheet.WriteNumber(5, 1, 1340); // sheet.WriteChartColor(5, 2, scBrown);
sheet.WriteText(6, 0, 'America'); sheet.WriteNumber(6, 1, 653 + 368); // sheet.WriteChartColor(6, 2, scRed); sheet.WriteText(6, 0, 'America'); sheet.WriteNumber(6, 1, 653 + 368); // sheet.WriteChartColor(6, 2, scRed);
@ -53,6 +54,15 @@ begin
ser.LabelPosition := lpOutside; ser.LabelPosition := lpOutside;
ser.Line.Color := scWhite; ser.Line.Color := scWhite;
ser.LabelFormat := '#,##0'; ser.LabelFormat := '#,##0';
// Individual sector colors
// Must be complete, otherwise will be ignored by Calc and replaced by default colors
ser.AddDataPointStyle(scYellow);
ser.AddDataPointStyle(scMaroon);
ser.AddDataPointStyle(scRed);
ser.AddDataPointStyle(scWhite);
ser.AddDatapointStyle(scBlue);
//ser.SetFillColorRange(4, 2, 8, 2); //ser.SetFillColorRange(4, 2, 8, 2);
{ {

View File

@ -40,6 +40,7 @@ type
Width: Double; // mm Width: Double; // mm
Color: TsColor; // in hex: $00bbggrr, r=red, g=green, b=blue Color: TsColor; // in hex: $00bbggrr, r=red, g=green, b=blue
Transparency: Double; // in percent Transparency: Double; // in percent
procedure CopyFrom(ALine: TsChartLine);
end; end;
TsChartGradientStyle = (cgsLinear, cgsAxial, cgsRadial, cgsElliptic, cgsSquare, cgsRectangular); TsChartGradientStyle = (cgsLinear, cgsAxial, cgsRadial, cgsElliptic, cgsSquare, cgsRectangular);
@ -135,6 +136,7 @@ type
Hatch: Integer; Hatch: Integer;
Image: Integer; Image: Integer;
Transparency: Double; // 0.0 ... 1.0 Transparency: Double; // 0.0 ... 1.0
procedure CopyFrom(AFill: TsChartFill);
end; end;
TsChartLineSegment = record TsChartLineSegment = record
@ -312,6 +314,8 @@ type
TsChartDataLabels = set of TsChartDataLabel; TsChartDataLabels = set of TsChartDataLabel;
TsChartLabelPosition = (lpDefault, lpOutside, lpInside, lpCenter); TsChartLabelPosition = (lpDefault, lpOutside, lpInside, lpCenter);
TsChartDataPointStyle = class(TsChartFillElement);
TsChartSeries = class(TsChartElement) TsChartSeries = class(TsChartElement)
private private
FChartType: TsChartType; FChartType: TsChartType;
@ -331,11 +335,14 @@ type
FLine: TsChartLine; FLine: TsChartLine;
FFill: TsChartFill; FFill: TsChartFill;
FDataLabels: TsChartDataLabels; FDataLabels: TsChartDataLabels;
FDataPointStyles: TFPObjectList;
protected protected
function GetChartType: TsChartType; virtual; function GetChartType: TsChartType; virtual;
public public
constructor Create(AChart: TsChart); virtual; constructor Create(AChart: TsChart); virtual;
destructor Destroy; override; destructor Destroy; override;
procedure AddDataPointStyle(AFill: TsChartFill; ALine: TsChartLine; ACount: Integer = 1);
procedure AddDataPointStyle(AColor: TsColor; ACount: Integer = 1);
function GetCount: Integer; function GetCount: Integer;
function GetXCount: Integer; function GetXCount: Integer;
function GetYCount: Integer; function GetYCount: Integer;
@ -361,6 +368,7 @@ type
property ChartType: TsChartType read GetChartType; property ChartType: TsChartType read GetChartType;
property Count: Integer read GetCount; property Count: Integer read GetCount;
property DataLabels: TsChartDataLabels read FDataLabels write FDataLabels; property DataLabels: TsChartDataLabels read FDataLabels write FDataLabels;
property DataPointStyles: TFPObjectList read FDataPointStyles;
property FillColorRange: TsChartRange read FFillColorRange write FFillColorRange; property FillColorRange: TsChartRange read FFillColorRange write FFillColorRange;
property LabelBackground: TsChartFill read FLabelBackground write FLabelBackground; property LabelBackground: TsChartFill read FLabelBackground write FLabelBackground;
property LabelBorder: TsChartLine read FLabelBorder write FLabelBorder; property LabelBorder: TsChartLine read FLabelBorder write FLabelBorder;
@ -659,6 +667,20 @@ implementation
uses uses
fpSpreadsheet; fpSpreadsheet;
{ TsChartLine }
procedure TsChartLine.CopyFrom(ALine: TsChartLine);
begin
if ALine <> nil then
begin
Style := ALine.Style;
Width := ALine.Width;
Color := ALine.Color;
Transparency := ALine.Transparency;
end;
end;
{ TsChartGradient } { TsChartGradient }
constructor TsChartGradient.Create; constructor TsChartGradient.Create;
@ -900,6 +922,22 @@ begin
end; end;
{ TsChartFill }
procedure TsChartFill.CopyFrom(AFill: TsChartFill);
begin
if AFill <> nil then
begin
Style := AFill.Style;
Color := AFill.Color;
Gradient := AFill.Gradient;
Hatch := AFill.Hatch;
Image := AFill.Image;
Transparency := AFill.Transparency;
end;
end;
{ TsChartLineStyle } { TsChartLineStyle }
function TsChartLineStyle.GetID: String; function TsChartLineStyle.GetID: String;
@ -1194,6 +1232,8 @@ begin
FLine.Width := PtsToMM(DEFAULT_CHART_LINEWIDTH); FLine.Width := PtsToMM(DEFAULT_CHART_LINEWIDTH);
FLine.Color := DEFAULT_SERIES_COLORS[idx mod Length(DEFAULT_SERIES_COLORS)]; FLine.Color := DEFAULT_SERIES_COLORS[idx mod Length(DEFAULT_SERIES_COLORS)];
FDataPointStyles := TFPObjectList.Create;
FLabelFont := TsFont.Create; FLabelFont := TsFont.Create;
FLabelFont.Size := 9; FLabelFont.Size := 9;
@ -1213,6 +1253,7 @@ begin
FLabelBackground.Free; FLabelBackground.Free;
FLabelBorder.Free; FLabelBorder.Free;
FLabelFont.Free; FLabelFont.Free;
FDataPointStyles.Free;
FLine.Free; FLine.Free;
FFill.Free; FFill.Free;
FTitleAddr.Free; FTitleAddr.Free;
@ -1224,6 +1265,39 @@ begin
inherited; inherited;
end; end;
procedure TsChartSeries.AddDataPointStyle(AFill: TsChartFill; ALine: TsChartLine;
ACount: Integer = 1);
var
i: Integer;
dataPointStyle: TsChartDataPointStyle;
begin
if (AFill = nil) and (ALine = nil) then
for i := 1 to ACount do
FDataPointStyles.Add(nil)
else
for i := 1 to ACount do
begin
dataPointStyle := TsChartDataPointStyle.Create(FChart);
dataPointStyle.Background.CopyFrom(AFill);
dataPointStyle.Border.CopyFrom(ALine);
FDataPointStyles.Add(dataPointStyle);
end;
end;
procedure TsChartSeries.AddDataPointStyle(AColor: TsColor; ACount: Integer = 1);
var
i: Integer;
datapointStyle: TsChartDataPointStyle;
begin
for i := 1 to ACount do
begin
datapointStyle := TsChartDatapointStyle.Create(FChart);
dataPointStyle.Background.Style:= cfsSolid;
dataPointStyle.Background.Color := AColor;
FDataPointStyles.Add(datapointStyle);
end;
end;
function TsChartSeries.GetChartType: TsChartType; function TsChartSeries.GetChartType: TsChartType;
begin begin
Result := FChartType; Result := FChartType;

View File

@ -26,8 +26,8 @@ type
FPieSeriesStartAngle: Integer; FPieSeriesStartAngle: Integer;
FStreamList: TFPObjectList; FStreamList: TFPObjectList;
function FindStyleNode(AStyleNodes: TDOMNode; AStyleName: String): TDOMNode; function FindStyleNode(AStyleNodes: TDOMNode; AStyleName: String): TDOMNode;
procedure GetChartFillProps(ANode: TDOMNode; AChart: TsChart; AFill: TsChartFill); function GetChartFillProps(ANode: TDOMNode; AChart: TsChart; AFill: TsChartFill): Boolean;
procedure GetChartLineProps(ANode: TDOMNode; AChart: TsChart; ALine: TsChartLine); function GetChartLineProps(ANode: TDOMNode; AChart: TsChart; ALine: TsChartLine): Boolean;
procedure GetChartTextProps(ANode: TDOMNode; AFont: TsFont); procedure GetChartTextProps(ANode: TDOMNode; AFont: TsFont);
procedure ReadChartAxisGrid(ANode, AStyleNode: TDOMNode; AChart: TsChart; Axis: TsChartAxis); procedure ReadChartAxisGrid(ANode, AStyleNode: TDOMNode; AChart: TsChart; Axis: TsChartAxis);
@ -45,6 +45,8 @@ type
procedure ReadChartRegressionEquationStyle(AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries); procedure ReadChartRegressionEquationStyle(AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries);
procedure ReadChartRegressionProps(ANode, AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries); procedure ReadChartRegressionProps(ANode, AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries);
procedure ReadChartRegressionStyle(AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries); procedure ReadChartRegressionStyle(AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries);
procedure ReadChartSeriesDataPointStyle(AStyleNode: TDOMNode; AChart: TsChart;
ASeries: TsChartSeries; var AFill: TsChartFill; var ALine: TsChartLine);
procedure ReadChartSeriesProps(ANode, AStyleNode: TDOMNode; AChart: TsChart); procedure ReadChartSeriesProps(ANode, AStyleNode: TDOMNode; AChart: TsChart);
procedure ReadChartSeriesStyle(AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries); procedure ReadChartSeriesStyle(AStyleNode: TDOMNode; AChart: TsChart; ASeries: TsChartSeries);
procedure ReadChartTitleProps(ANode, AStyleNode: TDOMNode; AChart: TsChart; ATitle: TsChartText); procedure ReadChartTitleProps(ANode, AStyleNode: TDOMNode; AChart: TsChart; ATitle: TsChartText);
@ -89,6 +91,7 @@ type
function GetChartRegressionEquationStyleAsXML(AChart: TsChart; function GetChartRegressionEquationStyleAsXML(AChart: TsChart;
AEquation: TsRegressionEquation; AIndent, AStyleID: Integer): String; AEquation: TsRegressionEquation; AIndent, AStyleID: Integer): String;
function GetChartRegressionStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: Integer): String; function GetChartRegressionStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: Integer): String;
function GetChartSeriesDataPointStyleAsXML(AChart: TsChart; ASeriesIndex, APointIndex, AIndent, AStyleID: Integer): String;
function GetChartSeriesStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: integer): String; function GetChartSeriesStyleAsXML(AChart: TsChart; ASeriesIndex, AIndent, AStyleID: integer): String;
function GetNumberFormatID(ANumFormat: String): String; function GetNumberFormatID(ANumFormat: String): String;
@ -403,11 +406,16 @@ begin
FChartFiles.Add(AFileList); FChartFiles.Add(AFileList);
end; end;
procedure TsSpreadOpenDocChartReader.GetChartFillProps(ANode: TDOMNode; {@@ ----------------------------------------------------------------------------
AChart: TsChart; AFill: TsChartFill); Reads the fill style properties from the specified node. Returns FALSE, if
the node contains no fill-specific attributes.
-------------------------------------------------------------------------------}
function TsSpreadOpenDocChartReader.GetChartFillProps(ANode: TDOMNode;
AChart: TsChart; AFill: TsChartFill): Boolean;
var var
{%H-}nodeName: String; {%H-}nodeName: String;
s: String; sFill: String;
sOpac: String;
sc: String; sc: String;
sn: String; sn: String;
opacity: Double; opacity: Double;
@ -417,8 +425,8 @@ var
begin begin
nodeName := ANode.NodeName; nodeName := ANode.NodeName;
s := GetAttrValue(ANode, 'draw:fill'); sFill := GetAttrValue(ANode, 'draw:fill');
case s of case sFill of
'none': 'none':
AFill.Style := cfsNoFill; AFill.Style := cfsNoFill;
'', 'solid': '', 'solid':
@ -472,13 +480,19 @@ begin
end; end;
end; end;
s := GetAttrValue(ANode, 'draw:opacity'); sOpac := GetAttrValue(ANode, 'draw:opacity');
if (s <> '') and TryPercentStrToFloat(s, opacity) then if (sOpac <> '') and TryPercentStrToFloat(sOpac, opacity) then
AFill.Transparency := 1.0 - opacity; AFill.Transparency := 1.0 - opacity;
Result := (sFill <> '') or (sc <> '') or (sn <> '') or (sOpac <> '');
end; end;
procedure TsSpreadOpenDocChartReader.GetChartLineProps(ANode: TDOMNode; { ------------------------------------------------------------------------------
AChart: TsChart; ALine: TsChartLine); Reads the line formatting properties from the specified node.
Returns FALSE, if there are no line-related attributes.
-------------------------------------------------------------------------------}
function TsSpreadOpenDocChartReader.GetChartLineProps(ANode: TDOMNode;
AChart: TsChart; ALine: TsChartLine): Boolean;
var var
{%H-}nodeName: String; {%H-}nodeName: String;
s: String; s: String;
@ -517,9 +531,11 @@ begin
if (sw <> '') and EvalLengthStr(sw, value, rel) then if (sw <> '') and EvalLengthStr(sw, value, rel) then
ALine.Width := value; ALine.Width := value;
so := 'draw:stroke-opacity'; so := GetAttrValue(ANode, 'draw:stroke-opacity');
if (so <> '') and TryPercentStrToFloat(so, value) then if (so <> '') and TryPercentStrToFloat(so, value) then
ALine.Transparency := 1.0 - value*0.01; ALine.Transparency := 1.0 - value*0.01;
Result := (s <> '') or (sc <> '') or (sw <> '') or (so <> '');
end; end;
procedure TsSpreadOpenDocChartReader.GetChartTextProps(ANode: TDOMNode; procedure TsSpreadOpenDocChartReader.GetChartTextProps(ANode: TDOMNode;
@ -1192,14 +1208,42 @@ begin
end; end;
end; end;
procedure TsSpreadOpenDocChartReader.ReadChartSeriesDataPointStyle(AStyleNode: TDOMNode;
AChart: TsChart; ASeries: TsChartSeries; var AFill: TsChartFill; var ALine: TsChartLine);
var
nodeName: string;
grNode: TDOMNode;
begin
AFill := nil;
ALine := nil;
nodeName := AStyleNode.NodeName;
AStyleNode := AStyleNode.FirstChild;
while AStyleNode <> nil do
begin
nodeName := AStyleNode.NodeName;
if nodeName = 'style:graphic-properties' then
begin
AFill := TsChartFill.Create;
if not GetChartFillProps(AStyleNode, AChart, AFill) then FreeAndNil(AFill);
ALine := TsChartLine.Create;
if not GetChartLineProps(AStyleNode, AChart, ALine) then FreeAndNil(ALine);
end;
AStyleNode := AStyleNode.NextSibling;
end;
end;
procedure TsSpreadOpenDocChartReader.ReadChartSeriesProps(ANode, AStyleNode: TDOMNode; procedure TsSpreadOpenDocChartReader.ReadChartSeriesProps(ANode, AStyleNode: TDOMNode;
AChart: TsChart); AChart: TsChart);
var var
s, nodeName: String; s, nodeName: String;
series: TsChartSeries; series: TsChartSeries;
fill: TsChartFill;
line: TsChartLine;
subNode: TDOMNode; subNode: TDOMNode;
styleNode: TDOMNode; styleNode: TDOMNode;
xyCounter: Integer; xyCounter: Integer;
n: Integer;
begin begin
s := GetAttrValue(ANode, 'chart:class'); s := GetAttrValue(ANode, 'chart:class');
case s of case s of
@ -1252,6 +1296,24 @@ begin
end; end;
'chart:regression-curve': 'chart:regression-curve':
ReadChartRegressionProps(subNode, AStyleNode, AChart, series); ReadChartRegressionProps(subNode, AStyleNode, AChart, series);
'chart:data-point':
begin
fill := nil;
line := nil;
n := 1;
s := GetAttrValue(subnode, 'chart:style-name');
if s <> '' then
begin
styleNode := FindStyleNode(AStyleNode, s);
ReadChartSeriesDataPointStyle(styleNode, AChart, series, fill, line); // creates fill and line!
end;
s := GetAttrValue(subnode, 'chart:repeated');
if (s <> '') then
n := StrToIntDef(s, 1);
series.AddDataPointStyle(fill, line, n);
fill.Free; // the styles have been copied to the series datapoint list and are not needed any more.
line.Free;
end;
end; end;
subnode := subNode.NextSibling; subnode := subNode.NextSibling;
end; end;
@ -2247,6 +2309,37 @@ begin
); );
end; end;
function TsSpreadOpenDocChartWriter.GetChartSeriesDataPointStyleAsXML(AChart: TsChart;
ASeriesIndex, APointIndex, AIndent, AStyleID: Integer): String;
var
series: TsChartSeries;
indent: String;
chartProps: String;
graphProps: String = '';
dataPointStyle: TsChartDataPointStyle;
begin
Result := '';
indent := DupeString(' ', AIndent);
series := AChart.Series[ASeriesIndex];
dataPointStyle := TsChartDataPointStyle(series.DataPointStyles[APointIndex]);
chartProps := 'chart:solid-type="cuboid" ';
if dataPointStyle.Background <> nil then
graphProps := graphProps + GetChartFillStyleGraphicPropsAsXML(AChart, dataPointStyle.Background);
if dataPointStyle.Border <> nil then
graphProps := graphProps + GetChartLineStyleGraphicPropsAsXML(AChart, dataPointStyle.Border);
Result := Format(
indent + '<style:style style:name="ch%d" style:family="chart">' + LE +
indent + ' <style:chart-properties %s/>' + LE +
indent + ' <style:graphic-properties %s/>' + LE +
indent + '</style:style>' + LE,
[ AStyleID, chartProps, graphProps ]
);
end;
{ <style:style style:name="ch1400" style:family="chart" style:data-style-name="N0"> { <style:style style:name="ch1400" style:family="chart" style:data-style-name="N0">
<style:chart-properties <style:chart-properties
@ -2326,9 +2419,9 @@ begin
if pos('\n', labelSeparator) > 0 then if pos('\n', labelSeparator) > 0 then
labelSeparator := StringReplace(labelSeparator, '\n', '<text:line-break/>', [rfReplaceAll, rfIgnoreCase]); labelSeparator := StringReplace(labelSeparator, '\n', '<text:line-break/>', [rfReplaceAll, rfIgnoreCase]);
labelSeparator := labelSeparator :=
' <chart:label-separator>' + LE + indent + ' <chart:label-separator>' + LE +
' <text:p>' + labelSeparator + '</text:p>' + LE + indent + ' <text:p>' + labelSeparator + '</text:p>' + LE +
' </chart:label-separator>' + LE; indent + ' </chart:label-separator>' + LE;
end; end;
if series.LabelBorder.Style <> clsNoLine then if series.LabelBorder.Style <> clsNoLine then
@ -2338,9 +2431,9 @@ begin
end; end;
if labelSeparator <> '' then if labelSeparator <> '' then
chartProps := ' <style:chart-properties ' + chartProps + '>' + LE + labelSeparator + ' </style:chart-properties>' chartProps := indent + ' <style:chart-properties ' + chartProps + '>' + LE + labelSeparator + indent + ' </style:chart-properties>'
else else
chartProps := ' <style:chart-properties ' + chartProps + '/>'; chartProps := indent + ' <style:chart-properties ' + chartProps + '/>';
// Graphic properties // Graphic properties
lineProps := GetChartLineStyleGraphicPropsAsXML(AChart, series.Line); lineProps := GetChartLineStyleGraphicPropsAsXML(AChart, series.Line);
@ -2361,7 +2454,7 @@ begin
Result := Format( Result := Format(
indent + '<style:style style:name="ch%d" style:family="chart" style:data-style-name="%s">' + LE + indent + '<style:style style:name="ch%d" style:family="chart" style:data-style-name="%s">' + LE +
indent + chartProps + LE + 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,
@ -3196,9 +3289,11 @@ var
needRegressionEquationStyle: Boolean = false; needRegressionEquationStyle: Boolean = false;
regression: TsChartRegression = nil; regression: TsChartRegression = nil;
titleAddr: String; titleAddr: String;
count: Integer; i, count: Integer;
styleID, dpStyleID: Integer;
begin begin
indent := DupeString(' ', AChartIndent); indent := DupeString(' ', AChartIndent);
styleID := AStyleID;
series := AChart.Series[ASeriesIndex]; series := AChart.Series[ASeriesIndex];
@ -3324,6 +3419,7 @@ begin
begin begin
regressionEquation := regressionEquation + Format('chart:style-name="ch%d" ', [AStyleID + 2]); regressionEquation := regressionEquation + Format('chart:style-name="ch%d" ', [AStyleID + 2]);
needRegressionEquationStyle := true; needRegressionEquationStyle := true;
styleID := AStyleID + 2;
end; end;
end; end;
if regression.DisplayEquation then if regression.DisplayEquation then
@ -3345,20 +3441,43 @@ begin
indent + ' <chart:equation %s />' + LE + indent + ' <chart:equation %s />' + LE +
indent + ' </chart:regression-curve>' + LE, indent + ' </chart:regression-curve>' + LE,
[ AStyleID + 1, regressionEquation ] [ AStyleID + 1, regressionEquation ]
)) ));
end else end else
AppendToStream(AChartStream, Format( AppendToStream(AChartStream, Format(
indent + ' <chart:regression-curve chart:style-name="ch%d"/>', indent + ' <chart:regression-curve chart:style-name="ch%d"/>',
[ AStyleID + 1 ] [ AStyleID + 1 ]
)); ));
needRegressionStyle := true; needRegressionStyle := true;
if styleID = AStyleID then
styleID := AStyleID + 1;
end; end;
end; end;
AppendToStream(AChartStream, Format( // Individual data point styles
indent + ' <chart:data-point chart:repeated="%d"/>' + LE, if series.DataPointStyles.Count = 0 then
[ count ] AppendToStream(AChartStream, Format(
)); indent + ' <chart:data-point chart:repeated="%d"/>' + LE,
[ count ]
))
else
begin
dpStyleID := styleID + 1;
for i := 0 to count - 1 do
begin
if (i >= series.DataPointStyles.Count) or (series.DataPointStyles[i] = nil) then
AppendToStream(AChartStream,
indent + ' <chart:data-point chart:repeated="1">' + LE
)
else
begin
AppendToStream(AChartStream, Format(
indent + ' <chart:data-point chart:style-name="ch%d" />' + LE, // ToDo: could contain "chart:repeated"
[ dpStyleID ]
));
inc(dpStyleID);
end;
end;
end;
AppendToStream(AChartStream, AppendToStream(AChartStream,
indent + '</chart:series>' + LE indent + '</chart:series>' + LE
); );
@ -3386,6 +3505,15 @@ begin
end; end;
end; end;
// Data point styles
for i := 0 to series.DataPointStyles.Count - 1 do
begin
inc(AStyleID);
AppendToStream(AStyleStream,
GetChartSeriesDataPointStyleAsXML(AChart, ASeriesIndex, i, AStyleIndent, AStyleID)
);
end;
// Next style // Next style
inc(AStyleID); inc(AStyleID);
end; end;

View File

@ -53,6 +53,7 @@ type
FTitleCol, FTitleRow: Cardinal; FTitleCol, FTitleRow: Cardinal;
FTitleSheetName: String; FTitleSheetName: String;
FCyclicX: Boolean; FCyclicX: Boolean;
FDataPointColors: array of TsColor;
function GetRange(AIndex: TsXYLRange): String; function GetRange(AIndex: TsXYLRange): String;
function GetTitle: String; function GetTitle: String;
function GetWorkbook: TsWorkbook; function GetWorkbook: TsWorkbook;
@ -82,6 +83,7 @@ type
procedure SetXRange(XIndex: Integer;ARange: TsChartRange); procedure SetXRange(XIndex: Integer;ARange: TsChartRange);
procedure SetYRange(YIndex: Integer; ARange: TsChartRange); procedure SetYRange(YIndex: Integer; ARange: TsChartRange);
procedure SetTitleAddr(Addr: TsChartCellAddr); procedure SetTitleAddr(Addr: TsChartCellAddr);
procedure UseDataPointColors(ASeries: TsChartSeries);
property PointsNumber: Cardinal read FPointsNumber; property PointsNumber: Cardinal read FPointsNumber;
property Workbook: TsWorkbook read GetWorkbook; property Workbook: TsWorkbook read GetWorkbook;
public public
@ -481,6 +483,8 @@ begin
end; end;
FCurItem.Color := clTAColor; // = clDefault FCurItem.Color := clTAColor; // = clDefault
if AIndex <= High(FDataPointColors) then
FCurItem.Color := FDataPointColors[AIndex];
if FRanges[rngColor] <> nil then if FRanges[rngColor] <> nil then
begin begin
GetXYItem(rngColor, 0, AIndex, dummyNumber, dummyString); GetXYItem(rngColor, 0, AIndex, dummyNumber, dummyString);
@ -537,6 +541,7 @@ end;
@param APointIndex Index of the data point for which the data are required @param APointIndex Index of the data point for which the data are required
@param ANumber (output) x or y coordinate of the data point @param ANumber (output) x or y coordinate of the data point
@param AText Data point marks label text @param AText Data point marks label text
@param AColor Individual data point color
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsWorkbookChartSource.GetXYItem(ARangeIndex:TsXYLRange; procedure TsWorkbookChartSource.GetXYItem(ARangeIndex:TsXYLRange;
AListIndex, APointIndex: Integer; out ANumber: Double; out AText: String); AListIndex, APointIndex: Integer; out ANumber: Double; out AText: String);
@ -891,6 +896,27 @@ begin
SetRangeFromChart(rngY, YIndex, ARange); SetRangeFromChart(rngY, YIndex, ARange);
end; end;
procedure TsWorkbookChartSource.UseDataPointColors(ASeries: TsChartSeries);
var
datapointStyle: TsChartDataPointStyle;
i: Integer;
begin
if ASeries = nil then
begin
SetLength(FDataPointColors, 0);
exit;
end;
SetLength(FDataPointColors, ASeries.DataPointStyles.Count);
for i := 0 to High(FDataPointColors) do
begin
datapointStyle := TsChartDataPointStyle(ASeries.DatapointStyles[i]);
FDataPointColors[i] := clTAColor;
if (dataPointStyle <> nil) and (datapointStyle.Background.Style = cfsSolid) then
FDataPointColors[i] := Convert_sColor_to_Color(dataPointStyle.Background.Color);
end;
end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
Setter method for the WorkbookSource Setter method for the WorkbookSource
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
@ -1038,6 +1064,9 @@ begin
if not ASeries.FillColorRange.IsEmpty then src.SetColorRange(ASeries.FillColorRange); if not ASeries.FillColorRange.IsEmpty then src.SetColorRange(ASeries.FillColorRange);
src.SetTitleAddr(ASeries.TitleAddr); src.SetTitleAddr(ASeries.TitleAddr);
// Copy individual data point colors to the chart series.
src.UseDataPointColors(ASeries);
if stackable then begin if stackable then begin
calcSrc := TCalculatedChartSource.Create(self); calcSrc := TCalculatedChartSource.Create(self);
calcSrc.Origin := src; calcSrc.Origin := src;