TAChart: Add new property "StartAngle" to TPieSeries. Update demo (new layout).

git-svn-id: trunk@60717 -
This commit is contained in:
wp 2019-03-18 22:35:15 +00:00
parent eb0786f83c
commit 0828a25696
6 changed files with 226 additions and 115 deletions

View File

@ -24,8 +24,8 @@ object Form1: TForm1
ClientWidth = 572
object ChartPie: TChart
Left = 0
Height = 384
Top = 147
Height = 407
Top = 124
Width = 572
AxisList = <
item
@ -44,11 +44,13 @@ object Form1: TForm1
end>
Foot.Brush.Color = clBtnFace
Foot.Font.Color = clBlue
Title.Brush.Color = clBtnFace
Title.Alignment = taLeftJustify
Title.Brush.Color = clNone
Title.Font.Color = clBlue
Title.Text.Strings = (
'TAChart'
' Click on a slice to explode/unexplode it'
)
Title.Visible = True
Toolset = ChartToolset1
Align = alClient
Color = clDefault
@ -58,6 +60,8 @@ object Form1: TForm1
Exploded = True
Marks.Distance = 40
Marks.Format = '%2:s'
Marks.Frame.Color = clSilver
Marks.LinkPen.Color = clSilver
Marks.Style = smsLabel
Source = ListChartSource1
end
@ -65,25 +69,27 @@ object Form1: TForm1
object Panel1: TPanel
AnchorSideTop.Side = asrCenter
Left = 0
Height = 147
Height = 124
Top = 0
Width = 572
Align = alTop
Alignment = taLeftJustify
Anchors = [akTop, akRight]
AutoSize = True
Caption = ' Click on a slice to explode/unexplode it'
ClientHeight = 147
BevelOuter = bvNone
ClientHeight = 124
ClientWidth = 572
TabOrder = 1
object seWords: TSpinEdit
AnchorSideTop.Control = Panel1
AnchorSideLeft.Control = lblWords
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = cbShowLabels
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = lblInnerRadius
Left = 324
Left = 222
Height = 23
Top = 7
Top = 6
Width = 72
Anchors = [akTop, akRight]
BorderSpacing.Top = 6
BorderSpacing.Right = 24
MaxValue = 10
@ -92,14 +98,16 @@ object Form1: TForm1
Value = 1
end
object lblWords: TLabel
AnchorSideLeft.Control = cbMarkPositions
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = seWords
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = seWords
Left = 253
Left = 151
Height = 15
Top = 11
Top = 10
Width = 63
Anchors = [akTop, akRight]
BorderSpacing.Left = 16
BorderSpacing.Right = 8
Caption = 'Label words'
ParentColor = False
@ -110,12 +118,12 @@ object Form1: TForm1
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = seWords
AnchorSideRight.Side = asrBottom
Left = 324
Left = 222
Height = 23
Top = 34
Top = 35
Width = 72
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 4
BorderSpacing.Top = 6
Increment = 5
MaxValue = 360
MinValue = -360
@ -126,9 +134,9 @@ object Form1: TForm1
AnchorSideTop.Control = seLabelAngle
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = seLabelAngle
Left = 256
Left = 154
Height = 15
Top = 38
Top = 39
Width = 60
Anchors = [akTop, akRight]
BorderSpacing.Right = 8
@ -136,16 +144,14 @@ object Form1: TForm1
ParentColor = False
end
object cbRotate: TCheckBox
AnchorSideTop.Control = cbMarkAttachment
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = cbMarkAttachment
AnchorSideLeft.Control = cbShowLabels
AnchorSideTop.Control = seLabelAngle
AnchorSideTop.Side = asrCenter
AnchorSideRight.Side = asrBottom
Left = 309
Left = 8
Height = 19
Top = 121
Top = 37
Width = 87
Alignment = taLeftJustify
Anchors = [akTop, akRight]
BorderSpacing.Top = 6
BorderSpacing.Bottom = 6
Caption = 'Rotate labels'
@ -153,16 +159,17 @@ object Form1: TForm1
TabOrder = 2
end
object cbMarkPositions: TComboBox
AnchorSideLeft.Control = cbShowLabels
AnchorSideTop.Control = cbMarkAttachment
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = seDepthBrightnessDelta
AnchorSideRight.Side = asrBottom
Left = 438
Left = 8
Height = 23
Top = 92
Top = 93
Width = 127
Anchors = [akTop, akRight]
AutoSize = False
BorderSpacing.Bottom = 6
BorderSpacing.Bottom = 8
ItemHeight = 15
ItemIndex = 0
Items.Strings = (
@ -177,26 +184,25 @@ object Form1: TForm1
end
object Cb3D: TCheckBox
AnchorSideLeft.Control = lblInnerRadius
AnchorSideTop.Control = seLabelAngle
AnchorSideTop.Control = seDepth
AnchorSideTop.Side = asrCenter
Left = 420
Left = 327
Height = 19
Top = 36
Top = 66
Width = 34
Caption = '3D'
OnChange = Cb3DChange
TabOrder = 4
end
object seInnerRadius: TSpinEdit
AnchorSideLeft.Control = seDepthBrightnessDelta
AnchorSideTop.Control = seWords
AnchorSideRight.Control = Panel1
AnchorSideRight.Side = asrBottom
Left = 503
Left = 410
Height = 23
Top = 7
Top = 6
Width = 62
Anchors = [akTop, akRight]
BorderSpacing.Right = 6
BorderSpacing.Right = 8
OnChange = seInnerRadiusChange
TabOrder = 5
end
@ -204,9 +210,9 @@ object Form1: TForm1
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = lblWords
AnchorSideRight.Control = seInnerRadius
Left = 420
Left = 327
Height = 15
Top = 11
Top = 10
Width = 75
Anchors = [akTop, akRight]
BorderSpacing.Right = 8
@ -216,12 +222,12 @@ object Form1: TForm1
object lblDepth: TLabel
AnchorSideLeft.Control = Cb3D
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = Cb3D
AnchorSideTop.Control = seDepth
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = seDepth
Left = 463
Left = 370
Height = 15
Top = 38
Top = 68
Width = 32
Anchors = [akTop, akRight]
BorderSpacing.Left = 12
@ -231,16 +237,14 @@ object Form1: TForm1
ParentColor = False
end
object seDepth: TSpinEdit
AnchorSideLeft.Control = seInnerRadius
AnchorSideTop.Control = seLabelAngle
AnchorSideLeft.Control = seDepthBrightnessDelta
AnchorSideTop.Control = seDistance
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = Panel1
AnchorSideRight.Side = asrBottom
Left = 503
Left = 410
Height = 23
Top = 34
Top = 64
Width = 62
Anchors = [akTop, akRight]
BorderSpacing.Right = 6
Enabled = False
OnChange = seDepthChange
@ -248,17 +252,17 @@ object Form1: TForm1
Value = 20
end
object seDepthBrightnessDelta: TSpinEdit
AnchorSideLeft.Control = seInnerRadius
AnchorSideLeft.Control = lblDepthBrightnessDelta
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = seDepth
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = Panel1
AnchorSideRight.Side = asrBottom
Left = 503
Left = 410
Height = 23
Top = 61
Top = 93
Width = 62
Anchors = [akTop, akRight]
BorderSpacing.Top = 4
BorderSpacing.Top = 6
BorderSpacing.Right = 6
Enabled = False
MaxValue = 255
@ -268,16 +272,17 @@ object Form1: TForm1
Value = -32
end
object lblDepthBrightnessDelta: TLabel
AnchorSideLeft.Control = cbMarkPositions
AnchorSideLeft.Control = seDistance
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = seDepthBrightnessDelta
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = seDepthBrightnessDelta
Left = 411
Left = 318
Height = 15
Top = 65
Top = 97
Width = 84
Alignment = taRightJustify
Anchors = [akTop, akRight]
BorderSpacing.Left = 24
BorderSpacing.Right = 8
Caption = 'Brightness delta'
Enabled = False
@ -285,14 +290,15 @@ object Form1: TForm1
WordWrap = True
end
object cbShowLabels: TCheckBox
AnchorSideTop.Control = seWords
AnchorSideTop.Side = asrCenter
AnchorSideLeft.Control = Panel1
AnchorSideTop.Control = Panel1
AnchorSideRight.Control = lblWords
Left = 155
Left = 8
Height = 19
Top = 9
Top = 8
Width = 82
Anchors = [akTop, akRight]
BorderSpacing.Left = 8
BorderSpacing.Top = 8
BorderSpacing.Right = 16
Caption = 'Show labels'
Checked = True
@ -304,9 +310,9 @@ object Form1: TForm1
AnchorSideTop.Control = seDistance
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = seDistance
Left = 271
Left = 169
Height = 15
Top = 67
Top = 68
Width = 45
Anchors = [akTop, akRight]
BorderSpacing.Right = 8
@ -318,9 +324,9 @@ object Form1: TForm1
AnchorSideTop.Side = asrBottom
AnchorSideRight.Control = seLabelAngle
AnchorSideRight.Side = asrBottom
Left = 324
Left = 222
Height = 23
Top = 63
Top = 64
Width = 72
Anchors = [akTop, akRight]
BorderSpacing.Top = 6
@ -329,16 +335,15 @@ object Form1: TForm1
Value = 40
end
object cbMarkAttachment: TComboBox
AnchorSideLeft.Control = lblDistance
AnchorSideLeft.Control = cbShowLabels
AnchorSideTop.Control = seDistance
AnchorSideTop.Side = asrBottom
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = seDistance
AnchorSideRight.Side = asrBottom
Left = 271
Left = 8
Height = 23
Top = 92
Top = 64
Width = 125
Anchors = [akTop, akLeft, akRight]
BorderSpacing.Top = 6
BorderSpacing.Bottom = 6
ItemHeight = 15
@ -354,19 +359,47 @@ object Form1: TForm1
Text = 'Default'
end
object cbMarkPositionsCentered: TCheckBox
AnchorSideTop.Control = cbRotate
AnchorSideLeft.Control = lblWords
AnchorSideTop.Control = cbMarkPositions
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = cbMarkPositions
AnchorSideRight.Side = asrBottom
Left = 418
Left = 151
Height = 19
Top = 121
Top = 95
Width = 147
Alignment = taLeftJustify
Anchors = [akTop, akRight]
Caption = 'Mark positions centered'
OnChange = cbMarkPositionsCenteredChange
TabOrder = 11
end
object lblStartAngle: TLabel
AnchorSideLeft.Side = asrBottom
AnchorSideTop.Control = seStartAngle
AnchorSideTop.Side = asrCenter
AnchorSideRight.Control = seStartAngle
Left = 346
Height = 15
Top = 39
Width = 56
Anchors = [akTop, akRight]
BorderSpacing.Right = 8
Caption = 'Start angle'
ParentColor = False
end
object seStartAngle: TSpinEdit
AnchorSideLeft.Control = seDepthBrightnessDelta
AnchorSideTop.Control = seLabelAngle
AnchorSideRight.Side = asrBottom
Left = 410
Height = 23
Top = 35
Width = 62
BorderSpacing.Right = 6
MaxValue = 180
MinValue = -180
OnChange = seStartAngleChange
TabOrder = 12
end
end
end
object tsPolar: TTabSheet

View File

@ -30,6 +30,7 @@ type
cbShowLabels: TCheckBox;
cbMarkPositionsCentered: TCheckBox;
lblDistance: TLabel;
lblStartAngle: TLabel;
seDepth: TSpinEdit;
seDepthBrightnessDelta: TSpinEdit;
lblInnerRadius: TLabel;
@ -44,6 +45,7 @@ type
pnlPolar: TPanel;
RandomChartSource1: TRandomChartSource;
sbTransparency: TScrollBar;
seStartAngle: TSpinEdit;
seWords: TSpinEdit;
seLabelAngle: TSpinEdit;
seInnerRadius: TSpinEdit;
@ -67,6 +69,7 @@ type
procedure seInnerRadiusChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure sbTransparencyChange(Sender: TObject);
procedure seStartAngleChange(Sender: TObject);
procedure seWordsChange(Sender: TObject);
procedure seLabelAngleChange(Sender: TObject);
end;
@ -194,6 +197,11 @@ begin
lblTransparency.Caption := 'Transparency (' + IntToStr(sbTransparency.Position) + ')';
end;
procedure TForm1.seStartAngleChange(Sender: TObject);
begin
ChartPiePieSeries1.StartAngle := seStartAngle.Value;
end;
procedure TForm1.seLabelAngleChange(Sender: TObject);
begin
ChartPiePieSeries1.Marks.LabelFont.Orientation := seLabelAngle.Value * 10;

View File

@ -4,11 +4,7 @@
<Version Value="12"/>
<PathDelim Value="\"/>
<General>
<Flags>
<CompatibilityMode Value="True"/>
</Flags>
<SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
</General>

View File

@ -63,6 +63,7 @@ function IsLineIntersectsLine(const AA, AB, AC, AD: TPoint): Boolean;
function IsPolygonIntersectsPolygon(const AP1, AP2: array of TPoint): Boolean;
function LineIntersectsRect(
var AA, AB: TDoublePoint; const ARect: TDoubleRect): Boolean;
function NormalizeAngle(Angle: Double): Double;
procedure NormalizeRect(var ARect: TRect); overload;
procedure NormalizeRect(var ARect: TDoubleRect); overload;
function MakeSquare(const ARect: TRect): TRect;
@ -499,6 +500,16 @@ begin
Result.cy := Max(Abs(pt1.Y), Abs(pt2.Y));
end;
// Normalizes an angle to be in the interval 0 .. 2 pi
function NormalizeAngle(Angle: Double): Double;
const
TWO_PI = 2.0 * pi;
begin
Result := Angle;
while Result > TWO_PI do Result -= TWO_PI;
while Result < 0 do Result += TWO_PI;
end;
procedure NormalizeRect(var ARect: TRect);
begin
with ARect do begin

View File

@ -49,10 +49,12 @@ type
FBase: TPoint;
FLabel: TLabelParams;
FOrigIndex: Integer;
FPrevAngle, FNextAngle: Double;
FPrevAngle, FNextAngle: Double; // in CCW direction
// FNextAngle may become less than FPrevAngle when crossing 360°
FVisible: Boolean;
function Angle: Double; inline;
function CenterAngle: Double; inline;
function FixedNextAngle: Double; inline;
end;
TPieMarkPositions = (pmpAround, pmpInside, pmpLeftRight);
@ -70,6 +72,7 @@ type
FRadius: Integer;
FInnerRadiusPercent: Integer;
FSlices: array of TPieSlice;
FStartAngle: Integer;
private
FEdgePen: TPen;
FExploded: Boolean;
@ -84,6 +87,7 @@ type
procedure SetMarkPositionCentered(AValue: Boolean);
procedure SetMarkPositions(AValue: TPieMarkPositions);
procedure SetRotateLabels(AValue: Boolean);
procedure SetStartAngle(AValue: Integer);
function SliceColor(AIndex: Integer): TColor;
function TryRadius(ADrawer: IChartDrawer): TRect;
protected
@ -95,6 +99,7 @@ type
property MarkPositionCentered: Boolean
read FMarkPositionCentered write SetMarkPositionCentered default false;
property Radius: Integer read FRadius;
property StartAngle: Integer read FStartAngle write SetStartAngle default 0;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
@ -194,6 +199,8 @@ uses
const
TWO_PI = 2 * pi;
PI_1_2 = pi / 2;
PI_3_2 = (3 / 2) * pi;
PI_1_4 = pi / 4;
PI_3_4 = (3 / 4) * pi;
PI_5_4 = (5 / 4) * pi;
@ -203,14 +210,30 @@ const
function TPieSlice.Angle: Double;
begin
Result := FNextAngle - FPrevAngle;
if FNextAngle < FPrevAngle then
Result := TWO_PI + FNextAngle - FPrevAngle
else
Result := FNextAngle - FPrevAngle;
end;
function TPieSlice.CenterAngle: Double;
begin
Result := (FNextAngle + FPrevAngle) / 2;
if FNextAngle <= FPrevAngle then
Result := NormalizeAngle((TWO_PI + FNextAngle + FPrevAngle) * 0.5)
else
Result := NormalizeAngle((FNextAngle + FPrevAngle) * 0.5);
end;
{ FixedNextAngle is guaranteed to be greater than FPrevAngle }
function TPieSlice.FixedNextAngle: Double;
begin
if FPrevAngle > FNextAngle then
Result := FNextAngle + TWO_PI
else
Result := FNextAngle;
end;
{ TLegendItemPieS }
procedure TLegendItemPie.Draw(ADrawer: IChartDrawer; const ARect: TRect);
@ -234,6 +257,7 @@ begin
FColors[AIndex] := AValue;
end;
{ TLegendItemPieSlice }
procedure TLegendItemPieSlice.Draw(ADrawer: IChartDrawer; const ARect: TRect);
@ -265,6 +289,7 @@ begin
Self.FMarkDistancePercent := FMarkDistancePercent;
Self.FMarkPositionCentered := FMarkPositionCentered;
Self.FRotateLabels := FRotateLabels;
Self.FStartAngle := FStartAngle;
end;
inherited Assign(ASource);
end;
@ -359,11 +384,15 @@ var
begin
if AInside and (FInnerRadiusPercent = 0) then
exit;
if AInside then
isVisible := (ASlice.FPrevAngle < PI_7_4) and (ASlice.FNextAngle > PI_3_4)
if ASlice.Angle >= pi then
isVisible := true
else
isVisible := not (InRange(ASlice.FPrevAngle, PI_3_4, PI_7_4) and
InRange(ASlice.FNextAngle, PI_3_4, PI_7_4) );
if AInside then
isVisible := InRange(ASlice.FPrevAngle, PI_3_4, PI_7_4) or InRange(ASlice.FNextAngle, PI_3_4, PI_7_4)
else
isVisible := (ASlice.FPrevAngle >= PI_7_4) or (ASlice.FPrevAngle <= PI_3_4) or
(ASlice.FNextAngle >= PI_7_4) or (ASlice.FNextAngle <= PI_3_4);
if not isVisible then
exit;
@ -376,6 +405,7 @@ var
angle1 := IfThen(InRange(ASlice.FPrevAngle, PI_3_4, PI_7_4), PI_7_4, ASlice.FPrevAngle);
angle2 := IfThen(InRange(ASlice.FNextAngle, PI_3_4, PI_7_4), PI_3_4, ASlice.FNextAngle);
end;
if angle2 < angle1 then angle2 += TWO_PI;
numSteps := Max(Round(TWO_PI * (angle2 - angle1) * r / STEP), 2);
SetLength(p, 2 * numSteps + 1);
for i := 0 to numSteps - 1 do begin
@ -408,7 +438,10 @@ var
p: Array of TPoint;
begin
angle1 := ASlice.FPrevAngle;
angle2 := ASlice.FNextAngle;
if ASlice.FNextAngle < ASlice.FPrevAngle then
angle2 := TWO_PI + ASlice.FNextAngle
else
angle2 := ASlice.FNextAngle;
ni := Max(Round(TWO_PI * (angle2 - angle1) * innerRadius / STEP), 2);
no := Max(Round(TWO_PI * (angle2 - angle1) * FRadius / STEP), 2);
SetLength(p, ni + no);
@ -470,7 +503,7 @@ begin
end;
// Fix edge of ulta-long slice
for ps in FSlices do
if ps.FNextAngle - ps.FPrevAngle > pi then begin;
if ps.Angle >= pi then begin;
DrawVisibleArc3D(ps);
break;
end;
@ -508,18 +541,22 @@ var
ps: TPieSlice;
innerRadius: Integer;
begin
innerRadius := CalcInnerRadius;
for ps in FSlices do begin
if not ps.FVisible then continue;
c := APoint - ps.FBase;
pointAngle := ArcTan2(-c.Y, c.X);
innerRadius := CalcInnerRadius;
if pointAngle < 0 then
pointAngle += 2 * Pi;
if
InRange(pointAngle, ps.FPrevAngle, ps.FNextAngle) and
InRange(Sqr(c.X) + Sqr(c.Y), Sqr(innerRadius), Sqr(FRadius))
then
exit(ps.FOrigIndex);
if not InRange(sqr(c.X) + sqr(c.Y), sqr(innerRadius), sqr(FRadius)) then
continue;
pointAngle := NormalizeAngle(ArcTan2(-c.Y, c.X));
if ps.FNextAngle <= ps.FPrevAngle then begin
if InRange(pointAngle, ps.FPrevAngle - TWO_PI, ps.FNextAngle) or
InRange(pointAngle, ps.FPrevAngle, ps.FNextAngle + TWO_PI)
then
exit(ps.FOrigIndex);
end else begin
if InRange(pointAngle, ps.FPrevAngle, ps.FNextAngle) then
exit(ps.FOrigIndex);
end;
end;
Result := -1;
end;
@ -676,6 +713,13 @@ begin
UpdateParentChart;
end;
procedure TCustomPieSeries.SetStartAngle(AValue: Integer);
begin
if FStartAngle = AValue then exit;
FStartAngle := AValue mod 360;
UpdateParentChart;
end;
function TCustomPieSeries.SliceColor(AIndex: Integer): TColor;
const
SLICE_COLORS: array [0..14] of TColor = (
@ -691,19 +735,32 @@ end;
procedure TCustomPieSeries.SortSlices(out ASlices: TSliceArray);
function GetAngleForSorting(ASlice: TPieSlice): Double;
var
next_angle: double;
begin
next_angle := ASlice.FixedNextAngle;
if ((ASlice.FPrevAngle >= PI_5_4) or (ASlice.FPrevAngle <= PI_1_4)) and
InRange(ASlice.FNextAngle, PI_1_4, PI_5_4)
then
// Slice crossing the 45° point --> must be last slice to draw
Result := PI_1_4
else
if InRange(ASlice.FPrevAngle, PI_1_4, PI_5_4) and InRange(next_angle, PI_5_4, TWO_PI + PI_1_4)
then
// Slice crossing the 225° point --> must be first slice to draw
Result := PI_5_4
else
Result := IfThen(InRange(ASlice.FPrevAngle, PI_1_4, PI_5_4), ASlice.FPrevAngle, next_angle);
end;
function CompareSlices(ASlice1, ASlice2: TPieSlice): Integer;
var
angle1, angle2: Double;
begin
if (ASlice1.FPrevAngle >= PI_3_4) and (ASlice1.FNextAngle >= PI_5_4) then
angle1 := ASlice1.FNextAngle
else
angle1 := IfThen(InRange(ASlice1.FPrevAngle, PI_1_4, PI_5_4), ASlice1.FPrevAngle, ASlice1.FNextAngle);
if (ASlice2.FPrevAngle >= PI_3_4) and (ASlice2.FNextAngle >= PI_5_4) then
angle2 := ASlice2.FNextAngle
else
angle2 := IfThen(InRange(ASlice2.FPrevAngle, PI_1_4, PI_5_4), ASlice2.FPrevAngle, ASlice2.FNextAngle);
Result := CompareValue(cos(angle1 - PI_1_4), cos(angle2 - PI_1_4));
angle1 := GetAngleForSorting(ASlice1) - PI_1_4;
angle2 := GetAngleForSorting(ASlice2) - PI_1_4;
Result := CompareValue(cos(angle1), cos(angle2));
end;
procedure QuickSort(const L, R: Integer);
@ -735,9 +792,9 @@ begin
SetLength(ASlices, Length(FSlices) + 1);
j := 0;
for i:=0 to High(FSlices) do begin
if FSlices[i].FNextAngle - FSlices[i].FPrevAngle >= pi then begin
if FSlices[i].Angle >= pi then begin
ASlices[j] := FSlices[i];
ASlices[j].FNextAngle := (FSlices[i].FPrevAngle + FSlices[i].FNextAngle) * 0.5;
ASlices[j].FNextAngle := FSlices[i].CenterAngle;
ASlices[j+1] := FSlices[i];
ASlices[j+1].FPrevAngle := ASlices[j].FNextAngle;
inc(j, 2);
@ -820,7 +877,7 @@ function TCustomPieSeries.TryRadius(ADrawer: IChartDrawer): TRect;
pmpInside:
FCenter -= Ofs(AAngle);
pmpLeftRight:
FCenter += Ofs(IfThen(InRange(AAngle, Pi / 2, 3 * Pi / 2), Pi, 0));
FCenter += Ofs(IfThen(InRange(AAngle, PI_1_2, PI_3_2), pi, 0));
end;
for i := 0 to High(p) do
ExpandRect(Result, p[i] + FCenter);
@ -832,13 +889,16 @@ const
var
i, j: Integer;
di: PChartDataItem;
prevAngle: Double = 0;
prevAngle: Double;
a, total: Double;
scaled_depth: Integer;
start_angle: Double;
next_angle: Double;
begin
Result.TopLeft := FCenter;
Result.BottomRight := FCenter;
scaled_depth := ADrawer.Scale(Depth);
start_angle := NormalizeAngle((FStartAngle mod 360) / 180 * pi);
SetLength(FSlices, Count);
j := 0;
// This is a workaround for db source invalidating the cache due to
@ -846,24 +906,26 @@ begin
total := Source.ValuesTotal;
if total = 0 then
exit;
prevAngle := start_angle;
for i := 0 to Count - 1 do begin
di := Source[i];
if IsNan(di^.Y) then continue;
with FSlices[j] do begin
FOrigIndex := i;
FPrevAngle := prevAngle;
FNextAngle := FPrevAngle + CycleToRad(di^.Y / total);
next_angle := FPrevAngle + CycleToRad(di^.Y / total);
FNextAngle := NormalizeAngle(next_angle);
FVisible := not IsNan(di^.X);
if FVisible then begin
FBase := FCenter;
a := CenterAngle;
if Exploded and (di^.X > 0) then
FBase += EndPoint(a, FRadius * di^.X);
ExpandRect(Result, FBase, FRadius, -FPrevAngle, -FNextAngle);
ExpandRect(Result, FBase, FRadius, -FPrevAngle, -next_angle);
if Depth > 0 then
ExpandRect(
Result, FBase + Point(scaled_depth, -scaled_depth),
FRadius, -FPrevAngle, -FNextAngle);
FRadius, -FPrevAngle, -next_angle);
if FMarkPositionCentered then
FLabel.FAttachment := EndPoint(a, (CalcInnerRadius + FRadius) div 2) + FBase
else

View File

@ -134,6 +134,7 @@ type
property MarkPositions;
property Marks;
property RotateLabels;
property StartAngle;
property Source;
end;