diff --git a/components/tachart/demo/html/main.lfm b/components/tachart/demo/html/main.lfm
index 11b7fc30a5..b8c09a44bb 100644
--- a/components/tachart/demo/html/main.lfm
+++ b/components/tachart/demo/html/main.lfm
@@ -1,17 +1,17 @@
object MainForm: TMainForm
Left = 280
- Height = 432
+ Height = 452
Top = 130
Width = 655
Caption = 'HTML demo'
- ClientHeight = 432
+ ClientHeight = 452
ClientWidth = 655
OnCreate = FormCreate
LCLVersion = '1.9.0.0'
object BottomPanel: TPanel
Left = 8
Height = 91
- Top = 333
+ Top = 353
Width = 647
Align = alBottom
AutoSize = True
@@ -26,11 +26,11 @@ object MainForm: TMainForm
Left = 0
Height = 78
Top = 8
- Width = 221
+ Width = 327
AutoFill = True
AutoSize = True
BorderSpacing.InnerBorder = 4
- Caption = 'HTML'
+ Caption = 'Show HTML codes'
ChildSizing.LeftRightSpacing = 6
ChildSizing.TopBottomSpacing = 6
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
@@ -38,21 +38,23 @@ object MainForm: TMainForm
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
- ChildSizing.ControlsPerLine = 3
+ ChildSizing.ControlsPerLine = 4
ClientHeight = 58
- ClientWidth = 217
- Columns = 3
+ ClientWidth = 323
+ Columns = 4
Items.Strings = (
'title'
'footer'
'legend'
+ 'series labels'
+ 'x axis labels'
'x axis title'
'y axis title'
)
OnItemClick = CgHTMLItemClick
TabOrder = 0
Data = {
- 050000000202020202
+ 0700000002020202020202
}
end
object BtnCopyToClipboard: TButton
@@ -108,7 +110,7 @@ object MainForm: TMainForm
end
object Chart: TChart
Left = 8
- Height = 317
+ Height = 337
Top = 8
Width = 639
AxisList = <
@@ -119,7 +121,7 @@ object MainForm: TMainForm
Title.LabelFont.Height = -16
Title.LabelFont.Orientation = 900
Title.Visible = True
- Title.Caption = 'Area, cm2'
+ Title.Caption = 'Area A, cm2'
Title.TextFormat = tfHTML
end
item
@@ -127,20 +129,22 @@ object MainForm: TMainForm
Grid.Style = psSolid
Grid.Visible = False
Alignment = calBottom
+ Marks.TextFormat = tfHTML
Minors = <>
Title.LabelFont.Height = -16
Title.Visible = True
- Title.Caption = 'Angle α'
+ Title.Caption = 'Angle α, °'
Title.TextFormat = tfHTML
+ OnMarkToText = ChartAxisList1MarkToText
end>
BackColor = clWhite
Foot.Alignment = taLeftJustify
Foot.Brush.Color = clBtnFace
Foot.Brush.Style = bsClear
- Foot.Font.Color = clBlue
+ Foot.Font.Color = clGray
Foot.Text.Strings = (
'Reference:'
- 'W. Shakespeare, "J. Irreproducible Results", 38, 512 (2017)'
+ 'W. Shakespeare, "J. Irreprod. Res.", 38, 512 (2017)'
)
Foot.TextFormat = tfHTML
Foot.Visible = True
@@ -148,7 +152,7 @@ object MainForm: TMainForm
Legend.Visible = True
Title.Brush.Color = clBtnFace
Title.Brush.Style = bsClear
- Title.Font.Color = clBlue
+ Title.Font.Color = clNavy
Title.Font.Height = -19
Title.Font.Style = [fsBold]
Title.Text.Strings = (
@@ -159,35 +163,35 @@ object MainForm: TMainForm
Align = alClient
BorderSpacing.Around = 8
Color = clWhite
- object RedSeries: TLineSeries
- Title = 'Red series'
+ object DataSeries: TLineSeries
+ Marks.Format = '%2:s'
+ Marks.Frame.Color = clGray
+ Marks.LinkPen.Color = clGray
+ Marks.Style = smsLabel
+ Marks.TextFormat = tfHTML
+ Title = 'Measured'
LinePen.Color = clRed
- Source = RedSource
+ LineType = ltNone
+ Pointer.Brush.Color = clRed
+ Pointer.Style = psCircle
+ ShowPoints = True
end
- object BlueSeries: TLineSeries
- Title = 'Blue series'
- LinePen.Color = clBlue
- Source = BlueSource
+ object FitSeries: TFitSeries
+ Marks.Alignment = taCenter
+ Marks.TextFormat = tfHTML
+ Title = 'Fit curve (blue)'
+ Pen.Color = clBlue
+ Pointer.Visible = False
+ Source = ListChartSource
+ OnFitComplete = FitSeriesFitComplete
end
end
- object RedSource: TRandomChartSource
- PointsNumber = 20
- RandSeed = 1926906778
- XMax = 90
- XMin = 0
- YMax = 10
- YMin = 4
- left = 121
- top = 52
+ object ListChartSource: TListChartSource
+ left = 224
+ top = 88
end
- object BlueSource: TRandomChartSource
- PointsNumber = 30
- RandSeed = 1926958054
- XMax = 90
- XMin = 0
- YMax = 8
- YMin = 0
- left = 120
- top = 111
+ object ListChartSource_Fit: TListChartSource
+ left = 224
+ top = 153
end
end
diff --git a/components/tachart/demo/html/main.pas b/components/tachart/demo/html/main.pas
index 956321a2f2..bd6ae8a54a 100644
--- a/components/tachart/demo/html/main.pas
+++ b/components/tachart/demo/html/main.pas
@@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, FileUtil, TAGraph, TASeries, TASources, Forms, Controls,
- Graphics, Dialogs, ExtCtrls, StdCtrls;
+ Graphics, Dialogs, ExtCtrls, StdCtrls, TAChartAxisUtils, TAFuncSeries;
type
@@ -18,17 +18,21 @@ type
BtnSaveSVG: TButton;
Chart: TChart;
CgHTML: TCheckGroup;
- RedSource: TRandomChartSource;
- BlueSource: TRandomChartSource;
- RedSeries: TLineSeries;
- BlueSeries: TLineSeries;
+ FitSeries: TFitSeries;
+ ListChartSource: TListChartSource;
+ DataSeries: TLineSeries;
BottomPanel: TPanel;
+ ListChartSource_Fit: TListChartSource;
procedure BtnCopyToClipboardClick(Sender: TObject);
procedure BtnSaveWMFClick(Sender: TObject);
procedure BtnSaveSVGClick(Sender: TObject);
procedure CgHTMLItemClick(Sender: TObject; Index: integer);
+ procedure ChartAxisList1MarkToText(var AText: String; AMark: Double);
+ procedure FitSeriesFitComplete(Sender: TObject);
procedure FormCreate(Sender: TObject);
+
private
+ procedure CreateData;
public
@@ -42,7 +46,7 @@ implementation
{$R *.lfm}
uses
- TAChartUtils, {$IFDEF WINDOWS}TADrawerWMF,{$ENDIF} TADrawerSVG;
+ Math, TAChartUtils, {$IFDEF WINDOWS}TADrawerWMF,{$ENDIF} TADrawerSVG;
{ TMainForm }
@@ -70,26 +74,86 @@ procedure TMainForm.CgHTMLItemClick(Sender: TObject; Index: integer);
var
tf: TChartTextFormat;
begin
- if CgHTML.Checked[Index] then tf := tfHTML else tf := tfNormal;
+ if CgHTML.Checked[Index] then tf := tfNormal else tf := tfHTML;
case Index of
0: Chart.Title.TextFormat := tf;
1: Chart.Foot.TextFormat := tf;
2: Chart.Legend.TextFormat := tf;
- 3: Chart.BottomAxis.Title.TextFormat := tf;
- 4: Chart.LeftAxis.Title.TextFormat := tf;
+ 3: DataSeries.Marks.TextFormat := tf;
+ 4: Chart.BottomAxis.Marks.TextFormat := tf;
+ 5: Chart.BottomAxis.Title.TextFormat := tf;
+ 6: Chart.LeftAxis.Title.TextFormat := tf;
end;
end;
+procedure TMainForm.ChartAxisList1MarkToText(var AText: String; AMark: Double);
+begin
+ AText := AText + '°';
+end;
+
+procedure TMainForm.CreateData;
+const
+ N = 20;
+ MIN = 0;
+ MAX = 90;
+ OUTLIER_INDEX = 12;
+var
+ i: Integer;
+ x, y: Double;
+ s: String;
+begin
+ for i:=0 to N-1 do begin
+ x := MIN + (MAX - MIN) * i / (N-1) + 5*(random - 0.5);
+ if i = OUTLIER_INDEX then begin
+ y := 631;
+ s := 'Defective device!' + LineEnding + '(α = ' + FormatFloat('0.00', x) + '°)';
+ end else
+ begin
+ y := x*x / 10 + (random - 0.5) * 100;
+ s := '';
+ end;
+ ListChartSource.Add(x, y, s);
+ if i <> OUTLIER_INDEX then
+ ListChartSource_Fit.Add(x, y);
+ end;
+ DataSeries.Source := ListChartSource;
+ FitSeries.Source := ListChartSource_Fit;
+end;
+
+procedure TMainForm.FitSeriesFitComplete(Sender: TObject);
+var
+ p: Array of Double;
+ i: Integer;
+ s: String;
+begin
+ SetLength(p, FitSeries.ParamCount);
+ for i:=0 to FitSeries.ParamCount-1 do
+ p[i] := FitSeries.Param[i];
+
+ s := FitSeries.EquationText.
+ x('α').
+ y('A').
+ NumFormat('%.2f').
+ DecimalSeparator('.').
+ Params(p).
+ Get;
+ FitSeries.Title := 'Fitted: ' + s;
+end;
+
procedure TMainForm.FormCreate(Sender: TObject);
begin
- CgHTML.Checked[0] := Chart.Title.TextFormat = tfHTML;
- CgHTML.Checked[1] := Chart.Foot.TextFormat = tfHTML;
- CgHTML.Checked[2] := Chart.Legend.TextFormat = tfHTML;
- CgHTML.Checked[3] := Chart.BottomAxis.Title.TextFormat = tfHTML;
- CgHTML.Checked[4] := Chart.LeftAxis.Title.TextFormat = tfHTML;
+ CreateData;
+
+ CgHTML.Checked[0] := Chart.Title.TextFormat = tfNormal;
+ CgHTML.Checked[1] := Chart.Foot.TextFormat = tfNormal;
+ CgHTML.Checked[2] := Chart.Legend.TextFormat = tfNormal;
+ CgHTML.Checked[3] := DataSeries.Marks.TextFormat = tfNormal;
+ CgHTML.Checked[4] := Chart.BottomAxis.Marks.TextFormat = tfNormal;
+ CgHTML.Checked[5] := Chart.BottomAxis.Title.TextFormat = tfNormal;
+ CgHTML.Checked[6] := Chart.LeftAxis.Title.TextFormat = tfNormal;
{$IFDEF WINDOWS}
- Chart.Foot.Text[1] := '' + Chart.Foot.Text[1] + '';
+ Chart.Foot.Text[1] := '' + Chart.Foot.Text[1] + '';
{$ELSE}
BtnSaveWMF.Hide;
{$ENDIF}
diff --git a/components/tachart/tafitutils.pas b/components/tachart/tafitutils.pas
index 12cb029733..b5c320b14e 100644
--- a/components/tachart/tafitutils.pas
+++ b/components/tachart/tafitutils.pas
@@ -14,6 +14,9 @@ unit TAFitUtils;
interface
+uses
+ TAChartUtils;
+
type
TFitEquation = (
fePolynomial, // y = b0 + b1*x + b2*x^2 + ... bn*x^n
@@ -23,43 +26,51 @@ type
);
IFitEquationText = interface
+ function DecimalSeparator(AValue: Char): IFitEquationText;
function Equation(AEquation: TFitEquation): IFitEquationText;
function X(AText: String): IFitEquationText;
function Y(AText: String): IFitEquationText;
function NumFormat(AFormat: String): IFitEquationText;
function NumFormats(const AFormats: array of String): IFitEquationText;
function Params(const AParams: array of Double): IFitEquationText;
+ function TextFormat(AFormat: TChartTextFormat): IFitEquationText;
function Get: String;
end;
TFitEmptyEquationText = class(TInterfacedObject, IFitEquationText)
public
+ function DecimalSeparator(AValue: Char): IFitEquationText;
function Equation(AEquation: TFitEquation): IFitEquationText;
function X(AText: String): IFitEquationText;
function Y(AText: String): IFitEquationText;
function NumFormat(AFormat: String): IFitEquationText;
function NumFormats(const AFormats: array of String): IFitEquationText;
function Params(const AParams: array of Double): IFitEquationText;
+ function TextFormat(AFormat: TChartTextFormat): IFitEquationText;
function Get: String;
end;
TFitEquationText = class(TInterfacedObject, IFitEquationText)
strict private
+ FDecSep: Char;
FEquation: TFitEquation;
FX: String;
FY: String;
FNumFormat: String;
FNumFormats: array of String;
FParams: array of Double;
+ FTextFormat: TChartTextFormat;
function GetNumFormat(AIndex: Integer): String;
public
constructor Create;
+ function DecimalSeparator(AValue: Char): IFitEquationText;
function Equation(AEquation: TFitEquation): IFitEquationText;
function X(AText: String): IFitEquationText;
function Y(AText: String): IFitEquationText;
function NumFormat(AFormat: String): IFitEquationText;
function NumFormats(const AFormats: array of String): IFitEquationText;
function Params(const AParams: array of Double): IFitEquationText;
+ function TextFormat(AFormat: TChartTextFormat): IFitEquationText;
function Get: String;
end;
@@ -68,15 +79,22 @@ type
implementation
uses
- TAChartUtils, StrUtils, SysUtils;
+ StrUtils, SysUtils;
operator := (AEq: IFitEquationText): String;
begin
Result := AEq.Get;
end;
+
{ TFitEmptyEquationText }
+function TFitEmptyEquationText.DecimalSeparator(AValue: Char): IFitEquationText;
+begin
+ Unused(AValue);
+ Result := Self;
+end;
+
function TFitEmptyEquationText.Equation(
AEquation: TFitEquation): IFitEquationText;
begin
@@ -109,6 +127,12 @@ begin
Result := Self;
end;
+function TFitEmptyEquationText.TextFormat(AFormat: TChartTextFormat): IFitEquationText;
+begin
+ Unused(AFormat);
+ Result := Self;
+end;
+
function TFitEmptyEquationText.X(AText: String): IFitEquationText;
begin
Unused(AText);
@@ -128,6 +152,13 @@ begin
FX := 'x';
FY := 'y';
FNumFormat := '%.9g';
+ FDecSep := DefaultFormatSettings.DecimalSeparator;
+end;
+
+function TFitEquationText.DecimalSeparator(AValue: Char): IFitEquationText;
+begin
+ FDecSep := AValue;
+ Result := self;
end;
function TFitEquationText.Equation(AEquation: TFitEquation): IFitEquationText;
@@ -139,24 +170,54 @@ end;
function TFitEquationText.Get: String;
var
ps: String = '';
+ s: String;
i: Integer;
+ fs: TFormatSettings;
begin
- if Length(FParams) = 0 then exit('');
- Result := Format('%s = ' + GetNumFormat(0), [FY, FParams[0]]);
+ if Length(FParams) = 0 then
+ exit('');
+
+ fs := DefaultFormatSettings;
+ fs.DecimalSeparator := FDecSep;
+
+ Result := Format('%s = ' + GetNumFormat(0), [FY, FParams[0]], fs);
if FEquation in [fePolynomial, feLinear] then
for i := 1 to High(FParams) do begin
- if FParams[i] = 0 then continue;
- if i > 1 then ps := Format('^%d', [i]);
- Result += Format(
- ' %s ' + GetNumFormat(i) + '*%s%s',
- [IfThen(FParams[i] > 0, '+', '-'), Abs(FParams[i]), FX, ps]);
+ if FParams[i] = 0 then
+ continue;
+ if FTextFormat = tfNormal then
+ begin
+ if i > 1 then ps := Format('^%d', [i]);
+ s := '*%s%s';
+ end else
+ begin
+ if i > 1 then ps := Format('%d', [i]);
+ s := '·%s%s';
+ end;
+ Result += Format(' %s ' + GetNumFormat(i) + s,
+ [IfThen(FParams[i] > 0, '+', '-'), Abs(FParams[i]), FX, ps], fs
+ );
end
else if (Length(FParams) >= 2) and (FParams[0] <> 0) and (FParams[1] <> 0) then
case FEquation of
feExp:
- Result += Format(' * exp(' + GetNumFormat(1) +' * %s)', [FParams[1], FX]);
+ if FTextFormat = tfNormal then
+ Result += Format(' * exp(' + GetNumFormat(1) +' * %s)',
+ [FParams[1], FX], fs
+ )
+ else
+ Result += Format(' · e' + GetNumFormat(1) + '· %s',
+ [FParams[1], FX], fs
+ );
fePower:
- Result += Format(' * %s^' + GetNumFormat(1), [FX, FParams[1]]);
+ if FTextFormat = tfNormal then
+ Result += Format(' * %s^' + GetNumFormat(1),
+ [FX, FParams[1]], fs
+ )
+ else
+ Result += Format(' · %s' + GetNumFormat(1) + '',
+ [FX, FParams[1]], fs
+ );
end;
end;
@@ -196,6 +257,12 @@ begin
Result := Self;
end;
+function TFitEquationText.TextFormat(AFormat: TChartTextFormat): IFitEquationText;
+begin
+ FTextFormat := AFormat;
+ Result := Self;
+end;
+
function TFitEquationText.X(AText: String): IFitEquationText;
begin
FX := AText;
diff --git a/components/tachart/tafuncseries.pas b/components/tachart/tafuncseries.pas
index 6b2a510261..079e14e65f 100644
--- a/components/tachart/tafuncseries.pas
+++ b/components/tachart/tafuncseries.pas
@@ -1489,7 +1489,7 @@ begin
Result := TFitEquationText.Create
else
Result := TFitEmptyEquationText.Create;
- Result.Equation(FitEquation).Params(FFitParams);
+ Result.TextFormat(Marks.TextFormat).Equation(FitEquation).Params(FFitParams);
end;
procedure TFitSeries.ExecFit;