TAChart: Avoid crash of chart if an axis is destroyed. Add chart properties HorAxis and VertAxis.

git-svn-id: trunk@60162 -
This commit is contained in:
wp 2019-01-23 23:19:00 +00:00
parent ceb99f5f2e
commit 59e51e3587
3 changed files with 43 additions and 19 deletions

View File

@ -244,7 +244,7 @@ type
{ TAxisCoeffHelper }
TAxisCoeffHelper = object
FAxis: TChartAxis;
FAxisIsFlipped: Boolean;
FImageLo, FImageHi: Integer;
FLo, FHi: Integer;
FMin, FMax: PDouble;
@ -252,7 +252,7 @@ type
function CalcScale(ASign: Integer): Double;
constructor Init(AAxis: TChartAxis; AImageLo, AImageHi: Integer;
AMarginLo, AMarginHi, ARequiredMarginLo, ARequiredMarginHi, AMinDataSpace: Integer;
HasMarksInMargin: Boolean; AMin, AMax: PDouble);
AHasMarksInMargin, AAxisIsVertical: Boolean; AMin, AMax: PDouble);
procedure UpdateMinMax(AConv: TAxisConvFunc);
end;
@ -1246,11 +1246,9 @@ end;
constructor TAxisCoeffHelper.Init(AAxis: TChartAxis; AImageLo, AImageHi: Integer;
AMarginLo, AMarginHi, ARequiredMarginLo, ARequiredMarginHi, AMinDataSpace: Integer;
HasMarksInMargin: Boolean; AMin, AMax: PDouble);
AHasMarksInMargin, AAxisIsVertical: Boolean; AMin, AMax: PDouble);
begin
Assert(AAxis <> nil);
FAxis := AAxis;
FAxisIsFlipped := (AAxis <> nil) and AAxis.IsFlipped;
FImageLo := AImageLo;
FImageHi := AImageHi;
FMin := AMin;
@ -1258,8 +1256,8 @@ begin
FLo := FImageLo + AMarginLo;
FHi := FImageHi + AMarginHi;
if HasMarksInMargin then begin
if FAxis.IsVertical then begin
if AHasMarksInMargin then begin
if AAxisIsVertical then begin
if (FHi + AMinDataSpace >= FLo) then
EnsureGuaranteedSpace(FHi, FLo, FImageHi, FImageLo,
ARequiredMarginHi, ARequiredMarginLo, AMinDataSpace);
@ -1277,7 +1275,7 @@ begin
Result := ASign
else
Result := (FHi - FLo) / (FMax^ - FMin^);
if FAxis.IsFlipped then
if FAxisIsFlipped then
Result := -Result;
end;
@ -1290,7 +1288,7 @@ procedure TAxisCoeffHelper.UpdateMinMax(AConv: TAxisConvFunc);
begin
FMin^ := AConv(FImageLo);
FMax^ := AConv(FImageHi);
if FAxis.IsFlipped then
if FAxisIsFlipped then
Exchange(FMin^, FMax^);
end;

View File

@ -556,10 +556,18 @@ begin
end;
function TCustomChartSeries.IsRotated: Boolean;
var
x_normal, y_normal: Boolean;
x_axis: TChartAxis = nil;
y_axis: TChartAxis = nil;
begin
Result :=
(AxisIndexX >= 0) and FChart.AxisList[AxisIndexX].IsVertical and
(AxisIndexY >= 0) and not FChart.AxisList[AxisIndexY].IsVertical;
if InRange(AxisIndexX, 0, FChart.AxisList.Count-1) then
x_axis := FChart.AxisList[AxisIndexX];
if InRange(AxisIndexY, 0, FChart.AxisList.Count-1) then
y_axis := FChart.AxisList[AxisIndexY];
x_normal := (x_axis = nil) or (not x_axis.IsVertical);
y_normal := (y_axis = nil) or y_axis.IsVertical;
Result := (not x_normal) and (not y_normal);
end;
function TCustomChartSeries.LegendTextSingle: String;
@ -1427,8 +1435,9 @@ begin
lmpNegative: isNeg := true;
lmpInside: isNeg := Source[AIndex]^.Y >= ref;
end;
if (IsRotated and ParentChart.IsRightToLeft) xor GetAxisY.Inverted then
isNeg := not isNeg;
if Assigned(GetAxisY) then
if (IsRotated and ParentChart.IsRightToLeft) xor GetAxisY.Inverted then
isNeg := not isNeg;
Result := DIR[IsRotated, isNeg];
end;

View File

@ -252,10 +252,12 @@ type
AReader: TReader; const AClassName: String; var AClass: TComponentClass);
function GetChartHeight: Integer;
function GetChartWidth: Integer;
function GetHorAxis: TChartAxis;
function GetMargins(ADrawer: IChartDrawer): TRect;
function GetRenderingParams: TChartRenderingParams;
function GetSeriesCount: Integer;
function GetToolset: TBasicChartToolset;
function GetVertAxis: TChartAxis;
procedure HideReticule; deprecated 'Use DatapointCrosshairTool instead';
procedure SetAntialiasingMode(AValue: TChartAntialiasingMode);
@ -385,6 +387,7 @@ type
property ClipRect: TRect read FClipRect;
property CurrentExtent: TDoubleRect read FCurrentExtent;
property ExtentBroadcaster: TBroadcaster read FExtentBroadcaster;
property HorAxis: TChartAxis read GetHorAxis;
property IsZoomed: Boolean read FIsZoomed;
property LogicalExtent: TDoubleRect read FLogicalExtent write SetLogicalExtent;
property MinDataSpace: Integer
@ -396,6 +399,7 @@ type
read GetRenderingParams write SetRenderingParams;
property ReticulePos: TPoint read FReticulePos write SetReticulePos; deprecated 'Use DatapointCrosshairTool instead';
property SeriesCount: Integer read GetSeriesCount;
property VertAxis: TChartAxis read GetVertAxis;
property XGraphMax: Double read FCurrentExtent.b.X;
property XGraphMin: Double read FCurrentExtent.a.X;
property YGraphMax: Double read FCurrentExtent.b.Y;
@ -588,15 +592,16 @@ var
rX, rY: TAxisCoeffHelper;
begin
rX.Init(
BottomAxis, FClipRect.Left, FClipRect.Right, AMargin.Left, -AMargin.Right,
HorAxis, FClipRect.Left, FClipRect.Right, AMargin.Left, -AMargin.Right,
AChartMargins.Left, AChartMargins.Right, AMinDataSpace,
(AMargin.Left <> AChartMargins.Left) or (AMargin.Right <> AChartMargins.Right),
@FCurrentExtent.a.X, @FCurrentExtent.b.X);
false, @FCurrentExtent.a.X, @FCurrentExtent.b.X);
rY.Init(
LeftAxis, FClipRect.Bottom, FClipRect.Top, -AMargin.Bottom, AMargin.Top,
VertAxis, FClipRect.Bottom, FClipRect.Top, -AMargin.Bottom, AMargin.Top,
AChartMargins.Bottom, AChartMargins.Top, AMinDataSpace,
(AMargin.Top <> AChartMargins.Top) or (AMargin.Bottom <> AChartMargins.Bottom),
@FCurrentExtent.a.Y, @FCurrentExtent.b.Y);
true, @FCurrentExtent.a.Y, @FCurrentExtent.b.Y);
FScale.X := rX.CalcScale(1);
FScale.Y := rY.CalcScale(-1);
@ -1213,6 +1218,12 @@ begin
end;
end;
function TChart.GetHorAxis: TChartAxis;
begin
Result := BottomAxis;
if Result = nil then Result := GetAxisByAlign(calTop);
end;
function TChart.GetLegendItems(AIncludeHidden: Boolean): TChartLegendItems;
var
s: TBasicChartSeries;
@ -1269,6 +1280,12 @@ begin
Result := FBuiltinToolset;
end;
function TChart.GetVertAxis: TChartAxis;
begin
Result := LeftAxis;
if Result = nil then Result := GetAxisByAlign(calRight);
end;
function TChart.GraphToImage(const AGraphPoint: TDoublePoint): TPoint;
begin
Result := Point(XGraphToImage(AGraphPoint.X), YGraphToImage(AGraphPoint.Y));