mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-07 12:18:03 +02:00
TAChart: Rework of sorting by TCustomChartSource and TListChartSource. Issue #35356, patch by Marcin Wiazowski
git-svn-id: trunk@61248 -
This commit is contained in:
parent
71fad749a4
commit
0fce68a18e
@ -212,6 +212,7 @@ type
|
||||
out AUpperDelta, ALowerDelta: Double): Boolean;
|
||||
function GetHasErrorBars(Which: Integer): Boolean;
|
||||
function GetItem(AIndex: Integer): PChartDataItem; virtual; abstract;
|
||||
function HasSameSorting(ASource: TCustomChartSource): Boolean; virtual;
|
||||
procedure InvalidateCaches;
|
||||
procedure SetSortBy(AValue: TChartSortBy); virtual;
|
||||
procedure SetSortDir(AValue: TChartSortDir); virtual;
|
||||
@ -283,14 +284,16 @@ type
|
||||
procedure SetOnCompare(AValue: TChartSortCompare);
|
||||
procedure SetSorted(AValue: Boolean);
|
||||
protected
|
||||
FCompareProc: TChartSortCompare;
|
||||
FData: TFPList;
|
||||
FSorted: Boolean;
|
||||
function DefaultCompare(AItem1, AItem2: Pointer): Integer; virtual;
|
||||
function DoCompare(AItem1, AItem2: Pointer): Integer; virtual;
|
||||
procedure ExecSort(ACompare: TChartSortCompare); virtual;
|
||||
procedure DoSort; virtual;
|
||||
function GetCount: Integer; override;
|
||||
function GetItem(AIndex: Integer): PChartDataItem; override;
|
||||
function ItemAdd(AItem: PChartDataItem): Integer;
|
||||
procedure ItemInsert(AIndex: Integer; AItem: PChartDataItem);
|
||||
function ItemFind(AItem: PChartDataItem; L: Integer = 0; R: Integer = High(Integer)): Integer;
|
||||
function ItemModified(AIndex: Integer): Integer;
|
||||
procedure SetSortBy(AValue: TChartSortBy); override;
|
||||
procedure SetSortDir(AValue: TChartSortDir); override;
|
||||
procedure SetSortIndex(AValue: Cardinal); override;
|
||||
@ -1298,6 +1301,20 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomChartSource.HasSameSorting(ASource: TCustomChartSource): Boolean;
|
||||
begin
|
||||
case SortBy of
|
||||
sbX, sbY:
|
||||
Result := ASource.IsSorted and (ASource.SortBy = SortBy) and
|
||||
(ASource.SortDir = SortDir) and (ASource.SortIndex = SortIndex);
|
||||
sbColor, sbText:
|
||||
Result := ASource.IsSorted and (ASource.SortBy = SortBy) and
|
||||
(ASource.SortDir = SortDir);
|
||||
sbCustom:
|
||||
Result := false;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomChartSource.HasXErrorBars: Boolean;
|
||||
begin
|
||||
Result := GetHasErrorBars(0);
|
||||
@ -1596,71 +1613,129 @@ begin
|
||||
Result := CompareValue(x1, x2);
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.DefaultCompare(AItem1, AItem2: Pointer): Integer;
|
||||
function TCustomSortedChartSource.DoCompare(AItem1, AItem2: Pointer): Integer;
|
||||
var
|
||||
item1: PChartDataItem absolute AItem1;
|
||||
item2: PChartDataItem absolute AItem2;
|
||||
d1, d2: Double;
|
||||
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;
|
||||
case FSortBy of
|
||||
sbX:
|
||||
if FSortIndex = 0 then
|
||||
Result := CompareFloat(item1^.X, item2^.X)
|
||||
else
|
||||
if FSortIndex < FXCount then begin
|
||||
if FSortIndex <= Cardinal(Length(item1^.XList)) then
|
||||
d1 := item1^.XList[FSortIndex - 1]
|
||||
else
|
||||
d1 := SafeNan;
|
||||
if FSortIndex <= Cardinal(Length(item2^.XList)) then
|
||||
d2 := item2^.XList[FSortIndex - 1]
|
||||
else
|
||||
d2 := SafeNan;
|
||||
Result := CompareFloat(d1, d2);
|
||||
end else
|
||||
Result := 0;
|
||||
sbY:
|
||||
if FSortIndex = 0 then
|
||||
Result := CompareFloat(item1^.Y, item2^.Y)
|
||||
else
|
||||
if FSortIndex < FYCount then begin
|
||||
if FSortIndex <= Cardinal(Length(item1^.YList)) then
|
||||
d1 := item1^.YList[FSortIndex - 1]
|
||||
else
|
||||
d1 := SafeNan;
|
||||
if FSortIndex <= Cardinal(Length(item2^.YList)) then
|
||||
d2 := item2^.YList[FSortIndex - 1]
|
||||
else
|
||||
d2 := SafeNan;
|
||||
Result := CompareFloat(d1, d2);
|
||||
end else
|
||||
Result := 0;
|
||||
sbColor:
|
||||
Result := CompareValue(item1^.Color, item2^.Color);
|
||||
sbText:
|
||||
Result := CompareText(item1^.Text, item2^.Text);
|
||||
sbCustom:
|
||||
if Assigned(FOnCompare) then
|
||||
Result := FOnCompare(AItem1, AItem2)
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
if FSortDir = sdDescending then Result := -Result;
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.DoCompare(AItem1, AItem2: Pointer): Integer;
|
||||
begin
|
||||
Result := FCompareProc(AItem1, AItem2);
|
||||
end;
|
||||
{ Built-in sorting algorithm of the ChartSource - a QuickSort algorithm, copied
|
||||
from the Classes unit and modified. Modifications are:
|
||||
- uses a DoCompare() virtual method for comparisons,
|
||||
- does NOT exchange equal items - this would have some side effect here: let's
|
||||
consider sorting by X, in the ascending order, for the following data points:
|
||||
X=3, Text='ccc'
|
||||
X=2, Text='bbb 1'
|
||||
X=2, Text='bbb 2'
|
||||
X=2, Text='bbb 3'
|
||||
X=1, Text='aaa'
|
||||
|
||||
{ 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);
|
||||
after sorting, data would be (note the reversed 'bbb' order):
|
||||
X=1, Text='aaa'
|
||||
X=2, Text='bbb 3'
|
||||
X=2, Text='bbb 2'
|
||||
X=2, Text='bbb 1'
|
||||
X=3, Text='ccc'
|
||||
|
||||
after sorting AGAIN, data would be (note the original 'bbb' order):
|
||||
X=1, Text='aaa'
|
||||
X=2, Text='bbb 1'
|
||||
X=2, Text='bbb 2'
|
||||
X=2, Text='bbb 3'
|
||||
X=3, Text='ccc'
|
||||
}
|
||||
procedure TCustomSortedChartSource.DoSort;
|
||||
|
||||
procedure QuickSort(L, R: Longint);
|
||||
var
|
||||
I, J: Longint;
|
||||
P, Q: Pointer;
|
||||
begin
|
||||
repeat
|
||||
I := L;
|
||||
J := R;
|
||||
P := FData.List^[(L + R) div 2];
|
||||
repeat
|
||||
while ACompare(P, FData.List^[I]) > 0 do
|
||||
I := I + 1;
|
||||
while ACompare(P, FData.List^[J]) < 0 do
|
||||
J := J - 1;
|
||||
If I <= J then
|
||||
begin
|
||||
Q := FData.List^[I];
|
||||
FData.List^[I] := FData.List^[J];
|
||||
FData.List^[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;
|
||||
repeat
|
||||
I := L;
|
||||
J := R;
|
||||
P := FData.List^[(L + R) div 2];
|
||||
repeat
|
||||
while DoCompare(P, FData.List^[I]) > 0 do
|
||||
I := I + 1;
|
||||
while DoCompare(P, FData.List^[J]) < 0 do
|
||||
J := J - 1;
|
||||
if I <= J then
|
||||
begin
|
||||
// do NOT exchange equal items
|
||||
if DoCompare(FData.List^[I], FData.List^[J]) <> 0 then begin
|
||||
Q := FData.List^[I];
|
||||
FData.List^[I] := FData.List^[J];
|
||||
FData.List^[J] := Q;
|
||||
end;
|
||||
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);
|
||||
QuickSort(0, FData.Count - 1);
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.GetCount: Integer;
|
||||
@ -1673,6 +1748,78 @@ begin
|
||||
Result := PChartDataItem(FData.Items[AIndex]);
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.ItemAdd(AItem: PChartDataItem): Integer;
|
||||
begin
|
||||
if IsSorted then begin
|
||||
Result := ItemFind(AItem);
|
||||
FData.Insert(Result, AItem);
|
||||
end else
|
||||
Result := FData.Add(AItem);
|
||||
end;
|
||||
|
||||
procedure TCustomSortedChartSource.ItemInsert(AIndex: Integer; AItem: PChartDataItem);
|
||||
begin
|
||||
if IsSorted then
|
||||
if AIndex <> ItemFind(AItem) then
|
||||
raise ESortError.CreateFmt('%0:s.ItemInsert cannot insert data at the requested '+
|
||||
'position, because source is sorted', [ClassName]);
|
||||
FData.Insert(AIndex, AItem);
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.ItemFind(AItem: PChartDataItem; L: Integer = 0; R: Integer = High(Integer)): Integer;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
if not IsSorted then
|
||||
raise ESortError.CreateFmt('%0:s.ItemFind can be called only for sorted source', [ClassName]);
|
||||
|
||||
if R >= FData.Count then
|
||||
R := FData.Count - 1;
|
||||
|
||||
// special optimization for adding sorted data at the end
|
||||
if R >= 0 then
|
||||
if DoCompare(FData.List^[R], AItem) <= 0 then
|
||||
exit(R + 1);
|
||||
|
||||
// use binary search
|
||||
if L < 0 then
|
||||
L := 0;
|
||||
while L <= R do
|
||||
begin
|
||||
I := L + (R - L) div 2;
|
||||
if DoCompare(FData.List^[I], AItem) <= 0 then
|
||||
L := I + 1
|
||||
else
|
||||
R := I - 1;
|
||||
end;
|
||||
Result := L;
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.ItemModified(AIndex: Integer): Integer;
|
||||
begin
|
||||
Result := AIndex;
|
||||
if IsSorted then begin
|
||||
if FData.Count < 2 then exit;
|
||||
if (AIndex < 0) or (AIndex >= FData.Count) then exit;
|
||||
|
||||
if AIndex > 0 then
|
||||
if DoCompare(FData.List^[AIndex - 1], FData.List^[AIndex]) > 0 then begin
|
||||
Result := ItemFind(FData.List^[AIndex], 0, AIndex - 1);
|
||||
// no Dec(Result) here, as it is below
|
||||
FData.Move(AIndex, Result);
|
||||
exit; // optimization: the item cannot be unsorted from both sides
|
||||
// simultaneously, so we can exit now
|
||||
end;
|
||||
|
||||
if AIndex < FData.Count - 1 then
|
||||
if DoCompare(FData.List^[AIndex], FData.List^[AIndex + 1]) > 0 then begin
|
||||
Result := ItemFind(FData.List^[AIndex], AIndex + 1, FData.Count - 1);
|
||||
Dec(Result);
|
||||
FData.Move(AIndex, Result);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCustomSortedChartSource.IsSorted: Boolean;
|
||||
begin
|
||||
case FSortBy of
|
||||
@ -1737,11 +1884,7 @@ begin
|
||||
FSorted := SaveSorted;
|
||||
end;
|
||||
|
||||
if FSortBy = sbCustom then
|
||||
FCompareProc := FOnCompare
|
||||
else
|
||||
FCompareProc := @DefaultCompare;
|
||||
ExecSort(@DoCompare);
|
||||
DoSort;
|
||||
Notify;
|
||||
end;
|
||||
|
||||
|
@ -27,8 +27,6 @@ type
|
||||
FDataPoints: TStrings;
|
||||
FXCountMin: Cardinal;
|
||||
FYCountMin: Cardinal;
|
||||
procedure AddAt(
|
||||
APos: Integer; const AX, AY: Double; const ALabel: String; AColor: TChartColor);
|
||||
procedure ClearCaches;
|
||||
function NewItem: PChartDataItem;
|
||||
procedure SetDataPoints(const AValue: TStrings);
|
||||
@ -57,12 +55,12 @@ type
|
||||
procedure Clear;
|
||||
procedure CopyFrom(ASource: TCustomChartSource);
|
||||
procedure Delete(AIndex: Integer);
|
||||
procedure SetColor(AIndex: Integer; AColor: TChartColor);
|
||||
procedure SetText(AIndex: Integer; const AValue: String);
|
||||
procedure SetXList(AIndex: Integer; const AXList: array of Double);
|
||||
function SetColor(AIndex: Integer; AColor: TChartColor): Integer;
|
||||
function SetText(AIndex: Integer; const AValue: String): Integer;
|
||||
function SetXList(AIndex: Integer; const AXList: array of Double): Integer;
|
||||
function SetXValue(AIndex: Integer; const AValue: Double): Integer;
|
||||
procedure SetYList(AIndex: Integer; const AYList: array of Double);
|
||||
procedure SetYValue(AIndex: Integer; const AValue: Double);
|
||||
function SetYList(AIndex: Integer; const AYList: array of Double): Integer;
|
||||
function SetYValue(AIndex: Integer; const AValue: Double): Integer;
|
||||
published
|
||||
property DataPoints: TStrings read FDataPoints write SetDataPoints;
|
||||
property XCount;
|
||||
@ -373,7 +371,7 @@ begin
|
||||
item := FSource.NewItem;
|
||||
try
|
||||
Parse(S, item);
|
||||
FSource.FData.Insert(Index, item);
|
||||
FSource.ItemInsert(Index, item);
|
||||
except
|
||||
Dispose(item);
|
||||
raise;
|
||||
@ -489,30 +487,20 @@ end;
|
||||
function TListChartSource.Add(
|
||||
const AX, AY: Double; const ALabel: String = '';
|
||||
const AColor: TChartColor = clTAColor): Integer;
|
||||
begin
|
||||
Result := FData.Count;
|
||||
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.
|
||||
// So, is the user wants to add many (>10000) points to a graph,
|
||||
// he should pre-sort them to avoid performance penalty.
|
||||
while (Result > 0) and (Item[Result - 1]^.X > AX) do
|
||||
Dec(Result);
|
||||
AddAt(Result, AX, AY, ALabel, AColor);
|
||||
end;
|
||||
|
||||
procedure TListChartSource.AddAt(
|
||||
APos: Integer; const AX, AY: Double; const ALabel: String; AColor: TChartColor);
|
||||
var
|
||||
pcd: PChartDataItem;
|
||||
begin
|
||||
pcd := NewItem;
|
||||
pcd^.X := AX;
|
||||
pcd^.Y := AY;
|
||||
pcd^.Color := AColor;
|
||||
pcd^.Text := ALabel;
|
||||
FData.Insert(APos, pcd);
|
||||
try
|
||||
pcd^.X := AX;
|
||||
pcd^.Y := AY;
|
||||
pcd^.Color := AColor;
|
||||
pcd^.Text := ALabel;
|
||||
Result := ItemAdd(pcd);
|
||||
except
|
||||
Dispose(pcd);
|
||||
raise;
|
||||
end;
|
||||
UpdateCachesAfterAdd(AX, AY);
|
||||
end;
|
||||
|
||||
@ -530,9 +518,9 @@ begin
|
||||
try
|
||||
Result := Add(AX[0], AY[0], ALabel, AColor);
|
||||
if Length(AX) > 1 then
|
||||
SetXList(Result, AX[1..High(AX)]);
|
||||
Result := SetXList(Result, AX[1..High(AX)]);
|
||||
if Length(AY) > 1 then
|
||||
SetYList(Result, AY[1..High(AY)]);
|
||||
Result := SetYList(Result, AY[1..High(AY)]);
|
||||
finally
|
||||
Dec(FUpdateCount);
|
||||
end;
|
||||
@ -552,7 +540,7 @@ begin
|
||||
try
|
||||
Result := Add(AX, AY[0], ALabel, AColor);
|
||||
if Length(AY) > 1 then
|
||||
SetYList(Result, AY[1..High(AY)]);
|
||||
Result := SetYList(Result, AY[1..High(AY)]);
|
||||
finally
|
||||
Dec(FUpdateCount);
|
||||
end;
|
||||
@ -591,6 +579,7 @@ end;
|
||||
procedure TListChartSource.CopyFrom(ASource: TCustomChartSource);
|
||||
var
|
||||
i: Integer;
|
||||
pcd: PChartDataItem;
|
||||
begin
|
||||
if ASource.XCount < FXCountMin then
|
||||
raise EXCountError.CreateFmt(rsSourceCountError2, [ClassName, FXCountMin, 'x']);
|
||||
@ -602,23 +591,23 @@ begin
|
||||
Clear;
|
||||
XCount := ASource.XCount;
|
||||
YCount := ASource.YCount;
|
||||
for i := 0 to ASource.Count - 1 do
|
||||
with ASource[i]^ do begin
|
||||
AddAt(FData.Count, X, Y, Text, Color);
|
||||
SetXList(FData.Count - 1, XList);
|
||||
SetYList(FData.Count - 1, YList);
|
||||
end;
|
||||
FData.Capacity := ASource.Count;
|
||||
|
||||
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;
|
||||
pcd := nil;
|
||||
try // optimization: don't execute try..except..end in a loop
|
||||
for i := 0 to ASource.Count - 1 do begin
|
||||
pcd := NewItem;
|
||||
pcd^ := ASource[i]^;
|
||||
FData.Add(pcd); // don't use ItemAdd() here
|
||||
pcd := nil;
|
||||
end;
|
||||
except
|
||||
if pcd <> nil then
|
||||
Dispose(pcd);
|
||||
raise;
|
||||
end;
|
||||
|
||||
if IsSorted and (not HasSameSorting(ASource)) then Sort;
|
||||
finally
|
||||
EndUpdate;
|
||||
end;
|
||||
@ -680,12 +669,13 @@ begin
|
||||
if YCount > 1 then SetLength(Result^.YList, YCount - 1);
|
||||
end;
|
||||
|
||||
procedure TListChartSource.SetColor(AIndex: Integer; AColor: TChartColor);
|
||||
function TListChartSource.SetColor(AIndex: Integer; AColor: TChartColor): Integer;
|
||||
begin
|
||||
with Item[AIndex]^ do begin
|
||||
if Color = AColor then exit;
|
||||
if Color = AColor then exit(AIndex);
|
||||
Color := AColor;
|
||||
end;
|
||||
Result := ItemModified(AIndex);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
@ -701,12 +691,13 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.SetText(AIndex: Integer; const AValue: String);
|
||||
function TListChartSource.SetText(AIndex: Integer; const AValue: String): Integer;
|
||||
begin
|
||||
with Item[AIndex]^ do begin
|
||||
if Text = AValue then exit;
|
||||
if Text = AValue then exit(AIndex);
|
||||
Text := AValue;
|
||||
end;
|
||||
Result := ItemModified(AIndex);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
@ -725,8 +716,8 @@ begin
|
||||
Notify;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.SetXList(
|
||||
AIndex: Integer; const AXList: array of Double);
|
||||
function TListChartSource.SetXList(
|
||||
AIndex: Integer; const AXList: array of Double): Integer;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@ -734,6 +725,7 @@ begin
|
||||
for i := 0 to Min(High(AXList), High(XList)) do
|
||||
XList[i] := AXList[i];
|
||||
FXListExtentIsValid := false;
|
||||
Result := ItemModified(AIndex);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
@ -757,26 +749,13 @@ var
|
||||
end;
|
||||
|
||||
begin
|
||||
if IsSortedByXAsc then
|
||||
if IsNan(AValue) then
|
||||
raise EChartError.CreateFmt('X = NaN in sorted source %s', [NameOrClassName(Self)]);
|
||||
Result := AIndex;
|
||||
with Item[AIndex]^ do begin
|
||||
if IsEquivalent(X, AValue) then exit; // IsEquivalent() can compare also NaNs
|
||||
if IsEquivalent(X, AValue) then exit(AIndex); // IsEquivalent() can compare also NaNs
|
||||
oldX := X;
|
||||
X := AValue;
|
||||
end;
|
||||
UpdateExtent;
|
||||
if IsSortedByXAsc then begin
|
||||
if AValue > oldX then
|
||||
while (Result < Count - 1) and (Item[Result + 1]^.X < AValue) do
|
||||
Inc(Result)
|
||||
else
|
||||
while (Result > 0) and (Item[Result - 1]^.X > AValue) do
|
||||
Dec(Result);
|
||||
if Result <> AIndex then
|
||||
FData.Move(AIndex, Result);
|
||||
end;
|
||||
Result := ItemModified(AIndex);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
@ -795,8 +774,8 @@ begin
|
||||
Notify;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.SetYList(
|
||||
AIndex: Integer; const AYList: array of Double);
|
||||
function TListChartSource.SetYList(
|
||||
AIndex: Integer; const AYList: array of Double): Integer;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
@ -805,10 +784,11 @@ begin
|
||||
YList[i] := AYList[i];
|
||||
FCumulativeExtentIsValid := false;
|
||||
FYListExtentIsValid := false;
|
||||
Result := ItemModified(AIndex);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
procedure TListChartSource.SetYValue(AIndex: Integer; const AValue: Double);
|
||||
function TListChartSource.SetYValue(AIndex: Integer; const AValue: Double): Integer;
|
||||
var
|
||||
oldY: Double;
|
||||
|
||||
@ -829,13 +809,14 @@ var
|
||||
|
||||
begin
|
||||
with Item[AIndex]^ do begin
|
||||
if IsEquivalent(Y, AValue) then exit; // IsEquivalent() can compare also NaNs
|
||||
if IsEquivalent(Y, AValue) then exit(AIndex); // IsEquivalent() can compare also NaNs
|
||||
oldY := Y;
|
||||
Y := AValue;
|
||||
end;
|
||||
if FValuesTotalIsValid then
|
||||
FValuesTotal += NumberOr(AValue) - NumberOr(oldY);
|
||||
UpdateExtent;
|
||||
Result := ItemModified(AIndex);
|
||||
Notify;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user