mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-06 00:20:13 +02:00
TAChart: Fix axis click tool sometimes detecting wrong axis part.
This commit is contained in:
parent
f3d26660e7
commit
9e3e23a440
@ -83,10 +83,15 @@ type
|
|||||||
|
|
||||||
{ TChartAxis }
|
{ TChartAxis }
|
||||||
|
|
||||||
|
type
|
||||||
TChartAxisHitTest = (ahtTitle, ahtLine, ahtLabels, ahtGrid,
|
TChartAxisHitTest = (ahtTitle, ahtLine, ahtLabels, ahtGrid,
|
||||||
ahtAxisStart, ahtAxisCenter, ahtAxisEnd);
|
ahtAxisStart, ahtAxisCenter, ahtAxisEnd);
|
||||||
TChartAxisHitTests = set of TChartAxisHitTest;
|
TChartAxisHitTests = set of TChartAxisHitTest;
|
||||||
|
|
||||||
|
const
|
||||||
|
ALL_CHARTAXIS_HITTESTS = [ahtTitle, ahtLine, ahtLabels, ahtGrid, ahtAxisStart, ahtAxisCenter, ahtAxisEnd];
|
||||||
|
|
||||||
|
type
|
||||||
TChartAxis = class(TChartBasicAxis)
|
TChartAxis = class(TChartBasicAxis)
|
||||||
strict private
|
strict private
|
||||||
FListener: TListener;
|
FListener: TListener;
|
||||||
@ -157,7 +162,9 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
public
|
public
|
||||||
procedure Assign(ASource: TPersistent); override;
|
procedure Assign(ASource: TPersistent); override;
|
||||||
function GetHitTestInfoAt(APoint: TPoint; ADelta: Integer): TChartAxisHitTests; virtual;
|
function GetHitTestInfoAt(APoint: TPoint; ADelta: Integer;
|
||||||
|
ATest: TChartAxisHitTests = ALL_CHARTAXIS_HITTESTS): TChartAxisHitTests; virtual;
|
||||||
|
function GetLabeledAxisRect: TRect;
|
||||||
procedure Draw;
|
procedure Draw;
|
||||||
procedure DrawTitle(ASize: Integer);
|
procedure DrawTitle(ASize: Integer);
|
||||||
function GetChart: TCustomChart; inline;
|
function GetChart: TCustomChart; inline;
|
||||||
@ -495,91 +502,133 @@ begin
|
|||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TChartAxis.GetHitTestInfoAt(APoint: TPoint;
|
function TChartAxis.GetHitTestInfoAt(APoint: TPoint; ADelta: Integer;
|
||||||
ADelta: Integer): TChartAxisHitTests;
|
ATest: TChartAxisHitTests = ALL_CHARTAXIS_HITTESTS): TChartAxisHitTests;
|
||||||
var
|
var
|
||||||
R: TRect;
|
R, Rax, Rline: TRect;
|
||||||
w, h, loc: Integer;
|
dist, loc: Integer;
|
||||||
p: Integer;
|
p: Integer;
|
||||||
t: TChartValueText;
|
t: TChartValueText;
|
||||||
begin
|
begin
|
||||||
Result := [];
|
Result := [];
|
||||||
if IsPointInPolygon(APoint, FTitlePolygon) then
|
|
||||||
Include(Result, ahtTitle)
|
if (ahtTitle in ATest) and IsPointInPolygon(APoint, FTitlePolygon) then
|
||||||
else begin
|
begin
|
||||||
R := FAxisRect;
|
Include(Result, ahtTitle);
|
||||||
case FAlignment of
|
exit;
|
||||||
calLeft:
|
end;
|
||||||
begin
|
|
||||||
R.Right := R.Left + Max(ADelta, TickInnerLength);
|
Rax := GetLabeledAxisRect;
|
||||||
R.Left := R.Left - Max(ADelta, TickLength);
|
Rline := Rax;
|
||||||
end;
|
case FAlignment of
|
||||||
calRight:
|
calLeft:
|
||||||
begin
|
begin
|
||||||
R.Left := R.Right - Max(ADelta, TickInnerLength);
|
Rline.Right := Rline.Left + Max(ADelta, TickInnerLength);
|
||||||
R.Right := R.Right + Max(ADelta, TickLength);
|
Rline.Left := Rline.Left - Max(ADelta, TickLength);
|
||||||
end;
|
if not InRange(APoint.Y, Rax.Top, Rax.Bottom) then
|
||||||
calTop:
|
exit;
|
||||||
begin
|
end;
|
||||||
R.Bottom := R.Top + Max(ADelta, TickInnerLength);
|
calRight:
|
||||||
R.Top := R.Top - Max(ADelta, TickLength);
|
begin
|
||||||
end;
|
Rline.Left := Rline.Right - Max(ADelta, TickInnerLength);
|
||||||
calBottom:
|
Rline.Right := Rline.Right + Max(ADelta, TickLength);
|
||||||
begin
|
if not InRange(APoint.Y, Rax.Top, Rax.Bottom) then
|
||||||
R.Top := R.Bottom - Max(ADelta, TickInnerLength);
|
exit;
|
||||||
R.Bottom := R.Bottom + Max(ADelta, TickLength);
|
end;
|
||||||
end;
|
calTop:
|
||||||
end;
|
begin
|
||||||
if IsPointInRect(APoint, R) then
|
Rline.Bottom := Rline.Top + Max(ADelta, TickInnerLength);
|
||||||
Include(Result, ahtLine)
|
Rline.Top := Rline.Top - Max(ADelta, TickLength);
|
||||||
else if IsPointInside(APoint) then
|
if not InRange(APoint.X, Rax.Left, RAx.Right) then
|
||||||
Include(Result, ahtLabels)
|
exit;
|
||||||
else begin
|
end;
|
||||||
R := FHelper.FClipRect^;
|
calBottom:
|
||||||
for t in FMarkValues do begin
|
begin
|
||||||
|
Rline.Top := Rline.Bottom - Max(ADelta, TickInnerLength);
|
||||||
|
Rline.Bottom := Rline.Bottom + Max(ADelta, TickLength);
|
||||||
|
if not InRange(APoint.X, Rax.Left, RAx.Right) then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (ahtLine in ATest) and IsPointInRect(APoint, Rline) then
|
||||||
|
Include(Result, ahtLine)
|
||||||
|
else
|
||||||
|
if (ahtLabels in ATest) and IsPointInside(APoint) then
|
||||||
|
Include(Result, ahtLabels)
|
||||||
|
else
|
||||||
|
if (ahtGrid in ATest) then
|
||||||
|
begin
|
||||||
|
R := Rax;
|
||||||
|
if IsPointInRect(APoint, R) and Grid.Visible then
|
||||||
|
for t in FMarkValues do
|
||||||
|
begin
|
||||||
p := FHelper.GraphToImage(FHelper.FAxisTransf(t.FValue));
|
p := FHelper.GraphToImage(FHelper.FAxisTransf(t.FValue));
|
||||||
if IsVertical then begin
|
if IsVertical then
|
||||||
|
begin
|
||||||
R.Top := p - ADelta;
|
R.Top := p - ADelta;
|
||||||
R.Bottom := p + ADelta;
|
R.Bottom := p + ADelta;
|
||||||
end else begin
|
end else
|
||||||
|
begin
|
||||||
R.Left := p - ADelta;
|
R.Left := p - ADelta;
|
||||||
R.Right := p + ADelta;
|
R.Right := p + aDelta;
|
||||||
end;
|
end;
|
||||||
if IsPointInRect(APoint, R) then begin
|
if IsPointInRect(APoint, R) then
|
||||||
|
begin
|
||||||
Include(Result, ahtGrid);
|
Include(Result, ahtGrid);
|
||||||
break;
|
exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if Result = [] then
|
if Result = [] then
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
R := FHelper.FClipRect^;
|
if [ahtAxisStart, ahtAxisCenter, ahtAxisEnd] * ATest <> [] then
|
||||||
|
begin
|
||||||
|
R := Rax;
|
||||||
if IsVertical then begin
|
if IsVertical then begin
|
||||||
h := R.Bottom - R.Top;
|
dist := abs(R.Bottom - R.Top) div 4;
|
||||||
p := APoint.Y - R.Top;
|
p := abs(APoint.Y - R.Top);
|
||||||
if p < h div 4 then
|
if p < dist then
|
||||||
loc := +1
|
loc := +1
|
||||||
else if p > h - h div 4 then
|
else if p > 3 * dist then
|
||||||
loc := -1
|
loc := -1
|
||||||
else
|
else
|
||||||
loc := 0;
|
loc := 0;
|
||||||
end else begin
|
end else begin
|
||||||
w := abs(R.Right - R.Left);
|
dist := abs(R.Right - R.Left) div 4;
|
||||||
p := abs(APoint.X - R.Left);
|
p := abs(APoint.X - R.Left);
|
||||||
if p < w div 4 then
|
if p < dist then
|
||||||
loc := -1
|
loc := -1
|
||||||
else if p > w - w div 4 then
|
else if p > 3 * dist then
|
||||||
loc := +1
|
loc := +1
|
||||||
else
|
else
|
||||||
loc := 0;
|
loc := 0;
|
||||||
end;
|
end;
|
||||||
if IsFlipped then loc := -loc;
|
if IsFlipped then
|
||||||
|
loc := -loc;
|
||||||
case loc of
|
case loc of
|
||||||
-1: Include(Result, ahtAxisStart);
|
-1: if (ahtAxisStart in ATest) then Include(Result, ahtAxisStart);
|
||||||
0: Include(Result, ahtAxisCenter);
|
0: if (ahtAxisCenter in ATest) then Include(Result, ahtAxisCenter);
|
||||||
+1: Include(Result, ahtAxisEnd);
|
+1: if (ahtAxisEnd in ATest) then Include(Result, ahtAxisEnd);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TChartAxis.GetLabeledAxisRect: TRect;
|
||||||
|
begin
|
||||||
|
Result := FHelper.FClipRect^; //FAxisRect;
|
||||||
|
if FAtDataOnly then
|
||||||
|
begin
|
||||||
|
if IsVertical then
|
||||||
|
begin
|
||||||
|
Result.Bottom := FHelper.GraphToImage(FHelper.MinForMarks);
|
||||||
|
Result.Top := FHelper.GraphToImage(FHelper.MaxForMarks);
|
||||||
|
end else
|
||||||
|
begin
|
||||||
|
Result.Left := FHelper.GraphToImage(FHelper.MinForMarks);
|
||||||
|
Result.Right := FHelper.GraphToImage(FHelper.MaxForMarks);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
@ -253,6 +253,8 @@ type
|
|||||||
procedure GetClipRange(out AMin, AMax: Integer); virtual; abstract;
|
procedure GetClipRange(out AMin, AMax: Integer); virtual; abstract;
|
||||||
function GetDefaultPenColor: TColor;
|
function GetDefaultPenColor: TColor;
|
||||||
function GraphToImage(AGraph: Double): Integer; virtual; abstract;
|
function GraphToImage(AGraph: Double): Integer; virtual; abstract;
|
||||||
|
property MaxForMarks: Double read FMaxForMarks;
|
||||||
|
property MinForMarks: Double read FMinForMarks;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TAxisDrawHelperClass = class of TAxisDrawHelper;
|
TAxisDrawHelperClass = class of TAxisDrawHelper;
|
||||||
|
@ -2337,14 +2337,30 @@ function TAxisClickTool.GetHitTestInfo(APoint: TPoint): Boolean;
|
|||||||
var
|
var
|
||||||
ax: TChartAxis;
|
ax: TChartAxis;
|
||||||
begin
|
begin
|
||||||
|
{ We must test the axes twice because some positions may be misinterpreted
|
||||||
|
to belong to other axes. A click on the axis line of an additional left axis
|
||||||
|
may be interpreted as a click on the bottom axis since the bottom axis usually
|
||||||
|
tested before the 2nd y axis. }
|
||||||
|
for ax in FChart.AxisList do
|
||||||
|
begin
|
||||||
|
FHitTest := ax.GetHitTestInfoAt(APoint, FGrabRadius, [ahtLine, ahtAxisStart, ahtAxisCenter, ahtAxisEnd]);
|
||||||
|
if FHitTest <> [] then
|
||||||
|
begin
|
||||||
|
FAxis := ax;
|
||||||
|
Result := true;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
for ax in FChart.AxisList do begin
|
for ax in FChart.AxisList do begin
|
||||||
FHitTest := ax.GetHitTestInfoAt(APoint, FGrabRadius);
|
FHitTest := ax.GetHitTestInfoAt(APoint, FGrabRadius, ALL_CHARTAXIS_HITTESTS - [ahtLine]);
|
||||||
if FHitTest <> [] then begin
|
if FHitTest <> [] then begin
|
||||||
FAxis := ax;
|
FAxis := ax;
|
||||||
Result := true;
|
Result := true;
|
||||||
exit;
|
exit;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Result := false;
|
Result := false;
|
||||||
FAxis := nil;
|
FAxis := nil;
|
||||||
FHitTest := [];
|
FHitTest := [];
|
||||||
|
Loading…
Reference in New Issue
Block a user