From 638e9ad8ae9305b41ff34c86914f64a875dccaa0 Mon Sep 17 00:00:00 2001 From: wp_xyz Date: Mon, 9 Aug 2021 13:44:15 +0200 Subject: [PATCH] TAChart: Add a TChartLiveView demo for paned chart (multi-axis) (cherry picked from commit 79a2acf2986406a81d01d7c9f6e3ef4397059c85) --- .../tachart/demo/liveview_paned/main.lfm | 257 ++++++++++++++++++ .../tachart/demo/liveview_paned/main.pas | 202 ++++++++++++++ .../demo/liveview_paned/panedliveviewdemo.lpi | 79 ++++++ .../demo/liveview_paned/panedliveviewdemo.lpr | 25 ++ 4 files changed, 563 insertions(+) create mode 100644 components/tachart/demo/liveview_paned/main.lfm create mode 100644 components/tachart/demo/liveview_paned/main.pas create mode 100644 components/tachart/demo/liveview_paned/panedliveviewdemo.lpi create mode 100644 components/tachart/demo/liveview_paned/panedliveviewdemo.lpr diff --git a/components/tachart/demo/liveview_paned/main.lfm b/components/tachart/demo/liveview_paned/main.lfm new file mode 100644 index 0000000000..53a0d3ba0b --- /dev/null +++ b/components/tachart/demo/liveview_paned/main.lfm @@ -0,0 +1,257 @@ +object Form1: TForm1 + Left = 609 + Height = 693 + Top = 149 + Width = 496 + Caption = 'MainForm' + ClientHeight = 693 + ClientWidth = 496 + OnCreate = FormCreate + LCLVersion = '2.3.0.0' + object Chart1: TChart + Left = 0 + Height = 624 + Top = 0 + Width = 496 + AxisList = < + item + Grid.Color = clMenu + Grid.Style = psSolid + Alignment = calBottom + AxisPen.Visible = True + Marks.LabelBrush.Style = bsClear + Minors = <> + Range.UseMin = True + Title.LabelFont.Style = [fsBold] + Title.Visible = True + Title.Caption = 'Time, s' + Title.LabelBrush.Style = bsClear + end + item + Grid.Color = clMenu + Grid.Style = psSolid + AtDataOnly = True + AxisPen.Visible = True + Group = 1 + Marks.AtDataOnly = True + Marks.LabelBrush.Style = bsClear + Minors = <> + Range.Max = 1 + Range.Min = -1 + Range.UseMax = True + Range.UseMin = True + Title.LabelFont.Orientation = 900 + Title.LabelFont.Style = [fsBold] + Title.Visible = True + Title.Caption = 'Position, cm' + Title.LabelBrush.Style = bsClear + Title.PositionOnMarks = True + Transformations = PositionTransformations + end + item + Grid.Color = clMenu + Grid.Style = psSolid + AtDataOnly = True + AxisPen.Visible = True + Group = 1 + Marks.AtDataOnly = True + Marks.LabelBrush.Style = bsClear + Minors = <> + Range.Max = 1 + Range.Min = -1 + Range.UseMax = True + Range.UseMin = True + Title.LabelFont.Orientation = 900 + Title.LabelFont.Style = [fsBold] + Title.Visible = True + Title.Caption = 'Velocity, cm/s' + Title.LabelBrush.Style = bsClear + Title.PositionOnMarks = True + Transformations = VelocityTransformations + end + item + Grid.Color = clMenu + Grid.Style = psSolid + AtDataOnly = True + AxisPen.Visible = True + Group = 1 + Marks.AtDataOnly = True + Marks.LabelBrush.Style = bsClear + Minors = <> + Range.Max = 1 + Range.Min = -1 + Range.UseMax = True + Range.UseMin = True + Title.LabelFont.Orientation = 900 + Title.LabelFont.Style = [fsBold] + Title.Visible = True + Title.Caption = 'Acceleration, cm/s2 ' + Title.LabelBrush.Style = bsClear + Title.PositionOnMarks = True + Title.TextFormat = tfHTML + Transformations = AccelerationTransformations + end> + Frame.Visible = False + Title.Font.Height = -16 + Title.Font.Style = [fsBold] + Title.Text.Strings = ( + 'Damped pendulum' + ) + Title.Visible = True + Align = alClient + object PositionSeries: TLineSeries + AxisIndexX = 0 + AxisIndexY = 1 + end + object VelocitySeries: TLineSeries + AxisIndexX = 0 + AxisIndexY = 2 + end + object AccelerationSeries: TLineSeries + AxisIndexX = 0 + AxisIndexY = 3 + end + end + object Panel1: TPanel + Left = 8 + Height = 49 + Top = 636 + Width = 480 + Align = alBottom + AutoSize = True + BorderSpacing.Around = 8 + BevelOuter = bvNone + ClientHeight = 49 + ClientWidth = 480 + TabOrder = 1 + object cbLiveView: TCheckBox + AnchorSideLeft.Control = Panel1 + AnchorSideTop.Control = btnReset + AnchorSideTop.Side = asrCenter + Left = 0 + Height = 19 + Top = 3 + Width = 114 + Caption = 'Scrolling live view' + Checked = True + OnChange = cbLiveViewChange + State = cbChecked + TabOrder = 0 + end + object cbFrozenAxes: TCheckBox + AnchorSideLeft.Control = cbLiveView + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btnReset + AnchorSideTop.Side = asrCenter + Left = 146 + Height = 19 + Top = 3 + Width = 122 + BorderSpacing.Left = 32 + Caption = 'Frozen vertical axes' + Checked = True + OnChange = cbFrozenAxesChange + State = cbChecked + TabOrder = 1 + end + object btnReset: TButton + AnchorSideLeft.Control = btnStopResume + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = Panel1 + Left = 387 + Height = 25 + Top = 0 + Width = 75 + BorderSpacing.Left = 4 + BorderSpacing.Right = 8 + Caption = 'Reset' + OnClick = btnResetClick + TabOrder = 2 + end + object btnStopResume: TButton + AnchorSideLeft.Control = cbFrozenAxes + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = Panel1 + Left = 308 + Height = 25 + Top = 0 + Width = 75 + BorderSpacing.Left = 40 + Caption = 'Stop' + OnClick = btnStopResumeClick + TabOrder = 3 + end + object Label1: TLabel + AnchorSideLeft.Control = cbLiveView + AnchorSideTop.Control = seViewportSize + AnchorSideTop.Side = asrCenter + Left = 0 + Height = 15 + Top = 30 + Width = 88 + Caption = 'Viewport size (s):' + end + object seViewportSize: TFloatSpinEdit + AnchorSideLeft.Control = Label1 + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = cbLiveView + AnchorSideTop.Side = asrBottom + Left = 96 + Height = 23 + Top = 26 + Width = 58 + Alignment = taRightJustify + BorderSpacing.Left = 8 + BorderSpacing.Top = 4 + DecimalPlaces = 0 + MaxValue = 60 + MinValue = 1 + OnChange = seViewportSizeChange + TabOrder = 4 + Value = 10 + end + end + object Bevel1: TBevel + Left = 0 + Height = 4 + Top = 624 + Width = 496 + Align = alBottom + Shape = bsBottomLine + end + object PositionTransformations: TChartAxisTransformations + Left = 213 + Top = 34 + object PositionAutoScaleTransform: TAutoScaleAxisTransform + MaxValue = 3.4 + MinValue = 2.4 + end + end + object VelocityTransformations: TChartAxisTransformations + Left = 213 + Top = 102 + object VelocityScaleTransform: TAutoScaleAxisTransform + MaxValue = 2.2 + MinValue = 1.2 + end + end + object AccelerationTransformations: TChartAxisTransformations + Left = 213 + Top = 176 + object AccelerationAutoScaleTransform: TAutoScaleAxisTransform + end + end + object Timer: TTimer + Enabled = False + Interval = 100 + OnTimer = TimerTimer + Left = 216 + Top = 287 + end + object ChartLiveView1: TChartLiveView + Chart = Chart1 + ViewportSize = 10 + Left = 216 + Top = 367 + end +end diff --git a/components/tachart/demo/liveview_paned/main.pas b/components/tachart/demo/liveview_paned/main.pas new file mode 100644 index 0000000000..a9ea877fad --- /dev/null +++ b/components/tachart/demo/liveview_paned/main.pas @@ -0,0 +1,202 @@ +{ This project demonstrates application of a TChartLiveView to a multiple-axis + chart ("paned chart"). } + +unit main; + +{$mode objfpc}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, + Spin, TAGraph, TATransformations, TASeries, TAChartLiveView; + +type + + { TForm1 } + + TForm1 = class(TForm) + AccelerationAutoScaleTransform: TAutoScaleAxisTransform; + Bevel1: TBevel; + btnReset: TButton; + btnStopResume: TButton; + Chart1: TChart; + ChartLiveView1: TChartLiveView; + cbLiveView: TCheckBox; + cbFrozenAxes: TCheckBox; + Label1: TLabel; + PositionSeries: TLineSeries; + seViewportSize: TFloatSpinEdit; + Timer: TTimer; + VelocitySeries: TLineSeries; + AccelerationSeries: TLineSeries; + PositionTransformations: TChartAxisTransformations; + PositionAutoScaleTransform: TAutoScaleAxisTransform; + VelocityTransformations: TChartAxisTransformations; + AccelerationTransformations: TChartAxisTransformations; + Panel1: TPanel; + VelocityScaleTransform: TAutoScaleAxisTransform; + procedure btnResetClick(Sender: TObject); + procedure btnStopResumeClick(Sender: TObject); + procedure cbFrozenAxesChange(Sender: TObject); + procedure cbLiveViewChange(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure seViewportSizeChange(Sender: TObject); + procedure TimerTimer(Sender: TObject); + private + FStartTime: TDateTime; + + public + + end; + +var + Form1: TForm1; + +implementation + +{$R *.lfm} + +uses + //DateUtils, + Math; + +const + A0 = 10.0; // (initial) oscillation amplitude + t0 = 5.0; // oscillation period + td = 20.0; // damping time constant + TWO_PI = 2.0*pi; + +{ TForm1 } + +{ Simulates position, velocity and acceleration of an oscillating body. The + oscillation is damped, i.e. the excursions are decreasing with time. Parameters + describing this damped oscillation are A0, t0 and td given above. } +procedure TForm1.TimerTimer(Sender: TObject); +var + t: Double; + x, v, a: Double; + exp_factor, sin_factor, cos_factor: Double; +begin + if PositionSeries.Count = 0 then + FStartTime := Now(); + + t := (Now() - FStartTime) * SecsPerDay; + exp_factor := exp(-t/td); + sin_factor := sin(TWO_PI * t / t0); + cos_factor := cos(TWO_PI * t / t0); + + // Position: an exponentially damped sinusoidal motion + x := A0 * sin_factor * exp_factor; + + // velocity = dx/dt + v := 1.0 / (t0*td) * (A0 * exp_factor * (2.0*pi*td * cos_factor - t0 * sin_factor)); + + // acceleration = dv/dt = d2x/dt2 + a := x / sqr(td) - sqr(TWO_PI/t0) * x - 2.0*TWO_PI*A0/(t0*td) * exp_factor * cos_factor; + + // Add values to series + PositionSeries.AddXY(t, x); + VelocitySeries.AddXY(t, v); + AccelerationSeries.AddXY(t, a); +end; + +{ Toggles between normal view and scrolling live view. In case of normal view + the entire extent of the chart is shown. } +procedure TForm1.cbLiveViewChange(Sender: TObject); +begin + ChartLiveView1.Active := cbLiveView.Checked; + if not ChartLiveView1.Active then + Chart1.ZoomFull; +end; + +{ Toggles between automatic scaling of the axes and predefined axis limits + (see FormCreate for the predefined values). } +procedure TForm1.cbFrozenAxesChange(Sender: TObject); +var + i: Integer; + wasActive: Boolean; +begin + wasActive := ChartLiveView1.Active; + ChartLiveView1.Active := false; // LiveView must be off when changing axes + for i := 1 to 3 do + with Chart1.AxisList[i].Range do + begin + UseMax := cbFrozenAxes.Checked; + UseMin := cbFrozenAxes.Checked; + end; + ChartLiveView1.Active := wasActive; // Restore liveview state +end; + +{ Resets and starts a new data generation run. } +procedure TForm1.btnResetClick(Sender: TObject); +begin + Timer.Enabled := false; + PositionSeries.Clear; + VelocitySeries.Clear; + AccelerationSeries.Clear; + Timer.Enabled := true; + btnStopResume.Caption := 'Stop'; +end; + +{ Stop or resume the data generation. When stopped a line break is added to the + series. } +procedure TForm1.btnStopResumeClick(Sender: TObject); +var + t: Double; +begin + Timer.Enabled := not Timer.Enabled; + if Timer.Enabled then + btnStopResume.Caption := 'Stop' + else begin + btnStopResume.Caption := 'Resume'; + // Add a break to the curves + t := (Now() - FStartTime) * SecsPerDay; + PositionSeries.AddXY(t, NaN); + VelocitySeries.AddXY(t, NaN); + AccelerationSeries.AddXY(t, NaN); + end; +end; + +procedure TForm1.FormCreate(Sender: TObject); +begin + { The following settings could also be made in the object inspector. } + + // LiveView must be off when setting up the axes. + with Chart1.AxisList[1].Range do + begin + UseMax := true; + UseMin := true; + Max := 10; + Min := -10; + end; + with Chart1.AxisList[2].Range do + begin + UseMax := true; + UseMin := true; + Max := 15; + Min := -15; + end; + with Chart1.AxisList[3].Range do + begin + UseMax := true; + UseMin := true; + Max := 15.0; + Min := -15.0; + end; + + // Activate the live view + ChartLiveView1.Active := true; + + // Start the "measurement" + Timer.Enabled := true; +end; + +{ Set the liveview's ViewportSize according to the value in the SpinEdit } +procedure TForm1.seViewportSizeChange(Sender: TObject); +begin + ChartLiveView1.ViewportSize := seViewportSize.Value; +end; + +end. + diff --git a/components/tachart/demo/liveview_paned/panedliveviewdemo.lpi b/components/tachart/demo/liveview_paned/panedliveviewdemo.lpi new file mode 100644 index 0000000000..f2c1845a39 --- /dev/null +++ b/components/tachart/demo/liveview_paned/panedliveviewdemo.lpi @@ -0,0 +1,79 @@ + + + + + + + + + <Scaled Value="True"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + </XPManifest> + </General> + <BuildModes> + <Item Name="Default" Default="True"/> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="TAChartLazarusPkg"/> + </Item> + <Item> + <PackageName Value="LCL"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="panedliveviewdemo.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="main.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="Form1"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="panedliveviewdemo"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Options> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/components/tachart/demo/liveview_paned/panedliveviewdemo.lpr b/components/tachart/demo/liveview_paned/panedliveviewdemo.lpr new file mode 100644 index 0000000000..46835943f3 --- /dev/null +++ b/components/tachart/demo/liveview_paned/panedliveviewdemo.lpr @@ -0,0 +1,25 @@ +program panedliveviewdemo; + +{$mode objfpc}{$H+} + +uses + {$IFDEF UNIX} + cthreads, + {$ENDIF} + {$IFDEF HASAMIGA} + athreads, + {$ENDIF} + Interfaces, // this includes the LCL widgetset + Forms, main, tachartlazaruspkg + { you can add units after this }; + +{$R *.res} + +begin + RequireDerivedFormResource:=True; + Application.Scaled:=True; + Application.Initialize; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. +