fpspreadsheet: Simplify chart gradient creation

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@9464 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz 2024-09-24 18:07:41 +00:00
parent 80838e3529
commit d19010191f
3 changed files with 60 additions and 74 deletions

View File

@ -71,25 +71,22 @@ type
private private
FSteps: TsChartGradientSteps; FSteps: TsChartGradientSteps;
function GetColor(AIndex: Integer): TsChartColor; function GetColor(AIndex: Integer): TsChartColor;
function GetIntensity(AIndex: Integer): Double;
function GetSteps(AIndex: Integer): TsChartGradientStep; function GetSteps(AIndex: Integer): TsChartGradientStep;
procedure SetStep(AIndex: Integer; AValue: Double; AColor: TsChartColor; AIntensity: Double); procedure SetStep(AIndex: Integer; AValue: Double; AColor: TsChartColor);
public public
Name: String; Name: String;
Style: TsChartGradientStyle; Style: TsChartGradientStyle;
Border: Double; // 0.0 ... 1.0 Border: Double; // 0.0 ... 1.0 ( fraction along the gradient extent where the gradient begins )
CenterX, CenterY: Double; // 0.0 ... 1.0 ( for gradients which are not linear ) CenterX, CenterY: Double; // 0.0 ... 1.0 ( for gradients which are not linear )
Angle: Double; // degrees, 0° = horizontal, grows CCW Angle: Double; // for linear gradient in degrees, 0° = horizontal, grows CCW, from start to end color
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
procedure CopyFrom(ASource: TsChartGradient); procedure CopyFrom(ASource: TsChartGradient);
procedure AddStep(AValue: Double; AColor: TsChartColor; AIntensity: Single = 1.0); procedure AddStep(AValue: Double; AColor: TsChartColor);
function NumSteps: Integer; function NumSteps: Integer;
property Steps[AIndex: Integer]: TsChartGradientStep read GetSteps; property Steps[AIndex: Integer]: TsChartGradientStep read GetSteps;
property StartColor: TsChartColor index 0 read GetColor; property StartColor: TsChartColor index 0 read GetColor;
property StartIntensity: Double index 0 read GetIntensity;
property EndColor: TsChartColor index 1 read GetColor; property EndColor: TsChartColor index 1 read GetColor;
property EndIntensity: Double index 1 read GetIntensity;
end; end;
TsChartGradientList = class(TFPObjectList) TsChartGradientList = class(TFPObjectList)
@ -99,26 +96,20 @@ type
public public
function AddGradient(AName: String; AGradient: TsChartGradient): Integer; function AddGradient(AName: String; AGradient: TsChartGradient): Integer;
function AddGradient(AName: String; AStyle: TsChartGradientStyle; function AddGradient(AName: String; AStyle: TsChartGradientStyle;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; ACenterX, ACenterY, AAngle: Double;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer; ABorder: Double = 0.0): Integer;
function AddAxialGradient(AName: String; AStartColor, AEndColor: TsChartColor; function AddAxialGradient(AName: String; AStartColor, AEndColor: TsChartColor;
AStartIntensity, AEndIntensity: Double; AAngle: Double; ABorder: Double = 0.0): Integer;
ABorder, AAngle: Double): Integer;
function AddEllipticGradient(AName: String; AStartColor, AEndColor: TsChartColor; function AddEllipticGradient(AName: String; AStartColor, AEndColor: TsChartColor;
AStartIntensity, AEndIntensity: Double; ACenterX, ACenterY, AAngle: Double; ABorder: Double = 0.0): Integer;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer;
function AddLinearGradient(AName: String; AStartColor, AEndColor: TsChartColor; function AddLinearGradient(AName: String; AStartColor, AEndColor: TsChartColor;
AStartIntensity, AEndIntensity: Double; AAngle: Double; ABorder: Double = 0.0): Integer;
ABorder, AAngle: Double): Integer;
function AddRadialGradient(AName: String; AStartColor, AEndColor: TsChartColor; function AddRadialGradient(AName: String; AStartColor, AEndColor: TsChartColor;
AStartIntensity, AEndIntensity: Double; ACenterX, ACenterY: Double; ABorder: Double = 0.0): Integer;
ABorder, ACenterX, ACenterY: Double): Integer;
function AddRectangularGradient(AName: String; AStartColor, AEndColor: TsChartColor; function AddRectangularGradient(AName: String; AStartColor, AEndColor: TsChartColor;
AStartIntensity, AEndIntensity: Double; ACenterX, ACenterY, AAngle: Double; ABorder: Double = 0.0): Integer;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer;
function AddSquareGradient(AName: String; AStartColor, AEndColor: TsChartColor; function AddSquareGradient(AName: String; AStartColor, AEndColor: TsChartColor;
AStartIntensity, AEndIntensity: Double; ACenterX, ACenterY, AAngle: Double; ABorder: Double = 0.0): Integer;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer;
function IndexOfName(AName: String): Integer; function IndexOfName(AName: String): Integer;
function FindByName(AName: String): TsChartGradient; function FindByName(AName: String): TsChartGradient;
property Items[AIndex: Integer]: TsChartGradient read GetItem write SetItem; default; property Items[AIndex: Integer]: TsChartGradient read GetItem write SetItem; default;
@ -970,8 +961,8 @@ constructor TsChartGradient.Create;
begin begin
inherited Create; inherited Create;
SetLength(FSteps, 2); SetLength(FSteps, 2);
SetStep(0, 0.0, ChartColor(scBlack), 1.0); SetStep(0, 0.0, ChartColor(scBlack));
SetStep(1, 1.0, ChartColor(scWhite), 1.0); SetStep(1, 1.0, ChartColor(scWhite));
end; end;
destructor TsChartGradient.Destroy; destructor TsChartGradient.Destroy;
@ -983,8 +974,7 @@ end;
{ Adds a new color step to the gradient. The new color is inserted at the { Adds a new color step to the gradient. The new color is inserted at the
correct index according to its value so that all values in the steps are correct index according to its value so that all values in the steps are
ordered. If the exact value is already existing the gradient step is replaced.} ordered. If the exact value is already existing the gradient step is replaced.}
procedure TsChartGradient.AddStep(AValue: Double; AColor: TsChartColor; procedure TsChartGradient.AddStep(AValue: Double; AColor: TsChartColor);
AIntensity: Single = 1.0);
var var
i, j, idx: Integer; i, j, idx: Integer;
begin begin
@ -1014,7 +1004,7 @@ begin
SetLength(FSteps, 1); SetLength(FSteps, 1);
idx := 0; idx := 0;
end; end;
SetStep(idx, AValue, AColor, AIntensity); SetStep(idx, AValue, AColor);
end; end;
procedure TsChartGradient.CopyFrom(ASource: TsChartGradient); procedure TsChartGradient.CopyFrom(ASource: TsChartGradient);
@ -1040,14 +1030,6 @@ begin
end; end;
end; end;
function TsChartGradient.GetIntensity(AIndex: Integer): Double;
begin
case AIndex of
0: Result := FSteps[0].Intensity;
1: Result := FSteps[High(FSteps)].Intensity;
end;
end;
function TsChartGradient.GetSteps(AIndex: Integer): TsChartGradientStep; function TsChartGradient.GetSteps(AIndex: Integer): TsChartGradientStep;
begin begin
if AIndex < 0 then AIndex := 0; if AIndex < 0 then AIndex := 0;
@ -1061,35 +1043,31 @@ begin
end; end;
procedure TsChartGradient.SetStep(AIndex: Integer; AValue: Double; procedure TsChartGradient.SetStep(AIndex: Integer; AValue: Double;
AColor: TsChartColor; AIntensity: Double); AColor: TsChartColor);
begin begin
FSteps[AIndex].Value := AValue; FSteps[AIndex].Value := AValue;
FSteps[AIndex].Color := AColor; FSteps[AIndex].Color := AColor;
FSteps[AIndex].Intensity := AIntensity;
end; end;
{ TsChartGradientList } { TsChartGradientList }
function TsChartGradientList.AddAxialGradient(AName: String; function TsChartGradientList.AddAxialGradient(AName: String;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; AAngle: Double; ABorder: Double = 0.0): Integer;
ABorder, AAngle: Double): Integer;
begin begin
Result := AddGradient(AName, cgsAxial, Result := AddGradient(AName, cgsAxial,
AStartColor, AEndColor, AStartColor, AEndColor,
AStartIntensity, AEndIntensity, 0.0, 0.0, AAngle, ABorder
ABorder, 0.0, 0.0, AAngle
); );
end; end;
function TsChartGradientList.AddEllipticGradient(AName: String; function TsChartGradientList.AddEllipticGradient(AName: String;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; ACenterX, ACenterY, AAngle: Double;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer; ABorder: Double = 0.0): Integer;
begin begin
Result := AddGradient(AName, cgsElliptic, Result := AddGradient(AName, cgsElliptic,
AStartColor, AEndColor, AStartColor, AEndColor,
AStartIntensity, AEndIntensity, ACenterX, ACenterY, AAngle, ABorder
ABorder, ACenterX, ACenterY, AAngle
); );
end; end;
@ -1105,8 +1083,8 @@ begin
end; end;
function TsChartGradientList.AddGradient(AName: String; AStyle: TsChartGradientStyle; function TsChartGradientList.AddGradient(AName: String; AStyle: TsChartGradientStyle;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; ACenterX, ACenterY, AAngle: Double;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer; ABorder: Double = 0.0): Integer;
var var
item: TsChartGradient; item: TsChartGradient;
begin begin
@ -1121,8 +1099,8 @@ begin
item := Items[Result]; item := Items[Result];
item.Name := AName; item.Name := AName;
item.Style := AStyle; item.Style := AStyle;
item.AddStep(0.0, AStartColor, AStartIntensity); item.AddStep(0.0, AStartColor);
item.AddStep(1.0, AEndColor, AEndIntensity); item.AddStep(1.0, AEndColor);
item.Border := ABorder; item.Border := ABorder;
item.Angle := AAngle; item.Angle := AAngle;
item.CenterX := ACenterX; item.CenterX := ACenterX;
@ -1130,45 +1108,42 @@ begin
end; end;
function TsChartGradientList.AddLinearGradient(AName: String; function TsChartGradientList.AddLinearGradient(AName: String;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; AAngle: Double; ABorder: Double = 0.0): Integer;
ABorder,AAngle: Double): Integer;
begin begin
Result := AddGradient(AName, cgsLinear, Result := AddGradient(AName, cgsLinear,
AStartColor, AEndColor, AStartIntensity, AEndIntensity, AStartColor, AEndColor, 0.0, 0.0, AAngle, ABorder
ABorder, 0.0, 0.0, AAngle
); );
end; end;
function TsChartGradientList.AddRadialGradient(AName: String; function TsChartGradientList.AddRadialGradient(AName: String;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; ACenterX, ACenterY: Double;
ABorder, ACenterX, ACenterY: Double): Integer; ABorder: Double = 0.0): Integer;
begin begin
Result := AddGradient(AName, cgsRadial, Result := AddGradient(AName, cgsRadial,
AStartColor, AEndColor, AStartColor, AEndColor,
AStartIntensity, AEndIntensity, ACenterX, ACenterY, 0, ABorder
ABorder, ACenterX, ACenterY, 0
); );
end; end;
function TsChartGradientList.AddRectangularGradient(AName: String; function TsChartGradientList.AddRectangularGradient(AName: String;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; ACenterX, ACenterY, AAngle: Double;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer; ABorder: Double = 0.0): Integer;
begin begin
Result := AddGradient(AName, cgsRectangular, Result := AddGradient(AName, cgsRectangular,
AStartColor, AEndColor, AStartColor, AEndColor,
AStartIntensity, AEndIntensity, ACenterX, ACenterY, AAngle,
ABorder, ACenterX, ACenterY, AAngle ABorder
); );
end; end;
function TsChartGradientList.AddSquareGradient(AName: String; function TsChartGradientList.AddSquareGradient(AName: String;
AStartColor, AEndColor: TsChartColor; AStartIntensity, AEndIntensity: Double; AStartColor, AEndColor: TsChartColor; ACenterX, ACenterY, AAngle: Double;
ABorder, ACenterX, ACenterY, AAngle: Double): Integer; ABorder: Double = 0.0): Integer;
begin begin
Result := AddGradient(AName, cgsSquare, Result := AddGradient(AName, cgsSquare,
AStartColor, AEndColor, AStartColor, AEndColor,
AStartIntensity, AEndIntensity, ACenterX, ACenterY, AAngle,
ABorder, ACenterX, ACenterY, AAngle ABorder
); );
end; end;
@ -2847,8 +2822,6 @@ begin
FHatches := TsChartHatchList.Create; FHatches := TsChartHatchList.Create;
FImages := TsChartImageList.Create; FImages := TsChartImageList.Create;
fgradients.AddLinearGradient('g1', ChartColor(scRed), ChartColor(scBlue), 1, 1, 0, 0);
FWorksheet := nil; FWorksheet := nil;
FRow := 0; FRow := 0;
FCol := 0; FCol := 0;

View File

@ -302,6 +302,10 @@ begin
end; end;
end; end;
function ModifyColor(AColor: TsChartColor; AIntensity: double): TsChartColor;
begin
Result.Color := LumModOff(AColor.Color, AIntensity, 0.0);
end;
{------------------------------------------------------------------------------} {------------------------------------------------------------------------------}
{ internal number formats } { internal number formats }
@ -2016,10 +2020,12 @@ begin
s := GetAttrValue(ANode, 'draw:start-intensity'); s := GetAttrValue(ANode, 'draw:start-intensity');
if not TryPercentStrToFloat(s, startIntensity) then if not TryPercentStrToFloat(s, startIntensity) then
startIntensity := 1.0; startIntensity := 1.0;
startIntensity := EnsureRange(startIntensity, 0.0, 1.0);
s := GetAttrValue(ANode, 'draw:end-intensity'); s := GetAttrValue(ANode, 'draw:end-intensity');
if not TryPercentStrToFloat(s, endIntensity) then if not TryPercentStrToFloat(s, endIntensity) then
endIntensity := 1.0; endIntensity := 1.0;
endIntensity := EnsureRange(endIntensity, 0.0, 1.0);
s := GetAttrValue(ANode, 'draw:border'); s := GetAttrValue(ANode, 'draw:border');
if not TryPercentStrToFloat(s, border) then if not TryPercentStrToFloat(s, border) then
@ -2032,7 +2038,7 @@ begin
angle := StrToFloatDef(s, 0.0, FPointSeparatorSettings); angle := StrToFloatDef(s, 0.0, FPointSeparatorSettings);
{ ods has angle=0 in vertical direction, and orientation is CW { ods has angle=0 in vertical direction, and orientation is CW
--> We must transform to fps angular orientations (0° horizontal, CCW) } --> We must transform to fps angular orientations (0° horizontal, CCW) }
angle := (90.0 - angle) mod 360; angle := (90.0 + angle) mod 360;
end; end;
s := GetAttrValue(ANode, 'draw:cx'); s := GetAttrValue(ANode, 'draw:cx');
@ -2043,8 +2049,9 @@ begin
if not TryPercentStrToFloat(s, centerY) then if not TryPercentStrToFloat(s, centerY) then
centerY := 0.0; centerY := 0.0;
AChart.Gradients.AddGradient(styleName, gradientStyle, i := AChart.Gradients.AddGradient(styleName, gradientStyle,
startColor, endColor, startIntensity, endIntensity, ModifyColor(startColor, startIntensity),
ModifyColor(endColor, endIntensity),
border, centerX, centerY, angle); border, centerX, centerY, angle);
end; end;
@ -3547,7 +3554,7 @@ begin
[ ASCIIName(gradient.Name), gradient.Name, [ ASCIIName(gradient.Name), gradient.Name,
GRADIENT_STYLES[gradient.Style], GRADIENT_STYLES[gradient.Style],
ColorToHTMLColorStr(gradient.StartColor.Color), ColorToHTMLColorStr(gradient.EndColor.Color), ColorToHTMLColorStr(gradient.StartColor.Color), ColorToHTMLColorStr(gradient.EndColor.Color),
gradient.StartIntensity * 100, gradient.EndIntensity * 100, 100.0, 100.0,
gradient.Border * 100 gradient.Border * 100
] ]
); );
@ -3555,7 +3562,7 @@ begin
cgsLinear, cgsAxial: cgsLinear, cgsAxial:
style := style + Format( style := style + Format(
'draw:angle="%.0fdeg" ', 'draw:angle="%.0fdeg" ',
[ (90 - gradient.Angle) mod 360 ], // transform to fps angle orientations [ (90 + gradient.Angle) mod 360 ], // transform to fps angle orientations
FPointSeparatorSettings FPointSeparatorSettings
); );
cgsElliptic, cgsSquare, cgsRectangular: cgsElliptic, cgsSquare, cgsRectangular:

View File

@ -231,6 +231,12 @@ begin
Result := nil; Result := nil;
end; end;
function PositiveAngle(Angle: Double): Double;
begin
Result := Angle;
while Result < 0 do
Result := Result + 360.0;
end;
type type
TsOpenedCustomLineSeries = class(TsCustomLineSeries) TsOpenedCustomLineSeries = class(TsCustomLineSeries)
@ -751,7 +757,7 @@ begin
value := StrToFloatDef(s, 0.0, FPointSeparatorSettings) / FACTOR_MULTIPLIER; value := StrToFloatDef(s, 0.0, FPointSeparatorSettings) / FACTOR_MULTIPLIER;
color := ChartColor(scWhite); color := ChartColor(scWhite);
ReadChartColor(child.FirstChild, color); ReadChartColor(child.FirstChild, color);
gradient.AddStep(value, color, 1.0); gradient.AddStep(value, color);
end; end;
child := child.NextSibling; child := child.NextSibling;
end; end;
@ -761,7 +767,7 @@ begin
gradient.Style := cgsLinear; gradient.Style := cgsLinear;
s := GetAttrValue(ANode, 'ang'); s := GetAttrValue(ANode, 'ang');
if TryStrToFloat(s, value, FPointSeparatorSettings) then if TryStrToFloat(s, value, FPointSeparatorSettings) then
gradient.Angle := value / ANGLE_MULTIPLIER; gradient.Angle := -value / ANGLE_MULTIPLIER; // xlsx CW, fps CCW
end; end;
'a:path': 'a:path':
begin begin
@ -3542,7 +3548,7 @@ begin
case gradient.Style of case gradient.Style of
cgsLinear: cgsLinear:
gStyle := indent + Format(' <a:lin ang="%.0f" scaled="1"/>', gStyle := indent + Format(' <a:lin ang="%.0f" scaled="1"/>',
[ gradient.Angle * ANGLE_MULTIPLIER ] [ PositiveAngle(-gradient.Angle) * ANGLE_MULTIPLIER ] // xlsx gradient direction is CW, fps CCW
); );
cgsAxial, cgsAxial,
cgsRadial, cgsRadial,