TAChart: Override TBarSeries.GetNearestPoint to accept clicks inside the bar, new property ToolTarget (http://forum.lazarus.freepascal.org/index.php/topic,35342.0.html)

git-svn-id: trunk@53896 -
This commit is contained in:
wp 2017-01-07 23:06:09 +00:00
parent 8aaec43f37
commit 363f930d54
3 changed files with 87 additions and 2 deletions

View File

@ -34,7 +34,8 @@ type
TNearestPointResults = record
FDist: Integer;
FImg: TPoint;
FIndex: Integer;
FIndex: Integer; // Point index
FYIndex: Integer; // Index to be used in Source.GetY()
FValue: TDoublePoint;
end;
@ -1239,6 +1240,7 @@ begin
if dist >= AResults.FDist then continue;
AResults.FDist := dist;
AResults.FIndex := i;
AResults.FYIndex := 0; // to do: find yindex of stacked series
AResults.FImg := pt;
AResults.FValue := sp;
end;

View File

@ -34,8 +34,11 @@ type
TBarWidthStyle = (bwPercent, bwPercentMin);
TBarSeries = class;
TBarToolTarget = (bttDatapoint, bttBar);
TBeforeDrawBarEvent = procedure (
ASender: TBarSeries; ACanvas: TCanvas; const ARect: TRect;
APointIndex, AStackIndex: Integer; var ADoDefaultDrawing: Boolean
@ -50,6 +53,7 @@ type
FBarPen: TPen;
FBarWidthPercent: Integer;
FBarWidthStyle: TBarWidthStyle;
FToolTarget: TBarToolTarget;
FOnBeforeDrawBar: TBeforeDrawBarEvent;
FZeroLevel: Double;
@ -78,6 +82,8 @@ type
function GetBarWidth(AIndex: Integer): Integer;
procedure Draw(ADrawer: IChartDrawer); override;
function Extent: TDoubleRect; override;
function GetNearestPoint(const AParams: TNearestPointParams;
out AResults: TNearestPointResults): Boolean; override;
published
property AxisIndexX;
property AxisIndexY;
@ -95,6 +101,8 @@ type
read GetSeriesColor write SetSeriesColor stored false default clRed;
property Source;
property Styles;
property ToolTarget: TBarToolTarget
read FToolTarget write FToolTarget default bttDataPoint;
property UseReticule;
property ZeroLevel: Double
read FZeroLevel write SetZeroLevel stored IsZeroLevelStored;
@ -1122,6 +1130,73 @@ begin
GetLegendItemsRect(AItems, BarBrush);
end;
function TBarSeries.GetNearestPoint(const AParams: TNearestPointParams;
out AResults: TNearestPointResults): Boolean;
var
pointIndex: Integer;
graphClickPt: TDoublePoint;
sp, p: TDoublePoint;
ofs, w: Double;
heights: TDoubleDynArray;
y, z: Double;
stackindex: Integer;
begin
if FToolTarget = bttDatapoint then
begin
Result := inherited;
exit;
end;
Result := false;
AResults.FDist := Sqr(AParams.FRadius) + 1;
AResults.FIndex := -1;
if IsRotated then
z := AxisToGraphX(ZeroLevel)
else
z := AxisToGraphY(ZeroLevel);
SetLength(heights, Source.YCount + 1);
// clicked point in image coordinates
graphClickPt := ParentChart.ImageToGraph(AParams.FPoint);
if IsRotated then
Exchange(graphclickpt.X, graphclickpt.Y);
// Iterate through all points of the series
for pointIndex := 0 to Count - 1 do begin
sp := Source[pointindex]^.Point;
if IsNan(sp) then
continue;
BarOffsetWidth(sp.X, pointindex, ofs, w);
sp.X := sp.X + ofs;
if not InRange(graphClickPt.X, sp.X - w, sp.X + w) then
continue;
heights[0] := z;
heights[1] := NumberOr(sp.Y, z);
for stackIndex := 1 to Source.YCount-1 do begin
y := NumberOr(Source[pointindex]^.YList[stackIndex - 1], 0);
heights[stackIndex + 1] := heights[stacKindex] + y;
end;
for stackindex := 0 to High(heights)-1 do
if ((heights[stackindex] < heights[stackindex + 1]) and
InRange(graphClickPt.Y, heights[stackindex], heights[stackIndex + 1]))
or
((heights[stackindex + 1] < heights[stackindex]) and
InRange(graphClickPt.Y, heights[stackindex + 1], heights[stackIndex]))
then begin
AResults.FDist := 0;
AResults.FIndex := pointindex;
AResults.FYIndex := stackIndex;
AResults.FValue := DoublePoint(Source[pointindex]^.X, Source[pointindex]^.GetY(stackIndex));
if IsRotated then
Exchange(AResults.FValue.X, AResults.FValue.Y);
AResults.FImg := ParentChart.GraphToImage(AResults.FValue);
Result := true;
exit;
end;
end;
end;
function TBarSeries.GetSeriesColor: TColor;
begin
Result := FBarBrush.Color;

View File

@ -411,6 +411,7 @@ type
strict protected
FNearestGraphPoint: TDoublePoint;
FPointIndex: Integer;
FYIndex: Integer;
FSeries: TBasicChartSeries;
procedure FindNearestPoint(APoint: TPoint);
property MouseInsideOnly: Boolean
@ -423,6 +424,7 @@ type
property NearestGraphPoint: TDoublePoint read FNearestGraphPoint;
property PointIndex: Integer read FPointIndex;
property Series: TBasicChartSeries read FSeries;
property YIndex: Integer read FYIndex;
published
property AffectedSeries: String
read GetAffectedSeries write SetAffectedSeries;
@ -497,6 +499,7 @@ type
FOnHintLocation: TChartToolHintLocationEvent;
FPrevPointIndex: Integer;
FPrevSeries: TBasicChartSeries;
FPrevYIndex: Integer;
FUseApplicationHint: Boolean;
FUseDefaultHintText: Boolean;
procedure HideHint;
@ -1603,6 +1606,7 @@ begin
FAffectedSeries.Init;
SetPropDefaults(Self, ['GrabRadius']);
FPointIndex := -1;
FYIndex := 0;
end;
procedure TDataPointTool.FindNearestPoint(APoint: TPoint);
@ -1664,6 +1668,7 @@ begin
if best.FDist = MaxInt then exit;
FSeries := bestS;
FPointIndex := best.FIndex;
FYIndex := best.FYIndex;
FNearestGraphPoint := FChart.ImageToGraph(best.FImg);
end;
@ -1836,12 +1841,15 @@ begin
HideHint;
exit;
end;
if (FPrevSeries = Series) and (FPrevPointIndex = PointIndex) then
if (FPrevSeries = Series) and (FPrevPointIndex = PointIndex) and
(FPrevYIndex = YIndex)
then
exit;
if FPrevSeries = nil then
SetCursor;
FPrevSeries := Series;
FPrevPointIndex := PointIndex;
FPrevYIndex := YIndex;
h := GetHintText;
APoint := FChart.ClientToScreen(APoint);
if Assigned(OnHintPosition) then