mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-23 00:09:27 +01:00
TAChart: Define bubble size in TBubbleseries as percentage - new.
This commit is contained in:
parent
dd3322cfc0
commit
120d66d06e
@ -41,9 +41,10 @@ type
|
|||||||
TBubbleOverrideColor = (bocBrush, bocPen);
|
TBubbleOverrideColor = (bocBrush, bocPen);
|
||||||
TBubbleOverrideColors = set of TBubbleOverrideColor;
|
TBubbleOverrideColors = set of TBubbleOverrideColor;
|
||||||
TBubbleRadiusUnits = (
|
TBubbleRadiusUnits = (
|
||||||
bruX, // Circle with radius given in x axis units
|
bruX, // Circle with radius given in x axis units
|
||||||
bruY, // Circle with radius given in y axis units
|
bruY, // Circle with radius given in y axis units
|
||||||
bruXY // Ellipse
|
bruXY, // Ellipse
|
||||||
|
bruPercentage // Percentage of the smallest dimension of plot area
|
||||||
);
|
);
|
||||||
|
|
||||||
{ TBubbleSeries }
|
{ TBubbleSeries }
|
||||||
@ -53,13 +54,17 @@ type
|
|||||||
FBubbleBrush: TBrush;
|
FBubbleBrush: TBrush;
|
||||||
FBubblePen: TPen;
|
FBubblePen: TPen;
|
||||||
FOverrideColor: TBubbleOverrideColors;
|
FOverrideColor: TBubbleOverrideColors;
|
||||||
|
FBubbleRadiusPercentage: Integer;
|
||||||
FBubbleRadiusUnits: TBubbleRadiusUnits;
|
FBubbleRadiusUnits: TBubbleRadiusUnits;
|
||||||
|
FBubbleScalingFactor: Double;
|
||||||
procedure SetBubbleBrush(AValue: TBrush);
|
procedure SetBubbleBrush(AValue: TBrush);
|
||||||
procedure SetBubblePen(AValue: TPen);
|
procedure SetBubblePen(AValue: TPen);
|
||||||
|
procedure SetBubbleRadiusPercentage(AValue: Integer);
|
||||||
procedure SetBubbleRadiusUnits(AValue: TBubbleRadiusUnits);
|
procedure SetBubbleRadiusUnits(AValue: TBubbleRadiusUnits);
|
||||||
procedure SetOverrideColor(AValue: TBubbleOverrideColors);
|
procedure SetOverrideColor(AValue: TBubbleOverrideColors);
|
||||||
protected
|
protected
|
||||||
function GetBubbleRect(AItem: PChartDataItem; out ARect: TRect): Boolean;
|
function CalcBubbleScalingFactor(const ARect: TRect): Double;
|
||||||
|
function GetBubbleRect(AItem: PChartDataItem; AFactor: Double; out ARect: TRect): Boolean;
|
||||||
function GetLabelDataPoint(AIndex, AYIndex: Integer): TDoublePoint; override;
|
function GetLabelDataPoint(AIndex, AYIndex: Integer): TDoublePoint; override;
|
||||||
procedure GetLegendItems(AItems: TChartLegendItems); override;
|
procedure GetLegendItems(AItems: TChartLegendItems); override;
|
||||||
function GetSeriesColor: TColor; override;
|
function GetSeriesColor: TColor; override;
|
||||||
@ -86,6 +91,8 @@ type
|
|||||||
property AxisIndexY;
|
property AxisIndexY;
|
||||||
property BubbleBrush: TBrush read FBubbleBrush write SetBubbleBrush;
|
property BubbleBrush: TBrush read FBubbleBrush write SetBubbleBrush;
|
||||||
property BubblePen: TPen read FBubblePen write SetBubblePen;
|
property BubblePen: TPen read FBubblePen write SetBubblePen;
|
||||||
|
property BubbleRadiusPercentage: Integer read FBubbleRadiusPercentage
|
||||||
|
write SetBubbleRadiusPercentage default 20;
|
||||||
property BubbleRadiusUnits: TBubbleRadiusUnits read FBubbleRadiusUnits
|
property BubbleRadiusUnits: TBubbleRadiusUnits read FBubbleRadiusUnits
|
||||||
write SetBubbleRadiusUnits default bruXY;
|
write SetBubbleRadiusUnits default bruXY;
|
||||||
property MarkPositions;
|
property MarkPositions;
|
||||||
@ -532,10 +539,25 @@ begin
|
|||||||
with TBubbleSeries(ASource) do begin
|
with TBubbleSeries(ASource) do begin
|
||||||
Self.BubbleBrush := FBubbleBrush;
|
Self.BubbleBrush := FBubbleBrush;
|
||||||
Self.BubblePen := FBubblePen;
|
Self.BubblePen := FBubblePen;
|
||||||
|
Self.BubbleRadiusUnits := FBubbleRadiusUnits;
|
||||||
|
Self.BubbleRadiusPercentage := FBubbleRadiusPercentage;
|
||||||
|
Self.OverrideColor := FOverrideColor;
|
||||||
end;
|
end;
|
||||||
inherited Assign(ASource);
|
inherited Assign(ASource);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TBubbleSeries.CalcBubbleScalingFactor(const ARect: TRect): Double;
|
||||||
|
var
|
||||||
|
rMin, rMax: Double;
|
||||||
|
begin
|
||||||
|
if FBubbleRadiusUnits = bruPercentage then
|
||||||
|
begin
|
||||||
|
Source.YRange(1, rMin, rMax);
|
||||||
|
Result := Min(ARect.Width, ARect.Height) * FBubbleRadiusPercentage * PERCENT / abs(rMax);
|
||||||
|
end else
|
||||||
|
Result := 1.0;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TBubbleSeries.Create(AOwner: TComponent);
|
constructor TBubbleSeries.Create(AOwner: TComponent);
|
||||||
begin
|
begin
|
||||||
inherited Create(AOwner);
|
inherited Create(AOwner);
|
||||||
@ -544,7 +566,9 @@ begin
|
|||||||
FBubblePen.OnChange := @StyleChanged;
|
FBubblePen.OnChange := @StyleChanged;
|
||||||
FBubbleBrush := TBrush.Create;
|
FBubbleBrush := TBrush.Create;
|
||||||
FBubbleBrush.OnChange := @StyleChanged;
|
FBubbleBrush.OnChange := @StyleChanged;
|
||||||
|
FBubbleRadiusPercentage := 20;
|
||||||
FBubbleRadiusUnits := bruXY;
|
FBubbleRadiusUnits := bruXY;
|
||||||
|
FBubbleScalingFactor := 1.0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TBubbleSeries.Destroy;
|
destructor TBubbleSeries.Destroy;
|
||||||
@ -584,9 +608,11 @@ begin
|
|||||||
NormalizeRect(clipR);
|
NormalizeRect(clipR);
|
||||||
ADrawer.ClippingStart(clipR);
|
ADrawer.ClippingStart(clipR);
|
||||||
|
|
||||||
|
FBubbleScalingFactor := CalcBubbleScalingFactor(clipR);
|
||||||
|
|
||||||
for i := 0 to Count - 1 do begin
|
for i := 0 to Count - 1 do begin
|
||||||
item := Source[i];
|
item := Source[i];
|
||||||
if not GetBubbleRect(item, irect) then
|
if not GetBubbleRect(item, FBubbleScalingFactor, irect) then
|
||||||
continue;
|
continue;
|
||||||
if not IntersectRect(dummyR, clipR, irect) then
|
if not IntersectRect(dummyR, clipR, irect) then
|
||||||
continue;
|
continue;
|
||||||
@ -594,19 +620,24 @@ begin
|
|||||||
ADrawer.SetPenParams(BubblePen.Style, ColorDef(item^.Color, BubblePen.Color));
|
ADrawer.SetPenParams(BubblePen.Style, ColorDef(item^.Color, BubblePen.Color));
|
||||||
if bocBrush in OverrideColor then
|
if bocBrush in OverrideColor then
|
||||||
ADrawer.SetBrushColor(ColorDef(item^.Color, BubbleBrush.Color));
|
ADrawer.SetBrushColor(ColorDef(item^.Color, BubbleBrush.Color));
|
||||||
|
|
||||||
ADrawer.Ellipse(irect.Left, irect.Top, irect.Right, irect.Bottom);
|
ADrawer.Ellipse(irect.Left, irect.Top, irect.Right, irect.Bottom);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
GetXYCountNeeded(nx, ny);
|
GetXYCountNeeded(nx, ny);
|
||||||
if Source.YCount > ny then
|
if Source.YCount >= ny then
|
||||||
for i := 0 to ny - 1 do DrawLabels(ADrawer, i)
|
for i := 0 to ny - 1 do DrawLabels(ADrawer, i)
|
||||||
else
|
else
|
||||||
DrawLabels(ADrawer);
|
DrawLabels(ADrawer);
|
||||||
|
|
||||||
ADrawer.ClippingStop;
|
ADrawer.ClippingStop;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Calculates the extent of the series such that bubbles are not clipped.
|
||||||
|
But note that this method is correct only for BubbleRadiusUnits bruXY, it
|
||||||
|
would crash for bruX and bruY. Adjust Chart.Margins or Chart.ExpandPercentage
|
||||||
|
in these cases. }
|
||||||
function TBubbleSeries.Extent: TDoubleRect;
|
function TBubbleSeries.Extent: TDoubleRect;
|
||||||
// to do: this method is correct only for BubbleRadiusMode bruXY.
|
|
||||||
// The radius calculation in case of bruX or bruY causes a crash.,,
|
|
||||||
var
|
var
|
||||||
i: Integer;
|
i: Integer;
|
||||||
r: Double;
|
r: Double;
|
||||||
@ -617,27 +648,32 @@ begin
|
|||||||
if IsEmpty then exit;
|
if IsEmpty then exit;
|
||||||
if not RequestValidChartScaling then exit;
|
if not RequestValidChartScaling then exit;
|
||||||
|
|
||||||
for i := 0 to Count - 1 do begin
|
if FBubbleRadiusUnits = bruXY then
|
||||||
item := Source[i];
|
begin
|
||||||
sp := item^.Point;
|
for i := 0 to Count - 1 do begin
|
||||||
if TAChartUtils.IsNaN(sp) then
|
item := Source[i];
|
||||||
continue;
|
sp := item^.Point;
|
||||||
r := item^.YList[0];
|
if TAChartUtils.IsNaN(sp) then
|
||||||
if Math.IsNaN(r) then
|
continue;
|
||||||
continue;
|
r := item^.YList[0];
|
||||||
rp := DoublePoint(r, r);
|
if Math.IsNaN(r) then
|
||||||
gp := AxisToGraph(sp);
|
continue;
|
||||||
gq := AxisToGraph(sp + rp);
|
rp := DoublePoint(r, r);
|
||||||
rp := gq - gp;
|
gp := AxisToGraph(sp);
|
||||||
|
gq := AxisToGraph(sp + rp);
|
||||||
|
rp := gq - gp;
|
||||||
|
|
||||||
Result.a.X := Min(Result.a.X, sp.x - rp.x);
|
Result.a.X := Min(Result.a.X, sp.x - rp.x);
|
||||||
Result.b.X := Max(Result.b.X, sp.x + rp.x);
|
Result.b.X := Max(Result.b.X, sp.x + rp.x);
|
||||||
Result.a.Y := Min(Result.a.Y, sp.y - rp.y);
|
Result.a.Y := Min(Result.a.Y, sp.y - rp.y);
|
||||||
Result.b.Y := Max(Result.b.Y, sp.y + rp.y);
|
Result.b.Y := Max(Result.b.Y, sp.y + rp.y);
|
||||||
end;
|
end;
|
||||||
|
end else
|
||||||
|
Result := Source.BasicExtent;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TBubbleSeries.GetBubbleRect(AItem: PChartDataItem; out ARect: TRect): Boolean;
|
function TBubbleSeries.GetBubbleRect(AItem: PChartDataItem;
|
||||||
|
AFactor: Double; out ARect: TRect): Boolean;
|
||||||
var
|
var
|
||||||
sp: TDoublePoint; // source point in axis units
|
sp: TDoublePoint; // source point in axis units
|
||||||
p: TPoint; // bubble center in image units
|
p: TPoint; // bubble center in image units
|
||||||
@ -673,6 +709,12 @@ begin
|
|||||||
ARect.TopLeft := ParentChart.GraphToImage(AxisToGraph(DoublePoint(sp.x - r, sp.y - r)));
|
ARect.TopLeft := ParentChart.GraphToImage(AxisToGraph(DoublePoint(sp.x - r, sp.y - r)));
|
||||||
ARect.BottomRight := ParentChart.GraphToImage(AxisToGraph(DoublePoint(sp.x + r, sp.y + r)));
|
ARect.BottomRight := ParentChart.GraphToImage(AxisToGraph(DoublePoint(sp.x + r, sp.y + r)));
|
||||||
end;
|
end;
|
||||||
|
bruPercentage:
|
||||||
|
begin
|
||||||
|
p := ParentChart.GraphToImage(AxisToGraph(sp));
|
||||||
|
ri := round(r * AFactor);
|
||||||
|
ARect := Rect(p.x - ri, p.y - ri, p.x + ri, p.y + ri);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
NormalizeRect(ARect);
|
NormalizeRect(ARect);
|
||||||
Result := true;
|
Result := true;
|
||||||
@ -691,7 +733,7 @@ var
|
|||||||
isneg: Boolean;
|
isneg: Boolean;
|
||||||
dir: TLabelDirection;
|
dir: TLabelDirection;
|
||||||
begin
|
begin
|
||||||
if (AYIndex = 1) and GetBubbleRect(Source.Item[AIndex + FLoBound], R) then begin
|
if (AYIndex = 1) and GetBubbleRect(Source.Item[AIndex + FLoBound], FBubbleScalingFactor, R) then begin
|
||||||
isNeg := IS_NEGATIVE[MarkPositions];
|
isNeg := IS_NEGATIVE[MarkPositions];
|
||||||
if Assigned(GetAxisY) then
|
if Assigned(GetAxisY) then
|
||||||
if (IsRotated and ParentChart.IsRightToLeft) xor GetAxisY.Inverted then
|
if (IsRotated and ParentChart.IsRightToLeft) xor GetAxisY.Inverted then
|
||||||
@ -732,7 +774,7 @@ begin
|
|||||||
if Result and (nptYList in AParams.FTargets) and (nptYList in ToolTargets) then
|
if Result and (nptYList in AParams.FTargets) and (nptYList in ToolTargets) then
|
||||||
if (AResults.FYIndex = 1) then begin
|
if (AResults.FYIndex = 1) then begin
|
||||||
item := Source[AResults.FIndex];
|
item := Source[AResults.FIndex];
|
||||||
GetBubbleRect(item, iRect);
|
GetBubbleRect(item, FBubbleScalingFactor, iRect);
|
||||||
rx := (iRect.Right - iRect.Left) div 2;
|
rx := (iRect.Right - iRect.Left) div 2;
|
||||||
ry := (iRect.Bottom - iRect.Top) div 2;
|
ry := (iRect.Bottom - iRect.Top) div 2;
|
||||||
p := ParentChart.GraphToImage(AxisToGraph(item^.Point));
|
p := ParentChart.GraphToImage(AxisToGraph(item^.Point));
|
||||||
@ -746,7 +788,7 @@ begin
|
|||||||
dist := MaxInt;
|
dist := MaxInt;
|
||||||
for i := 0 to Count - 1 do begin
|
for i := 0 to Count - 1 do begin
|
||||||
item := Source[i];
|
item := Source[i];
|
||||||
if not GetBubbleRect(item, irect) then
|
if not GetBubbleRect(item, FBubbleScalingFactor, irect) then
|
||||||
continue;
|
continue;
|
||||||
rx := (iRect.Right - iRect.Left) div 2;
|
rx := (iRect.Right - iRect.Left) div 2;
|
||||||
ry := (iRect.Bottom - iRect.Top) div 2;
|
ry := (iRect.Bottom - iRect.Top) div 2;
|
||||||
@ -862,6 +904,13 @@ begin
|
|||||||
UpdateParentChart;
|
UpdateParentChart;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TBubbleSeries.SetBubbleRadiusPercentage(AValue: Integer);
|
||||||
|
begin
|
||||||
|
if FBubbleRadiusPercentage = AValue then exit;
|
||||||
|
FBubbleRadiusPercentage := AValue;
|
||||||
|
UpdateParentChart;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TBubbleSeries.SetBubbleRadiusUnits(AValue: TBubbleRadiusUnits);
|
procedure TBubbleSeries.SetBubbleRadiusUnits(AValue: TBubbleRadiusUnits);
|
||||||
begin
|
begin
|
||||||
if FBubbleRadiusUnits = AValue then exit;
|
if FBubbleRadiusUnits = AValue then exit;
|
||||||
@ -892,7 +941,7 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
item := Source[APointIdx];
|
item := Source[APointIdx];
|
||||||
GetBubbleRect(item, iRect);
|
GetBubbleRect(item, FBubbleScalingFactor, iRect);
|
||||||
rx := (iRect.Right - iRect.Left) div 2;
|
rx := (iRect.Right - iRect.Left) div 2;
|
||||||
ry := (iRect.Bottom - iRect.Top) div 2;
|
ry := (iRect.Bottom - iRect.Top) div 2;
|
||||||
p := ParentChart.GraphToImage(AxisToGraph(item^.Point));
|
p := ParentChart.GraphToImage(AxisToGraph(item^.Point));
|
||||||
@ -940,6 +989,7 @@ begin
|
|||||||
center := AxisToGraphY((a.y + b.y) * 0.5);
|
center := AxisToGraphY((a.y + b.y) * 0.5);
|
||||||
UpdateLabelDirectionReferenceLevel(0, 0, center);
|
UpdateLabelDirectionReferenceLevel(0, 0, center);
|
||||||
scMarksDistance := ADrawer.Scale(Marks.Distance);
|
scMarksDistance := ADrawer.Scale(Marks.Distance);
|
||||||
|
|
||||||
for i := FLoBound to FUpBound do begin
|
for i := FLoBound to FUpBound do begin
|
||||||
for j := 0 to Min(1, Source.YCount-1) do begin
|
for j := 0 to Min(1, Source.YCount-1) do begin
|
||||||
gp := GetLabelDataPoint(i, j);
|
gp := GetLabelDataPoint(i, j);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user