TAChart: Usa HTML tags in fit equation of TFitSeries. Use FitSeries in html demo.

git-svn-id: trunk@55449 -
This commit is contained in:
wp 2017-07-05 11:03:02 +00:00
parent d4b7ead41d
commit e4049c3629
4 changed files with 201 additions and 66 deletions

View File

@ -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, cm<sup>2</cm>'
Title.Caption = 'Area A, cm<sup>2</cm>'
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 &alpha;'
Title.Caption = 'Angle &alpha;, &deg;'
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 = (
'<u>Reference</u>:'
'W. Shakespeare, <i>"J. Irreproducible Results"</i>, <b>38</b>, 512 (2017)'
'W. Shakespeare, <i>"J. Irreprod. Res."</i>, <b>38</b>, 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 = '<font color="red">Red</font> series'
object DataSeries: TLineSeries
Marks.Format = '%2:s'
Marks.Frame.Color = clGray
Marks.LinkPen.Color = clGray
Marks.Style = smsLabel
Marks.TextFormat = tfHTML
Title = '<font color="red">Measured</font>'
LinePen.Color = clRed
Source = RedSource
LineType = ltNone
Pointer.Brush.Color = clRed
Pointer.Style = psCircle
ShowPoints = True
end
object BlueSeries: TLineSeries
Title = '<font color="blue">Blue</font> series'
LinePen.Color = clBlue
Source = BlueSource
object FitSeries: TFitSeries
Marks.Alignment = taCenter
Marks.TextFormat = tfHTML
Title = 'Fit curve (<font color="blue">blue</font>)'
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

View File

@ -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 + '&deg;';
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 + '(&alpha; = ' + FormatFloat('0.00', x) + '&deg;)';
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('&alpha;').
y('A').
NumFormat('%.2f').
DecimalSeparator('.').
Params(p).
Get;
FitSeries.Title := '<font color="blue">Fitted:</font> ' + 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] := '<font name="Times New Roman" color="blue">' + Chart.Foot.Text[1] + '</font>';
Chart.Foot.Text[1] := '<font name="Times New Roman" color="gray">' + Chart.Foot.Text[1] + '</font>';
{$ELSE}
BtnSaveWMF.Hide;
{$ENDIF}

View File

@ -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('<sup>%d</sup>', [i]);
s := '&middot;%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(' &middot; e<sup>' + GetNumFormat(1) + '&middot; %s</sup>',
[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(' &middot; %s<sup>' + GetNumFormat(1) + '</sup>',
[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;

View File

@ -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;