unit main;

{$mode objfpc}{$H+}

interface

uses
  LCLVersion,
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Spin,
  ComCtrls, ExtCtrls,
  TAGraph, TASeries, TASources, TAStyles, TACustomSeries, TACustomSource;

type

  { TForm1 }

  TForm1 = class(TForm)
    BtnNewData: TButton;
    Chart1: TChart;
    Chart1AreaSeries1: TAreaSeries;
    Chart2: TChart;
    Chart2AreaSeries1: TAreaSeries;
    Chart2AreaSeries2: TAreaSeries;
    Chart2LineSeries1: TLineSeries;
    Chart2LineSeries2: TLineSeries;
    ChartStyles1: TChartStyles;
    CbStacked: TCheckBox;
    CbRotated: TCheckBox;
    Cb3D: TCheckBox;
    CbUseZeroLevel: TCheckBox;
    CbBanded: TCheckBox;
    CbShowDropLines: TCheckBox;
    CbShowDataLabels: TCheckBox;
    CbLabelsAt: TComboBox;
    CbShowLegend: TCheckBox;
    CbCentered: TCheckBox;
    EdYCount: TSpinEdit;
    EdDepthBrightnessDelta: TSpinEdit;
    EdZeroLevel: TFloatSpinEdit;
    Label1: TLabel;
    LblDepthBrightnessDelta: TLabel;
    LblCount: TLabel;
    LblYCount: TLabel;
    PageControl1: TPageControl;
    Panel1: TPanel;
    EdCount: TSpinEdit;
    PgGeneral: TTabSheet;
    PgErrorRange: TTabSheet;
    ChartSourceArea1: TUserDefinedChartSource;
    ChartSourceLine1: TUserDefinedChartSource;
    ChartSourceArea2: TUserDefinedChartSource;
    ChartSourceLine2: TUserDefinedChartSource;
    procedure BtnNewDataClick(Sender: TObject);
    procedure CbBandedChange(Sender: TObject);
    procedure CbCenteredChange(Sender: TObject);
    procedure CbLabelsAtChange(Sender: TObject);
    procedure CbShowDataLabelsChange(Sender: TObject);
    procedure CbShowLegendChange(Sender: TObject);
    procedure CbStackedChange(Sender: TObject);
    procedure CbRotatedChange(Sender: TObject);
    procedure Cb3DChange(Sender: TObject);
    procedure CbUseZeroLevelChange(Sender: TObject);
    procedure ChartSourceArea1GetChartDataItem({%H-}ASource: TUserDefinedChartSource;
      AIndex: Integer; var AItem: TChartDataItem);
    procedure ChartSourceArea2GetChartDataItem(
      {%H-}ASource: TUserDefinedChartSource; AIndex: Integer;
      var AItem: TChartDataItem);
    procedure ChartSourceLine1GetChartDataItem({%H-}ASource: TUserDefinedChartSource;
      AIndex: Integer; var AItem: TChartDataItem);
    procedure ChartSourceLine2GetChartDataItem(
      {%H-}ASource: TUserDefinedChartSource; AIndex: Integer;
      var AItem: TChartDataItem);
    procedure CbShowDropLinesChange(Sender: TObject);
    procedure EdDepthBrightnessDeltaChange(Sender: TObject);
    procedure EdYCountChange(Sender: TObject);
    procedure EdZeroLevelChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure EdCountChange(Sender: TObject);
  private
    procedure PopulateSeries(N, NY: Integer);
    procedure UpdateStyles(Count: Integer);

  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

uses
  Math, TAChartUtils, TATextElements;

type
  TData = record
    x, y, dy: Double;
  end;
  TDataArray = array of TData;

var
  Data1, Data2: TDataArray;

{ TForm1 }

procedure TForm1.BtnNewDataClick(Sender: TObject);
begin
  PopulateSeries(EdCount.Value, EdYCount.Value);
end;

procedure TForm1.CbBandedChange(Sender: TObject);
begin
  Chart1AreaSeries1.Banded := CbBanded.Checked;
  if Chart1AreaSeries1.Banded then
    UpdateStyles(Chart1AreaSeries1.ListSource.YCount-1)
  else
    UpdateStyles(Chart1AreaSeries1.ListSource.YCount);
end;

procedure TForm1.CbCenteredChange(Sender: TObject);
begin
  Chart1AreaSeries1.MarkPositionCentered := CbCentered.Checked;
  if CbCentered.Checked then begin
    Chart1AreaSeries1.Marks.Distance := 0;
    Chart1AreaSeries1.Marks.Attachment := maCenter;
  end else begin
    Chart1AreaSeries1.Marks.Distance := 20;
    Chart1AreaSeries1.Marks.Attachment := maDefault;
  end;
end;

procedure TForm1.CbLabelsAtChange(Sender: TObject);
begin
  if CbLabelsAt.ItemIndex = 0 then
    Chart1AreaSeries1.Marks.YIndex := - 1
  else
    Chart1AreaSeries1.Marks.YIndex := CbLabelsAt.ItemIndex - 1;
end;

procedure TForm1.CbShowDataLabelsChange(Sender: TObject);
begin
  if CbShowDataLabels.Checked then begin
    Chart1AreaSeries1.Marks.Style := smsLabel;
    Chart1AreaSeries1.Marks.Format := '%.2f';
  end else
    Chart1AreaSeries1.Marks.Style := smsNone;
  CbCentered.Enabled := CbShowDataLabels.Checked;
  CbLabelsAt.Enabled := CbShowDataLabels.Checked;
end;

procedure TForm1.CbShowLegendChange(Sender: TObject);
begin
  Chart1.Legend.Visible := CbShowLegend.Checked;
end;

procedure TForm1.CbStackedChange(Sender: TObject);
begin
  Chart1AreaSeries1.Stacked := CbStacked.Checked;
end;

procedure TForm1.CbRotatedChange(Sender: TObject);
var
  tmp: Integer;
begin
  tmp := Chart1AreaSeries1.AxisIndexX;
  Chart1AreaSeries1.AxisIndexX := Chart1AreaSeries1.AxisIndexY;
  Chart1AreaSeries1.AxisIndexY := tmp;
end;

procedure TForm1.Cb3DChange(Sender: TObject);
const
  DEPTH = 20;
begin
  Chart1AreaSeries1.Depth := IfThen(Cb3D.Checked, DEPTH, 0);
  Chart1.Margins.Right := 4 + Chart1AreaSeries1.Depth;
  Chart1.Margins.Top := 4 + Chart1AreaSeries1.Depth;
  EdDepthBrightnessDelta.Enabled := Cb3D.Checked;
  lblDepthBrightnessDelta.Enabled := Cb3D.Checked;
end;

procedure TForm1.CbUseZeroLevelChange(Sender: TObject);
begin
  Chart1AreaSeries1.UseZeroLevel := CbUseZeroLevel.Checked;
end;

procedure TForm1.ChartSourceArea1GetChartDataItem(
  ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
begin
  AItem.X := Data1[AIndex].x;
  AItem.Y := Data1[AIndex].y - Data1[AIndex].dy;
  AItem.YList[0] := Data1[AIndex].y + Data1[AIndex].dy;
end;

procedure TForm1.ChartSourceArea2GetChartDataItem(
  ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
begin
  AItem.X := Data2[AIndex].x;
  AItem.Y := Data2[AIndex].y;
  AItem.YList[0] := -Data2[AIndex].dy;
  AItem.YList[1] := 2*Data2[AIndex].dy;
end;

procedure TForm1.ChartSourceLine1GetChartDataItem(
  ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
begin
  AItem.X := Data1[AIndex].X;
  AItem.Y := Data1[AIndex].Y;
end;

procedure TForm1.ChartSourceLine2GetChartDataItem(
  ASource: TUserDefinedChartSource; AIndex: Integer; var AItem: TChartDataItem);
begin
  AItem.X := Data2[AIndex].X;
  AItem.Y := Data2[AIndex].Y;
end;

procedure TForm1.CbShowDropLinesChange(Sender: TObject);
begin
  if CbShowDropLines.Checked then
    Chart1AreaSeries1.AreaLinesPen.Style := psSolid
  else
    Chart1AreaSeries1.AreaLinesPen.Style := psClear;
end;

procedure TForm1.EdDepthBrightnessDeltaChange(Sender: TObject);
begin
  Chart1AreaSeries1.DepthBrightnessDelta := EdDepthBrightnessDelta.Value;
end;

procedure TForm1.EdYCountChange(Sender: TObject);
begin
  PopulateSeries(EdCount.Value, EdYCount.Value);
end;

procedure TForm1.EdZeroLevelChange(Sender: TObject);
begin
  Chart1AreaSeries1.ZeroLevel := EdZeroLevel.Value;
end;

procedure TForm1.FormCreate(Sender: TObject);
const
  N1 = 20;
  N2 = 25;
  XMIN = -10;
  XMAX = +10;
var
  i: Integer;
begin
  PopulateSeries(EdCount.Value, EdYCount.Value);

  SetLength(Data1, N1);
  for i:=0 to N1-1 do begin
    Data1[i].x := XMIN + (XMAX - XMIN) * i / (N1-1);
    Data1[i].y := sin(Data1[i].x * 0.5);
    Data1[i].dy := randg(0.2, 0.05);
  end;
  ChartSourceLine1.YCount := 1;
  ChartSourceLine1.PointsNumber := N1;
  ChartSourceArea1.YCount := 2;
  ChartSourceArea1.PointsNumber := N1;

  SetLength(Data2, N2);
  for i:=0 to N2-1 do begin
    Data2[i].x := XMIN + (XMAX - XMIN) * i / (N2-1);
    Data2[i].y := cos(Data2[i].x); // + randg(0, 0.2);
    Data2[i].dy := randg(0.2, 0.05);
  end;
  ChartSourceLine2.YCount := 1;
  ChartSourceLine2.PointsNumber := N2;
  ChartSourceArea2.YCount := 3;
  ChartSourceArea2.PointsNumber := N2;

  Chart2AreaSeries1.Banded := true;
  Chart2AreaSeries2.Banded := true;
end;

procedure TForm1.EdCountChange(Sender: TObject);
begin
  PopulateSeries(EdCount.Value, EdYCount.Value);
end;

procedure TForm1.PopulateSeries(N, NY: Integer);
var
  i: Integer;
  idx: Integer;
begin
  Chart1AreaSeries1.Clear;
  Chart1AreaSeries1.ListSource.YCount := NY;
  for i:=1 to N do
    Chart1AreaSeries1.AddXY(i, Random, [0.1 + Random, 0.2 + Random, 0.3 + Random, 0.2 + Random]);

  UpdateStyles(Chart1AreaSeries1.ListSource.YCount);

  idx := CbLabelsAt.ItemIndex;
  CbLabelsAt.Clear;
  CbLabelsAt.Items.Add('all');
  for i:= 0 to NY - 1 do
    CbLabelsAt.Items.Add('y index ' + IntToStr(i));
  if (idx > -1) and (idx < CblabelsAt.Items.Count) then
    CbLabelsAt.ItemIndex := idx
  else
    CbLabelsAt.ItemIndex := 0;
end;

procedure TForm1.UpdateStyles(Count: Integer);
const
  COLORS: array[0..4] of TColor = (clRed, clBlue, clYellow, clGreen, clFuchsia);
var
  i: Integer;
begin
  ChartStyles1.Styles.Clear;
  for i := 1 to Count do
    with ChartStyles1.Add do begin
      Brush.Color := COLORS[i-1];
      Pen.Width := 3;
      Text := 'Curve ' + IntToStr(i);
    end;
end;

end.

