TAChart: Calculate transformation coefficients iteratively

git-svn-id: trunk@31709 -
This commit is contained in:
ask 2011-07-16 16:17:26 +00:00
parent f13bf300dd
commit d4b0f89e8f
2 changed files with 36 additions and 38 deletions

View File

@ -132,7 +132,7 @@ type
function GetChart: TCustomChart; inline; function GetChart: TCustomChart; inline;
function IsVertical: Boolean; inline; function IsVertical: Boolean; inline;
procedure Measure( procedure Measure(
ADrawer: IChartDrawer; const AExtent: TDoubleRect; AFirstPass: Boolean; ADrawer: IChartDrawer; const AExtent: TDoubleRect;
var AMeasureData: TChartAxisGroup); var AMeasureData: TChartAxisGroup);
published published
property Alignment default calLeft; property Alignment default calLeft;
@ -189,9 +189,8 @@ type
var AIndex: Integer); var AIndex: Integer);
function GetAxis(AIndex: Integer): TChartAxis; function GetAxis(AIndex: Integer): TChartAxis;
function GetEnumerator: TChartAxisEnumerator; function GetEnumerator: TChartAxisEnumerator;
procedure Measure( function Measure(
ADrawer: IChartDrawer; const AExtent: TDoubleRect; ADrawer: IChartDrawer; const AExtent: TDoubleRect): TChartAxisMargins;
AFirstPass: Boolean; var AMargins: TChartAxisMargins);
procedure Prepare(ARect: TRect); procedure Prepare(ARect: TRect);
procedure PrepareGroups; procedure PrepareGroups;
procedure SetAxis(AIndex: Integer; AValue: TChartAxis); procedure SetAxis(AIndex: Integer; AValue: TChartAxis);
@ -209,7 +208,7 @@ type
TAxisCoeffHelper = object TAxisCoeffHelper = object
FAxis: TChartAxis; FAxis: TChartAxis;
FImageLo, FImageHi, FMarginLo, FMarginHi: Integer; FImageLo, FImageHi: Integer;
FLo, FHi: Integer; FLo, FHi: Integer;
FMin, FMax: PDouble; FMin, FMax: PDouble;
function CalcOffset(AScale: Double): Double; function CalcOffset(AScale: Double): Double;
@ -529,11 +528,9 @@ end;
procedure TChartAxis.Measure( procedure TChartAxis.Measure(
ADrawer: IChartDrawer; const AExtent: TDoubleRect; ADrawer: IChartDrawer; const AExtent: TDoubleRect;
AFirstPass: Boolean; var AMeasureData: TChartAxisGroup); var AMeasureData: TChartAxisGroup);
function MaxMarksSize(AMin, AMax: Double): TPoint; function MaxMarksSize(AMin, AMax: Double): TPoint;
const
SOME_DIGIT = '0';
var var
t: String; t: String;
begin begin
@ -541,17 +538,9 @@ procedure TChartAxis.Measure(
if AMin = AMax then exit; if AMin = AMax then exit;
GetMarkValues(AMin, AMax); GetMarkValues(AMin, AMax);
if not Marks.Visible then exit; if not Marks.Visible then exit;
for t in FMarkTexts do begin for t in FMarkTexts do
// CalculateTransformationCoeffs changes axis interval, so it is possibile
// that a new mark longer then existing ones is introduced.
// That will change marks width and reduce view area,
// requiring another call to CalculateTransformationCoeffs...
// So punt for now and just reserve space for extra digit unconditionally.
if AFirstPass then
t += SOME_DIGIT;
Result := MaxPoint(Marks.MeasureLabel(ADrawer, t), Result); Result := MaxPoint(Marks.MeasureLabel(ADrawer, t), Result);
end; end;
end;
function TitleSize: Integer; function TitleSize: Integer;
var var
@ -757,22 +746,22 @@ begin
AList.Sort(ACompare); AList.Sort(ACompare);
end; end;
procedure TChartAxisList.Measure( function TChartAxisList.Measure(
ADrawer: IChartDrawer; const AExtent: TDoubleRect; ADrawer: IChartDrawer; const AExtent: TDoubleRect): TChartAxisMargins;
AFirstPass: Boolean; var AMargins: TChartAxisMargins);
var var
g: ^TChartAxisGroup; g: ^TChartAxisGroup;
procedure UpdateMarginsForMarks(AFirst, ALast: TChartAxisAlignment); procedure UpdateMarginsForMarks(AFirst, ALast: TChartAxisAlignment);
begin begin
AMargins[AFirst] := Max(AMargins[AFirst], g^.FFirstMark); Result[AFirst] := Max(Result[AFirst], g^.FFirstMark);
AMargins[ALast] := Max(AMargins[ALast], g^.FLastMark); Result[ALast] := Max(Result[ALast], g^.FLastMark);
end; end;
var var
i, j, ai: Integer; i, j, ai: Integer;
axis: TChartAxis; axis: TChartAxis;
begin begin
FillChar(Result, SizeOf(Result), 0);
ai := 0; ai := 0;
for i := 0 to High(FGroups) do begin for i := 0 to High(FGroups) do begin
g := @FGroups[i]; g := @FGroups[i];
@ -782,11 +771,10 @@ begin
g^.FTitleSize := 0; g^.FTitleSize := 0;
for j := 0 to g^.FCount - 1 do begin for j := 0 to g^.FCount - 1 do begin
axis := TChartAxis(FGroupOrder[ai]); axis := TChartAxis(FGroupOrder[ai]);
axis.Measure(ADrawer, AExtent, AFirstPass, g^); axis.Measure(ADrawer, AExtent, g^);
ai += 1; ai += 1;
end; end;
if AFirstPass then Result[axis.Alignment] += g^.FSize + g^.FTitleSize;
AMargins[axis.Alignment] += g^.FSize + g^.FTitleSize;
end; end;
ai := 0; ai := 0;
for i := 0 to High(FGroups) do begin for i := 0 to High(FGroups) do begin
@ -872,12 +860,10 @@ begin
FAxis := AAxis; FAxis := AAxis;
FImageLo := AImageLo; FImageLo := AImageLo;
FImageHi := AImageHi; FImageHi := AImageHi;
FMarginLo := AMarginLo;
FMarginHi := AMarginHi;
FMin := AMin; FMin := AMin;
FMax := AMax; FMax := AMax;
FLo := FImageLo + FMarginLo; FLo := FImageLo + AMarginLo;
FHi := FImageHi + FMarginHi; FHi := FImageHi + AMarginHi;
end; end;
function TAxisCoeffHelper.CalcScale(ASign: Integer): Double; function TAxisCoeffHelper.CalcScale(ASign: Integer): Double;

View File

@ -1104,8 +1104,11 @@ end;
procedure TChart.PrepareAxis(ADrawer: IChartDrawer); procedure TChart.PrepareAxis(ADrawer: IChartDrawer);
var var
axisMargin: TChartAxisMargins = (0, 0, 0, 0); axisMargin: TChartAxisMargins;
a: TChartAxisAlignment; a: TChartAxisAlignment;
cr: TRect;
tries: Integer;
prevExt: TDoubleRect;
begin begin
if not AxisVisible then begin if not AxisVisible then begin
FClipRect.Left += Depth; FClipRect.Left += Depth;
@ -1114,15 +1117,24 @@ begin
exit; exit;
end; end;
// There is a cyclic dependency: extent -> visible marks -> margins.
// We recalculate them iteratively hoping that the process converges.
AxisList.PrepareGroups; AxisList.PrepareGroups;
AxisList.Measure(ADrawer, CurrentExtent, true, axisMargin); CalculateTransformationCoeffs(Rect(0, 0, 0, 0));
cr := FClipRect;
for tries := 1 to 10 do begin
axisMargin := AxisList.Measure(ADrawer, CurrentExtent);
axisMargin[calLeft] := Max(axisMargin[calLeft], Depth); axisMargin[calLeft] := Max(axisMargin[calLeft], Depth);
axisMargin[calBottom] := Max(axisMargin[calBottom], Depth); axisMargin[calBottom] := Max(axisMargin[calBottom], Depth);
FClipRect := cr;
for a := Low(a) to High(a) do for a := Low(a) to High(a) do
SideByAlignment(FClipRect, a, -axisMargin[a]); SideByAlignment(FClipRect, a, -axisMargin[a]);
prevExt := FCurrentExtent;
FCurrentExtent := FLogicalExtent;
CalculateTransformationCoeffs(GetMargins(ADrawer)); CalculateTransformationCoeffs(GetMargins(ADrawer));
AxisList.Measure(ADrawer, CurrentExtent, false, axisMargin); if prevExt = FCurrentExtent then break;
prevExt := FCurrentExtent;
end;
AxisList.Prepare(FClipRect); AxisList.Prepare(FClipRect);
end; end;