From 4ed00f8de55aeca26b01347c6872832e9bd0cc2f Mon Sep 17 00:00:00 2001 From: ask Date: Sat, 16 Jul 2011 17:37:01 +0000 Subject: [PATCH] TAChart: Use TAxisDrawHelper for axis measuring git-svn-id: trunk@31712 - --- components/tachart/tachartaxis.pas | 147 +++++++++++------------- components/tachart/tachartaxisutils.pas | 41 +++++-- components/tachart/tagraph.pas | 21 ++-- 3 files changed, 107 insertions(+), 102 deletions(-) diff --git a/components/tachart/tachartaxis.pas b/components/tachart/tachartaxis.pas index 233dfabadc..c969b78fe0 100644 --- a/components/tachart/tachartaxis.pas +++ b/components/tachart/tachartaxis.pas @@ -97,6 +97,7 @@ type strict private FAlignment: TChartAxisAlignment; FGroup: Integer; + FHelper: TAxisDrawHelper; FInverted: Boolean; FMinors: TChartMinorAxisList; FOnMarkToText: TChartAxisMarkToTextEvent; @@ -124,16 +125,15 @@ type destructor Destroy; override; public procedure Assign(ASource: TPersistent); override; - procedure Draw( - ADrawer: IChartDrawer; const AClipRect: TRect; - const ATransf: ICoordTransformer; const AZOffset: TPoint); - procedure DrawTitle( - ADrawer: IChartDrawer; const ACenter, AZOffset: TPoint; ASize: Integer); + procedure Draw; + procedure DrawTitle(const ACenter: TPoint; ASize: Integer); function GetChart: TCustomChart; inline; function IsVertical: Boolean; inline; procedure Measure( - ADrawer: IChartDrawer; const AExtent: TDoubleRect; - var AMeasureData: TChartAxisGroup); + const AExtent: TDoubleRect; var AMeasureData: TChartAxisGroup); + procedure PrepareHelper( + ADrawer: IChartDrawer; const ATransf: ICoordTransformer; + AClipRect: PRect; AMaxZPosition: Integer); published property Alignment default calLeft; property Group: Integer read FGroup write SetGroup default 0; @@ -183,14 +183,10 @@ type destructor Destroy; override; public function Add: TChartAxis; inline; - procedure Draw( - ADrawer: IChartDrawer; const AClipRect: TRect; - const ATransf: ICoordTransformer; ACurrentZ, AMaxZ: Integer; - var AIndex: Integer); + procedure Draw(ACurrentZ: Integer; var AIndex: Integer); function GetAxis(AIndex: Integer): TChartAxis; function GetEnumerator: TChartAxisEnumerator; - function Measure( - ADrawer: IChartDrawer; const AExtent: TDoubleRect): TChartAxisMargins; + function Measure(const AExtent: TDoubleRect): TChartAxisMargins; procedure Prepare(ARect: TRect); procedure PrepareGroups; procedure SetAxis(AIndex: Integer; AValue: TChartAxis); @@ -375,72 +371,48 @@ begin FreeAndNil(FTitle); FreeAndNil(FMinors); FreeAndNil(FListener); + FreeAndNil(FHelper); inherited; end; -procedure TChartAxis.Draw( - ADrawer: IChartDrawer; const AClipRect: TRect; - const ATransf: ICoordTransformer; const AZOffset: TPoint); - - function MakeDrawHelper(AAxis: TChartBasicAxis): TAxisDrawHelper; - begin - if IsVertical then - Result := TAxisDrawHelperY.Create - else - Result := TAxisDrawHelperX.Create; - try - Result.FAxis := AAxis; - Result.FClipRect := AClipRect; - Result.FDrawer := ADrawer; - Result.FTransf := ATransf; - Result.FZOffset := AZOffset; - Result.BeginDrawing; - except - Result.Free; - raise; - end; - end; - +procedure TChartAxis.Draw; var i, j, c, ic, fixedCoord: Integer; axisTransf: TTransformFunc; - dh, dhMinor: TAxisDrawHelper; + dhMinor: TAxisDrawHelper; pv, v: Double; begin if not Visible then exit; if Marks.Visible then - ADrawer.Font := Marks.LabelFont; + FHelper.FDrawer.Font := Marks.LabelFont; fixedCoord := TChartAxisMargins(FAxisRect)[Alignment]; v := 0; - dh := MakeDrawHelper(Self); - try - axisTransf := @GetTransform.AxisToGraph; - for i := 0 to High(FMarkValues) do begin - pv := v; - v := axisTransf(FMarkValues[i]); - dh.DrawMark(fixedCoord, v, FMarkTexts[i]); - if (i = 0) or (v = pv) then continue; - for j := 0 to Minors.Count - 1 do begin - ic := Minors[j].IntervalsCount; - if not Minors[j].Visible or (ic < 2) then continue; - dhMinor := MakeDrawHelper(Minors[j]); - try - for c := 1 to ic - 1 do - dhMinor.DrawMark(fixedCoord, WeightedAverage(pv, v, c / ic), ''); - dhMinor.EndDrawing; - finally - dhMinor.Free; - end; + FHelper.BeginDrawing; + axisTransf := @GetTransform.AxisToGraph; + for i := 0 to High(FMarkValues) do begin + pv := v; + v := axisTransf(FMarkValues[i]); + FHelper.DrawMark(fixedCoord, v, FMarkTexts[i]); + if (i = 0) or (v = pv) then continue; + for j := 0 to Minors.Count - 1 do begin + ic := Minors[j].IntervalsCount; + if not Minors[j].Visible or (ic < 2) then continue; + dhMinor := FHelper.Clone; + dhMinor.FAxis := Minors[j]; + try + dhMinor.BeginDrawing; + for c := 1 to ic - 1 do + dhMinor.DrawMark(fixedCoord, WeightedAverage(pv, v, c / ic), ''); + dhMinor.EndDrawing; + finally + dhMinor.Free; end; end; - dh.EndDrawing; - finally - dh.Free; end; + FHelper.EndDrawing; end; -procedure TChartAxis.DrawTitle( - ADrawer: IChartDrawer; const ACenter, AZOffset: TPoint; ASize: Integer); +procedure TChartAxis.DrawTitle(const ACenter: TPoint; ASize: Integer); var p: TPoint; dummy: TPointArray = nil; @@ -455,8 +427,8 @@ begin calRight: p.X := FTitleRect.Right + d; calBottom: p.Y := FTitleRect.Bottom + d; end; - p += AZOffset; - Title.DrawLabel(ADrawer, p, p, Title.Caption, dummy); + p += FHelper.FZOffset; + Title.DrawLabel(FHelper.FDrawer, p, p, Title.Caption, dummy); end; function TChartAxis.GetAlignment: TChartAxisAlignment; @@ -527,8 +499,7 @@ begin end; procedure TChartAxis.Measure( - ADrawer: IChartDrawer; const AExtent: TDoubleRect; - var AMeasureData: TChartAxisGroup); + const AExtent: TDoubleRect; var AMeasureData: TChartAxisGroup); function MaxMarksSize(AMin, AMax: Double): TPoint; var @@ -539,7 +510,7 @@ procedure TChartAxis.Measure( GetMarkValues(AMin, AMax); if not Marks.Visible then exit; for t in FMarkTexts do - Result := MaxPoint(Marks.MeasureLabel(ADrawer, t), Result); + Result := MaxPoint(Marks.MeasureLabel(FHelper.FDrawer, t), Result); end; function TitleSize: Integer; @@ -548,13 +519,13 @@ procedure TChartAxis.Measure( begin if not Title.Visible or (Title.Caption = '') then exit(0); - sz := Title.MeasureLabel(ADrawer, Title.Caption); + sz := Title.MeasureLabel(FHelper.FDrawer, Title.Caption); Result := IfThen(IsVertical, sz.cx, sz.cy) + Title.Distance; end; function FirstLastSize(AIndex: Integer): Integer; begin - with Marks.MeasureLabel(ADrawer, FMarkTexts[AIndex]) do + with Marks.MeasureLabel(FHelper.FDrawer, FMarkTexts[AIndex]) do Result := IfThen(IsVertical, cy, cx) div 2; end; @@ -569,7 +540,8 @@ begin if Marks.DistanceToCenter then sz := sz div 2; if sz > 0 then - sz += ADrawer.Scale(TickLength) + ADrawer.Scale(Marks.Distance); + sz += FHelper.FDrawer.Scale(TickLength) + + FHelper.FDrawer.Scale(Marks.Distance); with AMeasureData do begin FSize := Max(sz, FSize); FTitleSize := Max(TitleSize, FTitleSize); @@ -580,6 +552,23 @@ begin end; end; +procedure TChartAxis.PrepareHelper( + ADrawer: IChartDrawer; const ATransf: ICoordTransformer; + AClipRect: PRect; AMaxZPosition: Integer); +begin + FreeAndNil(FHelper); + if IsVertical then + FHelper := TAxisDrawHelperY.Create + else + FHelper := TAxisDrawHelperX.Create; + FHelper.FAxis := Self; + FHelper.FClipRect := AClipRect; + FHelper.FDrawer := ADrawer; + FHelper.FTransf := ATransf; + FHelper.FZOffset.X := Min(ZPosition, AMaxZPosition); + FHelper.FZOffset.Y := -FHelper.FZOffset.X; +end; + procedure TChartAxis.SetAlignment(AValue: TChartAxisAlignment); begin if FAlignment = AValue then exit; @@ -695,20 +684,13 @@ begin inherited Destroy; end; -procedure TChartAxisList.Draw( - ADrawer: IChartDrawer; const AClipRect: TRect; - const ATransf: ICoordTransformer; ACurrentZ, AMaxZ: Integer; - var AIndex: Integer); -var - zoffset: TPoint; +procedure TChartAxisList.Draw(ACurrentZ: Integer; var AIndex: Integer); begin while AIndex < FZOrder.Count do with TChartAxis(FZOrder[AIndex]) do begin if ACurrentZ < ZPosition then break; - zoffset.Y := Min(ZPosition, AMaxZ); - zoffset.X := - zoffset.Y; - Draw(ADrawer, AClipRect, ATransf, zoffset); - DrawTitle(ADrawer, FCenterPoint, zoffset, FGroups[FGroupIndex].FTitleSize); + Draw; + DrawTitle(FCenterPoint, FGroups[FGroupIndex].FTitleSize); AIndex += 1; end; end; @@ -746,8 +728,7 @@ begin AList.Sort(ACompare); end; -function TChartAxisList.Measure( - ADrawer: IChartDrawer; const AExtent: TDoubleRect): TChartAxisMargins; +function TChartAxisList.Measure(const AExtent: TDoubleRect): TChartAxisMargins; var g: ^TChartAxisGroup; @@ -771,7 +752,7 @@ begin g^.FTitleSize := 0; for j := 0 to g^.FCount - 1 do begin axis := TChartAxis(FGroupOrder[ai]); - axis.Measure(ADrawer, AExtent, g^); + axis.Measure(AExtent, g^); ai += 1; end; Result[axis.Alignment] += g^.FSize + g^.FTitleSize; diff --git a/components/tachart/tachartaxisutils.pas b/components/tachart/tachartaxisutils.pas index f4f0e5f8c6..b0fe0b8315 100644 --- a/components/tachart/tachartaxisutils.pas +++ b/components/tachart/tachartaxisutils.pas @@ -170,7 +170,7 @@ type function TryApplyStripes: Boolean; inline; public FAxis: TChartBasicAxis; - FClipRect: TRect; + FClipRect: ^TRect; FDrawer: IChartDrawer; FPrevCoord: Integer; FPrevLabelPoly: TPointArray; @@ -180,11 +180,15 @@ type FZOffset: TPoint; procedure BeginDrawing; virtual; + constructor Create; virtual; + function Clone: TAxisDrawHelper; procedure DrawMark( AFixedCoord: Integer; AMark: Double; const AText: String); procedure EndDrawing; virtual; abstract; end; + TAxisDrawHelperClass = class of TAxisDrawHelper; + { TAxisDrawHelperX } TAxisDrawHelperX = class(TAxisDrawHelper) @@ -232,6 +236,21 @@ begin FScaledTickLength := FDrawer.Scale(FAxis.TickLength); end; +function TAxisDrawHelper.Clone: TAxisDrawHelper; +begin + Result := TAxisDrawHelperClass(ClassType).Create; + Result.FAxis := FAxis; + Result.FClipRect := FClipRect; + Result.FDrawer := FDrawer; + Result.FTransf := FTransf; + Result.FZOffset := FZOffset; +end; + +constructor TAxisDrawHelper.Create; +begin + inherited; +end; + procedure TAxisDrawHelper.DrawLabel(ALabelCenter: TPoint; const AText: String); begin ALabelCenter += FZOffset; @@ -275,7 +294,7 @@ end; procedure TAxisDrawHelperX.BeginDrawing; begin inherited; - FPrevCoord := FClipRect.Left; + FPrevCoord := FClipRect^.Left; end; procedure TAxisDrawHelperX.DrawLabelAndTick( @@ -295,7 +314,7 @@ end; procedure TAxisDrawHelperX.EndDrawing; begin if FAxis.Grid.Visible and TryApplyStripes then - BarZ(FPrevCoord + 1, FClipRect.Top + 1, FClipRect.Right, FClipRect.Bottom); + BarZ(FPrevCoord + 1, FClipRect^.Top + 1, FClipRect^.Right, FClipRect^.Bottom); end; function TAxisDrawHelperX.GraphToImage(AGraph: Double): Integer; @@ -306,13 +325,13 @@ end; procedure TAxisDrawHelperX.GridLine(ACoord: Integer); begin if TryApplyStripes then - BarZ(FPrevCoord + 1, FClipRect.Top + 1, ACoord, FClipRect.Bottom); - LineZ(Point(ACoord, FClipRect.Top), Point(ACoord, FClipRect.Bottom)); + BarZ(FPrevCoord + 1, FClipRect^.Top + 1, ACoord, FClipRect^.Bottom); + LineZ(Point(ACoord, FClipRect^.Top), Point(ACoord, FClipRect^.Bottom)); end; function TAxisDrawHelperX.IsInClipRange(ACoord: Integer): Boolean; begin - Result := InRange(ACoord, FClipRect.Left, FClipRect.Right); + Result := InRange(ACoord, FClipRect^.Left, FClipRect^.Right); end; { TAxisDrawHelperY } @@ -320,7 +339,7 @@ end; procedure TAxisDrawHelperY.BeginDrawing; begin inherited; - FPrevCoord := FClipRect.Bottom; + FPrevCoord := FClipRect^.Bottom; end; procedure TAxisDrawHelperY.DrawLabelAndTick( @@ -340,7 +359,7 @@ end; procedure TAxisDrawHelperY.EndDrawing; begin if FAxis.Grid.Visible and TryApplyStripes then - BarZ(FClipRect.Left + 1, FClipRect.Top + 1, FClipRect.Right, FPrevCoord); + BarZ(FClipRect^.Left + 1, FClipRect^.Top + 1, FClipRect^.Right, FPrevCoord); end; function TAxisDrawHelperY.GraphToImage(AGraph: Double): Integer; @@ -351,13 +370,13 @@ end; procedure TAxisDrawHelperY.GridLine(ACoord: Integer); begin if TryApplyStripes then - BarZ(FClipRect.Left + 1, FPrevCoord, FClipRect.Right, ACoord); - LineZ(Point(FClipRect.Left, ACoord), Point(FClipRect.Right, ACoord)); + BarZ(FClipRect^.Left + 1, FPrevCoord, FClipRect^.Right, ACoord); + LineZ(Point(FClipRect^.Left, ACoord), Point(FClipRect^.Right, ACoord)); end; function TAxisDrawHelperY.IsInClipRange(ACoord: Integer): Boolean; begin - Result := InRange(ACoord, FClipRect.Top, FClipRect.Bottom); + Result := InRange(ACoord, FClipRect^.Top, FClipRect^.Bottom); end; { TChartAxisTitle } diff --git a/components/tachart/tagraph.pas b/components/tachart/tagraph.pas index b540621cfc..ccadf97699 100644 --- a/components/tachart/tagraph.pas +++ b/components/tachart/tagraph.pas @@ -668,7 +668,7 @@ begin if not Active then continue; // Interleave axises with series according to ZPosition. if AxisVisible then - AxisList.Draw(ADrawer, FClipRect, Self, ZPosition, d, axisIndex); + AxisList.Draw(ZPosition, axisIndex); OffsetDrawArea(Min(ZPosition, d), Min(Depth, d)); ADrawer.ClippingStart(FClipRect); try @@ -688,7 +688,7 @@ begin end; end; if AxisVisible then - AxisList.Draw(ADrawer, FClipRect, Self, MaxInt, d, axisIndex); + AxisList.Draw(MaxInt, axisIndex); end; {$IFDEF LCLGtk2} @@ -1105,10 +1105,11 @@ end; procedure TChart.PrepareAxis(ADrawer: IChartDrawer); var axisMargin: TChartAxisMargins; - a: TChartAxisAlignment; + aa: TChartAxisAlignment; cr: TRect; tries: Integer; prevExt: TDoubleRect; + axis: TChartAxis; begin if not AxisVisible then begin FClipRect.Left += Depth; @@ -1117,24 +1118,28 @@ begin exit; end; + AxisList.PrepareGroups; + for axis in AxisList do + axis.PrepareHelper(ADrawer, Self, @FClipRect, Depth); + // There is a cyclic dependency: extent -> visible marks -> margins. // We recalculate them iteratively hoping that the process converges. - AxisList.PrepareGroups; CalculateTransformationCoeffs(Rect(0, 0, 0, 0)); cr := FClipRect; for tries := 1 to 10 do begin - axisMargin := AxisList.Measure(ADrawer, CurrentExtent); + FClipRect := cr; + axisMargin := AxisList.Measure(CurrentExtent); axisMargin[calLeft] := Max(axisMargin[calLeft], Depth); axisMargin[calBottom] := Max(axisMargin[calBottom], Depth); - FClipRect := cr; - for a := Low(a) to High(a) do - SideByAlignment(FClipRect, a, -axisMargin[a]); + for aa := Low(aa) to High(aa) do + SideByAlignment(FClipRect, aa, -axisMargin[aa]); prevExt := FCurrentExtent; FCurrentExtent := FLogicalExtent; CalculateTransformationCoeffs(GetMargins(ADrawer)); if prevExt = FCurrentExtent then break; prevExt := FCurrentExtent; end; + AxisList.Prepare(FClipRect); end;