TAChart: New event OnSeriesClick for TLegendClickTool to report series of clicked legend item. Issue #39437.

This commit is contained in:
wp_xyz 2021-10-23 16:51:23 +02:00
parent 49a220e7c3
commit 6422aaa213
2 changed files with 98 additions and 10 deletions

View File

@ -173,6 +173,7 @@ type
strict private
FAlignment: TLegendAlignment;
FBackgroundBrush: TChartLegendBrush;
FColCount: Integer;
FColumnCount: TLegendColumnCount;
FFixedItemWidth: Cardinal;
FFixedItemHeight: Cardinal;
@ -184,9 +185,11 @@ type
FGroupTitles: TStrings;
FInverted: Boolean;
FItemFillOrder: TLegendItemFillOrder;
FItemSize: TPoint;
FLegendRect: TRect;
FMarginX: TChartDistance;
FMarginY: TChartDistance;
FRowCount: Integer;
FSpacing: TChartDistance;
FSymbolFrame: TChartPen;
FSymbolWidth: TChartDistance;
@ -227,6 +230,7 @@ type
procedure Assign(Source: TPersistent); override;
procedure Draw(var AData: TChartLegendDrawingData);
function IsPointInBounds(APoint: TPoint): Boolean;
function ItemClicked(ADrawer: IChartDrawer; APoint: TPoint; AItems: TChartLegendItems): Integer;
procedure Prepare(var AData: TChartLegendDrawingData; var AClipRect: TRect);
procedure SortItemsByOrder(AItems: TChartLegendItems);
procedure UpdateBidiMode;
@ -731,6 +735,62 @@ begin
end;
end;
function TChartLegend.IsPointInBounds(APoint: TPoint): Boolean;
begin
Result := IsPointInRect(APoint, FLegendRect);
end;
function TChartLegend.ItemClicked(ADrawer: IChartDrawer; APoint: TPoint;
AItems: TChartLegendItems): Integer;
var
i, x, y: Integer;
prevFont: TFont = nil;
r: TRect;
isRTL: Boolean;
space, symwid: Integer;
data: TChartLegendDrawingData;
begin
with data do begin
FDrawer := ADrawer;
FBounds := Self.FLegendRect;
FColCount := Self.FColCount;
FItems := AItems;
FItemSize := Self.FItemSize;
FRowCount := Self.FRowCount;
isRTL := FDrawer.GetRightToLeft;
space := FDrawer.Scale(Spacing);
symwid := FDrawer.Scale(SymbolWidth);
for i := 0 to FItems.Count - 1 do begin
FItems[i].UpdateFont(FDrawer, prevFont);
x := 0;
y := 0;
case ItemFillOrder of
lfoColRow: DivMod(i, FRowCount, x, y);
lfoRowCol: DivMod(i, FColCount, y, x);
end;
if isRTL then
r := Bounds(
FBounds.Right - space - (x+1) * (FItemSize.X + space),
FBounds.Top + space + y * (FItemSize.Y + space),
symwid + Space + FItemSize.X,
FItemSize.Y)
else
r := Bounds(
FBounds.Left + space + x * (FItemSize.X + space) - symwid,
FBounds.Top + space + y * (FItemSize.Y + space),
symwid + space + FItemSize.X ,
FItemSize.Y);
if PtInRect(r, APoint) then
begin
Result := i;
exit;
end;
OffsetRect(r, 0, FItemSize.Y + space);
end;
end;
Result := -1;
end;
function TChartLegend.MeasureItem(
ADrawer: IChartDrawer; AItems: TChartLegendItems): TPoint;
var
@ -756,11 +816,6 @@ begin
Result.Y := ADrawer.Scale(FixedItemHeight);
end;
function TChartLegend.IsPointInBounds(APoint: TPoint): Boolean;
begin
Result := IsPointInRect(APoint, FLegendRect);
end;
procedure TChartLegend.Prepare(
var AData: TChartLegendDrawingData; var AClipRect: TRect);
var
@ -775,6 +830,9 @@ begin
FColCount := Max(Min(ColumnCount, FItems.Count), 1);
FRowCount := (FItems.Count - 1) div FColCount + 1;
FItemSize := MeasureItem(FDrawer, FItems);
Self.FItemSize := FItemSize;
Self.FColCount := FColCount;
Self.FRowCount := FRowCount;
legendSize.X := (FItemSize.X + space) * FColCount + space;
legendSize.Y := (FItemSize.Y + space) * FRowCount + space;
end;

View File

@ -649,10 +649,13 @@ type
TLegendClickEvent = procedure (ASender: TChartTool;
ALegend: TChartLegend) of object;
TLegendSeriesClickEvent = procedure (ASender: TChartTool;
ALegend: TChartLegend; ASeries: TBasicChartSeries) of object;
TLegendClickTool = class(TChartTool)
private
FOnClick: TLegendClickEvent;
FOnSeriesClick: TLegendSeriesClickEvent;
FLegend: TChartLegend;
public
constructor Create(AOwner: TComponent); override;
@ -660,6 +663,7 @@ type
procedure MouseUp(APoint: TPoint); override;
published
property OnClick: TLegendClickEvent read FOnClick write FOnClick;
property OnSeriesClick: TLegendSeriesClickEvent read FOnSeriesClick write FOnSeriesClick;
end;
@ -2339,19 +2343,45 @@ end;
procedure TLegendClickTool.MouseDown(APoint: TPoint);
begin
if FChart.Legend.IsPointInBounds(APoint) then begin
if Assigned(FChart.Legend) and FChart.Legend.IsPointInBounds(APoint) then begin
Activate;
Handled;
end;
end;
procedure TLegendClickTool.MouseUp(APoint: TPoint);
var
li: TLegendItem;
idx: Integer;
ser: TBasicChartSeries;
items: TChartLegendItems;
begin
if IsActive and FChart.Legend.IsPointInBounds(APoint) then begin
FLegend := FChart.Legend;
if Assigned(FOnClick) and (FLegend <> nil) then FOnClick(Self, FLegend);
end else
if not (IsActive and Assigned(FChart.Legend)) then
begin
FLegend := nil;
exit;
end;
FLegend := FChart.Legend;
if Assigned(FOnClick) and FLegend.IsPointInBounds(APoint) then
FOnClick(Self, FLegend);
if Assigned(FOnSeriesClick) then
begin
try
items := FChart.GetLegendItems;
idx := FLegend.ItemClicked(FChart.Drawer, APoint, items);
if idx <> -1 then
begin
ser := TBasicChartSeries(items[idx].Owner);
if Assigned(ser) then
FOnSeriesClick(Self, FLegend, ser);
end;
finally
items.Free;
end;
end;
end;
{ -------- }