mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-11 17:55:55 +02:00
TAChart: Refactor axis marks generation
git-svn-id: trunk@31764 -
This commit is contained in:
parent
82d446ecb3
commit
de32d99c42
@ -33,13 +33,6 @@ const
|
||||
|
||||
type
|
||||
|
||||
TChartValueText = record
|
||||
FValue: Double;
|
||||
FText: String;
|
||||
end;
|
||||
|
||||
TChartValueTextArray = array of TChartValueText;
|
||||
|
||||
{ TChartMinorAxis }
|
||||
|
||||
TChartMinorAxis = class(TChartBasicAxis)
|
||||
@ -99,8 +92,7 @@ type
|
||||
TChartAxis = class(TChartBasicAxis)
|
||||
strict private
|
||||
FListener: TListener;
|
||||
FMarkTexts: TStringDynArray;
|
||||
FMarkValues: TDoubleDynArray;
|
||||
FMarkValues: TChartValueTextArray;
|
||||
|
||||
procedure GetMarkValues(AMin, AMax: Double);
|
||||
procedure VisitSource(ASource: TCustomChartSource; var AData);
|
||||
@ -413,35 +405,23 @@ begin
|
||||
end;
|
||||
|
||||
procedure TChartAxis.Draw;
|
||||
var
|
||||
i, j, fixedCoord: Integer;
|
||||
axisTransf: TTransformFunc;
|
||||
pv, v: Double;
|
||||
minorMarks: TChartValueTextArray;
|
||||
m: TChartValueText;
|
||||
begin
|
||||
if not Visible then exit;
|
||||
if Marks.Visible then
|
||||
FHelper.FDrawer.Font := Marks.LabelFont;
|
||||
fixedCoord := TChartAxisMargins(FAxisRect)[Alignment];
|
||||
v := 0;
|
||||
FHelper.BeginDrawing;
|
||||
FHelper.DrawAxisLine(AxisPen, fixedCoord);
|
||||
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;
|
||||
|
||||
procedure DrawMinors(AFixedCoord: Integer; AMin, AMax: Double);
|
||||
var
|
||||
j: Integer;
|
||||
minorMarks: TChartValueTextArray;
|
||||
m: TChartValueText;
|
||||
begin
|
||||
if IsNan(AMin) or (AMin = AMax) then exit;
|
||||
for j := 0 to Minors.Count - 1 do begin
|
||||
minorMarks := Minors[j].GetMarkValues(pv, v);
|
||||
minorMarks := Minors[j].GetMarkValues(AMin, AMax);
|
||||
if minorMarks = nil then continue;
|
||||
with FHelper.Clone do begin
|
||||
FAxis := Minors[j];
|
||||
try
|
||||
BeginDrawing;
|
||||
for m in minorMarks do
|
||||
DrawMark(fixedCoord, m.FValue, m.FText);
|
||||
DrawMark(AFixedCoord, m.FValue, m.FText);
|
||||
EndDrawing;
|
||||
finally
|
||||
Free;
|
||||
@ -449,6 +429,27 @@ begin
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
var
|
||||
fixedCoord: Integer;
|
||||
pv, v: Double;
|
||||
axisTransf: TTransformFunc;
|
||||
t: TChartValueText;
|
||||
begin
|
||||
if not Visible then exit;
|
||||
if Marks.Visible then
|
||||
FHelper.FDrawer.Font := Marks.LabelFont;
|
||||
fixedCoord := TChartAxisMargins(FAxisRect)[Alignment];
|
||||
pv := NaN;
|
||||
FHelper.BeginDrawing;
|
||||
FHelper.DrawAxisLine(AxisPen, fixedCoord);
|
||||
axisTransf := @GetTransform.AxisToGraph;
|
||||
for t in FMarkValues do begin
|
||||
v := axisTransf(t.FValue);
|
||||
FHelper.DrawMark(fixedCoord, v, t.FText);
|
||||
DrawMinors(fixedCoord, pv, v);
|
||||
pv := v;
|
||||
end;
|
||||
FHelper.EndDrawing;
|
||||
end;
|
||||
|
||||
@ -500,12 +501,12 @@ var
|
||||
i: Integer;
|
||||
d: TAxisDataExtent;
|
||||
vis: TChartOnVisitSources;
|
||||
t: TChartValueText;
|
||||
begin
|
||||
AMin := GetTransform.GraphToAxis(AMin);
|
||||
AMax := GetTransform.GraphToAxis(AMax);
|
||||
EnsureOrder(AMin, AMax);
|
||||
SetLength(FMarkValues, 0);
|
||||
SetLength(FMarkTexts, 0);
|
||||
vis := TChartAxisList(Collection).OnVisitSources;
|
||||
if Marks.AtDataOnly and Assigned(vis) then begin
|
||||
d.FMin := AMin;
|
||||
@ -514,16 +515,17 @@ begin
|
||||
end
|
||||
else
|
||||
Marks.SourceDef.ValuesInRange(
|
||||
AMin, AMax, Marks.Format, IsVertical, FMarkValues, FMarkTexts);
|
||||
AMin, AMax, Marks.Format, IsVertical, FMarkValues);
|
||||
if Inverted then
|
||||
for i := 0 to High(FMarkValues) div 2 do begin
|
||||
Exchange(FMarkValues[i], FMarkValues[High(FMarkValues) - i]);
|
||||
Exchange(FMarkTexts[i], FMarkTexts[High(FMarkValues) - i]);
|
||||
t := FMarkValues[i];
|
||||
FMarkValues[i] := FMarkValues[High(FMarkValues) - i];
|
||||
FMarkValues[High(FMarkValues) - i] := t;
|
||||
end;
|
||||
|
||||
if Assigned(FOnMarkToText) then
|
||||
for i := 0 to High(FMarkTexts) do
|
||||
FOnMarkToText(FMarkTexts[i], FMarkValues[i]);
|
||||
for i := 0 to High(FMarkValues) do
|
||||
FOnMarkToText(FMarkValues[i].FText, FMarkValues[i].FValue);
|
||||
end;
|
||||
|
||||
function TChartAxis.GetTransform: TChartAxisTransformations;
|
||||
@ -543,14 +545,14 @@ procedure TChartAxis.Measure(
|
||||
|
||||
function MaxMarksSize(AMin, AMax: Double): TPoint;
|
||||
var
|
||||
t: String;
|
||||
t: TChartValueText;
|
||||
begin
|
||||
Result := Point(0, 0);
|
||||
if AMin = AMax then exit;
|
||||
GetMarkValues(AMin, AMax);
|
||||
if not Marks.Visible then exit;
|
||||
for t in FMarkTexts do
|
||||
Result := MaxPoint(Marks.MeasureLabel(FHelper.FDrawer, t), Result);
|
||||
for t in FMarkValues do
|
||||
Result := MaxPoint(Marks.MeasureLabel(FHelper.FDrawer, t.FText), Result);
|
||||
end;
|
||||
|
||||
function TitleSize: Integer;
|
||||
@ -564,9 +566,9 @@ procedure TChartAxis.Measure(
|
||||
Result += FHelper.FDrawer.Scale(Title.Distance);
|
||||
end;
|
||||
|
||||
function FirstLastSize(AIndex: Integer): Integer;
|
||||
function FirstLastSize(AText: String): Integer;
|
||||
begin
|
||||
with Marks.MeasureLabel(FHelper.FDrawer, FMarkTexts[AIndex]) do
|
||||
with Marks.MeasureLabel(FHelper.FDrawer, AText) do
|
||||
Result := IfThen(IsVertical, cy, cx) div 2;
|
||||
end;
|
||||
|
||||
@ -581,6 +583,7 @@ procedure TChartAxis.Measure(
|
||||
|
||||
var
|
||||
sz, rmin, rmax, c, i: Integer;
|
||||
t: TChartValueText;
|
||||
begin
|
||||
if not Visible then exit;
|
||||
if IsVertical then
|
||||
@ -597,16 +600,17 @@ begin
|
||||
with AMeasureData do begin
|
||||
FSize := Max(sz, FSize);
|
||||
FTitleSize := Max(TitleSize, FTitleSize);
|
||||
for i := 0 to High(FMarkTexts) do begin
|
||||
c := FHelper.GraphToImage(FMarkValues[i]);
|
||||
for t in FMarkValues do begin
|
||||
c := FHelper.GraphToImage(t.FValue);
|
||||
if not InRange(c, rmin, rmax) then continue;
|
||||
FFirstMark := Max(FirstLastSize(i) - c + rmin, FFirstMark);
|
||||
FFirstMark := Max(FirstLastSize(t.FText) - c + rmin, FFirstMark);
|
||||
break;
|
||||
end;
|
||||
for i := High(FMarkTexts) downto 0 do begin
|
||||
c := FHelper.GraphToImage(FMarkValues[i]);
|
||||
for i := High(FMarkValues) downto 0 do begin
|
||||
t := FMarkValues[i];
|
||||
c := FHelper.GraphToImage(t.FValue);
|
||||
if not InRange(c, rmin, rmax) then continue;
|
||||
FLastMark := Max(FirstLastSize(i) - rmax + c, FLastMark);
|
||||
FLastMark := Max(FirstLastSize(t.FText) - rmax + c, FLastMark);
|
||||
break;
|
||||
end;
|
||||
if Arrow.Visible then begin
|
||||
@ -724,7 +728,7 @@ begin
|
||||
lmax := Min(ext.b.X, FMax);
|
||||
end;
|
||||
Marks.SourceDef.ValuesInRange(
|
||||
lmin, lmax, Marks.Format, IsVertical, FMarkValues, FMarkTexts);
|
||||
lmin, lmax, Marks.Format, IsVertical, FMarkValues);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
@ -29,6 +29,13 @@ type
|
||||
EEditableSourceRequired = class(EChartError);
|
||||
EYCountError = class(EChartError);
|
||||
|
||||
TChartValueText = record
|
||||
FValue: Double;
|
||||
FText: String;
|
||||
end;
|
||||
|
||||
TChartValueTextArray = array of TChartValueText;
|
||||
|
||||
{ TChartDataItem }
|
||||
|
||||
TChartDataItem = object
|
||||
@ -79,7 +86,7 @@ type
|
||||
function IsSorted: Boolean; virtual;
|
||||
procedure ValuesInRange(
|
||||
AMin, AMax: Double; const AFormat: String; AUseY: Boolean;
|
||||
var AValues: TDoubleDynArray; var ATexts: TStringDynArray); virtual;
|
||||
var AValues: TChartValueTextArray); virtual;
|
||||
function ValuesTotal: Double; virtual;
|
||||
function XOfMax: Double;
|
||||
function XOfMin: Double;
|
||||
@ -411,15 +418,15 @@ end;
|
||||
|
||||
procedure TCustomChartSource.ValuesInRange(
|
||||
AMin, AMax: Double; const AFormat: String; AUseY: Boolean;
|
||||
var AValues: TDoubleDynArray; var ATexts: TStringDynArray);
|
||||
var AValues: TChartValueTextArray);
|
||||
|
||||
var
|
||||
cnt: Integer;
|
||||
|
||||
procedure Push(AValue: Double; AIndex: Integer);
|
||||
begin
|
||||
AValues[cnt] := AValue;
|
||||
ATexts[cnt] := FormatItem(AFormat, AIndex, 0);
|
||||
AValues[cnt].FValue := AValue;
|
||||
AValues[cnt].FText := FormatItem(AFormat, AIndex, 0);
|
||||
cnt += 1;
|
||||
end;
|
||||
|
||||
@ -429,7 +436,6 @@ var
|
||||
begin
|
||||
cnt := Length(AValues);
|
||||
SetLength(AValues, cnt + Count + 2);
|
||||
SetLength(ATexts, cnt + Count + 2);
|
||||
v := 0;
|
||||
li := 0;
|
||||
for i := 0 to Count - 1 do begin
|
||||
@ -444,7 +450,6 @@ begin
|
||||
if not InRange(v, AMin, AMax) then
|
||||
Push(v, li);
|
||||
SetLength(AValues, cnt);
|
||||
SetLength(ATexts, cnt);
|
||||
end;
|
||||
|
||||
function TCustomChartSource.ValuesTotal: Double;
|
||||
|
@ -35,7 +35,7 @@ type
|
||||
public
|
||||
procedure ValuesInRange(
|
||||
AMin, AMax: Double; const AFormat: String; AUseY: Boolean;
|
||||
var AValues: TDoubleDynArray; var ATexts: TStringDynArray); override;
|
||||
var AValues: TChartValueTextArray); override;
|
||||
end;
|
||||
|
||||
TDateTimeStep = (
|
||||
@ -59,7 +59,7 @@ type
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
procedure ValuesInRange(
|
||||
AMin, AMax: Double; const AFormat: String; AUseY: Boolean;
|
||||
var AValues: TDoubleDynArray; var ATexts: TStringDynArray); override;
|
||||
var AValues: TChartValueTextArray); override;
|
||||
published
|
||||
property DateTimeFormat: String read FDateTimeFormat write FDateTimeFormat;
|
||||
property Steps: TDateTimeSteps
|
||||
@ -144,7 +144,8 @@ begin
|
||||
end; {case AxisScale}
|
||||
end;
|
||||
|
||||
function GetIntervals(AMin, AMax: Double; AInverted: Boolean): TDoubleDynArray;
|
||||
function GetIntervals(
|
||||
AMin, AMax: Double; AInverted: Boolean): TChartValueTextArray;
|
||||
const
|
||||
INV_TO_SCALE: array [Boolean] of TAxisScale = (asIncreasing, asDecreasing);
|
||||
var
|
||||
@ -169,12 +170,12 @@ begin
|
||||
repeat
|
||||
if IsZero(m) then
|
||||
m := 0;
|
||||
Result[markCount] := m;
|
||||
Result[markCount].FValue := m;
|
||||
markCount += 1;
|
||||
crossCount += Ord(InRange(m, AMin, AMax) <> InRange(m + step, AMin, AMax));
|
||||
m += step;
|
||||
until (crossCount = 2) or (m + step = m);
|
||||
Result[markCount] := m;
|
||||
Result[markCount].FValue := m;
|
||||
end;
|
||||
|
||||
procedure Register;
|
||||
@ -206,17 +207,16 @@ end;
|
||||
|
||||
procedure TIntervalChartSource.ValuesInRange(
|
||||
AMin, AMax: Double; const AFormat: String; AUseY: Boolean;
|
||||
var AValues: TDoubleDynArray; var ATexts: TStringDynArray);
|
||||
var AValues: TChartValueTextArray);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
Unused(AUseY);
|
||||
if AMin > AMax then exit;
|
||||
AValues := GetIntervals(AMin, AMax, false);
|
||||
SetLength(ATexts, Length(AValues));
|
||||
for i := 0 to High(AValues) do
|
||||
// Extra format arguments for compatibility with FormatItem.
|
||||
ATexts[i] := Format(AFormat, [AValues[i], 0.0, '', 0.0, 0.0]);
|
||||
AValues[i].FText := Format(AFormat, [AValues[i].FValue, 0.0, '', 0.0, 0.0]);
|
||||
end;
|
||||
|
||||
{ TDateTimeIntervalChartSource }
|
||||
@ -227,9 +227,9 @@ begin
|
||||
FSteps := DATE_TIME_STEPS_ALL;
|
||||
end;
|
||||
|
||||
procedure TDateTimeIntervalChartSource.ValuesInRange(AMin, AMax: Double;
|
||||
const AFormat: String; AUseY: Boolean; var AValues: TDoubleDynArray;
|
||||
var ATexts: TStringDynArray);
|
||||
procedure TDateTimeIntervalChartSource.ValuesInRange(
|
||||
AMin, AMax: Double; const AFormat: String; AUseY: Boolean;
|
||||
var AValues: TChartValueTextArray);
|
||||
const
|
||||
YEAR = 365.25;
|
||||
STEP_INTERVALS: array [TDateTimeStep] of Double = (
|
||||
@ -284,7 +284,7 @@ begin
|
||||
if (AMax - AMin) / STEP_INTERVALS[dtsCentury] > MAX_STEPS then begin
|
||||
inherited ValuesInRange(
|
||||
AMin / STEP_INTERVALS[dtsYear], AMax / STEP_INTERVALS[dtsYear],
|
||||
AFormat, AUseY, AValues, ATexts);
|
||||
AFormat, AUseY, AValues);
|
||||
exit;
|
||||
end;
|
||||
s := Low(s);
|
||||
@ -303,13 +303,12 @@ begin
|
||||
end;
|
||||
i := Length(AValues);
|
||||
SetLength(AValues, i + cnt);
|
||||
SetLength(ATexts, i + cnt);
|
||||
|
||||
FillChar(prevSt, SizeOf(prevSt), $FF);
|
||||
x := start;
|
||||
while x <= AMax do begin
|
||||
AValues[i] := x;
|
||||
ATexts[i] := Format(AFormat, [x, 0.0, FormatLabel, 0.0, 0.0]);
|
||||
AValues[i].FValue := x;
|
||||
AValues[i].FText := Format(AFormat, [x, 0.0, FormatLabel, 0.0, 0.0]);
|
||||
i += 1;
|
||||
case s of
|
||||
dtsCentury: x := IncYear(x, 100);
|
||||
@ -319,8 +318,8 @@ begin
|
||||
otherwise x += si;
|
||||
end;
|
||||
end;
|
||||
AValues[i] := x;
|
||||
ATexts[i] := Format(AFormat, [x, 0.0, FormatLabel, 0.0, 0.0]);
|
||||
AValues[i].FValue := x;
|
||||
AValues[i].FText := Format(AFormat, [x, 0.0, FormatLabel, 0.0, 0.0]);
|
||||
end;
|
||||
|
||||
end.
|
||||
|
Loading…
Reference in New Issue
Block a user