TAChart: Add new series type TFieldSeries. Add sheet "field" in demo "multi".

git-svn-id: trunk@51757 -
This commit is contained in:
wp 2016-02-29 14:17:41 +00:00
parent 5d6a59cbb4
commit 53d48e17bf
13 changed files with 539 additions and 32 deletions

View File

@ -8,23 +8,23 @@ object Form1: TForm1
ClientWidth = 529
OnCreate = FormCreate
Position = poScreenCenter
LCLVersion = '1.1'
LCLVersion = '1.7'
object PageControl1: TPageControl
Left = 0
Height = 459
Top = 0
Width = 529
ActivePage = tsBubble
ActivePage = tsField
Align = alClient
TabIndex = 0
TabIndex = 4
TabOrder = 0
object tsBubble: TTabSheet
Caption = 'Bubble'
ClientHeight = 433
ClientHeight = 431
ClientWidth = 521
object chBubble: TChart
Left = 0
Height = 433
Height = 431
Top = 0
Width = 521
AxisList = <
@ -49,7 +49,6 @@ object Form1: TForm1
'TAChart'
)
Align = alClient
ParentColor = False
object Chart1BubbleSeries1: TBubbleSeries
Marks.Attachment = maCenter
Marks.Distance = 0
@ -64,11 +63,11 @@ object Form1: TForm1
end
object tsStacked: TTabSheet
Caption = 'Stacked'
ClientHeight = 433
ClientHeight = 431
ClientWidth = 521
object chStacked: TChart
Left = 0
Height = 391
Height = 389
Top = 0
Width = 521
AxisList = <
@ -94,7 +93,6 @@ object Form1: TForm1
'TAChart'
)
Align = alClient
ParentColor = False
object chStackedBarSeries1: TBarSeries
Legend.GroupIndex = 0
Legend.Multiplicity = lmStyle
@ -145,7 +143,7 @@ object Form1: TForm1
object pnStackedControls: TPanel
Left = 0
Height = 42
Top = 391
Top = 389
Width = 521
Align = alBottom
BevelOuter = bvNone
@ -169,7 +167,7 @@ object Form1: TForm1
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 3
ClientHeight = 24
ClientHeight = 22
ClientWidth = 177
Columns = 3
ItemIndex = 0
@ -183,9 +181,9 @@ object Form1: TForm1
end
object cbPercentage: TCheckBox
Left = 192
Height = 17
Height = 19
Top = 15
Width = 75
Width = 79
Caption = 'Percentage'
OnChange = cbPercentageChange
TabOrder = 1
@ -206,7 +204,7 @@ object Form1: TForm1
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 3
ClientHeight = 24
ClientHeight = 22
ClientWidth = 220
Columns = 3
Items.Strings = (
@ -224,11 +222,11 @@ object Form1: TForm1
end
object tsWhiskers: TTabSheet
Caption = 'Box-and-whiskers'
ClientHeight = 433
ClientHeight = 431
ClientWidth = 521
object chWhiskers: TChart
Left = 0
Height = 433
Height = 431
Top = 0
Width = 521
AxisList = <
@ -251,7 +249,6 @@ object Form1: TForm1
'TAChart'
)
Align = alClient
ParentColor = False
object chWhiskersBoxAndWhiskerSeries1: TBoxAndWhiskerSeries
Title = 't1'
BoxBrush.Color = clGreen
@ -264,11 +261,11 @@ object Form1: TForm1
end
object tsOHLC: TTabSheet
Caption = 'OHLC'
ClientHeight = 433
ClientHeight = 431
ClientWidth = 521
object chOHLC: TChart
Left = 0
Height = 433
Height = 431
Top = 0
Width = 521
AxisList = <
@ -297,19 +294,113 @@ object Form1: TForm1
Title.Visible = True
Align = alClient
Color = clSkyBlue
ParentColor = False
object chOHLCOpenHighLowCloseSeries1: TOpenHighLowCloseSeries
Title = 'test'
CandlestickDownBrush.Color = clRed
CandlestickUpBrush.Color = clLime
DownLinePen.Color = clRed
DownLinePen.EndCap = pecSquare
DownLinePen.Width = 2
LinePen.Color = clBlue
LinePen.EndCap = pecSquare
LinePen.Width = 2
Mode = mOHLC
TickWidth = 30
end
end
end
object tsField: TTabSheet
Caption = 'Field'
ClientHeight = 431
ClientWidth = 521
object chField: TChart
Left = 0
Height = 397
Top = 0
Width = 521
AxisList = <
item
Grid.Visible = False
Minors = <>
Title.LabelFont.Orientation = 900
end
item
Grid.Visible = False
Alignment = calBottom
Minors = <>
end>
BackColor = clWhite
Foot.Brush.Color = clBtnFace
Foot.Font.Color = clBlue
Legend.Visible = True
Title.Brush.Color = clBtnFace
Title.Font.Color = clBlue
Title.Text.Strings = (
'TAChart'
)
Align = alClient
object chFieldFieldSeries1: TFieldSeries
Title = 'Vector field'
Arrow.BaseLength = 30
Arrow.Length = 40
Arrow.Visible = True
Arrow.Width = 20
Pen.Color = clBlue
end
end
object Panel1: TPanel
Left = 0
Height = 34
Top = 397
Width = 521
Align = alBottom
BevelOuter = bvNone
ClientHeight = 34
ClientWidth = 521
TabOrder = 1
object rbRadial: TRadioButton
Left = 8
Height = 19
Top = 8
Width = 49
Caption = 'radial'
Checked = True
OnChange = FieldTypeChange
TabOrder = 1
TabStop = True
end
object rbTangential: TRadioButton
Left = 77
Height = 19
Top = 8
Width = 73
Caption = 'tangential'
OnChange = FieldTypeChange
TabOrder = 0
end
object Label1: TLabel
Left = 208
Height = 15
Top = 10
Width = 95
Caption = 'Max vector length'
ParentColor = False
end
object edMaxVectorLength: TFloatSpinEdit
Left = 320
Height = 23
Top = 6
Width = 74
Alignment = taRightJustify
Increment = 0.1
MaxValue = 10
MinValue = 0.1
OnChange = edMaxVectorLengthChange
TabOrder = 2
Value = 0.5
end
end
end
end
object lcsBubble: TListChartSource
DataPoints.Strings = (

View File

@ -6,7 +6,8 @@ interface
uses
Classes, ComCtrls, ExtCtrls, StdCtrls, SysUtils, FileUtil, Forms, Controls,
Graphics, Dialogs, TAGraph, TAMultiSeries, TASeries, TASources, TAStyles;
Graphics, Dialogs, Spin, TAGraph, TAMultiSeries, TASeries, TASources,
TAStyles;
type
@ -16,6 +17,8 @@ type
ccsStacked: TCalculatedChartSource;
cbPercentage: TCheckBox;
cgShowStackLevels: TCheckGroup;
chField: TChart;
chFieldFieldSeries1: TFieldSeries;
chOHLC: TChart;
ChartStyles1: TChartStyles;
chOHLCOpenHighLowCloseSeries1: TOpenHighLowCloseSeries;
@ -27,19 +30,29 @@ type
Chart1BubbleSeries1: TBubbleSeries;
chStackedBarSeries1: TBarSeries;
chWhiskersBoxAndWhiskerSeries1: TBoxAndWhiskerSeries;
edMaxVectorLength: TFloatSpinEdit;
Label1: TLabel;
lcsBubble: TListChartSource;
PageControl1: TPageControl;
Panel1: TPanel;
pnStackedControls: TPanel;
rbRadial: TRadioButton;
rbTangential: TRadioButton;
rgStackedSeries: TRadioGroup;
rcsStacked: TRandomChartSource;
tsField: TTabSheet;
tsOHLC: TTabSheet;
tsWhiskers: TTabSheet;
tsStacked: TTabSheet;
tsBubble: TTabSheet;
procedure cbPercentageChange(Sender: TObject);
procedure cgShowStackLevelsItemClick(Sender: TObject; Index: integer);
procedure edMaxVectorLengthChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FieldTypeChange(Sender: TObject);
procedure rgStackedSeriesClick(Sender: TObject);
private
procedure CreateFieldSeriesData;
end;
var
@ -50,7 +63,7 @@ implementation
{$R *.lfm}
uses
TAChartUtils;
TAChartUtils, TAGeometry;
{ TForm1 }
@ -74,6 +87,47 @@ begin
ccsStacked.ReorderYList := s[1..Length(s) - 1];
end;
procedure TForm1.CreateFieldSeriesData;
const
NX = 21;
NY = 21;
MIN = -5.0;
MAX = +5.0;
var
i, j: Integer;
x, y, r: Double;
v: TDoublePoint;
begin
v := DoublePoint(2.0, 2.0);
r := sqrt(sqr(v.x) + sqr(v.y));
chFieldFieldSeries1.Clear;
for j := 0 to NY - 1 do begin
y := MIN + (MAX - MIN) / (NY - 1) * j;
for i := 0 to NX - 1 do begin
x := MIN + (MAX - MIN) / (NX - 1) * i;
r := sqr(x) + sqr(y);
if r > 0.1 then begin
if rbRadial.Checked then
v := DoublePoint(x/r, y/r) // radial vector
else
if rbTangential.Checked then
v := DoublePoint(y/r, -x/r); // tangential vector
chFieldFieldSeries1.AddVector(x, y, v.x, v.y);
end;
end;
end;
// Since the data points, in this example, have a distance of 0.5 units we
// can avoid overlapping of vectors if they are scaled to a length of 0.5
// units as well.
chFieldFieldSeries1.NormalizeVectors(0.5);
end;
procedure TForm1.edMaxVectorLengthChange(Sender: TObject);
begin
chFieldFieldSeries1.NormalizeVectors(EdMaxVectorLength.Value);
chField.Invalidate;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
ylist: array [1..4] of Double;
@ -104,6 +158,13 @@ begin
Exchange(ylist[1], ylist[2]);
chOHLCOpenHighLowCloseSeries1.AddXY(i, y, ylist);
end;
CreateFieldSeriesData;
end;
procedure TForm1.FieldTypeChange(Sender: TObject);
begin
CreateFieldSeriesData;
end;
procedure TForm1.rgStackedSeriesClick(Sender: TObject);

View File

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="9"/>
@ -46,7 +46,6 @@
<Unit0>
<Filename Value="multidemo.lpr"/>
<IsPartOfProject Value="True"/>
<UnitName Value="multidemo"/>
</Unit0>
<Unit1>
<Filename Value="Main.pas"/>
@ -54,7 +53,6 @@
<ComponentName Value="Form1"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<UnitName Value="Main"/>
</Unit1>
</Units>
</ProjectOptions>
@ -78,12 +76,6 @@
</Win32>
</Options>
</Linking>
<Other>
<CompilerMessages>
<UseMsgFile Value="True"/>
</CompilerMessages>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="3">

View File

@ -101,6 +101,10 @@ msgstr "Entf."
msgid "Distance measurement"
msgstr "Distanzmessung"
#: tachartstrconsts.rsfieldseries
msgid "Vector field series"
msgstr "Vektorfeld-Diagramm"
#: tachartstrconsts.rsfunctionseries
msgid "Function series"
msgstr "Funktions-Diagramm"

View File

@ -89,6 +89,10 @@ msgstr "Poista"
msgid "Distance measurement"
msgstr "Etäisyysmittaus"
#: tachartstrconsts.rsfieldseries
msgid "Vector field series"
msgstr ""
#: tachartstrconsts.rsfunctionseries
msgid "Function series"
msgstr "Funktiokuvaaja"

View File

@ -99,6 +99,10 @@ msgstr "Supprimer"
msgid "Distance measurement"
msgstr "Mesure des distances"
#: tachartstrconsts.rsfieldseries
msgid "Vector field series"
msgstr ""
#: tachartstrconsts.rsfunctionseries
msgid "Function series"
msgstr "Séries de fonctions"

View File

@ -99,6 +99,10 @@ msgstr "Törlés"
msgid "Distance measurement"
msgstr "Távolságmérés"
#: tachartstrconsts.rsfieldseries
msgid "Vector field series"
msgstr ""
#: tachartstrconsts.rsfunctionseries
msgid "Function series"
msgstr "Függvény"
@ -204,3 +208,4 @@ msgstr "Nem sikerült átnevezni a komponenseket: %s"
#: tachartstrconsts.tastoolseditortitle
msgid "Edit tools"
msgstr "Eszközök szerkesztése"

View File

@ -89,6 +89,10 @@ msgstr ""
msgid "Distance measurement"
msgstr ""
#: tachartstrconsts.rsfieldseries
msgid "Vector field series"
msgstr ""
#: tachartstrconsts.rsfunctionseries
msgid "Function series"
msgstr ""

View File

@ -99,6 +99,10 @@ msgstr "Удалить"
msgid "Distance measurement"
msgstr "Измерение расстояния"
#: tachartstrconsts.rsfieldseries
msgid "Vector field series"
msgstr ""
#: tachartstrconsts.rsfunctionseries
msgid "Function series"
msgstr "Диаграмма по функции"
@ -204,3 +208,4 @@ msgstr "Невозможно переименовать компоненты: %s
#: tachartstrconsts.tastoolseditortitle
msgid "Edit tools"
msgstr "Редактор средств диаграмм"

View File

@ -102,6 +102,10 @@ msgstr "Radera"
msgid "Distance measurement"
msgstr "Avståndsmätning"
#: tachartstrconsts.rsfieldseries
msgid "Vector field series"
msgstr ""
#: tachartstrconsts.rsfunctionseries
msgid "Function series"
msgstr "Funktionskurva"

View File

@ -14,6 +14,7 @@ resourcestring
rsColorMapSeries = 'Color map series';
rsConstantLine = 'Constant line';
rsCubicSplineSeries = 'Cubic spline series';
rsFieldSeries = 'Vector field series';
rsFunctionSeries = 'Function series';
rsLeastSquaresFitSeries = 'Least-squares fit series';
rsLineSeries = 'Line series';

View File

@ -75,6 +75,7 @@ function NextNumberSeq(
function PointDist(const A, B: TPoint): Integer; inline;
function PointDistX(const A, B: TPoint): Integer; inline;
function PointDistY(const A, B: TPoint): Integer; inline;
function PointLineDist(const P, A, B: TPoint): Integer;
function ProjToRect(
const APt: TDoublePoint; const ARect: TDoubleRect): TDoublePoint;
function RectIntersectsRect(
@ -542,6 +543,24 @@ begin
Result := Min(Abs(Int64(A.Y) - B.Y), MaxInt);
end;
function PointLineDist(const P, A,B: TPoint): Integer;
var
v, w, Q: TPoint;
dot: Int64;
lv: Integer;
begin
if A = B then
Result := PointDist(A, P)
else begin
v := B - A; // Vector pointing along line from A to B
w := P - A; // Vector pointing from A to P
dot := Int64(v.x) * w.x + Int64(v.y) * w.y; // dot product v . w
lv := PointDist(A, B); // Length of vector AB
Q := (v * dot) div lv; // Projection of P onto line A-B, seen from A
Result := PointDist(Q, w); // Length from A to Q
end;
end;
function ProjToRect(
const APt: TDoublePoint; const ARect: TDoubleRect): TDoublePoint;
begin

View File

@ -16,7 +16,7 @@ interface
uses
Classes, Graphics,
TAChartUtils, TACustomSeries, TADrawUtils, TALegend;
TAChartUtils, TATypes, TACustomSeries, TADrawUtils, TALegend;
const
DEF_BOX_WIDTH = 50;
@ -185,6 +185,43 @@ type
property Source;
end;
TFieldSeries = class(TBasicPointSeries)
private
FArrow: TChartArrow;
FPen: TPen;
procedure SetArrow(AValue: TChartArrow);
procedure SetPen(AValue: TPen);
protected
procedure AfterAdd; override;
procedure DrawVector(ADrawer: IChartDrawer; AStartPt, AEndPt: TDoublePoint;
APen: TPen);
function GetColor(AIndex: Integer): TColor; inline;
function GetVectorPoints(AIndex: Integer;
out AStartPt, AEndPt: TDoublePoint): Boolean; inline;
public
procedure Assign(ASource: TPersistent); override;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function AddVector(AX, AY, AVectorX, AVectorY: Double; AXLabel: String = '';
AColor: TColor = clTAColor): Integer; //inline;
function GetVector(AIndex: Integer): TDoublePoint; inline;
procedure SetVector(AIndex: Integer; const AValue: TDoublePoint); inline;
procedure Draw(ADrawer: IChartDrawer); override;
function Extent: TDoubleRect; override;
procedure GetLegendItems(AItems: TChartLegendItems); override;
function GetNearestPoint(const AParams: TNearestPointParams;
out AResults: TNearestPointResults): Boolean; override;
procedure NormalizeVectors(ALength: Double);
published
property Arrow: TChartArrow read FArrow write SetArrow;
property AxisIndexX;
property AxisIndexY;
property Pen: TPen read FPen write SetPen;
property Source;
end;
implementation
@ -218,6 +255,14 @@ type
procedure Draw(ADrawer: IChartDrawer; const ARect: TRect); override;
end;
TLegendItemField = class(TLegendItemLine)
strict private
FArrow: TChartArrow;
public
constructor Create(APen: TPen; AArrow: TChartArrow; const AText: String);
procedure Draw(ADrawer: IChartDrawer; const ARect: TRect); override;
end;
{ TLegendItemOHLCLine }
constructor TLegendItemOHLCLine.Create(ASeries: TOpenHighLowCloseSeries; const AText: String);
@ -340,6 +385,39 @@ begin
ADrawer.Line(symbol[5].TopLeft, symbol[5].BottomRight);
end;
{ TLegendItemField }
constructor TLegendItemField.Create(APen: TPen; AArrow: TChartArrow;
const AText: String);
begin
inherited Create(APen, AText);
FArrow := AArrow;
end;
procedure TLegendItemField.Draw(ADrawer: IChartDrawer; const ARect: TRect);
var
y: Integer;
len: Double;
arr: TChartArrow;
begin
inherited Draw(ADrawer, ARect);
if (FPen = nil) or (FArrow = nil) or not FArrow.Visible then
exit;
len := (ARect.Right - ARect.Left) * 0.01;
arr := TChartArrow.Create(nil);
try
arr.Assign(FArrow);
arr.SetOwner(nil);
arr.BaseLength := round(FArrow.BaseLength * len);
arr.Length := round(FArrow.Length * len);
arr.Width := round(FArrow.Width * len);
y := (ARect.Top + ARect.Bottom) div 2;
arr.Draw(ADrawer, Point(ARect.Right, y), 0, FPen);
finally
arr.Free;
end;
end;
{ TBubbleSeries }
@ -939,9 +1017,244 @@ begin
end;
{ TFieldSeries }
constructor TFieldSeries.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ListSource.XCount := 2;
ListSource.YCount := 2;
FArrow := TChartArrow.Create(ParentChart);
FArrow.Length := 20;
FArrow.Width := 10;
FArrow.Visible := true;
FPen := TPen.Create;
FPen.OnChange := @StyleChanged;
end;
destructor TFieldSeries.Destroy;
begin
FreeAndNil(FArrow);
FreeAndNil(FPen);
inherited;
end;
function TFieldSeries.AddVector(AX, AY, AVectorX, AVectorY: Double;
AXLabel: String = ''; AColor: TColor = clTAColor): Integer;
begin
Result := AddXY(AX, AY, AXLabel, AColor);
SetVector(Result, DoublePoint(AVectorX, AVectorY));
end;
procedure TFieldSeries.AfterAdd;
begin
inherited;
FArrow.SetOwner(ParentChart);
end;
procedure TFieldSeries.Assign(ASource: TPersistent);
begin
if ASource is TFieldSeries then
with TFieldSeries(ASource) do begin
Self.FArrow.Assign(FArrow);
Self.FPen := FPen;
end;
inherited Assign(ASource);
end;
procedure TFieldSeries.Draw(ADrawer: IChartDrawer);
var
ext: TDoubleRect;
i: Integer;
p1, p2: TDoublePoint;
lPen: TPen;
begin
with Extent do begin
ext.a := AxisToGraph(a);
ext.b := AxisToGraph(b);
end;
NormalizeRect(ext);
// Do not draw anything if the series extent does not intersect CurrentExtent.
if not RectIntersectsRect(ext, ParentChart.CurrentExtent) then exit;
lPen := TPen.Create;
lPen.Assign(FPen);
if (AxisIndexX < 0) and (AxisIndexY < 0) then begin
// Optimization: bypass transformations in the default case
for i := 0 to Count - 1 do
if GetVectorPoints(i, p1, p2) then begin
lPen.Color := GetColor(i);
DrawVector(ADrawer, p1, p2, lPen);
end;
end else begin
for i := 0 to Count - 1 do
if GetVectorPoints(i, p1, p2) then begin
p1 := DoublePoint(AxisToGraphX(p1.X), AxisToGraphY(p1.Y));
p2 := DoublePoint(AxisToGraphX(p2.X), AxisToGraphY(p2.Y));
lPen.Color := GetColor(i);
DrawVector(ADrawer, p1, p2, lPen);
end;
end;
lPen.Free;
end;
procedure TFieldSeries.DrawVector(ADrawer: IChartDrawer;
AStartPt, AEndPt: TDoublePoint; APen: TPen);
var
p1, p2: TPoint;
arr: TChartArrow;
len: Double;
begin
p1 := ParentChart.GraphToImage(AStartPt);
p2 := ParentChart.GraphToImage(AEndPt);
ADrawer.Pen := APen;
ADrawer.Line(p1.x, p1.y, p2.x, p2.y);
if FArrow.Visible then begin
len := sqrt(sqr(p2.x - p1.x) + sqr(p2.y - p1.y)) * 0.01;
arr := TChartArrow.Create(nil);
arr.Assign(FArrow);
arr.SetOwner(nil); // avoid repainting due to next commands
arr.BaseLength := round(FArrow.BaseLength * len);
arr.Length := round(FArrow.Length * len);
arr.Width := round(FArrow.Width * len);
arr.Draw(ADrawer, p2, arctan2(p2.y-p1.y, p2.x-p1.x), APen);
arr.Free;
end;
end;
function TFieldSeries.Extent: TDoubleRect;
var
p1, p2: TDoublePoint;
i: Integer;
begin
Result := Source.Extent;
for i := 0 to Source.Count - 1 do
if GetVectorPoints(i, p1, p2) then begin
UpdateMinMax(p1.X, Result.a.X, Result.b.X);
UpdateMinMax(p2.X, Result.a.X, Result.b.X);
UpdateMinMax(p1.Y, Result.a.Y, Result.b.Y);
UpdateMinMax(p2.Y, Result.a.Y, Result.b.Y);
end;
end;
function TFieldSeries.GetColor(AIndex: Integer): TColor;
begin
with Source.Item[AIndex]^ do
Result := TColor(IfThen(Color = clTAColor, FPen.Color, Color));
end;
procedure TFieldSeries.GetLegendItems(AItems: TChartLegendItems);
begin
AItems.Add(TLegendItemField.Create(FPen, FArrow, LegendTextSingle));
end;
function TFieldSeries.GetNearestPoint(const AParams: TNearestPointParams;
out AResults: TNearestPointResults): Boolean;
var
dist, i: Integer;
pt1, pt2: TPoint;
sp1, sp2: TDoublePoint;
R: TRect;
begin
AResults.FDist := Sqr(AParams.FRadius) + 1;
AResults.FIndex := -1;
for i := 0 to Count - 1 do begin
if not GetVectorPoints(i, sp1, sp2) then
Continue;
// End points of the vector arrow
pt1 := ParentChart.GraphToImage(AxisToGraph(sp1));
pt2 := ParentChart.GraphToImage(AxisToGraph(sp2));
// At first we check if the point is in the rect spanned by the vector.
R := Rect(pt1.x, pt1.y, pt2.x, pt2.y);
NormalizeRect(R);
R.TopLeft := R.TopLeft - Point(AParams.FRadius, AParams.FRadius);
R.BottomRight := R.BottomRight + Point(AParams.FRadius, AParams.FRadius);
if not IsPointInRect(AParams.FPoint, R) then continue;
// Calculate distance of point from line
dist := PointLineDist(AParams.FPoint, pt1, pt2);
if dist >= AParams.FRadius then continue;
AResults.FDist := dist;
AResults.FIndex := i;
AResults.FImg := (pt1 + pt2) div 2;
AResults.FValue := Source.Item[i]^.Point;
break;
end;
Result := AResults.FIndex >= 0;
end;
function TFieldSeries.GetVector(AIndex: Integer): TDoublePoint;
begin
with Source.Item[AIndex]^ do
Result := DoublePoint(XList[0], YList[0]);
end;
function TFieldSeries.GetVectorPoints(AIndex: Integer;
out AStartPt, AEndPt: TDoublePoint): Boolean;
var
dx, dy: Double;
begin
with Source.Item[AIndex]^ do begin
if isNaN(X) or IsNaN(Y) or IsNaN(XList[0]) or IsNaN(YList[0]) then
exit(false)
else begin
dx := XList[0] * 0.5;
dy := YList[0] * 0.5;
AStartPt := DoublePoint(X - dx, Y - dy);
AEndPt := DoublePoint(X + dx, Y + dy);
Result := true;
end;
end;
end;
procedure TFieldSeries.NormalizeVectors(ALength: Double);
var
factor, maxlen, len: Double;
i: Integer;
v: TDoublePoint;
begin
maxLen := 0;
for i := 0 to Count - 1 do begin
v := GetVector(i);
len := v.x * v.x + v.y * v.y;
len := sqrt(v.x*v.x + v.y*v.y);
// len := sqrt(sqr(v.x) + sqr(v.y));
maxLen := Max(len, maxlen);
end;
if maxLen = 0 then
exit;
factor := ALength / maxLen;
for i := 0 to Count - 1 do begin
v := GetVector(i);
SetVector(i, v*factor);
end;
end;
procedure TFieldSeries.SetArrow(AValue: TChartArrow);
begin
FArrow.Assign(AValue);
UpdateParentChart;
end;
procedure TFieldSeries.SetPen(AValue: TPen);
begin
FPen.Assign(AValue);
end;
procedure TFieldSeries.SetVector(AIndex: Integer; const AValue: TDoublePoint);
begin
with ListSource.Item[AIndex]^ do begin
XList[0] := AValue.X;
YList[0] := AValue.Y;
end;
end;
initialization
RegisterSeriesClass(TBubbleSeries, @rsBubbleSeries);
RegisterSeriesClass(TBoxAndWhiskerSeries, @rsBoxAndWhiskerSeries);
RegisterSeriesClass(TOpenHighLowCloseSeries, @rsOpenHighLowCloseSeries);
RegisterSeriesClass(TFieldSeries, @rsFieldSeries);
end.