lazarus/components/tachart/tachartliveview.pas
2020-08-16 17:03:16 +00:00

153 lines
3.4 KiB
ObjectPascal

unit TAChartLiveView;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, TAGraph, TAChartUtils;
type
TChartLiveViewExtentY = (lveAuto, lveFull, lveLogical);
TChartLiveView = class(TComponent)
private
FActive: Boolean;
FChart: TChart;
FExtentY: TChartLiveViewExtentY;
FListener: TListener;
FViewportSize: Double;
procedure FullExtentChanged(Sender: TObject);
procedure SetActive(const AValue: Boolean);
procedure SetChart(const AValue: TChart);
procedure SetExtentY(const AValue: TChartLiveViewExtentY);
procedure SetViewportSize(const AValue: Double);
procedure UpdateViewport;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Active: Boolean read FActive write SetActive default false;
property Chart: TChart read FChart write SetChart default nil;
property ExtentY: TChartLiveViewExtentY read FExtentY write SetExtentY default lveAuto;
property ViewportSize: double read FViewportSize write SetViewportSize;
end;
procedure Register;
implementation
uses
Math, TACustomSeries, TAEnumerators;
constructor TChartLiveView.Create(AOwner: TComponent);
begin
inherited;
FListener := TListener.Create(@FChart, @FullExtentChanged);
end;
destructor TChartLiveView.Destroy;
begin
FreeAndNil(FListener);
inherited;
end;
procedure TChartLiveView.FullExtentChanged(Sender: TObject);
begin
if (not FActive) or (FChart = nil) then
exit;
UpdateViewport;
end;
procedure TChartLiveView.SetActive(const AValue: Boolean);
begin
if FActive = AValue then exit;
FActive := AValue;
FullExtentChanged(nil);
end;
procedure TChartLiveView.SetChart(const AValue: TChart);
begin
if FChart = AValue then exit;
if FListener.IsListening then
FChart.FullExtentBroadcaster.Unsubscribe(FListener);
FChart := AValue;
if FChart <> nil then
FChart.FullExtentBroadcaster.Subscribe(FListener);
FullExtentChanged(Self);
end;
procedure TChartLiveview.SetExtentY(const AValue: TChartLiveViewExtentY);
begin
if FExtentY = AValue then exit;
FExtentY := AValue;
FullExtentChanged(nil);
end;
procedure TChartLiveView.SetViewportSize(const AValue: Double);
begin
if FViewportSize = AValue then exit;
FViewportSize := AValue;
FullExtentChanged(nil);
end;
procedure TChartLiveView.UpdateViewport;
var
fext, lext: TDoubleRect;
w: double;
i: Integer;
ymin, ymax: Double;
begin
if not FChart.ScalingValid then
exit;
fext := FChart.GetFullExtent();
lext := FChart.LogicalExtent;
w := lext.b.x - lext.a.x;
if FViewportSize = 0 then
w := lext.b.x - lext.a.x
else
w := FViewportSize;
lext.b.x := fext.b.x;
lext.a.x := lext.b.X - w;
if lext.a.x < fext.a.x then begin
lext.a.x := fext.a.x;
lext.b.x := lext.a.x + w;
end;
case FExtentY of
lveAuto:
begin
ymin := Infinity;
ymax := -Infinity;
for i := 0 to FChart.SeriesCount-1 do
if FChart.Series[i] is TChartSeries then
TChartSeries(FChart.Series[i]).FindYRange(lext.a.x, lext.b.x, ymin, ymax);
if (ymin <> Infinity) and (ymax <> -Infinity) then
begin
lext.a.y := ymin;
lext.b.y := ymax;
end;
end;
lveFull:
begin
lext.a.y := fext.a.y;
lext.b.y := fext.b.y;
end;
lveLogical:
;
end;
FChart.LogicalExtent := lext;
end;
procedure Register;
begin
RegisterComponents(CHART_COMPONENT_IDE_PAGE, [TChartLiveView]);
end;
end.