mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-26 10:19:14 +02:00
TAChart: Refactoring of chart sources for sorting. TListChartSource now can be sorted by X, Y, Text, etc. Issue #35356, modified patch by Marcin Wiazowski.
git-svn-id: trunk@60972 -
This commit is contained in:
parent
b03fd14109
commit
6908af06b3
components/tachart
languages
tachartstrconsts.de.potachartstrconsts.fi.potachartstrconsts.fr.potachartstrconsts.hu.potachartstrconsts.lt.potachartstrconsts.pl.potachartstrconsts.pottachartstrconsts.pt_BR.potachartstrconsts.ru.potachartstrconsts.se.potachartstrconsts.uk.potachartstrconsts.zh_CN.po
tachartstrconsts.pastacustomseries.pastacustomsource.pastamultiseries.pastasources.pas@ -471,6 +471,10 @@ msgstr "Diese %0:s-Instanz muss mindestens %1:d %2:s-Wert(e) pro Datenpunkt zur
|
||||
msgid "Editable chart source required"
|
||||
msgstr "Editierbare Chart-Datenquelle erforderlich"
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "Stern (Linien)"
|
||||
|
@ -459,6 +459,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr ""
|
||||
|
@ -469,6 +469,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "Étoile (lignes)"
|
||||
|
@ -469,6 +469,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "Csillag (vonalak)"
|
||||
|
@ -470,6 +470,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "Žvaigždės (linijos)"
|
||||
|
@ -468,6 +468,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr ""
|
||||
|
@ -459,6 +459,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr ""
|
||||
|
@ -469,6 +469,10 @@ msgstr "Esta instância %0:s deve ter ao menos %1:d %2:s valor(es) por ponto de
|
||||
msgid "Editable chart source required"
|
||||
msgstr "Fonte editável de gráfico requerida"
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "Estrela (linhas)"
|
||||
|
@ -469,6 +469,10 @@ msgstr "Этот экземпляр %0:s должен иметь не менее
|
||||
msgid "Editable chart source required"
|
||||
msgstr "Требуется доступный для редактирования источник данных для диаграммы"
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "Звезда (из линий)"
|
||||
|
@ -472,6 +472,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr ""
|
||||
|
@ -472,6 +472,10 @@ msgstr "Цей примірник %0:s повинен мати принаймн
|
||||
msgid "Editable chart source required"
|
||||
msgstr "Потрібне джерело діаграми, доступне для редагування"
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "Зірка (з ліній)"
|
||||
|
@ -470,6 +470,10 @@ msgstr ""
|
||||
msgid "Editable chart source required"
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rssourcesorterror
|
||||
msgid "Selected sorting parameters are not supported by %s."
|
||||
msgstr ""
|
||||
|
||||
#: tachartstrconsts.rsstarsymbol
|
||||
msgid "Star (lines)"
|
||||
msgstr "星(线)"
|
||||
|
@ -78,12 +78,12 @@ resourcestring
|
||||
rsSourceNotEditable = 'Editable chart source required';
|
||||
rsSourceCountError = '%0:s requires a chart source with at least %1:d %2:s value(s) per data point.';
|
||||
rsSourceCountError2 = 'This %0:s instance must have at least %1:d %2:s value(s) per data point.';
|
||||
rsSourceSortError = 'Selected sorting parameters are not supported by %s.';
|
||||
rsListSourceStringFormatError = 'The data value count in the %0:s.DataPoints '+
|
||||
'string "%1:s" differs from what is expected from XCount and YCount.';
|
||||
rsListSourceNumericError = 'The %0:s.DataPoints string "%1:s" is not a valid number.';
|
||||
rsListSourceColorError = 'The %0:s.DataPoints string "%1:s" is not an integer.';
|
||||
|
||||
|
||||
// Transformations
|
||||
tasAxisTransformsEditorTitle = 'Edit axis transformations';
|
||||
rsAutoScale = 'Auto scale';
|
||||
|
@ -1940,15 +1940,15 @@ begin
|
||||
{FLoBound and FUpBound fields may be outdated here (if axis' range has been
|
||||
changed after the last series' painting). FLoBound and FUpBound will be fully
|
||||
updated later, in a PrepareGraphPoints() call. But we need them now. If data
|
||||
source is sorted, obtaining FLoBound and FUpBound is very fast (binary search) -
|
||||
so we call FindExtentInterval() with True as the second parameter. If data
|
||||
source is not sorted, obtaining FLoBound and FUpBound requires enumerating all
|
||||
the data points to see, if they are in the current chart's viewport. But this
|
||||
is exactly what we are going to do in the loop below, so obtaining true FLoBound
|
||||
and FUpBound values makes no sense in this case - so we call FindExtentInterval()
|
||||
with False as the second parameter, thus setting FLoBound to 0 and FUpBound to
|
||||
Count-1}
|
||||
FindExtentInterval(ParentChart.CurrentExtent, Source.IsSorted);
|
||||
source is sorted by X in the ascending order, obtaining FLoBound and FUpBound
|
||||
is very fast (binary search) - so we call FindExtentInterval() with True as
|
||||
the second parameter. Otherwise, obtaining FLoBound and FUpBound requires
|
||||
enumerating all the data points to see, if they are in the current chart's
|
||||
viewport. But this is exactly what we are going to do in the loop below, so
|
||||
obtaining true FLoBound and FUpBound values makes no sense in this case - so
|
||||
we call FindExtentInterval() with False as the second parameter, thus setting
|
||||
FLoBound to 0 and FUpBound to Count-1}
|
||||
FindExtentInterval(ParentChart.CurrentExtent, Source.IsSortedByXAsc);
|
||||
|
||||
with Extent do
|
||||
center := AxisToGraphY((a.y + b.y) * 0.5);
|
||||
|
@ -71,9 +71,10 @@ type
|
||||
type
|
||||
EBufferError = class(EChartError);
|
||||
EEditableSourceRequired = class(EChartError);
|
||||
EListSourceStringError = class(EChartError);
|
||||
ESortError = class(EChartError);
|
||||
EXCountError = class(EChartError);
|
||||
EYCountError = class(EChartError);
|
||||
EListSourceStringError = class(EChartError);
|
||||
|
||||
TChartValueText = record
|
||||
FText: String;
|
||||
@ -175,9 +176,11 @@ type
|
||||
property IndexPlus: Integer index 0 read GetIndex write SetIndex default -1;
|
||||
property ValueMinus: Double index 1 read GetValue write SetValue stored IsErrorBarValueStored;
|
||||
property ValuePlus: Double index 0 read GetValue write SetValue stored IsErrorBarValueStored;
|
||||
|
||||
end;
|
||||
|
||||
TChartSortBy = (sbX, sbY, sbColor, sbText, sbCustom);
|
||||
TChartSortDir = (sdAscending, sdDescending);
|
||||
|
||||
TCustomChartSource = class(TBasicChartSource)
|
||||
strict private
|
||||
FErrorBarData: array[0..1] of TChartErrorBarData;
|
||||
@ -197,6 +200,9 @@ type
|
||||
FYListExtentIsValid: Boolean;
|
||||
FValuesTotal: Double;
|
||||
FValuesTotalIsValid: Boolean;
|
||||
FSortBy: TChartSortBy;
|
||||
FSortDir: TChartSortDir;
|
||||
FSortIndex: Cardinal;
|
||||
FXCount: Cardinal;
|
||||
FYCount: Cardinal;
|
||||
function CalcExtentXYList(UseXList: Boolean): TDoubleRect;
|
||||
@ -207,12 +213,19 @@ type
|
||||
function GetHasErrorBars(Which: Integer): Boolean;
|
||||
function GetItem(AIndex: Integer): PChartDataItem; virtual; abstract;
|
||||
procedure InvalidateCaches;
|
||||
procedure SetSortBy(AValue: TChartSortBy); virtual;
|
||||
procedure SetSortDir(AValue: TChartSortDir); virtual;
|
||||
procedure SetSortIndex(AValue: Cardinal); virtual;
|
||||
procedure SetXCount(AValue: Cardinal); virtual; abstract;
|
||||
procedure SetYCount(AValue: Cardinal); virtual; abstract;
|
||||
property XErrorBarData: TChartErrorBarData index 0 read GetErrorBarData
|
||||
write SetErrorBarData stored IsErrorBarDataStored;
|
||||
property YErrorBarData: TChartErrorBarData index 1 read GetErrorBarData
|
||||
write SetErrorBarData stored IsErrorBarDataStored;
|
||||
protected
|
||||
property SortBy: TChartSortBy read FSortBy write SetSortBy default sbX;
|
||||
property SortDir: TChartSortDir read FSortDir write SetSortDir default sdAscending;
|
||||
property SortIndex: Cardinal read FSortIndex write SetSortIndex default 0;
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
@ -247,6 +260,7 @@ type
|
||||
function IsXErrorIndex(AXIndex: Integer): Boolean;
|
||||
function IsYErrorIndex(AYIndex: Integer): Boolean;
|
||||
function IsSorted: Boolean; virtual;
|
||||
function IsSortedByXAsc: Boolean;
|
||||
procedure ValuesInRange(
|
||||
AParams: TValuesInRangeParams; var AValues: TChartValueTextArray); virtual;
|
||||
function ValuesTotal: Double; virtual;
|
||||
@ -288,7 +302,7 @@ procedure SetDataItemDefaults(var AItem: TChartDataItem);
|
||||
implementation
|
||||
|
||||
uses
|
||||
Math, StrUtils, SysUtils, TAMath;
|
||||
Math, StrUtils, SysUtils, TAMath, TAChartStrConsts;
|
||||
|
||||
function CompareChartValueTextPtr(AItem1, AItem2: Pointer): Integer;
|
||||
begin
|
||||
@ -895,8 +909,6 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
class procedure TCustomChartSource.CheckFormat(const AFormat: String);
|
||||
begin
|
||||
Format(AFormat, [0.0, 0.0, '', 0.0, 0.0]);
|
||||
@ -907,6 +919,9 @@ var
|
||||
i: Integer;
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FSortBy := sbX;
|
||||
FSortDir := sdAscending;
|
||||
FSortIndex := 0;
|
||||
FXCount := 1;
|
||||
FYCount := 1;
|
||||
for i:=Low(FErrorBarData) to High(FErrorBarData) do begin
|
||||
@ -1011,7 +1026,8 @@ end;
|
||||
|
||||
// ALB -> leftmost item where X >= AXMin, or Count if no such item
|
||||
// ALB -> rightmost item where X <= AXMax, or -1 if no such item
|
||||
// If the source is sorted, performs binary search. Otherwise, skips NaNs.
|
||||
// If the source is sorted by X in the ascending order, performs
|
||||
// binary search. Otherwise, skips NaNs.
|
||||
procedure TCustomChartSource.FindBounds(
|
||||
AXMin, AXMax: Double; out ALB, AUB: Integer);
|
||||
|
||||
@ -1041,7 +1057,7 @@ procedure TCustomChartSource.FindBounds(
|
||||
|
||||
begin
|
||||
EnsureOrder(AXMin, AXMax);
|
||||
if IsSorted then begin
|
||||
if IsSortedByXAsc then begin
|
||||
ALB := FindLB(AXMin, 0, Count - 1);
|
||||
AUB := FindUB(AXMax, 0, Count - 1);
|
||||
end
|
||||
@ -1250,6 +1266,16 @@ begin
|
||||
Result := (FIndex[AIndex] <> -1) or (FValue[AIndex] <> -1) or (FKind <> ebkNone);
|
||||
end;
|
||||
|
||||
function TCustomChartSource.IsSorted: Boolean; inline;
|
||||
begin
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
function TCustomChartSource.IsSortedByXAsc: Boolean;
|
||||
begin
|
||||
Result := IsSorted and (FSortBy = sbX) and (FSortDir = sdAscending) and (FSortIndex = 0);
|
||||
end;
|
||||
|
||||
function TCustomChartSource.IsXErrorIndex(AXIndex: Integer): Boolean;
|
||||
begin
|
||||
Result :=
|
||||
@ -1267,11 +1293,6 @@ begin
|
||||
(AYIndex > -1);
|
||||
end;
|
||||
|
||||
function TCustomChartSource.IsSorted: Boolean;
|
||||
begin
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
procedure TCustomChartSource.SetErrorBarData(AIndex: Integer;
|
||||
AValue: TChartErrorBarData);
|
||||
begin
|
||||
@ -1279,6 +1300,24 @@ begin
|
||||
Notify;
|
||||
end;
|
||||
|
||||
procedure TCustomChartSource.SetSortBy(AValue: TChartSortBy);
|
||||
begin
|
||||
if FSortBy <> AValue then
|
||||
raise ESortError.CreateFmt(rsSourceSortError, [ClassName]);
|
||||
end;
|
||||
|
||||
procedure TCustomChartSource.SetSortDir(AValue: TChartSortDir);
|
||||
begin
|
||||
if FSortDir <> AValue then
|
||||
raise ESortError.CreateFmt(rsSourceSortError, [ClassName]);
|
||||
end;
|
||||
|
||||
procedure TCustomChartSource.SetSortIndex(AValue: Cardinal);
|
||||
begin
|
||||
if FSortIndex <> AValue then
|
||||
raise ESortError.CreateFmt(rsSourceSortError, [ClassName]);
|
||||
end;
|
||||
|
||||
procedure TCustomChartSource.SortValuesInRange(
|
||||
var AValues: TChartValueTextArray; AStart, AEnd: Integer);
|
||||
var
|
||||
@ -1421,7 +1460,7 @@ begin
|
||||
cnt += 1;
|
||||
end;
|
||||
|
||||
if not IsSorted and not IsValueTextsSorted(AValues, start, cnt - 1) then begin
|
||||
if not IsSortedByXAsc and not IsValueTextsSorted(AValues, start, cnt - 1) then begin
|
||||
SortValuesInRange(AValues, start, cnt - 1);
|
||||
if aipUseMinLength in AParams.FIntervals.Options then
|
||||
cnt := EnsureMinLength(start, cnt - 1);
|
||||
|
@ -879,7 +879,7 @@ begin
|
||||
if Count = 0 then exit;
|
||||
if not RequestValidChartScaling then exit;
|
||||
|
||||
FindExtentInterval(ParentChart.CurrentExtent, Source.IsSorted);
|
||||
FindExtentInterval(ParentChart.CurrentExtent, Source.IsSortedByXAsc);
|
||||
with Extent do
|
||||
center := AxisToGraphY((a.y + b.y) * 0.5);
|
||||
UpdateLabelDirectionReferenceLevel(0, 0, center);
|
||||
|
@ -19,13 +19,33 @@ uses
|
||||
Classes, Types, TAChartUtils, TACustomSource;
|
||||
|
||||
type
|
||||
{ TListChartSource }
|
||||
TChartSortCompare = function(AItem1, AItem2: Pointer): Integer of object;
|
||||
|
||||
TListChartSource = class(TCustomChartSource)
|
||||
{ TCustomSortedChartSource }
|
||||
|
||||
TCustomSortedChartSource = class(TCustomChartSource)
|
||||
private
|
||||
FOnCompare: TChartSortCompare;
|
||||
procedure SetSorted(AValue: Boolean);
|
||||
protected
|
||||
FData: TFPList;
|
||||
FDataPoints: TStrings;
|
||||
FSorted: Boolean;
|
||||
function DefaultCompare(AItem1, AItem2: Pointer): Integer; virtual; abstract;
|
||||
procedure ExecSort(ACompare: TChartSortCompare); virtual;
|
||||
procedure SetSortBy(AValue: TChartSortBy); override;
|
||||
procedure SetSortDir(AValue: TChartSortDir); override;
|
||||
procedure SetSortIndex(AValue: Cardinal); override;
|
||||
property Sorted: Boolean read FSorted write SetSorted default false;
|
||||
property OnCompare: TChartSortCompare read FOnCompare write FOnCompare;
|
||||
public
|
||||
function IsSorted: Boolean; override;
|
||||
procedure Sort;
|
||||
end;
|
||||
|
||||
{ TListChartSource }
|
||||
TListChartSource = class(TCustomSortedChartSource)
|
||||
private
|
||||
FDataPoints: TStrings;
|
||||
FXCountMin: Cardinal;
|
||||
FYCountMin: Cardinal;
|
||||
procedure AddAt(
|
||||
@ -33,9 +53,9 @@ type
|
||||
procedure ClearCaches;
|
||||
function NewItem: PChartDataItem;
|
||||
procedure SetDataPoints(AValue: TStrings);
|
||||
procedure SetSorted(AValue: Boolean);
|
||||
procedure UpdateCachesAfterAdd(AX, AY: Double);
|
||||
protected
|
||||
function DefaultCompare(AItem1, AItem2: Pointer): Integer; override;
|
||||
function GetCount: Integer; override;
|
||||
function GetItem(AIndex: Integer): PChartDataItem; override;
|
||||
procedure Loaded; override;
|
||||
@ -61,23 +81,24 @@ type
|
||||
procedure Clear;
|
||||
procedure CopyFrom(ASource: TCustomChartSource);
|
||||
procedure Delete(AIndex: Integer);
|
||||
function IsSorted: Boolean; override;
|
||||
|
||||
procedure SetColor(AIndex: Integer; AColor: TChartColor);
|
||||
procedure SetText(AIndex: Integer; AValue: String);
|
||||
function SetXValue(AIndex: Integer; AValue: Double): Integer;
|
||||
procedure SetXList(AIndex: Integer; const AXList: array of Double);
|
||||
procedure SetYList(AIndex: Integer; const AYList: array of Double);
|
||||
procedure SetYValue(AIndex: Integer; AValue: Double);
|
||||
|
||||
procedure Sort;
|
||||
published
|
||||
property DataPoints: TStrings read FDataPoints write SetDataPoints;
|
||||
property Sorted: Boolean read FSorted write SetSorted default false;
|
||||
property XCount;
|
||||
property XErrorBarData;
|
||||
property YCount;
|
||||
property YErrorBarData;
|
||||
// Sorting
|
||||
property SortBy;
|
||||
property SortDir;
|
||||
property Sorted;
|
||||
property SortIndex;
|
||||
property OnCompare;
|
||||
end;
|
||||
|
||||
{ TMWCRandomGenerator }
|
||||
@ -203,6 +224,7 @@ type
|
||||
FOriginYCount: Cardinal;
|
||||
FPercentage: Boolean;
|
||||
FReorderYList: String;
|
||||
FSorted: Boolean;
|
||||
FYOrder: array of Integer;
|
||||
|
||||
procedure CalcAccumulation(AIndex: Integer);
|
||||
@ -228,7 +250,6 @@ type
|
||||
public
|
||||
constructor Create(AOwner: TComponent); override;
|
||||
destructor Destroy; override;
|
||||
|
||||
function IsSorted: Boolean; override;
|
||||
published
|
||||
property AccumulationDirection: TChartAccumulationDirection
|
||||
@ -253,6 +274,7 @@ uses
|
||||
Math, StrUtils, SysUtils, TAMath, TAChartStrConsts;
|
||||
|
||||
type
|
||||
TCustomChartSourceAccess = class(TCustomChartSource);
|
||||
|
||||
{ TListChartSourceStrings }
|
||||
|
||||
@ -276,6 +298,18 @@ type
|
||||
procedure Insert(Index: Integer; const S: String); override;
|
||||
end;
|
||||
|
||||
function CompareFloat(x1, x2: Double): Integer;
|
||||
begin
|
||||
if IsNaN(x1) and IsNaN(x2) then
|
||||
Result := 0
|
||||
else if IsNaN(x1) then
|
||||
Result := +1
|
||||
else if IsNaN(x2) then
|
||||
Result := -1
|
||||
else
|
||||
Result := CompareValue(x1, x2);
|
||||
end;
|
||||
|
||||
procedure Register;
|
||||
begin
|
||||
RegisterComponents(
|
||||
@ -285,6 +319,7 @@ begin
|
||||
]);
|
||||
end;
|
||||
|
||||
|
||||
{ TListChartSourceStrings }
|
||||
|
||||
procedure TListChartSourceStrings.Clear;
|
||||
@ -484,13 +519,106 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TCustomSortedChartSource }
|
||||
|
||||
{ Built-in sorting algorithm of the ChartSource, a standard QuickSort.
|
||||
Copied from the classes unit because the compare function must be a method. }
|
||||
procedure TCustomSortedChartSource.ExecSort(ACompare: TChartSortCompare);
|
||||
|
||||
procedure QuickSort(L, R: Longint);
|
||||
var
|
||||
I, J : Longint;
|
||||
P, Q : Pointer;
|
||||
begin
|
||||
repeat
|
||||
I := L;
|
||||
J := R;
|
||||
P := FData[(L + R) div 2];
|
||||
repeat
|
||||
while ACompare(P, FData[i]) > 0 do
|
||||
I := I + 1;
|
||||
while ACompare(P, FData[J]) < 0 do
|
||||
J := J - 1;
|
||||
If I <= J then
|
||||
begin
|
||||
Q := FData[I];
|
||||
FData[I] := FData[J];
|
||||
FData[J] := Q;
|
||||
I := I + 1;
|
||||
J := J - 1;
|
||||
end;
|
||||
until I > J;
|
||||
if J - L < R - I then
|
||||
begin
|
||||
if L < J then
|
||||
QuickSort(L, J);
|
||||
L := I;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if I < R then
|
||||
QuickSort(I, R);
|
||||
R := J;
|
||||
end;
|
||||
until L >= R;
|
||||
end;
|
||||
|
||||
begin
|
||||
if FData.Count < 2 then exit;
|
||||
QuickSort(0, FData.Count-1);
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.IsSorted: Boolean; inline;
|
||||
begin
|
||||
Result := FSorted;
|
||||
end;
|
||||
|
||||
procedure TCustomSortedChartSource.SetSortBy(AValue: TChartSortBy);
|
||||
begin
|
||||
if FSortBy = AValue then exit;
|
||||
FSortBy := AValue;
|
||||
Sort;
|
||||
end;
|
||||
|
||||
procedure TCustomSortedChartSource.SetSorted(AValue: Boolean);
|
||||
begin
|
||||
if FSorted = AValue then exit;
|
||||
FSorted := AValue;
|
||||
Sort;
|
||||
end;
|
||||
|
||||
procedure TCustomSortedChartSource.SetSortDir(AValue: TChartSortDir);
|
||||
begin
|
||||
if FSortDir = AValue then exit;
|
||||
FSortDir := AValue;
|
||||
Sort;
|
||||
end;
|
||||
|
||||
procedure TCustomSortedChartSource.SetSortIndex(AValue: Cardinal);
|
||||
begin
|
||||
if FSortIndex = AValue then exit;
|
||||
FSortIndex := AValue;
|
||||
Sort;
|
||||
end;
|
||||
|
||||
procedure TCustomSortedChartSource.Sort;
|
||||
begin
|
||||
if (FSortBy = sbCustom) then begin
|
||||
if Assigned(FOnCompare) then ExecSort(FOnCompare);
|
||||
end else
|
||||
ExecSort(@DefaultCompare);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
|
||||
{ TListChartSource }
|
||||
|
||||
function TListChartSource.Add(
|
||||
AX, AY: Double; const ALabel: String; AColor: TChartColor): Integer;
|
||||
begin
|
||||
Result := FData.Count;
|
||||
if Sorted then
|
||||
if IsSortedByXAsc then
|
||||
// Keep data points ordered by X coordinate.
|
||||
// Note that this leads to O(N^2) time except
|
||||
// for the case of adding already ordered points.
|
||||
@ -603,7 +731,17 @@ begin
|
||||
SetXList(FData.Count - 1, XList);
|
||||
SetYList(FData.Count - 1, YList);
|
||||
end;
|
||||
if Sorted and not ASource.IsSorted then Sort;
|
||||
|
||||
if IsSorted then begin
|
||||
if ASource.IsSorted and
|
||||
(SortBy = TCustomChartSourceAccess(ASource).SortBy) and
|
||||
(SortDir = TCustomChartSourceAccess(ASource).SortDir) and
|
||||
(SortIndex = TCustomChartSourceAccess(ASource).SortIndex) and
|
||||
(SortBy <> sbCustom)
|
||||
then
|
||||
exit;
|
||||
Sort;
|
||||
end;
|
||||
finally
|
||||
EndUpdate;
|
||||
end;
|
||||
@ -628,6 +766,21 @@ begin
|
||||
FYCount := FYCountMin;
|
||||
end;
|
||||
|
||||
function TListChartSource.DefaultCompare(AItem1, AItem2: Pointer): Integer;
|
||||
var
|
||||
item1: PChartDataItem absolute AItem1;
|
||||
item2: PChartDataItem absolute AItem2;
|
||||
begin
|
||||
case FSortBy of
|
||||
sbX: Result := CompareFloat(item1^.GetX(FSortIndex), item2^.GetX(FSortIndex));
|
||||
sbY: Result := CompareFloat(item1^.GetY(FSortIndex), item2^.GetY(FSortIndex));
|
||||
sbColor: Result := CompareValue(item1^.Color, item2^.Color);
|
||||
sbText: Result := CompareText(item1^.Text, item2^.Text);
|
||||
sbCustom: Result := FOnCompare(AItem1, AItem2);
|
||||
end;
|
||||
if FSortDir = sdDescending then Result := -Result;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.Delete(AIndex: Integer);
|
||||
begin
|
||||
// Optimization
|
||||
@ -670,11 +823,6 @@ begin
|
||||
Result := PChartDataItem(FData.Items[AIndex]);
|
||||
end;
|
||||
|
||||
function TListChartSource.IsSorted: Boolean;
|
||||
begin
|
||||
Result := Sorted;
|
||||
end;
|
||||
|
||||
function TListChartSource.NewItem: PChartDataItem;
|
||||
begin
|
||||
New(Result);
|
||||
@ -697,19 +845,12 @@ begin
|
||||
BeginUpdate;
|
||||
try
|
||||
FDataPoints.Assign(AValue);
|
||||
if Sorted then Sort;
|
||||
if IsSorted then Sort;
|
||||
finally
|
||||
EndUpdate;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.SetSorted(AValue: Boolean);
|
||||
begin
|
||||
if FSorted = AValue then exit;
|
||||
FSorted := AValue;
|
||||
if Sorted then Sort;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.SetText(AIndex: Integer; AValue: String);
|
||||
begin
|
||||
with Item[AIndex]^ do begin
|
||||
@ -766,7 +907,7 @@ var
|
||||
end;
|
||||
|
||||
begin
|
||||
if Sorted then
|
||||
if IsSortedByXAsc then
|
||||
if IsNan(AValue) then
|
||||
raise EChartError.CreateFmt('X = NaN in sorted source %s', [NameOrClassName(Self)]);
|
||||
oldX := Item[AIndex]^.X;
|
||||
@ -774,7 +915,7 @@ begin
|
||||
if IsEquivalent(oldX, AValue) then exit;
|
||||
Item[AIndex]^.X := AValue;
|
||||
UpdateExtent;
|
||||
if Sorted then begin
|
||||
if IsSortedByXAsc then begin
|
||||
if AValue > oldX then
|
||||
while (Result < Count - 1) and (Item[Result + 1]^.X < AValue) do
|
||||
Inc(Result)
|
||||
@ -844,32 +985,6 @@ begin
|
||||
Notify;
|
||||
end;
|
||||
|
||||
function CompareFloat(x1, x2: Double): Integer;
|
||||
begin
|
||||
if IsNaN(x1) and IsNaN(x2) then
|
||||
Result := 0
|
||||
else if IsNaN(x1) then
|
||||
Result := +1
|
||||
else if IsNaN(x2) then
|
||||
Result := -1
|
||||
else
|
||||
Result := CompareValue(x1, x2);
|
||||
end;
|
||||
|
||||
function CompareDataItemX(AItem1, AItem2: Pointer): Integer;
|
||||
var
|
||||
item1: PChartDataItem absolute AItem1;
|
||||
item2: PChartDataItem absolute AItem2;
|
||||
begin
|
||||
Result := CompareFloat(item1^.X, item2^.X);
|
||||
end;
|
||||
|
||||
procedure TListChartSource.Sort;
|
||||
begin
|
||||
FData.Sort(@CompareDataItemX);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.UpdateCachesAfterAdd(AX, AY: Double);
|
||||
begin
|
||||
if IsUpdating then exit; // Optimization
|
||||
@ -1035,7 +1150,7 @@ begin
|
||||
Result := @FCurItem;
|
||||
end;
|
||||
|
||||
function TRandomChartSource.IsSorted: Boolean;
|
||||
function TRandomChartSource.IsSorted: Boolean; inline;
|
||||
begin
|
||||
Result := not RandomX;
|
||||
end;
|
||||
@ -1142,9 +1257,9 @@ begin
|
||||
Result := @FItem;
|
||||
end;
|
||||
|
||||
function TUserDefinedChartSource.IsSorted: Boolean;
|
||||
function TUserDefinedChartSource.IsSorted: Boolean; inline;
|
||||
begin
|
||||
Result := Sorted;
|
||||
Result := FSorted;
|
||||
end;
|
||||
|
||||
procedure TUserDefinedChartSource.Reset;
|
||||
@ -1350,6 +1465,22 @@ end;
|
||||
|
||||
procedure TCalculatedChartSource.Changed(ASender: TObject);
|
||||
begin
|
||||
if FOrigin <> nil then begin
|
||||
FSortBy := TCustomChartSourceAccess(Origin).SortBy;
|
||||
FSortDir := TCustomChartSourceAccess(Origin).SortDir;
|
||||
FSortIndex := TCustomChartSourceAccess(Origin).SortIndex;
|
||||
// We recalculate Y values, so we can't guarantee, that transformed
|
||||
// data is still sorted by Y or by Origin's custom algorithm
|
||||
FSorted := (FSortBy in [sbX, sbColor, sbText]) and Origin.IsSorted;
|
||||
FXCount := Origin.XCount;
|
||||
end else begin
|
||||
FSortBy := sbX;
|
||||
FSortDir := sdAscending;
|
||||
FSortIndex := 0;
|
||||
FSorted := false;
|
||||
FXCount := 0;
|
||||
end;
|
||||
|
||||
if
|
||||
(FOrigin <> nil) and (ASender = FOrigin) and
|
||||
(FOrigin.YCount <> FOriginYCount)
|
||||
@ -1437,10 +1568,7 @@ end;
|
||||
|
||||
function TCalculatedChartSource.IsSorted: Boolean;
|
||||
begin
|
||||
if Origin <> nil then
|
||||
Result := Origin.IsSorted
|
||||
else
|
||||
Result := false;
|
||||
Result := FSorted;
|
||||
end;
|
||||
|
||||
procedure TCalculatedChartSource.RangeAround(
|
||||
|
Loading…
Reference in New Issue
Block a user