mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-12-21 07:40:29 +01:00
TAChart: Calculate transformation coefficients iteratively
git-svn-id: trunk@31709 -
This commit is contained in:
parent
f13bf300dd
commit
d4b0f89e8f
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user