66
73
TChartElement = class(TPersistent)
69
procedure SetVisible(const AValue: Boolean);
71
75
FOwner: TCustomChart;
77
procedure InitHelper(var AResult; AClass: TFPCanvasHelperClass);
78
procedure SetVisible(AValue: Boolean);
79
procedure StyleChanged(Sender: TObject); virtual;
72
81
function GetOwner: TPersistent; override;
73
procedure InitHelper(var AResult; AClass: TFPCanvasHelperClass);
74
procedure StyleChanged(Sender: TObject);
76
83
constructor Create(AOwner: TCustomChart);
78
procedure Assign(Source: TPersistent); override;
85
procedure Assign(ASource: TPersistent); override;
80
87
procedure SetOwner(AOwner: TCustomChart);
82
89
property Visible: Boolean read FVisible write SetVisible;
92
TChartMarksOverlapPolicy = (opIgnore, opHideNeighbour);
94
TChartTextElement = class(TChartElement)
97
FOverlapPolicy: TChartMarksOverlapPolicy;
98
procedure SetAlignment(AValue: TAlignment);
99
procedure SetClipped(AValue: Boolean);
100
procedure SetOverlapPolicy(AValue: TChartMarksOverlapPolicy);
102
FAlignment: TAlignment;
103
procedure AddMargins(ADrawer: IChartDrawer; var ASize: TPoint);
104
procedure ApplyLabelFont(ADrawer: IChartDrawer); virtual;
105
function IsMarginRequired: Boolean;
107
function GetFrame: TChartPen; virtual; abstract;
108
function GetLabelAngle: Double; virtual;
109
function GetLabelBrush: TBrush; virtual; abstract;
110
function GetLabelFont: TFont; virtual; abstract;
111
function GetLinkPen: TChartPen; virtual;
113
constructor Create(AOwner: TCustomChart);
115
procedure Assign(ASource: TPersistent); override;
117
ADrawer: IChartDrawer; const ADataPoint, ALabelCenter: TPoint;
118
const AText: String; var APrevLabelPoly: TPointArray);
119
function GetLabelPolygon(ADrawer: IChartDrawer; ASize: TPoint): TPointArray;
120
function MeasureLabel(ADrawer: IChartDrawer; const AText: String): TSize;
122
// If false, labels may overlap axises and legend.
123
property Clipped: Boolean read FClipped write SetClipped default true;
124
property OverlapPolicy: TChartMarksOverlapPolicy
125
read FOverlapPolicy write SetOverlapPolicy default opIgnore;
127
property Alignment: TAlignment
128
read FAlignment write SetAlignment;
131
TChartTitleFramePen = class(TChartPen)
133
property Visible default false;
87
TChartTitle = class(TChartElement)
89
FAlignment: TAlignment;
138
TChartTitle = class(TChartTextElement)
142
FFrame: TChartTitleFramePen;
93
143
FMargin: TChartDistance;
96
procedure SetAlignment(AValue: TAlignment);
97
146
procedure SetBrush(AValue: TBrush);
98
147
procedure SetFont(AValue: TFont);
99
procedure SetFrame(AValue: TChartPen);
148
procedure SetFrame(AValue: TChartTitleFramePen);
100
149
procedure SetMargin(AValue: TChartDistance);
101
150
procedure SetText(AValue: TStrings);
152
function GetFrame: TChartPen; override;
153
function GetLabelBrush: TBrush; override;
154
function GetLabelFont: TFont; override;
103
156
constructor Create(AOwner: TCustomChart);
104
157
destructor Destroy; override;
106
procedure Assign(Source: TPersistent); override;
159
procedure Assign(ASource: TPersistent); override;
161
ADrawer: IChartDrawer; ADir, ALeft, ARight: Integer; var AY: Integer);
108
property Alignment: TAlignment
109
read FAlignment write SetAlignment default taCenter;
163
property Alignment default taCenter;
110
164
property Brush: TBrush read FBrush write SetBrush;
111
165
property Font: TFont read FFont write SetFont;
112
property Frame: TChartPen read FFrame write SetFrame;
166
property Frame: TChartTitleFramePen read FFrame write SetFrame;
113
167
property Margin: TChartDistance
114
168
read FMargin write SetMargin default DEF_MARGIN;
115
169
property Text: TStrings read FText write SetText;
116
170
property Visible default false;
119
TChartMarksOverlapPolicy = (opIgnore, opHideNeighbour);
121
173
TChartMarkAttachment = (maDefault, maEdge, maCenter);
123
175
{ TGenericChartMarks }
125
177
{$IFNDEF fpdoc} // Workaround for issue #18549.
126
178
generic TGenericChartMarks<_TLabelBrush, _TLinkPen, _TFramePen> =
179
class(TChartTextElement)
129
TGenericChartMarks = class(TChartElement)
181
TGenericChartMarks = class(TChartTextElement)
184
FAdditionalAngle: Double;
185
FAttachment: TChartMarkAttachment;
132
188
function GetDistanceToCenter: Boolean;
133
function LabelAngle: Double; inline;
134
procedure PutLabelFontTo(ACanvas: TCanvas);
135
189
procedure SetAttachment(AValue: TChartMarkAttachment);
190
procedure SetDistance(AValue: TChartDistance);
136
191
procedure SetDistanceToCenter(AValue: Boolean);
138
FAdditionalAngle: Double;
139
FAttachment: TChartMarkAttachment;
192
procedure SetFormat(AValue: String);
193
procedure SetFrame(AValue: _TFramePen);
194
procedure SetLabelBrush(AValue: _TLabelBrush);
195
procedure SetLabelFont(AValue: TFont);
196
procedure SetLinkPen(AValue: _TLinkPen);
197
procedure SetStyle(AValue: TSeriesMarksStyle);
198
procedure SetYIndex(AValue: Integer);
141
200
FDistance: TChartDistance;
144
202
FLabelBrush: _TLabelBrush;
145
203
FLabelFont: TFont;
146
204
FLinkPen: _TLinkPen;
147
FOverlapPolicy: TChartMarksOverlapPolicy;
148
205
FStyle: TSeriesMarksStyle;
150
procedure SetClipped(AValue: Boolean);
151
procedure SetDistance(AValue: TChartDistance);
152
procedure SetFormat(const AValue: String);
153
procedure SetFrame(const AValue: _TFramePen);
154
procedure SetLabelBrush(const AValue: _TLabelBrush);
155
procedure SetLabelFont(const AValue: TFont);
156
procedure SetLinkPen(const AValue: _TLinkPen);
157
procedure SetOverlapPolicy(AValue: TChartMarksOverlapPolicy);
158
procedure SetStyle(const AValue: TSeriesMarksStyle);
160
function IsMarginRequired: Boolean;
207
procedure ApplyLabelFont(ADrawer: IChartDrawer); override;
208
function GetFrame: TChartPen; override;
209
function GetLabelAngle: Double; override;
210
function GetLabelBrush: TBrush; override;
211
function GetLabelFont: TFont; override;
212
function GetLinkPen: TChartPen; override;
162
214
constructor Create(AOwner: TCustomChart);
163
215
destructor Destroy; override;
166
procedure Assign(Source: TPersistent); override;
167
function CenterOffset(ACanvas: TCanvas; const AText: String): TSize;
169
ACanvas: TCanvas; const ADataPoint, ALabelCenter: TPoint;
170
const AText: String; var APrevLabelPoly: TPointArray);
171
function GetLabelPolygon(ASize: TPoint): TPointArray;
217
procedure Assign(ASource: TPersistent); override;
218
function CenterOffset(ADrawer: IChartDrawer; const AText: String): TSize;
172
219
function IsMarkLabelsVisible: Boolean;
173
function MeasureLabel(ACanvas: TCanvas; const AText: String): TSize;
174
220
procedure SetAdditionalAngle(AAngle: Double);
176
222
property DistanceToCenter: Boolean
265
312
EExtentError = class(EChartError);
314
TChartRange = class(TChartElement)
316
FBounds: array [1..2] of Double;
317
FUseBounds: array [1..2] of Boolean;
319
function GetBounds(AIndex: Integer): Double;
320
function GetUseBounds(AIndex: integer): Boolean;
321
function IsBoundsStored(AIndex: Integer): Boolean;
322
procedure SetBounds(AIndex: Integer; const AValue: Double);
323
procedure SetUseBounds(AIndex: Integer; AValue: Boolean);
325
procedure Assign(ASource: TPersistent); override;
326
procedure CheckBoundsOrder;
327
procedure Intersect(var AMin, AMax: Double);
329
property Max: Double index 2 read GetBounds write SetBounds stored IsBoundsStored;
330
property Min: Double index 1 read GetBounds write SetBounds stored IsBoundsStored;
331
property UseMax: Boolean index 2 read GetUseBounds write SetUseBounds default false;
332
property UseMin: Boolean index 1 read GetUseBounds write SetUseBounds default false;
269
TChartExtent = class (TChartElement)
337
TChartExtent = class(TChartElement)
271
339
FExtent: TDoubleRect;
272
340
FUseBounds: array [1..4] of Boolean;
274
342
function GetBounds(AIndex: Integer): Double;
275
343
function GetUseBounds(AIndex: integer): Boolean;
276
function IsBoundsStored(AIndex: Integer): boolean;
344
function IsBoundsStored(AIndex: Integer): Boolean;
277
345
procedure SetBounds(AIndex: Integer; const AValue: Double);
278
346
procedure SetUseBounds(AIndex: Integer; AValue: Boolean);
348
procedure Assign(ASource: TPersistent); override;
280
349
procedure CheckBoundsOrder;
351
property UseXMax: Boolean index 3 read GetUseBounds write SetUseBounds default false;
352
property UseXMin: Boolean index 1 read GetUseBounds write SetUseBounds default false;
353
property UseYMax: Boolean index 4 read GetUseBounds write SetUseBounds default false;
354
property UseYMin: Boolean index 2 read GetUseBounds write SetUseBounds default false;
355
property XMax: Double index 3 read GetBounds write SetBounds stored IsBoundsStored;
282
356
property XMin: Double index 1 read GetBounds write SetBounds stored IsBoundsStored;
357
property YMax: Double index 4 read GetBounds write SetBounds stored IsBoundsStored;
283
358
property YMin: Double index 2 read GetBounds write SetBounds stored IsBoundsStored;
284
property XMax: Double index 3 read GetBounds write SetBounds stored IsBoundsStored;
285
property YMax: Double index 4 read GetBounds write SetBounds stored IsBoundsStored;
286
property UseXMin: Boolean index 1 read GetUseBounds write SetUseBounds default false;
287
property UseYMin: Boolean index 2 read GetUseBounds write SetUseBounds default false;
288
property UseXMax: Boolean index 3 read GetUseBounds write SetUseBounds default false;
289
property UseYMax: Boolean index 4 read GetUseBounds write SetUseBounds default false;
361
TRectArray = array [1..4] of Integer;
292
363
{ TChartMargins }
294
TChartMargins = class (TChartElement)
365
TChartMargins = class(TChartElement)
298
369
0: (FRect: TRect;);
299
1: (FCoords: array [1..4] of Integer;);
370
1: (FCoords: TRectArray;);
301
372
function GetValue(AIndex: Integer): integer;
302
373
procedure SetValue(AIndex: integer; AValue: TChartDistance);
312
383
property Bottom: TChartDistance index 4 read GetValue write SetValue default DEF_MARGIN;
386
TChartArrow = class(TChartElement)
388
FBaseLength: TChartDistance;
389
FLength: TChartDistance;
390
FWidth: TChartDistance;
391
procedure SetBaseLength(AValue: TChartDistance);
392
procedure SetLength(AValue: TChartDistance);
393
procedure SetWidth(AValue: TChartDistance);
395
constructor Create(AOwner: TCustomChart);
397
procedure Assign(ASource: TPersistent); override;
399
ADrawer: IChartDrawer; const AEndPos: TPoint; AAngle: Double;
402
property BaseLength: TChartDistance
403
read FBaseLength write SetBaseLength default 0;
404
property Length: TChartDistance
405
read FLength write SetLength default DEF_ARROW_LENGTH;
406
property Visible default false;
407
property Width: TChartDistance
408
read FWidth write SetWidth default DEF_ARROW_WIDTH;
322
procedure TChartPen.Assign(Source: TPersistent);
415
procedure TChartPen.Assign(ASource: TPersistent);
324
if Source is TChartPen then
325
with TChartPen(Source) do
327
inherited Assign(Source);
417
if ASource is TChartPen then
418
FVisible := TChartPen(ASource).Visible;
419
inherited Assign(ASource);
330
422
constructor TChartPen.Create;
332
424
inherited Create;
425
SetPropDefaults(Self, ['Color', 'Style', 'Visible']);
336
428
procedure TChartPen.SetVisible(AValue: Boolean);
386
477
FOwner.StyleChanged(Sender);
480
{ TChartTextElement }
482
procedure TChartTextElement.AddMargins(
483
ADrawer: IChartDrawer; var ASize: TPoint);
485
if not IsMarginRequired then exit;
487
ASize += Point(Scale(MARKS_MARGIN_X), Scale(MARKS_MARGIN_Y)) * 2;
490
procedure TChartTextElement.ApplyLabelFont(ADrawer: IChartDrawer);
492
ADrawer.Font := GetLabelFont;
495
procedure TChartTextElement.Assign(ASource: TPersistent);
497
if ASource is TChartTextElement then
498
with TChartTextElement(ASource) do begin
499
Self.FAlignment := Alignment;
500
Self.FClipped := FClipped;
501
Self.FOverlapPolicy := FOverlapPolicy;
503
inherited Assign(ASource);
506
constructor TChartTextElement.Create(AOwner: TCustomChart);
508
inherited Create(AOwner);
510
FOverlapPolicy := opIgnore;
513
procedure TChartTextElement.DrawLabel(
514
ADrawer: IChartDrawer; const ADataPoint, ALabelCenter: TPoint;
515
const AText: String; var APrevLabelPoly: TPointArray);
517
labelPoly: TPointArray;
521
ApplyLabelFont(ADrawer);
522
ptText := ADrawer.TextExtent(AText);
524
labelPoly := GetLabelPolygon(ADrawer, ptText);
525
for i := 0 to High(labelPoly) do
526
labelPoly[i] += ALabelCenter;
529
(OverlapPolicy = opHideNeighbour) and
530
IsPolygonIntersectsPolygon(APrevLabelPoly, labelPoly)
533
APrevLabelPoly := labelPoly;
536
ADrawer.ClippingStop;
538
if (ADataPoint <> ALabelCenter) and GetLinkPen.Visible then begin
539
ADrawer.Pen := GetLinkPen;
540
ADrawer.Line(ADataPoint, ALabelCenter);
542
ADrawer.Brush := GetLabelBrush;
543
if IsMarginRequired then begin
544
if GetFrame.Visible then
545
ADrawer.Pen := GetFrame
547
ADrawer.SetPenParams(psClear, clTAColor);
548
ADrawer.Polygon(labelPoly, 0, Length(labelPoly));
551
ptText := RotatePoint(-ptText div 2, GetLabelAngle) + ALabelCenter;
552
ADrawer.TextOut.Pos(ptText).Alignment(Alignment).Width(w).Text(AText).Done;
554
ADrawer.ClippingStart;
557
function TChartTextElement.GetLabelAngle: Double;
559
// Negate to take into account top-down Y axis.
560
Result := -OrientToRad(GetLabelFont.Orientation);
563
function TChartTextElement.GetLabelPolygon(
564
ADrawer: IChartDrawer; ASize: TPoint): TPointArray;
566
AddMargins(ADrawer, ASize);
567
Result := RotateRect(ASize, GetLabelAngle);
570
function TChartTextElement.GetLinkPen: TChartPen;
575
function TChartTextElement.IsMarginRequired: Boolean;
578
Result := (GetLabelBrush.Style <> bsClear) or (Style <> psClear) and Visible;
581
function TChartTextElement.MeasureLabel(
582
ADrawer: IChartDrawer; const AText: String): TSize;
586
ApplyLabelFont(ADrawer);
587
sz := ADrawer.TextExtent(AText);
588
AddMargins(ADrawer, sz);
589
Result := MeasureRotatedRect(sz, GetLabelAngle);
592
procedure TChartTextElement.SetAlignment(AValue: TAlignment);
594
if FAlignment = AValue then exit;
595
FAlignment := AValue;
599
procedure TChartTextElement.SetClipped(AValue: Boolean);
601
if FClipped = AValue then exit;
606
procedure TChartTextElement.SetOverlapPolicy(AValue: TChartMarksOverlapPolicy);
608
if FOverlapPolicy = AValue then exit;
609
FOverlapPolicy := AValue;
391
procedure TChartTitle.Assign(Source: TPersistent);
615
procedure TChartTitle.Assign(ASource: TPersistent);
393
if Source is TChartTitle then
394
with TChartTitle(Source) do begin
395
Self.FAlignment := Alignment;
617
if ASource is TChartTitle then
618
with TChartTitle(ASource) do begin
396
619
Self.FBrush.Assign(Brush);
397
620
Self.FFont.Assign(Font);
398
621
Self.FFrame.Assign(Frame);
399
622
Self.FText.Assign(Text);
402
inherited Assign(Source);
625
inherited Assign(ASource);
405
628
constructor TChartTitle.Create(AOwner: TCustomChart);
468
717
{ TGenericChartMarks }
470
procedure TGenericChartMarks.Assign(Source: TPersistent);
472
if Source is Self.ClassType then
473
with TGenericChartMarks(Source) do begin
474
Self.FClipped := FClipped;
719
procedure TGenericChartMarks.ApplyLabelFont(ADrawer: IChartDrawer);
721
inherited ApplyLabelFont(ADrawer);
722
if FAdditionalAngle <> 0 then
723
ADrawer.AddToFontOrientation(RadToOrient(FAdditionalAngle));
726
procedure TGenericChartMarks.Assign(ASource: TPersistent);
728
if ASource is Self.ClassType then
729
with TGenericChartMarks(ASource) do begin
730
Self.FAttachment := FAttachment;
475
731
Self.FDistance := FDistance;
476
732
Self.FFormat := FFormat;
477
733
Self.FFrame.Assign(FFrame);
478
Self.FLabelBrush.Assign(FLabelBrush);
479
Self.FLabelFont.Assign(FLabelFont);
480
Self.FLinkPen.Assign(FLinkPen);
481
Self.FOverlapPolicy := FOverlapPolicy;
734
// FPC miscompiles virtual calls to generic type arguments,
735
// so as a workaround these assignments are moved to the specializations.
736
// Self.FLabelBrush.Assign(FLabelBrush);
737
// Self.FLabelFont.Assign(FLabelFont);
738
// Self.FLinkPen.Assign(FLinkPen);
482
739
Self.FStyle := FStyle;
740
Self.FYIndex := FYIndex;
484
inherited Assign(Source);
742
inherited Assign(ASource);
487
745
function TGenericChartMarks.CenterOffset(
488
ACanvas: TCanvas; const AText: String): TSize;
746
ADrawer: IChartDrawer; const AText: String): TSize;
490
Result := Point(Distance, Distance);
750
d := ADrawer.Scale(Distance);
751
Result := Point(d, d);
491
752
if not DistanceToCenter then
492
Result += MeasureLabel(ACanvas, AText) div 2;
753
Result += MeasureLabel(ADrawer, AText) div 2;
495
756
constructor TGenericChartMarks.Create(AOwner: TCustomChart);
497
758
inherited Create(AOwner);
499
759
InitHelper(FFrame, _TFramePen);
500
760
InitHelper(FLabelBrush, _TLabelBrush);
501
761
InitHelper(FLabelFont, TFont);
502
762
InitHelper(FLinkPen, _TLinkPen);
503
FOverlapPolicy := opIgnore;
504
763
FStyle := smsNone;
505
764
FVisible := true;
517
procedure TGenericChartMarks.DrawLabel(
518
ACanvas: TCanvas; const ADataPoint, ALabelCenter: TPoint;
519
const AText: String; var APrevLabelPoly: TPointArray);
521
wasClipping: Boolean = false;
522
labelPoly: TPointArray;
526
PutLabelFontTo(ACanvas);
527
ptText := ACanvas.TextExtent(AText);
528
labelPoly := GetLabelPolygon(ptText);
529
for i := 0 to High(labelPoly) do
530
labelPoly[i] += ALabelCenter;
533
(OverlapPolicy = opHideNeighbour) and
534
IsPolygonIntersectsPolygon(APrevLabelPoly, labelPoly)
537
APrevLabelPoly := labelPoly;
539
if not Clipped and ACanvas.Clipping then begin
540
ACanvas.Clipping := false;
544
if LinkPen.Visible then begin
545
ACanvas.Pen.Assign(LinkPen);
546
ACanvas.Line(ADataPoint, ALabelCenter);
548
ACanvas.Brush.Assign(LabelBrush);
549
if IsMarginRequired then begin
550
ACanvas.Pen.Assign(Frame);
551
ACanvas.Polygon(labelPoly);
554
ptText := RotatePoint(-ptText div 2, LabelAngle) + ALabelCenter;
555
ACanvas.TextOut(ptText.X, ptText.Y, AText);
557
ACanvas.Clipping := true;
560
776
function TGenericChartMarks.GetDistanceToCenter: Boolean;
562
778
Result := Attachment = maCenter;
565
function TGenericChartMarks.GetLabelPolygon(ASize: TPoint): TPointArray;
570
if IsMarginRequired then
571
ASize += Point(MARKS_MARGIN_X, MARKS_MARGIN_Y) * 2;
572
SetLength(Result, 4);
573
Result[0] := -ASize div 2;
574
Result[2] := Result[0] + ASize;
575
Result[1] := Point(Result[2].X, Result[0].Y);
576
Result[3] := Point(Result[0].X, Result[2].Y);
578
for i := 0 to High(Result) do
579
Result[i] := RotatePoint(Result[i], a);
582
function TGenericChartMarks.IsMarginRequired: Boolean;
585
(LabelBrush.Style <> bsClear) or
586
(Frame.Style <> psClear) and Frame.Visible;
781
function TGenericChartMarks.GetFrame: TChartPen;
786
function TGenericChartMarks.GetLabelAngle: Double;
788
Result := inherited GetLabelAngle - FAdditionalAngle;
791
function TGenericChartMarks.GetLabelBrush: TBrush;
793
Result := LabelBrush;
796
function TGenericChartMarks.GetLabelFont: TFont;
801
function TGenericChartMarks.GetLinkPen: TChartPen;
589
806
function TGenericChartMarks.IsMarkLabelsVisible: Boolean;
851
1044
StyleChanged(Self);
1049
procedure TChartRange.Assign(ASource: TPersistent);
1051
if ASource is TChartRange then
1052
with TChartRange(ASource) do begin
1053
Self.FBounds := FBounds;
1054
Self.FUseBounds := FUseBounds;
1056
inherited Assign(ASource);
1059
procedure TChartRange.CheckBoundsOrder;
1061
if UseMin and UseMax and (Min >= Max) then begin
1064
raise EExtentError.Create('ChartRange: Min >= Max');
1068
function TChartRange.GetBounds(AIndex: Integer): Double;
1070
Result := FBounds[AIndex];
1073
function TChartRange.GetUseBounds(AIndex: integer): Boolean;
1075
Result := FUseBounds[AIndex];
1078
procedure TChartRange.Intersect(var AMin, AMax: Double);
1080
if UseMin and (Min > AMin) then
1082
if UseMax and (Max < AMax)then
1086
function TChartRange.IsBoundsStored(AIndex: Integer): Boolean;
1088
Result := FBounds[AIndex] <> 0;
1091
procedure TChartRange.SetBounds(AIndex: Integer; const AValue: Double);
1093
FBounds[AIndex] := AValue;
1097
procedure TChartRange.SetUseBounds(AIndex: Integer; AValue: Boolean);
1099
FUseBounds[AIndex] := AValue;
854
1103
{ TChartExtent }
856
function TChartExtent.GetUseBounds(AIndex: Integer): Boolean;
858
Result := FUseBounds[AIndex];
861
function TChartExtent.IsBoundsStored(AIndex: Integer): boolean;
863
Result := FExtent.coords[AIndex] <> 0;
1105
procedure TChartExtent.Assign(ASource: TPersistent);
1107
if ASource is TChartExtent then
1108
with TChartExtent(ASource) do begin
1109
Self.FExtent := FExtent;
1110
Self.FUseBounds := FUseBounds;
1112
inherited Assign(ASource);
866
1115
procedure TChartExtent.CheckBoundsOrder;
921
1180
StyleChanged(Self);
1185
procedure TChartArrow.Assign(ASource: TPersistent);
1187
if ASource is TChartArrow then
1188
with TChartArrow(ASource) do begin
1189
Self.FBaseLength := FBaseLength;
1190
Self.FLength := FLength;
1191
Self.FWidth := FWidth;
1193
inherited Assign(ASource);
1196
constructor TChartArrow.Create(AOwner: TCustomChart);
1198
inherited Create(AOwner);
1199
FLength := DEF_ARROW_LENGTH;
1201
FWidth := DEF_ARROW_WIDTH;
1204
procedure TChartArrow.Draw(
1205
ADrawer: IChartDrawer; const AEndPos: TPoint; AAngle: Double;
1206
APen: TFPCustomPen);
1210
pt1, pt2, ptBase: TPoint;
1212
if not Visible then exit;
1213
da := ArcTan2(Width, Length);
1215
diag := -ADrawer.Scale(Round(Sqrt(Sqr(Length) + Sqr(Width))));
1216
pt1 := AEndPos + RotatePointX(diag, AAngle - da);
1217
pt2 := AEndPos + RotatePointX(diag, AAngle + da);
1218
if BaseLength > 0 then begin
1219
ptBase := AEndPos + RotatePointX(-ADrawer.Scale(BaseLength), AAngle);
1220
ADrawer.SetBrushParams(bsSolid, FPColorToChartColor(APen.FPColor));
1221
ADrawer.Polygon([pt1, AEndPos, pt2, ptBase], 0, 4);
1224
ADrawer.Polyline([pt1, AEndPos, pt2], 0, 3);
1227
procedure TChartArrow.SetBaseLength(AValue: TChartDistance);
1229
if FBaseLength = AValue then exit;
1230
FBaseLength := AValue;
1234
procedure TChartArrow.SetLength(AValue: TChartDistance);
1236
if FLength = AValue then exit;
1241
procedure TChartArrow.SetWidth(AValue: TChartDistance);
1243
if FWidth = AValue then exit;