TLazy + Data-Endpoints refactoring
This commit is contained in:
+59
-70
@@ -26,26 +26,18 @@ type
|
||||
type
|
||||
TPanel = class;
|
||||
|
||||
// Abstract base for a data series within the chart.
|
||||
TSeries = class abstract(TObject)
|
||||
protected
|
||||
function GetCount: Int64; virtual; abstract;
|
||||
function GetTotalCount: Int64; virtual; abstract;
|
||||
public
|
||||
property Count: Int64 read GetCount;
|
||||
property TotalCount: Int64 read GetTotalCount;
|
||||
end;
|
||||
|
||||
// Abstract base for a drawable layer in a panel.
|
||||
TLayer = class abstract(TObject)
|
||||
protected
|
||||
function GetCount: Int64; virtual; abstract;
|
||||
function GetTotalCount: Int64; virtual; abstract;
|
||||
function GetOwner: TMycChart; virtual; abstract;
|
||||
function GetSeries: TSeries; virtual; abstract;
|
||||
procedure Update; virtual; abstract;
|
||||
function Update: Boolean; virtual; abstract;
|
||||
public
|
||||
procedure Repaint;
|
||||
property Count: Int64 read GetCount;
|
||||
property TotalCount: Int64 read GetTotalCount;
|
||||
property Owner: TMycChart read GetOwner;
|
||||
property Series: TSeries read GetSeries;
|
||||
end;
|
||||
|
||||
TDataLayer = class abstract(TLayer)
|
||||
@@ -93,12 +85,12 @@ type
|
||||
TPanel = class(TObject)
|
||||
private
|
||||
FOwner: TMycChart;
|
||||
FSeriesList: TObjectList<TMycChart.TDataLayer>;
|
||||
FLayers: TObjectList<TMycChart.TDataLayer>;
|
||||
FWeight: Single;
|
||||
procedure SetWeight(const Value: Single);
|
||||
protected
|
||||
procedure Paint(const Canvas: TCanvas; const Viewport: TRectF; MasterTotalCount: Int64; ViewStartIndex, ViewCount: Int64);
|
||||
procedure Update(MasterTotalCount: Int64; ViewStartIndex: Int64; out SeriesChanged, SeriesRepaint: Boolean);
|
||||
function Update: Boolean;
|
||||
|
||||
public
|
||||
constructor Create(AOwner: TMycChart; AWeight: Single);
|
||||
@@ -144,6 +136,7 @@ type
|
||||
protected
|
||||
procedure Paint; override;
|
||||
procedure DoIdle;
|
||||
function Update: Boolean;
|
||||
procedure DoMouseLeave; override;
|
||||
procedure MouseWheel(Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean); override;
|
||||
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
|
||||
@@ -168,6 +161,7 @@ type
|
||||
property JumpButtonRect: TRectF read FJumpButtonRect;
|
||||
property ViewCount: Int64 read FViewCount;
|
||||
property ViewStartIndex: Int64 read FViewStartIndex;
|
||||
property XAxisSeries: TMycChart.TXAxisLayer read FXAxisSeries;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -230,7 +224,7 @@ begin
|
||||
Result.Point.X := X;
|
||||
Result.Point.Y := Y;
|
||||
Result.Idx := Round((rect.Right - X) * (FViewCount - 1) / rect.Width);
|
||||
if (Result.Idx < 0) or (Result.Idx >= FXAxisSeries.Series.Count) then
|
||||
if (Result.Idx < 0) or (Result.Idx >= FXAxisSeries.Count) then
|
||||
Result.Idx := -1;
|
||||
Result.BarX := NaN;
|
||||
if Result.Idx >= 0 then
|
||||
@@ -248,34 +242,34 @@ begin
|
||||
end;
|
||||
|
||||
procedure TMycChart.DoIdle;
|
||||
var
|
||||
prevTotalCount, newTotalCount: Int64;
|
||||
seriesChanged, seriesRepaint, repaintSignal: Boolean;
|
||||
countDelta: Int64;
|
||||
begin
|
||||
if Update then
|
||||
Repaint;
|
||||
end;
|
||||
|
||||
function TMycChart.Update: Boolean;
|
||||
begin
|
||||
if not Assigned(FXAxisSeries) then
|
||||
exit;
|
||||
exit(false);
|
||||
|
||||
prevTotalCount := FXAxisSeries.Series.TotalCount;
|
||||
FXAxisSeries.Update;
|
||||
newTotalCount := FXAxisSeries.Series.TotalCount;
|
||||
var prevTotalCount := FXAxisSeries.TotalCount;
|
||||
var seriesChanged := false;
|
||||
|
||||
seriesChanged := prevTotalCount <> newTotalCount;
|
||||
seriesRepaint := (FViewStartIndex = 0);
|
||||
if FXAxisSeries.Update then
|
||||
seriesChanged := (FViewStartIndex = 0);
|
||||
|
||||
for var panel in FPanelList do
|
||||
begin
|
||||
var panelChanged, panelRepaint: Boolean;
|
||||
panel.Update(prevTotalCount, FViewStartIndex, panelChanged, panelRepaint);
|
||||
seriesChanged := seriesChanged or panelChanged;
|
||||
seriesRepaint := seriesRepaint or panelRepaint;
|
||||
if panel.Update then
|
||||
seriesChanged := true;
|
||||
end;
|
||||
|
||||
// When we are not displaying live data, adjust start index accordingly
|
||||
if (FViewStartIndex > 0) then
|
||||
if FViewStartIndex > 0 then
|
||||
begin
|
||||
countDelta := newTotalCount - prevTotalCount;
|
||||
if (countDelta > 0) then
|
||||
var newTotalCount := FXAxisSeries.TotalCount;
|
||||
var countDelta := newTotalCount - prevTotalCount;
|
||||
if countDelta > 0 then
|
||||
begin
|
||||
FViewStartIndex := FViewStartIndex + countDelta;
|
||||
if (FViewStartIndex + FViewCount > newTotalCount) then
|
||||
@@ -283,10 +277,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
repaintSignal := FNeedRepaint.Reset;
|
||||
var repaintSignal := FNeedRepaint.Reset;
|
||||
|
||||
if repaintSignal or (seriesRepaint and seriesChanged) then
|
||||
Repaint;
|
||||
Result := repaintSignal or seriesChanged;
|
||||
end;
|
||||
|
||||
procedure TMycChart.DoMouseLeave;
|
||||
@@ -312,14 +305,14 @@ begin
|
||||
inherited;
|
||||
rect := Self.LocalRect;
|
||||
|
||||
if (not Assigned(FXAxisSeries)) or (FXAxisSeries.Series.Count <= 1) or (FViewCount <= 1) or (PanelCount = 0) then
|
||||
if (not Assigned(FXAxisSeries)) or (FXAxisSeries.Count <= 1) or (FViewCount <= 1) or (PanelCount = 0) then
|
||||
begin
|
||||
Canvas.Fill.Color := TAlphaColors.Gray;
|
||||
Canvas.FillText(rect, 'No Data', false, 1, [], TTextAlign.Center, TTextAlign.Center);
|
||||
Exit;
|
||||
end;
|
||||
|
||||
masterTotalCount := FXAxisSeries.Series.TotalCount;
|
||||
masterTotalCount := FXAxisSeries.TotalCount;
|
||||
|
||||
// Calculate total weight for proportional panel height
|
||||
totalWeight := 0;
|
||||
@@ -332,6 +325,7 @@ begin
|
||||
for var i := 0 to PanelCount - 1 do
|
||||
begin
|
||||
var panel := Panels[i];
|
||||
|
||||
panelHeight := panel.Weight * rect.Height / totalWeight;
|
||||
panelRect := TRectF.Create(rect.Left, currentY, rect.Right, currentY + panelHeight);
|
||||
|
||||
@@ -542,7 +536,7 @@ begin
|
||||
FViewStartIndex := FViewStartIndex - indexDelta;
|
||||
|
||||
// Clamp values
|
||||
maxIndex := FXAxisSeries.Series.Count - FViewCount;
|
||||
maxIndex := FXAxisSeries.Count - FViewCount;
|
||||
if (maxIndex < 0) then
|
||||
maxIndex := 0;
|
||||
if (FViewStartIndex < 0) then
|
||||
@@ -602,7 +596,7 @@ begin
|
||||
if not Assigned(FXAxisSeries) then
|
||||
exit;
|
||||
|
||||
var xAxisCount := FXAxisSeries.Series.Count;
|
||||
var xAxisCount := FXAxisSeries.Count;
|
||||
if (xAxisCount = 0) or (Width <= 0) then
|
||||
exit;
|
||||
|
||||
@@ -667,13 +661,13 @@ constructor TMycChart.TPanel.Create(AOwner: TMycChart; AWeight: Single);
|
||||
begin
|
||||
inherited Create;
|
||||
FOwner := AOwner;
|
||||
FSeriesList := TObjectList<TMycChart.TDataLayer>.Create(true);
|
||||
FLayers := TObjectList<TMycChart.TDataLayer>.Create(true);
|
||||
FWeight := AWeight;
|
||||
end;
|
||||
|
||||
destructor TMycChart.TPanel.Destroy;
|
||||
begin
|
||||
FSeriesList.Free;
|
||||
FLayers.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
@@ -684,7 +678,7 @@ function TMycChart.TPanel.AddDoubleSeries(
|
||||
): TMycChart.TDataLayer;
|
||||
begin
|
||||
Result := TChartLineLayer.Create(Self, DataProvider, ALineColor, ALineWidth);
|
||||
FSeriesList.Add(Result);
|
||||
FLayers.Add(Result);
|
||||
end;
|
||||
|
||||
function TMycChart.TPanel.AddOhlcSeries(
|
||||
@@ -695,7 +689,7 @@ function TMycChart.TPanel.AddOhlcSeries(
|
||||
begin
|
||||
Result :=
|
||||
TChartOhlcLayer.Create(Self, DataProvider, TMutable<TAlphaColor>.Constant(AUpColor), TMutable<TAlphaColor>.Constant(ADownColor));
|
||||
FSeriesList.Add(Result);
|
||||
FLayers.Add(Result);
|
||||
end;
|
||||
|
||||
procedure TMycChart.TPanel.Paint(const Canvas: TCanvas; const Viewport: TRectF; MasterTotalCount, ViewStartIndex, ViewCount: Int64);
|
||||
@@ -706,16 +700,16 @@ var
|
||||
xTransform: TFunc<Int64, Single>;
|
||||
yTransform: TFunc<Double, Single>;
|
||||
|
||||
function CalcView(Series: TMycChart.TSeries; out First, Last: Int64): Boolean;
|
||||
function CalcView(Layer: TMycChart.TDataLayer; out First, Last: Int64): Boolean;
|
||||
var
|
||||
seriesTotalCount, offset, startIdx: Int64;
|
||||
begin
|
||||
seriesTotalCount := series.TotalCount;
|
||||
seriesTotalCount := Layer.TotalCount;
|
||||
offset := MasterTotalCount - seriesTotalCount;
|
||||
startIdx := ViewStartIndex - offset;
|
||||
|
||||
First := Max(0, startIdx);
|
||||
Last := Min(series.Count, startIdx + ViewCount) - 1;
|
||||
Last := Min(Layer.Count, startIdx + ViewCount) - 1;
|
||||
Result := First <= Last;
|
||||
end;
|
||||
|
||||
@@ -724,12 +718,16 @@ begin
|
||||
localMin := 0;
|
||||
localMax := 0;
|
||||
|
||||
// Update data state
|
||||
for var layer in FLayers do
|
||||
layer.Update;
|
||||
|
||||
// 1. Calculate value range (Y-Axis) for this panel only
|
||||
for var series in FSeriesList do
|
||||
for var layer in FLayers do
|
||||
begin
|
||||
if CalcView(series.Series, seriesFirst, seriesLast) then
|
||||
if CalcView(layer, seriesFirst, seriesLast) then
|
||||
begin
|
||||
if series.GetValueRange(seriesFirst, seriesLast, seriesMin, seriesMax) then
|
||||
if layer.GetValueRange(seriesFirst, seriesLast, seriesMin, seriesMax) then
|
||||
begin
|
||||
if not rangeInitialized then
|
||||
begin
|
||||
@@ -760,18 +758,18 @@ begin
|
||||
yTransform := function(value: Double): Single begin Result := top + (1 - (value - localMin) / range) * height; end;
|
||||
|
||||
// 3. Paint all layers in this panel
|
||||
for var series in FSeriesList do
|
||||
for var layer in FLayers do
|
||||
begin
|
||||
if CalcView(series.Series, seriesFirst, seriesLast) then
|
||||
if CalcView(layer, seriesFirst, seriesLast) then
|
||||
begin
|
||||
var offset := MasterTotalCount - series.Series.TotalCount;
|
||||
var offset := MasterTotalCount - layer.TotalCount;
|
||||
xTransform :=
|
||||
function(index: Int64): Single
|
||||
begin
|
||||
Result := Viewport.Right - (((index + offset - ViewStartIndex) / (ViewCount - 1)) * Viewport.Width);
|
||||
end;
|
||||
|
||||
series.Paint(Canvas, seriesFirst, seriesLast, xTransform, yTransform);
|
||||
layer.Paint(Canvas, seriesFirst, seriesLast, xTransform, yTransform);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
@@ -789,23 +787,14 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMycChart.TPanel.Update(MasterTotalCount: Int64; ViewStartIndex: Int64; out SeriesChanged, SeriesRepaint: Boolean);
|
||||
var
|
||||
seriesCount: Int64;
|
||||
function TMycChart.TPanel.Update: Boolean;
|
||||
begin
|
||||
SeriesChanged := false;
|
||||
SeriesRepaint := false;
|
||||
for var series in FSeriesList do
|
||||
Result := false;
|
||||
for var layer in FLayers do
|
||||
begin
|
||||
seriesCount := series.Series.TotalCount;
|
||||
|
||||
if (ViewStartIndex <= MasterTotalCount - seriesCount) then
|
||||
SeriesRepaint := true;
|
||||
|
||||
series.Update;
|
||||
|
||||
if (seriesCount <> series.Series.TotalCount) then
|
||||
SeriesChanged := true;
|
||||
if layer.Update then
|
||||
if (Owner.ViewStartIndex <= Owner.FXAxisSeries.TotalCount - layer.TotalCount) then
|
||||
Result := true;
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -846,7 +835,7 @@ var
|
||||
textSize: TRectF;
|
||||
begin
|
||||
// Do not draw if no data or view is invalid
|
||||
if (not Assigned(Series)) or (Series.Count = 0) then
|
||||
if GetCount = 0 then
|
||||
exit;
|
||||
|
||||
// 1. Snap X to the candle's center
|
||||
|
||||
Reference in New Issue
Block a user