TAChart: Refactoring of chart sources for sorting. TListChartSource now can be sorted by X, Y, Text, etc. Issue , modified patch by Marcin Wiazowski.

git-svn-id: trunk@60972 -
This commit is contained in:
wp 2019-04-14 20:52:38 +00:00
parent b03fd14109
commit 6908af06b3
17 changed files with 299 additions and 84 deletions

View File

@ -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)"

View File

@ -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 ""

View File

@ -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)"

View File

@ -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)"

View File

@ -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)"

View File

@ -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 ""

View File

@ -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 ""

View File

@ -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)"

View File

@ -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 "Звезда (из линий)"

View File

@ -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 ""

View File

@ -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 "Зірка (з ліній)"

View File

@ -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 "星(线)"

View File

@ -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';

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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(