From 5fb72b751ababdba6dd73b96e4b19d5ee4369ccb Mon Sep 17 00:00:00 2001 From: wp Date: Mon, 4 Mar 2019 17:34:41 +0000 Subject: [PATCH] TAChart: Fix TFitSeries extent calculation to include the fitted curve. Issue #35183, patch by Marcin Wiazowski. git-svn-id: trunk@60585 - --- components/tachart/tafuncseries.pas | 25 +++++++++- components/tachart/tagraph.pas | 71 ++++++++++++++++++++--------- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/components/tachart/tafuncseries.pas b/components/tachart/tafuncseries.pas index b0379363ce..b503b6be2d 100644 --- a/components/tachart/tafuncseries.pas +++ b/components/tachart/tafuncseries.pas @@ -1601,7 +1601,7 @@ procedure TFitSeries.CalcXRange(out AXMin, AXMax: Double); var ext: TDoubleRect; begin - with Extent do begin + with Source.BasicExtent do begin ext.a := AxisToGraph(a); ext.b := AxisToGraph(b); end; @@ -1793,8 +1793,31 @@ begin end; function TFitSeries.Extent: TDoubleRect; +var + de : TIntervalList; begin Result := Source.BasicExtent; + if IsEmpty or (not Active) then exit; + + if ParentChart = nil then exit; + ParentChart.ScaleNeedsSecondPass := True; + if not ParentChart.ScaleValid then exit; + + if FAutoFit then ExecFit; + + if (FState = fpsValid) and (FErrCode = fitOK) then begin + de := PrepareIntervals; + try + with TDrawFuncHelper.Create(Self, de, @Calculate, Step) do + try + CalcAxisExtentY(Result.a.X, Result.b.X, Result.a.Y, Result.b.Y); + finally + Free; + end; + finally + de.Free; + end; + end; end; function TFitSeries.FitParams: TDoubleDynArray; diff --git a/components/tachart/tagraph.pas b/components/tachart/tagraph.pas index 3c15013fbd..1e7e2dece4 100644 --- a/components/tachart/tagraph.pas +++ b/components/tachart/tagraph.pas @@ -1,4 +1,4 @@ -{ +{ /*************************************************************************** TAGraph.pas ----------- @@ -233,6 +233,8 @@ type FOnExtentChanging: TChartEvent; FPrevLogicalExtent: TDoubleRect; FScale: TDoublePoint; // Coordinates transformation + FScaleValid: Boolean; + FScaleNeedsSecondPass: Boolean; FSavedClipRect: TRect; FClipRectLock: Integer; @@ -359,6 +361,8 @@ type function XImageToGraph(AX: Integer): Double; inline; function YGraphToImage(AY: Double): Integer; inline; function YImageToGraph(AY: Integer): Double; inline; + property ScaleValid: Boolean read FScaleValid; + property ScaleNeedsSecondPass: Boolean read FScaleNeedsSecondPass write FScaleNeedsSecondPass; public procedure LockClipRect; @@ -591,6 +595,7 @@ begin FOffset.Y := rY.CalcOffset(FScale.Y); rX.UpdateMinMax(@XImageToGraph); rY.UpdateMinMax(@YImageToGraph); + FScaleValid := True; end; procedure TChart.Clear(ADrawer: IChartDrawer; const ARect: TRect); @@ -686,6 +691,8 @@ begin FGUIConnectorListener := TListener.Create(@FGUIConnector, @StyleChanged); FScale := DoublePoint(1, -1); + FScaleValid := False; + FScaleNeedsSecondPass := False; Width := DEFAULT_CHART_WIDTH; Height := DEFAULT_CHART_HEIGHT; @@ -878,32 +885,49 @@ end; procedure TChart.Draw(ADrawer: IChartDrawer; const ARect: TRect); var ldd: TChartLegendDrawingData; + tmpExtent: TDoubleRect; + tries: Integer; s: TBasicChartSeries; ts: TBasicChartToolset; begin - Prepare; - - ADrawer.SetRightToLeft(BiDiMode <> bdLeftToRight); - - FClipRect := ARect; - with MarginsExternal do begin - FClipRect.Left += Left; - FClipRect.Top += Top; - FClipRect.Right -= Right; - FClipRect.Bottom -= Bottom; - end; - - with ClipRect do begin - FTitle.Measure(ADrawer, 1, Left, Right, Top); - FFoot.Measure(ADrawer, -1, Left, Right, Bottom); - end; - ldd.FItems := nil; - if Legend.Visible then - ldd := PrepareLegend(ADrawer, FClipRect); - try - PrepareAxis(ADrawer); + Prepare; + + ADrawer.SetRightToLeft(BiDiMode <> bdLeftToRight); + + for tries := 1 to 2 do + begin + FClipRect := ARect; + with MarginsExternal do begin + FClipRect.Left += Left; + FClipRect.Top += Top; + FClipRect.Right -= Right; + FClipRect.Bottom -= Bottom; + end; + + with ClipRect do begin + FTitle.Measure(ADrawer, 1, Left, Right, Top); + FFoot.Measure(ADrawer, -1, Left, Right, Bottom); + end; + + if Legend.Visible then + ldd := PrepareLegend(ADrawer, FClipRect); + + PrepareAxis(ADrawer); + + if not FScaleNeedsSecondPass then break; + + if FIsZoomed then break; // GetFullExtent() has not been called in this case, + // in the Prepare() call above + tmpExtent := GetFullExtent; // perform second pass + if tmpExtent = FLogicalExtent then break; // second pass hasn't changed the extent + + // as in the Prepare() call + FLogicalExtent := tmpExtent; + FCurrentExtent := FLogicalExtent; + end; + if Legend.Visible and not Legend.UseSidebar then Legend.Prepare(ldd, FClipRect); @@ -1470,6 +1494,9 @@ var a: TChartAxis; s: TBasicChartSeries; begin + FScaleValid := False; + FScaleNeedsSecondPass := False; + for a in AxisList do if a.Transformations <> nil then a.Transformations.SetChart(Self);