From 056f96d7b58a77c97b1c953043c814c6f69ede17 Mon Sep 17 00:00:00 2001 From: wp Date: Fri, 5 Apr 2019 12:13:04 +0000 Subject: [PATCH] TAChart: Caching of cumulative and x/y list extents of chart sources. Issue #35313, part of patch by Marcin Wiazowski. git-svn-id: trunk@60846 - --- components/tachart/tacustomsource.pas | 132 +++++++++++++++++--------- components/tachart/tasources.pas | 16 +++- 2 files changed, 102 insertions(+), 46 deletions(-) diff --git a/components/tachart/tacustomsource.pas b/components/tachart/tacustomsource.pas index 658c3b8d8c..f0278efa68 100644 --- a/components/tachart/tacustomsource.pas +++ b/components/tachart/tacustomsource.pas @@ -189,6 +189,12 @@ type strict protected FBasicExtent: TDoubleRect; FBasicExtentIsValid: Boolean; + FCumulativeExtent: TDoubleRect; + FCumulativeExtentIsValid: Boolean; + FXListExtent: TDoubleRect; + FXListExtentIsValid: Boolean; + FYListExtent: TDoubleRect; + FYListExtentIsValid: Boolean; FValuesTotal: Double; FValuesTotalIsValid: Boolean; FXCount: Cardinal; @@ -309,7 +315,7 @@ begin AItem.Color := clTAColor; AItem.Text := ''; for i := 0 to High(AItem.XList) do - Aitem.XList[i] := 0; + AItem.XList[i] := 0; for i := 0 to High(AItem.YList) do AItem.YList[i] := 0; end; @@ -832,40 +838,64 @@ var jyp, jyn: Integer; begin Result := Extent; - if (YCount < 2) and (XCount < 2) then exit; - // Skip the x and y values used for error bars when calculating the list extent. - if UseXList and (XErrorBarData.Kind = ebkChartSource) then begin - jxp := XErrorBarData.IndexPlus - 1; // -1 because XList is offset by 1 - jxn := XErrorBarData.IndexMinus - 1; - end else begin - jxp := -1; - jxn := -1; - end; - if YErrorBarData.Kind = ebkChartSource then begin - jyp := YErrorBarData.IndexPlus - 1; // -1 because YList is offset by 1 - jyn := YErrorBarData.IndexMinus - 1; - end else begin - jyp := -1; - jyn := -1; - end; + if UseXList and (XCount > 1) then begin + if not FXListExtentIsValid then begin + FXListExtent := EmptyExtent; - if UseXList and (XCount > 1) then - for i := 0 to Count - 1 do - with Item[i]^ do begin - for j := 0 to High(XList) do - if (j <> jxp) and (j <> jxn) then - UpdateMinMax(XList[j], Result.a.X, Result.b.X); + // Skip the x values used for error bars when calculating the list extent. + if XErrorBarData.Kind = ebkChartSource then begin + jxp := XErrorBarData.IndexPlus - 1; // -1 because XList index is offset by 1 + jxn := XErrorBarData.IndexMinus - 1; + end else begin + jxp := -1; + jxn := -1; end; - for i := 0 to Count - 1 do - with Item[i]^ do begin - for j := 0 to High(YList) do - if (j <> jyp) and (j <> jyn) then - UpdateMinMax(YList[j], Result.a.Y, Result.b.Y); - end + for i := 0 to Count - 1 do + with Item[i]^ do begin + for j := 0 to High(XList) do + if (j <> jxp) and (j <> jxn) then + UpdateMinMax(XList[j], FXListExtent.a.X, FXListExtent.b.X); + end; + + FXListExtentIsValid := true; + end; + + Result.a.X := Min(Result.a.X, FXListExtent.a.X); + Result.b.X := Max(Result.b.X, FXListExtent.b.X); + end; + + if (YCount > 1) then begin + if not FYListExtentIsValid then begin + FYListExtent := EmptyExtent; + + // Skip the y values used for error bars when calculating the list extent. + if YErrorBarData.Kind = ebkChartSource then begin + jyp := YErrorBarData.IndexPlus - 1; // -1 because YList index is offset by 1 + jyn := YErrorBarData.IndexMinus - 1; + end else begin + jyp := -1; + jyn := -1; + end; + + for i := 0 to Count - 1 do + with Item[i]^ do begin + for j := 0 to High(YList) do + if (j <> jyp) and (j <> jyn) then + UpdateMinMax(YList[j], FYListExtent.a.Y, FYListExtent.b.Y); + end; + + FYListExtentIsValid := true; + end; + + Result.a.Y := Min(Result.a.Y, FYListExtent.a.Y); + Result.b.Y := Max(Result.b.Y, FYListExtent.b.Y); + end; end; + + class procedure TCustomChartSource.CheckFormat(const AFormat: String); begin Format(AFormat, [0.0, 0.0, '', 0.0, 0.0]); @@ -919,28 +949,40 @@ function TCustomChartSource.ExtentCumulative: TDoubleRect; var h: Double; i, j: Integer; - jyp: Integer = -1; - jyn: Integer = -1; + jyp, jyn: Integer; begin Result := Extent; - if YCount < 2 then exit; - // Skip the y values used for error bars in calculating the cumulative sum. - if YErrorBarData.Kind = ebkChartSource then begin - jyp := YErrorBarData.IndexPlus - 1; // -1 because YList index is offset by 1 - jyn := YErrorBarData.IndexMinus - 1; - end; + if (YCount > 1) then begin + if not FCumulativeExtentIsValid then begin + FCumulativeExtent := EmptyExtent; - for i := 0 to Count - 1 do - with Item[i]^ do begin - h := NumberOr(Y); - for j := 0 to High(YList) do - if (j <> jyp) and (j <> jyn) then begin - h += NumberOr(YList[j]); - // If some of the Y values are negative, h may be non-monotonic. - UpdateMinMax(h, Result.a.Y, Result.b.Y); + // Skip the y values used for error bars when calculating the cumulative sum. + if YErrorBarData.Kind = ebkChartSource then begin + jyp := YErrorBarData.IndexPlus - 1; // -1 because YList index is offset by 1 + jyn := YErrorBarData.IndexMinus - 1; + end else begin + jyp := -1; + jyn := -1; + end; + + for i := 0 to Count - 1 do + with Item[i]^ do begin + h := NumberOr(Y); + for j := 0 to High(YList) do + if (j <> jyp) and (j <> jyn) then begin + h += NumberOr(YList[j]); + // If some of the Y values are negative, h may be non-monotonic. + UpdateMinMax(h, FCumulativeExtent.a.Y, FCumulativeExtent.b.Y); + end; end; + + FCumulativeExtentIsValid := true; end; + + Result.a.Y := Min(Result.a.Y, FCumulativeExtent.a.Y); + Result.b.Y := Max(Result.b.Y, FCumulativeExtent.b.Y); + end; end; { Calculates the extent including multiple y values (non-stacked) } diff --git a/components/tachart/tasources.pas b/components/tachart/tasources.pas index 406a81fe5f..59e2dac487 100644 --- a/components/tachart/tasources.pas +++ b/components/tachart/tasources.pas @@ -555,6 +555,12 @@ procedure TListChartSource.ClearCaches; begin FBasicExtent := EmptyExtent; FBasicExtentIsValid := true; + FCumulativeExtent := EmptyExtent; + FCumulativeExtentIsValid := true; + FXListExtent := EmptyExtent; + FXListExtentIsValid := true; + FYListExtent := EmptyExtent; + FYListExtentIsValid := true; FValuesTotal := 0; FValuesTotalIsValid := true; end; @@ -613,6 +619,9 @@ begin if FValuesTotalIsValid then FValuesTotal -= NumberOr(Y); end; + FCumulativeExtentIsValid := false; + FXListExtentIsValid := false; + FYListExtentIsValid := false; Dispose(Item[AIndex]); FData.Delete(AIndex); Notify; @@ -711,7 +720,7 @@ begin with Item[AIndex]^ do for i := 0 to Min(High(AXList), High(XList)) do XList[i] := AXList[i]; - // wp: Update x extent here ? + FXListExtentIsValid := false; end; function TListChartSource.SetXValue(AIndex: Integer; AValue: Double): Integer; @@ -777,6 +786,8 @@ begin with Item[AIndex]^ do for i := 0 to Min(High(AYList), High(YList)) do YList[i] := AYList[i]; + FCumulativeExtentIsValid := false; + FYListExtentIsValid := false; end; procedure TListChartSource.SetYValue(AIndex: Integer; AValue: Double); @@ -867,6 +878,9 @@ begin end; if FValuesTotalIsValid then FValuesTotal += NumberOr(AY); + FCumulativeExtentIsValid := false; + FXListExtentIsValid := false; + FYListExtentIsValid := false; Notify; end;