TAChart: Add TChartSourceBuffer utility class

git-svn-id: trunk@28800 -
This commit is contained in:
ask 2010-12-22 10:31:17 +00:00
parent 7cc2d96db6
commit b669510279
3 changed files with 130 additions and 23 deletions

View File

@ -25,6 +25,7 @@ uses
Classes, Types, TAChartUtils; Classes, Types, TAChartUtils;
type type
EBufferError = class(EChartError);
EEditableSourceRequired = class(EChartError); EEditableSourceRequired = class(EChartError);
EYCountError = class(EChartError); EYCountError = class(EChartError);
@ -87,6 +88,26 @@ type
property YCount: Cardinal read FYCount write SetYCount default 1; property YCount: Cardinal read FYCount write SetYCount default 1;
end; end;
{ TChartSourceBuffer }
TChartSourceBuffer = class
private
FBuf: array of TChartDataItem;
FCount: Cardinal;
FStart: Cardinal;
FSum: TChartDataItem;
function GetCapacity: Cardinal; inline;
procedure Put(AIndex: Integer; const AItem: TChartDataItem);
procedure Remove(AIndex: Integer);
procedure SetCapacity(AValue: Cardinal); inline;
public
procedure AddFirst(const AItem: TChartDataItem);
procedure AddLast(const AItem: TChartDataItem);
procedure Clear; inline;
procedure GetSum(var AItem: TChartDataItem);
property Capacity: Cardinal read GetCapacity write SetCapacity;
end;
procedure SetDataItemDefaults(var AItem: TChartDataItem); procedure SetDataItemDefaults(var AItem: TChartDataItem);
implementation implementation
@ -106,6 +127,89 @@ begin
AItem.YList[i] := 0; AItem.YList[i] := 0;
end; end;
{ TChartSourceBuffer }
procedure TChartSourceBuffer.AddFirst(const AItem: TChartDataItem);
begin
if Capacity = 0 then
raise EBufferError.Create('');
FStart := (FStart + Cardinal(High(FBuf))) mod Capacity;
if FCount = Capacity then
Remove(FStart)
else
FCount += 1;
Put(FStart, AItem);
end;
procedure TChartSourceBuffer.AddLast(const AItem: TChartDataItem);
begin
if Capacity = 0 then
raise EBufferError.Create('');
if FCount = Capacity then begin
Remove(FStart);
Put(FStart, AItem);
FStart += 1;
end
else begin
Put((FStart + FCount) mod Capacity, AItem);
FCount += 1;
end;
end;
procedure TChartSourceBuffer.Clear;
begin
FCount := 0;
FSum.Y := 0;
FSum.YList := nil;
end;
function TChartSourceBuffer.GetCapacity: Cardinal;
begin
Result := Length(FBuf);
end;
procedure TChartSourceBuffer.GetSum(var AItem: TChartDataItem);
begin
if FCount = 0 then
raise EBufferError.Create('Empty');
AItem.Y := FSum.Y;
AItem.YList := Copy(FSum.YList);
end;
procedure TChartSourceBuffer.Put(AIndex: Integer; const AItem: TChartDataItem);
var
i, oldLen: Integer;
begin
FBuf[AIndex] := AItem;
with FSum do begin
Y += AItem.Y;
oldLen := Length(YList);
SetLength(YList, Max(Length(AItem.YList), oldLen));
for i := oldLen to High(YList) do
YList[i] := 0;
for i := 0 to Min(High(YList), High(AItem.YList)) do
YList[i] += AItem.YList[i];
end;
end;
procedure TChartSourceBuffer.Remove(AIndex: Integer);
var
i: Integer;
begin
with FBuf[AIndex] do begin
FSum.Y -= Y;
for i := 0 to Min(High(FSum.YList), High(YList)) do
FSum.YList[i] -= YList[i];
end;
end;
procedure TChartSourceBuffer.SetCapacity(AValue: Cardinal);
begin
if AValue = Capacity then exit;
SetLength(FBuf, AValue);
Clear;
end;
{ TCustomChartSource } { TCustomChartSource }
procedure TCustomChartSource.AfterDraw; procedure TCustomChartSource.AfterDraw;

View File

@ -205,7 +205,7 @@ type
private private
FAccumulationMethod: TChartAccumulationMethod; FAccumulationMethod: TChartAccumulationMethod;
FAccumulationRange: Integer; FAccumulationRange: Integer;
FHistory: array of TChartDataItem; FHistory: TChartSourceBuffer;
FIndex: Integer; FIndex: Integer;
FItem: TChartDataItem; FItem: TChartDataItem;
FListener: TListener; FListener: TListener;
@ -218,7 +218,7 @@ type
procedure CalcAccumulation(AIndex: Integer); procedure CalcAccumulation(AIndex: Integer);
procedure CalcPercentage; procedure CalcPercentage;
procedure Changed(ASender: TObject); inline; procedure Changed(ASender: TObject); inline;
procedure ExtractItem(var AItem: TChartDataItem; AIndex: Integer); procedure ExtractItem(out AItem: TChartDataItem; AIndex: Integer);
procedure SetAccumulationMethod(AValue: TChartAccumulationMethod); procedure SetAccumulationMethod(AValue: TChartAccumulationMethod);
procedure SetAccumulationRange(AValue: Integer); procedure SetAccumulationRange(AValue: Integer);
procedure SetOrigin(AValue: TCustomChartSource); procedure SetOrigin(AValue: TCustomChartSource);
@ -999,28 +999,25 @@ end;
procedure TCalculatedChartSource.CalcAccumulation(AIndex: Integer); procedure TCalculatedChartSource.CalcAccumulation(AIndex: Integer);
var var
i, j: Integer; i: Integer;
begin begin
SetLength(FHistory, AccumulationRange); FHistory.Capacity := AccumulationRange;
if FIndex = AIndex - 1 then begin if FIndex = AIndex - 1 then begin
for i := High(FHistory) downto 1 do ExtractItem(FItem, AIndex);
FHistory[i] := FHistory[i - 1]; FHistory.AddLast(FItem);
ExtractItem(FHistory[0], AIndex);
end end
else else begin
for i := 0 to Min(High(FHistory), AIndex) do FHistory.Clear;
ExtractItem(FHistory[i], AIndex - i); for i := Max(AIndex - AccumulationRange + 1, 0) to AIndex do begin
SetDataItemDefaults(FItem); ExtractItem(FItem, i);
for i := 0 to Min(High(FHistory), AIndex) do begin FHistory.AddLast(FItem);
FItem.Y += FHistory[i].Y;
for j := 0 to High(FItem.YList) do
FItem.YList[j] += FHistory[i].YList[j];
end; end;
FItem.X := FHistory[0].X; end;
FHistory.GetSum(FItem);
if AccumulationMethod = camAverage then begin if AccumulationMethod = camAverage then begin
FItem.Y /= Min(AccumulationRange, AIndex + 1); FItem.Y /= Min(AccumulationRange, AIndex + 1);
for j := 0 to High(FItem.YList) do for i := 0 to High(FItem.YList) do
FItem.YList[j] /= Min(AccumulationRange, AIndex + 1); FItem.YList[i] /= Min(AccumulationRange, AIndex + 1);
end; end;
end; end;
@ -1051,17 +1048,19 @@ constructor TCalculatedChartSource.Create(AOwner: TComponent);
begin begin
inherited Create(AOwner); inherited Create(AOwner);
FIndex := -1; FIndex := -1;
FHistory := TChartSourceBuffer.Create;
FListener := TListener.Create(@FOrigin, @Changed); FListener := TListener.Create(@FOrigin, @Changed);
end; end;
destructor TCalculatedChartSource.Destroy; destructor TCalculatedChartSource.Destroy;
begin begin
FreeAndNil(FHistory);
FreeAndNil(FListener); FreeAndNil(FListener);
inherited Destroy; inherited Destroy;
end; end;
procedure TCalculatedChartSource.ExtractItem( procedure TCalculatedChartSource.ExtractItem(
var AItem: TChartDataItem; AIndex: Integer); out AItem: TChartDataItem; AIndex: Integer);
var var
t: TDoubleDynArray; t: TDoubleDynArray;
i: Integer; i: Integer;

View File

@ -74,11 +74,14 @@ begin
FSource.AccumulationMethod := camSum; FSource.AccumulationMethod := camSum;
FSource.AccumulationRange := 2; FSource.AccumulationRange := 2;
AssertEquals(3, FSource.YCount); AssertEquals(3, FSource.YCount);
AssertEquals(1, FSource[0]^.X);
AssertEquals(102, FSource[0]^.Y); AssertEquals(102, FSource[0]^.Y);
AssertEquals(2, FSource[1]^.X);
AssertEquals(102 + 202, FSource[1]^.Y); AssertEquals(102 + 202, FSource[1]^.Y);
AssertEquals(202 + 302, FSource[2]^.Y); AssertEquals(202 + 302, FSource[2]^.Y);
FSource.AccumulationMethod := camAverage; FSource.AccumulationMethod := camAverage;
AssertEquals((202 + 302) / 2, FSource[2]^.Y); AssertEquals((2002 + 2102) / 2, FSource[20]^.Y);
AssertEquals(1, FSource[0]^.X);
AssertEquals(102, FSource[0]^.Y); AssertEquals(102, FSource[0]^.Y);
AssertEquals((102 + 202) / 2, FSource[1]^.Y); AssertEquals((102 + 202) / 2, FSource[1]^.Y);
end; end;
@ -114,15 +117,16 @@ begin
end; end;
procedure TCalculatedSourceTest.SetUp; procedure TCalculatedSourceTest.SetUp;
var
i: Integer;
begin begin
inherited SetUp; inherited SetUp;
FOrigin := TListChartSource.Create(nil); FOrigin := TListChartSource.Create(nil);
FSource := TCalculatedChartSource.Create(nil); FSource := TCalculatedChartSource.Create(nil);
FSource.Origin := FOrigin; FSource.Origin := FOrigin;
FOrigin.YCount := 3; FOrigin.YCount := 3;
FOrigin.SetYList(FOrigin.Add(1, 102), [103, 104]); for i := 1 to 100 do
FOrigin.SetYList(FOrigin.Add(2, 202), [203, 204]); FOrigin.SetYList(FOrigin.Add(i, i * 100 + 2), [i * 100 + 3, i * 100 + 4]);
FOrigin.SetYList(FOrigin.Add(3, 302), [303, 304]);
end; end;
procedure TCalculatedSourceTest.TearDown; procedure TCalculatedSourceTest.TearDown;