6397 lines
192 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.Charts.TextMarkup;
using DevComponents.DotNetBar.Charts.Style;
namespace DevComponents.DotNetBar.Charts
{
public class PieChart : BaseChart, ISeriesPointContainer
{
#region Private variables
private ChartPieSeriesCollection _PieSeries;
private Point _CenterPoint;
private PointF _CenterPos = PointF.Empty;
private double _InnerRadius;
private double _InnerRadiusEx = double.NaN;
private double _OuterRadius = .8d;
private double _OuterRadiusEx = double.NaN;
private double _MaxPieOuterExtent;
private double _GridInnerRadius;
private double _GridInnerRadiusEx = double.NaN;
private double _GridOuterRadius = 1d;
private double _GridOuterRadiusEx = double.NaN;
private int _MinOuterRadius = 80;
private PieRadiusScale _PieRadiusScale = PieRadiusScale.Percentage;
private double _InnerMargin = .02d;
private double _InnerMarginEx = double.NaN;
private double _OuterMargin = 0d;
private double _SeriesMargin = .02d;
private double _ExplodedOffset = .05d;
private double _ExplodedMargin = .1d;
private double _DetachedOffset = .1d;
private int _MaxDetachedOffset = 100;
private double _ExplodedOffsetEx = double.NaN;
private int _MaxExplodedOffset = 100;
private int _MaxRingOutRadius = 48;
private int _MinRingOutRadius = 9;
private string _CenterLabel;
private CenterLabelVisibility _CenterLabelVisibility = CenterLabelVisibility.Always;
private BodyElement _CenterLabelMarkup;
private SymbolDef _ScaleSymDef = new SymbolDef();
private float _SymFontScale = -1;
private PieChartVisualStyle _ChartVisualStyle;
private EffectiveStyle<PieChartVisualStyle> _EffectiveChartStyle;
private EffectiveStyles<PieCenterVisualStyle> _EffectivePieCenterStyles;
private SliceLabelOverlapMode _SliceLabelOverlapMode = SliceLabelOverlapMode.NotSet;
private int _RingWeightTotal;
private PieSeriesPoint _LastHitPsp;
private PieSeriesPoint _HitPsp;
private ItemHitArea _LastHitArea;
private Tbool _CenterFirstSlice = Tbool.NotSet;
private Tbool _ShowAllRings = Tbool.NotSet;
private Tbool _ShowOtherSlice = Tbool.NotSet;
private MouseClickSliceAction _MouseClickSliceAction = MouseClickSliceAction.NotSet;
private MouseDoubleClickSliceAction _MouseDoubleClickSliceAction = MouseDoubleClickSliceAction.NotSet;
private PieSelectionMode _PieSelectionMode = PieSelectionMode.NotSet;
private PieRingOutDisplayMode _PieRingOutDisplayMode = PieRingOutDisplayMode.OnMouseOver;
private WhitespaceClickBehavior _WhitespaceClickBehavior = WhitespaceClickBehavior.ClearSelection;
private PspDragType _PspDragType;
private Tbool _EnableDragDetach = Tbool.NotSet;
private double _GridInterval = 10d;
private double _GridMinValue = 0d;
private double _GridMaxValue = 100d;
private List<PieLabel> _PieLabels;
private Rectangle _RenderBounds;
private SliceVisualLayout _SubSliceVisualLayout;
private uint _GlobalSelectionCount;
private States _States;
#endregion
public PieChart(string name)
: this()
{
Name = name;
}
public PieChart()
{
InitDefaultStates();
_EffectiveChartStyle = new EffectiveStyle<PieChartVisualStyle>(this);
_EffectivePieCenterStyles = new EffectiveStyles<PieCenterVisualStyle>(this);
}
#region InitDefaultStates
private void InitDefaultStates()
{
SetState(States.MultiSelect, true);
}
#endregion
#region Public properties
#region ActualInnerRadius
/// <summary>
/// Gets the actual, calculated inner radius of the pie.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public double ActualInnerRadius
{
get { return (InnerRadiusEx); }
}
#endregion
#region ActualOuterRadius
/// <summary>
/// Gets the actual, calculated outer radius of the pie.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public double ActualOuterRadius
{
get { return (OuterRadiusEx); }
}
#endregion
#region CenterFirstSlice
/// <summary>
/// Gets or sets whether the first pie slice is centered
/// on the starting angle or starts on the starting angle. Default is false.
/// </summary>
[DefaultValue(Tbool.NotSet), Category("Display")]
[Description("Indicates whether the first pie slice is centered on the starting angle or starts on the starting angle. Default is false.")]
public Tbool CenterFirstSlice
{
get { return (_CenterFirstSlice); }
set
{
if (value != _CenterFirstSlice)
{
_CenterFirstSlice = value;
OnPropertyChangedEx("CenterFirstSlice", VisualChangeType.Layout);
}
}
}
#endregion
#region CenterLabel
/// <summary>
/// Gets or sets the text to use for the center hole label.
/// </summary>
[DefaultValue(null), Category("Label")]
[Description("Indicates the text to use for the center hole label.")]
[Editor("DevComponents.DotNetBar.Design.TextMarkupUIEditor, DevComponents.DotNetBar.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(System.Drawing.Design.UITypeEditor))]
public string CenterLabel
{
get { return (_CenterLabel); }
set
{
if (value != _CenterLabel)
{
_CenterLabel = value;
MarkupCenterLabelChanged();
OnPropertyChangedEx("CenterLabel", VisualChangeType.Render);
}
}
}
#endregion
#region CenterLabelVisibility
/// <summary>
/// Gets or sets the mode used to determine if/when to display the center label.
/// </summary>
[DefaultValue(CenterLabelVisibility.Always), Category("Label")]
[Description("Indicates the mode used to determine if/when to display the center label.")]
public CenterLabelVisibility CenterLabelVisibility
{
get { return (_CenterLabelVisibility); }
set
{
if (value != _CenterLabelVisibility)
{
_CenterLabelVisibility = value;
OnPropertyChangedEx("CenterLabelVisibility", VisualChangeType.Render);
}
}
}
#endregion
#region CenterPoint
/// <summary>
/// Gets the calculated center Point for the pie.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Point CenterPoint
{
get { return (_CenterPoint); }
internal set { _CenterPoint = value; }
}
#endregion
#region CenterPos
/// <summary>
/// Gets or sets the offset from the default center x,y location of the chart. If
/// the values are between -1 and 1, then the offsets are taken as a percentage
/// of the width/height, otherwise they are taken as absolute pixel offsets.
/// </summary>
[Description("Indicates the offset from the default center x,y location of the chart. If the values are between -1 and 1, then the offsets are taken as a percentage of the width/height, otherwise they are taken as absolute pixel offsets.")]
[Editor("DevComponents.Charts.Design.PivotPointEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
[TypeConverter(typeof(PointFConverter))]
[Category("Offset")]
public PointF CenterPos
{
get { return (_CenterPos); }
set
{
if (value != _CenterPos)
{
_CenterPos = value;
OnPropertyChangedEx("CenterPos", VisualChangeType.Layout);
}
}
}
/// <summary>
/// Gets whether property should be serialized.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeCenterPos()
{
return (_CenterPos.IsEmpty == false);
}
/// <summary>
/// Resets property to its default value.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public void ResetCenterPos()
{
CenterPos = PointF.Empty;
}
#endregion
#region ChartSeries
/// <summary>
/// Gets a reference to the collection of PieSeries
/// </summary>
[Category("Data")]
[Description("Indicates the collection of Chart Series.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ChartPieSeriesCollection ChartSeries
{
get
{
if (_PieSeries == null)
{
_PieSeries = new ChartPieSeriesCollection();
_PieSeries.CollectionChanged += ChartSeriesCollectionChanged;
}
return (_PieSeries);
}
internal set
{
BaseSeries = null;
if (_PieSeries != null)
_PieSeries.CollectionChanged -= ChartSeriesCollectionChanged;
_PieSeries = value;
if (_PieSeries != null)
_PieSeries.CollectionChanged += ChartSeriesCollectionChanged;
}
}
#region ChartSeriesCollectionChanged
void ChartSeriesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
BaseSeries = null;
InvalidateValueCache();
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (PieSeries item in e.NewItems)
item.Parent = this;
break;
case NotifyCollectionChangedAction.Replace:
foreach (PieSeries item in e.OldItems)
item.Parent = null;
foreach (PieSeries item in e.NewItems)
item.Parent = this;
break;
case NotifyCollectionChangedAction.Remove:
foreach (PieSeries item in e.OldItems)
item.Parent = null;
break;
}
SeriesRangeChanged = true;
InvalidateLayout();
}
#endregion
#endregion
#region ChartVisualStyles
/// <summary>
/// Gets or sets the visual style for the Chart.
/// </summary>
[Category("Style")]
[Description("Indicates the visual style for the Chart.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public PieChartVisualStyle ChartVisualStyle
{
get
{
if (_ChartVisualStyle == null)
{
_ChartVisualStyle = new PieChartVisualStyle();
StyleVisualChangeHandler(null, _ChartVisualStyle);
}
return (_ChartVisualStyle);
}
set
{
if (_ChartVisualStyle != value)
{
PieChartVisualStyle oldValue = _ChartVisualStyle;
_ChartVisualStyle = value;
OnStyleChanged("ChartVisualStyle", oldValue, value);
if (oldValue != null)
oldValue.Dispose();
}
}
}
#endregion
#region CustomPalette
///<summary>
/// Gets or sets the custom palette for the chart.
///</summary>
[DefaultValue(null), Category("Appearance")]
[Description("Indicates the custom palette for the chart.")]
public override Color[] CustomPalette
{
get { return (base.CustomPalette); }
set
{
base.CustomPalette = value;
UpdatePaletteNeeded = true;
}
}
#endregion
#region DetachedOffset
/// <summary>
/// Gets or sets the default offset distance of a slice from the pie center, as measured
/// by a percentage of the pie radius (if less than 1), or absolute pixel amount (if greater than 1). Default is .1.
///
/// A value of 0 will restore the slice to its original position in the pie (which
/// may still be offset, if the pie is "exploded").
/// </summary>
[DefaultValue(.1d), Category("Offset")]
[Description("Indicates the default offset distance of a slice from the pie center, as measured by a percentage of the pie radius (if <= 1), or absolute pixel amount (if > 1). Default is .1.")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double DetachedOffset
{
get { return (_DetachedOffset); }
set
{
if (value != _DetachedOffset)
{
_DetachedOffset = value;
OnPropertyChangedEx("DetachedOffset", VisualChangeType.Layout);
}
}
}
#endregion
#region EffectiveChartStyle
/// <summary>
/// Gets a reference to the Chart's Effective (cached, composite) style.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public PieChartVisualStyle EffectiveChartStyle
{
get { return (_EffectiveChartStyle.Style); }
}
#endregion
#region EffectivePieCenterStyles
/// <summary>
/// Gets a reference to the Chart's Effective (cached, composite) Pie Center styles.
/// </summary>
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public EffectiveStyles<PieCenterVisualStyle> EffectivePieCenterStyle
{
get { return (_EffectivePieCenterStyles); }
}
#endregion
#region EnableCenterLabelMarkup
/// <summary>
/// Gets or sets whether text-markup support is enabled for the Center Label.
/// </summary>
[DefaultValue(false), Category("Appearance")]
[Description("Indicates whether text-markup support is enabled for the Center Label.")]
public bool EnableCenterLabelMarkup
{
get { return (TestState(States.EnableCenterLabelMarkup)); }
set
{
if (EnableCenterLabelMarkup != value)
{
SetState(States.EnableCenterLabelMarkup, value);
MarkupCenterLabelChanged();
OnPropertyChangedEx("EnableCenterLabelMarkup", VisualChangeType.Layout);
}
}
}
#endregion
#region EnableDragDetach
///<summary>
/// Gets or sets whether the user can, by default, detach
/// slices of the pie by Click and drag.
///</summary>
[DefaultValue(Tbool.NotSet), Category("Behavior")]
[Description("Indicates whether the user can, by default, detach slices of the pie by Click and drag.")]
public Tbool EnableDragDetach
{
get { return (_EnableDragDetach); }
set
{
if (value != _EnableDragDetach)
{
_EnableDragDetach = value;
OnPropertyChangedEx("EnableDragDetach", VisualChangeType.Layout);
}
}
}
#endregion
#region EnableShiftDragExplode
///<summary>
/// Gets or sets whether the user can explode the pie by
/// ShiftClick and drag.
///</summary>
[DefaultValue(false), Category("Behavior")]
[Description("Indicates whether the user can explode the pie by ShiftClick and drag.")]
public bool EnableShiftDragExplode
{
get { return (TestState(States.EnableShiftDragExplode)); }
set
{
if (value != EnableShiftDragExplode)
{
SetState(States.EnableShiftDragExplode, value);
OnPropertyChanged("EnableShiftDragExplode");
}
}
}
#endregion
#region ExplodedMargin
/// <summary>
/// Gets or sets the exploded between each series when the pie
/// is Exploded. The Margin is is measured as a percentage of the pie radius (if <= 1)
/// or the absolute pixel amount (if > 1). Default is .1.
/// </summary>
[DefaultValue(.1d), Category("Margin")]
[Description("Indicates the exploded between each series when the pie is Exploded. The Margin is is measured as a percentage of the pie radius (if <= 1) or the absolute pixel amount (if > 1). Default is .1.")]
public double ExplodedMargin
{
get { return (_ExplodedMargin); }
set
{
if (value != _ExplodedMargin)
{
_ExplodedMargin = value;
OnPropertyChangedEx("ExplodedMargin", VisualChangeType.Layout);
}
}
}
#endregion
#region ExplodedOffset
/// <summary>
/// Gets or sets the offset of each slice from the pie center when the pie
/// is Exploded. The offset is is measured as a percentage of the pie radius (if less than 1)
/// or the absolute pixel amount (if greater than 1). Default is .1.
///
/// Clicking a Detached slice will restore it to its original position in the pie, which
/// may still be offset by this amount, if the pie is 'exploded'.
/// </summary>
[DefaultValue(.05d), Category("Offset")]
[Description("Indicates the offset of each slice from the pie center when the pie is Exploded. The offset is is measured as a percentage of the pie radius (if <= 1) or the absolute pixel amount (if > 1). Default is .1.")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double ExplodedOffset
{
get { return (_ExplodedOffset); }
set
{
if (value != _ExplodedOffset)
{
_ExplodedOffset = value;
_ExplodedOffsetEx = double.NaN;
OnPropertyChangedEx("ExplodedOffset", VisualChangeType.Layout);
}
}
}
#endregion
#region GridInnerRadius
/// <summary>
/// Gets or sets the Inner radius of the pie grid, relative to the pie area. Can be a
/// percentage (if value is between 0 and 1) or pixel amount (if value > 1).
/// Defaults to 0.
/// </summary>
[DefaultValue(0d), Category("Radius")]
[Description("Indicates the Inner radius of the pie grid, relative to the pie area. Can be a percentage (if value is between 0 and 1) or pixel amount (if value > 1). Defaults to 0")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double GridInnerRadius
{
get { return (_GridInnerRadius); }
set
{
if (value != _GridInnerRadius)
{
_GridInnerRadius = value;
InvalidateValueCache();
OnPropertyChangedEx("GridInnerRadius", VisualChangeType.Layout);
}
}
}
#endregion
#region GridOuterRadius
/// <summary>
/// Gets or sets the outer radius of the pie grid, relative to the pie area. Can be a
/// percentage (if value is between 0 and 1) or pixel amount (if value > 1).
/// Defaults to 1 (ie 100 %).
/// </summary>
[DefaultValue(1d), Category("Radius")]
[Description("Indicates the outer radius of the pie grid, relative to the pie area. Can be a percentage (if value is between 0 and 1) or pixel amount (if value > 1). Defaults to 1")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double GridOuterRadius
{
get { return (_GridOuterRadius); }
set
{
if (value != _GridOuterRadius)
{
_GridOuterRadius = value;
InvalidateValueCache();
OnPropertyChangedEx("GridOuterRadius", VisualChangeType.Layout);
}
}
}
#endregion
#region GridInterval
/// <summary>
/// Gets or sets the radial grid interval (interval division between grid lines).
/// </summary>
[DefaultValue(10d), Category("Grid")]
[Description("Indicates the radial grid interval (interval division between grid lines).")]
public double GridInterval
{
get { return (_GridInterval); }
set
{
if (value != _GridInterval)
{
_GridInterval = value;
OnPropertyChangedEx("GridInterval", VisualChangeType.Layout);
}
}
}
#endregion
#region GridMaxValue
/// <summary>
/// Gets or sets the radial grid maximum value.
/// </summary>
[DefaultValue(100d), Category("Grid")]
[Description("Indicates the radial grid maximum value.")]
public double GridMaxValue
{
get { return (_GridMaxValue); }
set
{
if (value != _GridMaxValue)
{
_GridMaxValue = value;
OnPropertyChangedEx("GridMaxValue", VisualChangeType.Layout);
}
}
}
#endregion
#region GridMinValue
/// <summary>
/// Gets or sets the radial grid minimum value.
/// </summary>
[DefaultValue(0d), Category("Grid")]
[Description("Indicates the radial grid minimum value.")]
public double GridMinValue
{
get { return (_GridMinValue); }
set
{
if (value != _GridMinValue)
{
_GridMinValue = value;
OnPropertyChangedEx("GridMinValue", VisualChangeType.Layout);
}
}
}
#endregion
#region InnerMargin
/// <summary>
/// Gets or sets the inner pixel margin between the inner
/// most ring and the pie center. Default is .02d.
/// </summary>
[Description("Indicates the inner pixel margin between the inner most ring and the pie center. Default is .02d.")]
[DefaultValue(.02d), Category("Margin")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double InnerMargin
{
get { return (_InnerMargin); }
set
{
if (value != _InnerMargin)
{
_InnerMargin = value;
InvalidateValueCache();
OnPropertyChangedEx("InnerMargin", VisualChangeType.Layout);
}
}
}
#endregion
#region InnerRadius
/// <summary>
/// Gets or sets the size of the inner radius for the pie, relative to the plot
/// area. Can be a percentage (if value is between 0 and 1) or pixel amount (if value > 1).
/// A value > 0 will create an inner "hole" or donut chart.
/// </summary>
[DefaultValue(0d), Category("Radius")]
[Description("Indicates the size of the inner radius for the pie, relative to the plot area. Can be a percentage (if value is between 0 and 1) or pixel amount (if value > 1). A value > 0 will create an inner 'hole' or donut chart.")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double InnerRadius
{
get { return (_InnerRadius); }
set
{
if (value != _InnerRadius)
{
_InnerRadius = value;
InvalidateValueCache();
OnPropertyChangedEx("InnerRadius", VisualChangeType.Layout);
}
}
}
#endregion
#region IsExploded
/// <summary>
/// Gets or sets whether all slices of the pie have been pulled out, or
/// exploded, from the center of the pie. This attribute can be used to
/// create added emphasis or to highlight the entire pie. Default is false.
/// </summary>
[DefaultValue(false), Category("Display")]
[Description("Indicates whether all slices of the pie have been pulled out, or exploded, from the center of the pie. This attribute can be used to create added emphasis or to highlight the entire pie. Default is false.")]
public bool IsExploded
{
get { return (TestState(States.Exploded)); }
set
{
if (value != IsExploded)
{
SetState(States.Exploded, value);
_ExplodedOffsetEx = double.NaN;
OnPropertyChangedEx("IsExploded", VisualChangeType.Layout);
}
}
}
#endregion
#region MaxDetachedOffset
/// <summary>
/// Gets or sets the maximum Detached Offset value (in pixels) that
/// a pie slice can be detached. Default is 100.
/// </summary>
[DefaultValue(100), Category("Offset")]
[Description("Indicates the maximum DetachedOffset value (in pixels) that a pie slice can be detached. Default is 100.")]
public int MaxDetachedOffset
{
get { return (_MaxDetachedOffset); }
set
{
if (value != _MaxDetachedOffset)
{
_MaxDetachedOffset = value;
OnPropertyChangedEx("MaxDetachedOffset", VisualChangeType.Layout);
}
}
}
#endregion
#region MaxExplodedOffset
/// <summary>
/// Gets or sets the maximum ExplodedOffset value (in pixels) that
/// the pie may be exploded. Default is 100.
/// </summary>
[DefaultValue(100), Category("Offset")]
[Description("Indicates the maximum ExplodedOffset value (in pixels) that the pie may be exploded. Default is 100.")]
public int MaxExplodedOffset
{
get { return (_MaxExplodedOffset); }
set
{
if (value != _MaxExplodedOffset)
{
_MaxExplodedOffset = value;
OnPropertyChangedEx("MaxExplodedOffset", VisualChangeType.Layout);
}
}
}
#endregion
#region MaxRingOutRadius
/// <summary>
/// Gets or sets the maximum radius of the Center
/// RingOut image (in pixels). Default is 48.
/// </summary>
[DefaultValue(48), Category("Radius")]
[Description("Indicates the maximum radius of the Center RingOut image (in pixels). Default is 48.")]
public int MaxRingOutRadius
{
get { return (_MaxRingOutRadius); }
set
{
if (value != _MaxRingOutRadius)
{
_MaxRingOutRadius = value;
OnPropertyChanged("MaxRingOutRadius");
}
}
}
#endregion
#region MinOuterRadius
/// <summary>
/// Gets or sets the minimum outer radius of the chart, in pixels. Defaults to 80.
/// </summary>
[DefaultValue(80), Category("Radius")]
[Description("Indicates the minimum outer radius of the chart, in pixels. Defaults to 80.")]
public int MinOuterRadius
{
get { return (_MinOuterRadius); }
set
{
if (value != _MinOuterRadius)
{
_MinOuterRadius = value;
_OuterRadiusEx = double.NaN;
_ExplodedOffsetEx = double.NaN;
OnPropertyChangedEx("MinOuterRadius", VisualChangeType.Layout);
}
}
}
#endregion
#region MinRingOutRadius
/// <summary>
/// Gets or sets the minimum radius of the Center
/// RingOut image (in pixels). Default is 9.
/// </summary>
[DefaultValue(9), Category("Radius")]
[Description("Indicates the maximum radius of the Center RingOut image (in pixels). Default is 9.")]
public int MinRingOutRadius
{
get { return (_MinRingOutRadius); }
set
{
if (value != _MinRingOutRadius)
{
_MinRingOutRadius = value;
OnPropertyChanged("MinRingOutRadius");
}
}
}
#endregion
#region MouseClickAction
/// <summary>
/// Gets or sets the default action used when the user clicks on a pie slice. Default is 'None'.
/// </summary>
[DefaultValue(MouseClickSliceAction.NotSet), Category("Behavior")]
[Description("Indicates the default action used when the user clicks on a pie slice. Default is 'None'.")]
public MouseClickSliceAction MouseClickSliceAction
{
get { return (_MouseClickSliceAction); }
set
{
if (value != _MouseClickSliceAction)
{
_MouseClickSliceAction = value;
OnPropertyChanged("MouseClickSliceAction");
}
}
}
#endregion
#region MouseDoubleClickSliceAction
/// <summary>
/// Gets or sets the default action used when
/// the user double-clicks on a pie slice. Default is 'None'.
/// </summary>
[DefaultValue(MouseDoubleClickSliceAction.NotSet), Category("Behavior")]
[Description("Indicates the default action used when the user double-clicks on a pie slice. Default is 'None'.")]
public MouseDoubleClickSliceAction MouseDoubleClickSliceAction
{
get { return (_MouseDoubleClickSliceAction); }
set
{
if (value != _MouseDoubleClickSliceAction)
{
_MouseDoubleClickSliceAction = value;
OnPropertyChanged("MouseDoubleClickSliceAction");
}
}
}
#endregion
#region MultiSelect
///<summary>
/// Gets or sets whether multiple items can be selected by the user. Default is true.
///</summary>
[DefaultValue(true), Category("Behavior")]
[Description("Indicates whether multiple items can be selected by the user. Default is true.")]
public bool MultiSelect
{
get { return (TestState(States.MultiSelect)); }
set
{
if (value != MultiSelect)
{
SetState(States.MultiSelect, value);
OnPropertyChanged("MultiSelect");
}
}
}
#endregion
#region OuterMargin
/// <summary>
/// Gets or sets the outer pixel margin for the chart.
/// </summary>
[Description("Indicates the outer pixel margin for the chart.")]
[DefaultValue(0d), Category("Margin")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double OuterMargin
{
get { return (_OuterMargin); }
set
{
if (value != _OuterMargin)
{
_OuterMargin = value;
_OuterRadiusEx = double.NaN;
_ExplodedOffsetEx = double.NaN;
OnPropertyChangedEx("OuterMargin", VisualChangeType.Layout);
}
}
}
#endregion
#region OuterRadius
/// <summary>
/// Gets or sets the outer radius of the pie, relative to the plot area. Can be a
/// percentage (if value is between 0 and 1) or pixel amount (if value > 1).
/// Defaults to .8 (ie 80 %).
/// </summary>
[DefaultValue(.8d), Category("Radius")]
[Description("Indicates the outer radius of the pie, relative to the plot area. Can be a percentage (if value is between 0 and 1) or pixel amount (if value > 1). Defaults to .8")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public virtual double OuterRadius
{
get { return (_OuterRadius); }
set
{
if (value != _OuterRadius)
{
_OuterRadius = value;
InvalidateValueCache();
OnPropertyChangedEx("OuterRadius", VisualChangeType.Layout);
}
}
}
#endregion
#region PaletteGroup
/// <summary>
/// Gets or sets the palette color group to use (Light/Medium/Dark/Color1/MonoBlue/etc).
/// </summary>
[DefaultValue(PaletteGroup.Color1), Category("Appearance")]
[Description("Indicates the palette color group to use (Light/Medium/Dark/Color1/MonoBlue/etc.).")]
public override PaletteGroup PaletteGroup
{
get { return (base.PaletteGroup); }
set
{
if (value != PaletteGroup)
{
base.PaletteGroup = value;
UpdatePaletteNeeded = true;
}
}
}
#endregion
#region PieRadiusScale
/// <summary>
/// Gets or sets how the PieRadius values (InnerRadius, OuterRadius,
/// GridInnerRadius, and GridOuterRadius) are interpreted (as absolute
/// pixel values or as relative percentages).
/// </summary>
[DefaultValue(PieRadiusScale.Percentage), Category("Radius")]
[Description("Indicates how the PieRadius values (InnerRadius, OuterRadius, GridInnerRadius, and GridOuterRadius) are interpreted (as absolute pixel values or as relative percentages).")]
public PieRadiusScale PieRadiusScale
{
get { return (_PieRadiusScale); }
set
{
if (value != _PieRadiusScale)
{
_PieRadiusScale = value;
OnPropertyChangedEx("PieRadiusScale", VisualChangeType.Recalc);
}
}
}
#endregion
#region PieRingOutDisplayMode
/// <summary>
/// Gets or sets the display mode for the RingOut indicator (used
/// to move out a ring level when ShowAllRings is false and the
/// ActiveSeriesPointCollection has been set to an inner ring).
/// </summary>
[DefaultValue(PieRingOutDisplayMode.OnMouseOver), Category("Behavior")]
[Description("Indicates the display mode for the RingOut indicator (used to move out a ring level when ShowAllRings is false and the ActiveSeriesPointCollection has been set to an inner ring).")]
public PieRingOutDisplayMode PieRingOutDisplayMode
{
get { return (_PieRingOutDisplayMode); }
set
{
if (value != _PieRingOutDisplayMode)
{
_PieRingOutDisplayMode = value;
OnPropertyChangedEx("PieRingOutDisplayMode", VisualChangeType.Render);
}
}
}
#endregion
#region PieSelectionMode
/// <summary>
/// Gets or sets the default mode used to perform pie selections. Default is 'Slice'.
/// </summary>
[DefaultValue(PieSelectionMode.NotSet), Category("Behavior")]
[Description("Indicates the default mode used to perform pie selections. Default is 'Slice'.")]
public PieSelectionMode PieSelectionMode
{
get { return (_PieSelectionMode); }
set
{
if (value != _PieSelectionMode)
{
_PieSelectionMode = value;
OnPropertyChanged("PieSelectionMode");
}
}
}
#endregion
#region ReversePaletteColors
///<summary>
/// Gets or sets whether default palette colors are utilized in reverse order.
///</summary>
[DefaultValue(false), Category("Appearance")]
[Description("Indicates whether default palette colors are utilized in reverse order.")]
public override bool ReversePaletteColors
{
get { return (base.ReversePaletteColors); }
set
{
if (value != ReversePaletteColors)
{
base.ReversePaletteColors = value;
UpdatePaletteNeeded = true;
}
}
}
#endregion
#region ReverseRingOrder
/// <summary>
/// Gets or sets whether rings of the pie are presented in reverse order.
/// </summary>
[DefaultValue(false), Category("Appearance")]
[Description("Indicates whether rings of the pie are presented in reverse order.")]
public bool ReverseRingOrder
{
get { return (TestState(States.ReverseRingOrder)); }
set
{
if (value != ReverseRingOrder)
{
SetState(States.ReverseRingOrder, value);
OnPropertyChangedEx("ReverseRingOrder", VisualChangeType.Layout);
}
}
}
#endregion
#region SeriesMargin
/// <summary>
/// Gets or sets the margin between multiple series in
/// the chart, relative to the plot area. Can be a percentage (if
/// value is between 0 and 1) or pixel amount (if value > 1).
/// Defaults to .02
/// </summary>
[Description("Indicates the margin between multiple series in the chart, relative to the plot area. Can be a percentage (if value is between 0 and 1) or pixel amount (if value > 1). Defaults to .02")]
[DefaultValue(.02d), Category("Margin")]
[Editor("DevComponents.Charts.Design.RadiusRangeValueEditor, DevComponents.Charts.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
public double SeriesMargin
{
get { return (_SeriesMargin); }
set
{
if (value != _SeriesMargin)
{
_SeriesMargin = value;
OnPropertyChangedEx("SeriesMargin", VisualChangeType.Layout);
}
}
}
#endregion
#region SeriesOverlayEnabled
/// <summary>
/// Gets or sets whether chart series are, by default,
/// overlayed on top of each other. Default is false.
/// </summary>
[DefaultValue(false), Category("Display")]
[Description("Indicates whether chart series are, by default, overlayed on top of each other. Default is false.")]
public bool SeriesOverlayEnabled
{
get { return (TestState(States.SeriesOverlayEnabled)); }
set
{
if (value != SeriesOverlayEnabled)
{
SetState(States.SeriesOverlayEnabled, value);
OnPropertyChangedEx("SeriesOverlayEnabled", VisualChangeType.Layout);
}
}
}
#endregion
#region ShowAllRings
/// <summary>
/// Gets or sets whether all series rings are shown when rendering the chart.
/// If false, only one ring at a time is shown, with the ability to 'drill' up
/// or down, to display adjacent rings. Defaults to true'.
/// </summary>
[DefaultValue(Tbool.NotSet), Category("Display")]
[Description("Indicates whether all series rings are shown when rendering the chart. If false, only one ring at a time is shown, with the ability to 'drill' up or down, to display adjacent rings. Defaults to true.")]
public Tbool ShowAllRings
{
get { return (_ShowAllRings); }
set
{
if (value != _ShowAllRings)
{
_ShowAllRings = value;
OnPropertyChangedEx("ShowAllRings", VisualChangeType.Layout);
}
}
}
#region ShowAllRingsEx
internal bool ShowAllRingsEx
{
get { return (ShowAllRings != Tbool.False); }
}
#endregion
#endregion
#region ShowFullGrid
/// <summary>
/// Gets or sets whether the radial pie grid is displayed over the entire
/// pie (0 - 360 degrees) or only over the sweep angle. Default is false.
/// </summary>
[DefaultValue(false), Category("Grid")]
[Description("Indicates whether the radial pie grid is displayed over the entire pie (0 - 360 degrees) or only over the sweep angle. Default is false.")]
public bool ShowFullGrid
{
get { return (TestState(States.ShowFullGrid)); }
set
{
if (value != ShowFullGrid)
{
SetState(States.ShowFullGrid, value);
OnPropertyChangedEx("ShowFullGrid", VisualChangeType.Render);
}
}
}
#endregion
#region ShowGridOnTop
/// <summary>
/// Gets or sets whether the radial grid is displayed
/// on top of the pie (ShowPieGrid must also be true). Default is false.
/// </summary>
[DefaultValue(false), Category("Grid")]
[Description("Indicates whether the radial grid is displayed on top of the pie (ShowPieGrid must also be true). Default is false.")]
public bool ShowGridOnTop
{
get { return (TestState(States.ShowGridOnTop)); }
set
{
if (value != ShowGridOnTop)
{
SetState(States.ShowGridOnTop, value);
OnPropertyChangedEx("ShowGridOnTop", VisualChangeType.Render);
}
}
}
#endregion
#region ShowOtherSlice
/// <summary>
/// Gets or sets whether to consolidate 'excluded' pie slices
/// (due to MaxSlices or MinPercent settings) into a single slice
/// that represents 'Other' data values. Default is false.
/// </summary>
[DefaultValue(Tbool.NotSet), Category("Display")]
[Description("Indicates whether to consolidate 'excluded' pie slices (due to MaxSlices or MinPercent settings) into a single slice that represents 'Other' data values. Default is false.")]
public Tbool ShowOtherSlice
{
get { return (_ShowOtherSlice); }
set
{
if (value != _ShowOtherSlice)
{
_ShowOtherSlice = value;
SeriesRangeChanged = true;
OnPropertyChangedEx("ShowOtherSlice", VisualChangeType.Recalc);
}
}
}
#endregion
#region ShowPieGrid
/// <summary>
/// Gets or sets whether a radial grid is displayed for the chart. Defaults to false.
/// </summary>
[DefaultValue(false), Category("Grid")]
[Description("Indicates whether a radial grid is displayed for the chart. Defaults to false.")]
public bool ShowPieGrid
{
get { return (TestState(States.ShowPieGrid)); }
set
{
if (value != ShowPieGrid)
{
SetState(States.ShowPieGrid, value);
OnPropertyChangedEx("ShowPieGrid", VisualChangeType.Render);
}
}
}
#endregion
#region ShowSliceLabelsOnEntry
/// <summary>
/// Gets or sets whether all enabled slice labels will be shown
/// when the mouse enters the chart area. Default is false.
/// </summary>
[DefaultValue(false), Category("Label")]
[Description("Indicates whether all enabled slice labels will be shown when the mouse enters the chart area. Default is false.")]
public bool ShowSliceLabelsOnEntry
{
get { return (TestState(States.ShowSliceLabelsOnEntry)); }
set
{
if (value != ShowSliceLabelsOnEntry)
{
SetState(States.ShowSliceLabelsOnEntry, value);
OnPropertyChangedEx("ShowSliceLabelsOnEntry", VisualChangeType.Render);
}
}
}
#endregion
#region ShowToolTips
/// <summary>
/// Gets or sets whether tooltips are shown.
/// </summary>
[DefaultValue(false), Category("Appearance")]
[Description("Indicates whether tooltips are shown.")]
public bool ShowToolTips
{
get { return (TestState(States.ShowToolTips)); }
set
{
if (value != ShowToolTips)
{
SetState(States.ShowToolTips, value);
OnPropertyChanged("ShowToolTips");
}
}
}
#endregion
#region SliceLabelOverlapMode
/// <summary>
/// Gets or sets the mode for resolving overlapping outer slice labels.
/// Outer slice labels are only displayed for the outer-most chart series ring.
/// This setting only applies to individual series (ie. Overlapped series are
/// treated as distinct elements). Default is HideOverlapping.
/// </summary>
[DefaultValue(SliceLabelOverlapMode.NotSet), Category("Label")]
[Description("Indicates the mode for resolving overlapping outer slice labels. Outer slice labels are only displayed for the outer-most chart series ring. This setting only applies to individual series (ie. Overlapped series are treated as distinct elements). Default is HideOverlapping.")]
public SliceLabelOverlapMode SliceLabelOverlapMode
{
get { return (_SliceLabelOverlapMode); }
set
{
if (value != _SliceLabelOverlapMode)
{
_SliceLabelOverlapMode = value;
OnPropertyChangedEx("SliceLabelOverlapMode", VisualChangeType.Layout);
}
}
}
#endregion
#region SubSliceVisualLayout
/// <summary>
/// Gets or sets the default layout of chart SeriesPoints that are
/// subordinate to the chart.
/// </summary>
[Category("Layout")]
[Description("Indicates the default layout of chart SeriesPoints.")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public SliceVisualLayout SubSliceVisualLayout
{
get
{
if (_SubSliceVisualLayout == null)
SubSliceVisualLayout = new SliceVisualLayout(this);
return (_SubSliceVisualLayout);
}
set
{
if (value != _SubSliceVisualLayout)
{
if (_SubSliceVisualLayout != null)
_SubSliceVisualLayout.PropertyChanged -= SliceVisualLayout_PropertyChanged;
_SubSliceVisualLayout = value;
if (_SubSliceVisualLayout != null)
_SubSliceVisualLayout.PropertyChanged += SliceVisualLayout_PropertyChanged;
OnPropertyChangedEx("SubSliceVisualLayout", VisualChangeType.Recalc);
}
}
}
#region SliceVisualLayout_PropertyChanged
void SliceVisualLayout_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (ChartControl != null)
ChartControl.GlobalUpdateCount++;
VisualPropertyChangedEventArgs vce = e as VisualPropertyChangedEventArgs;
if (vce != null)
{
switch (vce.ChangeType)
{
case VisualChangeType.Recalc:
foreach (BaseSeries series in BaseSeries)
series.InvalidateRecalc();
break;
case VisualChangeType.Layout:
InvalidateLayout();
break;
default:
InvalidateRender();
break;
}
}
if (e is VisualPropertyChangedEventArgs)
OnPropertyChangedEx(e.PropertyName, ((VisualPropertyChangedEventArgs)e).ChangeType);
}
#endregion
#endregion
#region UseAlternateGridBackground
/// <summary>
/// Gets or sets whether the chart utilizes the alternate background color
/// when ShowPieGrid is enabled.
/// </summary>
[DefaultValue(false), Category("Grid")]
[Description("Indicates whether the chart utilizes the alternate background color when ShowPieGrid is enabled.")]
public bool UseAlternateGridBackground
{
get { return (TestState(States.UseAlternateGridBackground)); }
set
{
if (value != UseAlternateGridBackground)
{
SetState(States.UseAlternateGridBackground, value);
OnPropertyChangedEx("UseAlternateGridBackground", VisualChangeType.Render);
}
}
}
#endregion
#region WhitespaceClickBehavior
/// <summary>
/// Gets or sets the behavior when the user
/// clicks the mouse in the chart whitespace.
/// </summary>
[DefaultValue(WhitespaceClickBehavior.ClearSelection), Category("Behavior")]
[Description("Indicates the behavior when the user clicks the mouse in the chart whitespace.")]
public WhitespaceClickBehavior WhitespaceClickBehavior
{
get { return (_WhitespaceClickBehavior); }
set
{
if (value != _WhitespaceClickBehavior)
{
_WhitespaceClickBehavior = value;
OnPropertyChanged("WhitespaceClickBehavior");
}
}
}
#endregion
#endregion
#region Internal properties
#region ExplodedOffsetEx
internal double ExplodedOffsetEx
{
get
{
if (double.IsNaN(_ExplodedOffsetEx) == true)
_ExplodedOffsetEx = GetExplodedOffset();
return (_ExplodedOffsetEx);
}
}
#region GetExplodedOffset
internal double GetExplodedOffset()
{
if (IsExploded == true)
{
if (ExplodedOffset > 0)
{
if (ExplodedOffset >= 1)
return (ExplodedOffset);
return (OuterRadiusEx * ExplodedOffset);
}
}
return (0);
}
#endregion
#endregion
#region GlobalSelectionCount
internal uint GlobalSelectionCount
{
get { return (_GlobalSelectionCount); }
set { _GlobalSelectionCount = value; }
}
#endregion
#region GridInnerRadiusEx
internal double GridInnerRadiusEx
{
get
{
if (double.IsNaN(_GridInnerRadiusEx) == true)
{
_GridInnerRadiusEx = GridInnerRadius;
if (_GridInnerRadiusEx > 0)
{
if (PieRadiusScale == PieRadiusScale.Percentage || _GridInnerRadiusEx <= 1)
_GridInnerRadiusEx *= OuterRadiusEx;
}
_GridInnerRadiusEx += InnerRadiusEx;
}
return (_GridInnerRadiusEx);
}
}
#endregion
#region GridOuterRadiusEx
internal double GridOuterRadiusEx
{
get
{
if (double.IsNaN(_GridOuterRadiusEx) == true)
{
_GridOuterRadiusEx = GridOuterRadius;
if (_GridOuterRadiusEx > 0)
{
if (PieRadiusScale == PieRadiusScale.Percentage || _GridOuterRadiusEx <= 1)
_GridOuterRadiusEx *= OuterRadiusEx;
}
}
return (_GridOuterRadiusEx);
}
}
#endregion
#region HitPsp
internal PieSeriesPoint HitPsp
{
get { return (_HitPsp); }
set { _HitPsp = value; }
}
#endregion
#region InnerMarginEx
internal double InnerMarginEx
{
get
{
if (double.IsNaN(_InnerMarginEx) == true)
_InnerMarginEx = GetInnerMargin();
return (_InnerMarginEx);
}
}
#region GetInnerMargin
private double GetInnerMargin()
{
if (InnerMargin <= 0)
return (0);
if (PieRadiusScale == PieRadiusScale.Percentage || InnerMargin <= 1)
return (InnerMargin * OuterRadiusEx);
return (InnerMargin);
}
#endregion
#endregion
#region InnerRadiusEx
internal double InnerRadiusEx
{
get
{
if (double.IsNaN(_InnerRadiusEx) == true)
_InnerRadiusEx = GetInnerRadius();
return (_InnerRadiusEx);
}
}
#region GetInnerRadius
private double GetInnerRadius()
{
if (InnerRadius > 0)
{
if (PieRadiusScale == PieRadiusScale.Percentage || InnerRadius <= 1)
return (InnerRadius * OuterRadiusEx);
return (InnerRadius);
}
return (0);
}
#endregion
#endregion
#region IsDragging
internal bool IsDragging
{
get { return (TestState(States.Dragging)); }
set { SetState(States.Dragging, value); }
}
#endregion
#region MaxPieOuterExtent
internal double MaxPieOuterExtent
{
get { return (_MaxPieOuterExtent); }
set { _MaxPieOuterExtent = value; }
}
#endregion
#region OuterRadiusEx
internal double OuterRadiusEx
{
get
{
if (double.IsNaN(_OuterRadiusEx) == true)
{
_OuterRadiusEx = OuterRadiusExx;
if (OuterMargin > 0)
{
if (OuterMargin >= 1)
_OuterRadiusEx -= OuterMargin;
else
_OuterRadiusEx -= (_OuterRadiusEx * OuterMargin);
}
_OuterRadiusEx = Math.Max(0, _OuterRadiusEx);
}
return (_OuterRadiusEx);
}
}
#endregion
#region OuterRadiusExx
internal double OuterRadiusExx
{
get
{
double radius = OuterRadius;
if (radius > 0)
{
if (PieRadiusScale == PieRadiusScale.Percentage || radius <= 1)
radius *= (Math.Min(ContentBoundsEx.Width, ContentBoundsEx.Height) / 2);
}
return (Math.Max(MinOuterRadius, radius));
}
}
#endregion
#region PspDragType
internal PspDragType PspDragType
{
get { return (_PspDragType); }
set { _PspDragType = value; }
}
#endregion
#region RingOutRadius
internal int RingOutRadius
{
get
{
PieSeries series = GetInnerSeries();
if (series != null)
{
double radius = InnerRadiusEx;
if (InnerMarginEx > 0)
radius -= InnerMarginEx;
if (ShowAllRingsEx == true)
{
if (ExplodedOffsetEx > 0)
{
radius += ExplodedOffsetEx;
radius -= GetExplodedMargin(series);
}
}
radius = Math.Min(radius, Dpi.Width(MaxRingOutRadius));
return (int)(Math.Max(0, radius));
}
return (0);
}
}
#endregion
#region RingWeightTotal
internal int RingWeightTotal
{
get { return (_RingWeightTotal); }
set { _RingWeightTotal = value; }
}
#endregion
#region UpdatePaletteNeeded
internal bool UpdatePaletteNeeded
{
get { return (TestState(States.UpdatePaletteNeeded)); }
set { SetState(States.UpdatePaletteNeeded, value); }
}
#endregion
#endregion
#region OnResize
protected override bool OnResize(EventArgs e)
{
InvalidateValueCache();
return (base.OnResize(e));
}
#region InvalidateValueCache
private void InvalidateValueCache()
{
_InnerRadiusEx = double.NaN;
_OuterRadiusEx = double.NaN;
_GridInnerRadiusEx = double.NaN;
_GridOuterRadiusEx = double.NaN;
_ExplodedOffsetEx = double.NaN;
_InnerMarginEx = double.NaN;
}
#endregion
#endregion
#region MeasureOverride
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
{
ContainerVisualStyle cStyle = GetEffectiveContainerStyle();
PieChartVisualStyle pieStyle = EffectiveChartStyle;
BoundsRelative = layoutInfo.LayoutBounds;
UpdateDataBindings();
_PieLabels = null;
Rectangle oldFrameBounds = FrameBounds;
FrameBounds = GetAdjustedBounds(BoundsRelative, cStyle.Margin);
FrameBounds = GetAdjustedBounds(FrameBounds, cStyle.Padding);
FrameBounds = GetAdjustedBounds(FrameBounds, pieStyle.Margin);
if (FrameBounds != oldFrameBounds)
SeriesPointCount++;
ContentBounds = GetAdjustedBounds(FrameBounds, cStyle.BorderThickness);
ContentBounds = GetAdjustedBounds(ContentBounds, pieStyle.BorderThickness);
ContentBounds = GetAdjustedBounds(ContentBounds, pieStyle.Padding);
layoutInfo.LayoutBounds = ContentBounds;
foreach (ChartTitle title in Titles)
{
if (title.Visible == true)
title.Measure(layoutInfo);
}
if (pieStyle.DropShadow.Enabled == Tbool.True)
layoutInfo.LayoutBounds = GetShadowBounds(layoutInfo.LayoutBounds);
MeasureSeries(layoutInfo);
if (Legend.Visible == true)
Legend.Measure(layoutInfo);
Rectangle oldContentBoundsEx = ContentBoundsEx;
ContentBounds = layoutInfo.LayoutBounds;
ContentBoundsEx = ContentBounds;
Rectangle r = ContentBounds;
r.Size = new Size(
Math.Max(r.Size.Width, Dpi.Width(MinContentSize.Width)),
Math.Max(r.Size.Height, Dpi.Height(MinContentSize.Height)));
// Since our vertical scrollbar is reversed, we
// need to adjust the extended content area accordingly
if (r.Height > ContentBounds.Height)
r.Y -= (r.Height - ContentBounds.Height);
ContentBoundsEx = r;
FinalizeDataBindings();
InvalidateValueCache();
}
#region MeasureSeries
private void MeasureSeries(ChartLayoutInfo layoutInfo)
{
PieSeries[] aseries = new PieSeries[ChartSeries.Count];
ChartSeries.CopyTo(aseries, 0);
foreach (PieSeries series in aseries)
{
if (series.IsDisplayed == true)
series.Measure(layoutInfo);
}
if (SeriesRangeChanged == true)
{
SeriesRangeChanged = false;
UpdatePaletteNeeded = true;
RingWeightTotal = 0;
MaxPieOuterExtent = 0;
for (int i = 0; i < aseries.Length; i++)
{
PieSeries series = aseries[i];
if (series.IsDisplayed == true)
RingWeightTotal += series.RingWeight;
MeasurePieSlices(series, series.SeriesPoints);
if (series.PieOuterExtent > MaxPieOuterExtent)
MaxPieOuterExtent = series.PieOuterExtent;
}
if (SeriesOverlayEnabled == true)
UpdateSeriesOverlayValues(aseries);
}
if (UpdatePaletteNeeded == true)
{
UpdatePaletteNeeded = false;
int colorIndex = 0;
for (int i = 0; i < aseries.Length; i++)
UpdateSeriesPalette(aseries[i], ref colorIndex);
}
}
#region MeasurePieSlices
private void MeasurePieSlices(PieSeries series, PieSeriesPointCollection spc)
{
if (spc != null && spc.Count > 0)
{
int ringLevel = 0;
series.PieRings.Clear();
CalculatePieTotals(series, spc, ringLevel);
CalculateRingTotal(series);
CalculateSliceValues(spc);
GatherPieSlices(series, spc);
}
}
#region GetMaxSlices
private int GetMaxSlices(PieSeriesPointCollection spc)
{
int maxSlices = spc.Parent.SubSliceVisualLayout.MaxSlices;
if (maxSlices < 0)
maxSlices = SubSliceVisualLayout.MaxSlices;
return ((maxSlices >= 0) ? maxSlices : 100);
}
#endregion
#region GetMinPercent
private double GetMinPercent(PieSeriesPointCollection spc)
{
double minPercent = spc.Parent.SubSliceVisualLayout.MinPercent;
if (double.IsNaN(minPercent) || minPercent < 0)
minPercent = SubSliceVisualLayout.MinPercent;
if (double.IsNaN(minPercent) == true || minPercent < 0)
minPercent = .04d;
return (minPercent);
}
#endregion
#region CalculatePieTotals
private void CalculatePieTotals(
PieSeries series, PieSeriesPointCollection spc, int ringLevel)
{
if (spc.Count > 0)
{
spc.PieTotal = 0;
spc.PieTotalExtent = 0;
spc.PieMinExtent = double.MaxValue;
spc.PieMaxExtent = 0;
spc.PieRing = GetPieRingAtLevel(series, ringLevel);
int ringWeight = spc.PieRing.RingWeight;
int maxSlices = GetMaxSlices(spc);
int sliceCount = 0;
bool showOtherSlices = series.ShowOtherSliceEx(this);
foreach (PieSeriesPoint psp in spc)
{
if (psp != null && psp.Visible == true)
{
if (psp.ValueY.Length > 0)
{
sliceCount++;
double d = Convert.ToDouble(psp.ValueY[0]);
spc.PieTotal += d;
psp.PieRing = spc.PieRing;
if (psp.ValueY.Length > 1)
{
d = Convert.ToDouble(psp.ValueY[1]);
spc.PieTotalExtent += d;
if (d > spc.PieMaxExtent)
spc.PieMaxExtent = d;
if (d < spc.PieMinExtent)
spc.PieMinExtent = d;
psp.HasExtent = true;
}
if (psp.RingWeightEx >= 0)
{
if (psp.RingWeightEx > ringWeight)
ringWeight = psp.RingWeightEx;
}
spc.PieRing.Psps.Add(psp);
if (psp.SeriesPoints != null)
CalculatePieTotals(series, psp.SeriesPoints, ringLevel + 1);
}
}
spc.PieOuterExtent = Math.Max(psp.MinExtentEx, spc.PieMaxExtent);
if (spc.PieOuterExtent > series.PieOuterExtent)
series.PieOuterExtent = spc.PieOuterExtent;
if (showOtherSlices == false && sliceCount >= maxSlices)
break;
}
spc.PieRing.RingWeight = (ringWeight < 0) ? 100 : ringWeight;
int visCount = spc.VisibleCount;
spc.PieAverage = ((visCount > 0) ? (spc.PieTotal / visCount) : 0);
spc.PieAverageExtent = ((visCount > 0) ? (spc.PieTotalExtent / visCount) : 0);
}
}
#region GetPieRingAtLevel
private PieRing GetPieRingAtLevel(PieSeries series, int ringLevel)
{
foreach (PieRing ring in series.PieRings)
{
if (ring.RingLevel == ringLevel)
return (ring);
}
PieRing pieRing = new PieRing(ringLevel);
pieRing.ChartSeries = series;
series.PieRings.Add(pieRing);
return (pieRing);
}
#endregion
#endregion
#region CalculateRingTotal
private void CalculateRingTotal(PieSeries series)
{
int ringTotal = 0;
foreach (PieRing ring in series.PieRings)
ringTotal += ring.RingWeight;
series.RingWeightTotal = ringTotal;
}
#endregion
#region CalculateSliceValues
private void CalculateSliceValues(PieSeriesPointCollection spc)
{
if (spc != null)
{
foreach (PieSeriesPoint psp in spc)
{
if (psp != null && psp.Visible == true)
{
psp.SliceValue = 0;
psp.SliceExtent = 1;
if (psp.ValueY.Length > 0)
{
double d = Convert.ToDouble(psp.ValueY[0]);
psp.SliceValue = (spc.PieTotal > 0) ? (d / spc.PieTotal) : 0;
if (spc.PieOuterExtent > 0 && psp.ValueY.Length > 1)
{
d = Convert.ToDouble(psp.ValueY[1]);
psp.SliceExtent = d / spc.PieOuterExtent;
}
CalculateSliceValues(psp.SeriesPoints);
}
}
}
}
}
#endregion
#region GatherPieSlices
private void GatherPieSlices(PieSeries series, PieSeriesPointCollection spc)
{
int maxSlices = GetMaxSlices(spc);
double minPercent = GetMinPercent(spc);
PieSeriesPointCollection pieSlices = GetNewListSpc(spc);
PieSeriesPointCollection otherSlices = null;
if (series.ShowOtherSliceEx(this) == true)
{
otherSlices = GetNewListSpc(spc);
otherSlices.IsOther = true;
}
for (int i = 0; i < spc.Count; i++)
{
AddPieSeriesPoint(series, spc,
maxSlices, minPercent, i, pieSlices, otherSlices);
if (otherSlices == null && pieSlices.Count >= maxSlices)
break;
}
if (otherSlices != null && otherSlices.Count > 0)
{
double value = 0;
double extent = 0;
foreach (PieSeriesPoint psp in otherSlices)
{
if (psp.ValueY.Length > 0)
value += Convert.ToDouble(psp.ValueY[0]);
if (psp.ValueY.Length > 1)
{
double d = Convert.ToDouble(psp.ValueY[1]);
if (d > extent)
extent = value;
}
}
PieSeriesPoint opsp = spc.OtherSlicePsp;
opsp.ValueX = "Other";
opsp.ValueY[0] = value;
opsp.ValueY[1] = extent;
opsp.IsOther = true;
opsp.PieRing = spc.PieRing;
opsp.SliceValue = (spc.PieTotal > 0) ? (value / spc.PieTotal) : 0;
opsp.SliceExtent = (spc.PieOuterExtent > 0) ? (extent / spc.PieOuterExtent) : 1;
pieSlices.Add(opsp);
spc.PieRing.Psps.Add(opsp);
}
spc.PieSlices = pieSlices;
spc.OtherSlices = otherSlices;
}
#region GetNewListSpc
private PieSeriesPointCollection GetNewListSpc(PieSeriesPointCollection spc)
{
PieSeriesPointCollection spcNew = new PieSeriesPointCollection();
spcNew.PieAverage = spc.PieAverage;
spcNew.PieTotal = spc.PieTotal;
spcNew.PieAverageExtent = spc.PieAverageExtent;
spcNew.PieMaxExtent = spc.PieMaxExtent;
spcNew.PieMinExtent = spc.PieMinExtent;
spcNew.PieOuterExtent = spc.PieOuterExtent;
spcNew.PieTotalExtent = spc.PieTotalExtent;
spcNew.PieRing = spc.PieRing;
spcNew.Parent = spc.Parent;
return (spcNew);
}
#endregion
#region AddPieSeriesPoint
private void AddPieSeriesPoint(PieSeries series,
PieSeriesPointCollection spc, int maxSlices, double minPercent,
int index, PieSeriesPointCollection pieSlices, PieSeriesPointCollection otherSlices)
{
PieSeriesPoint psp = spc[index] as PieSeriesPoint;
if (psp != null && psp.Visible == true)
{
psp.IsInOtherEx = ((otherSlices != null) &&
(psp.IsInOther || (pieSlices.Count >= maxSlices || psp.SliceValue < minPercent)));
if (psp.IsInOtherEx == true)
{
psp.OrdinalValue = otherSlices.Count;
otherSlices.Add(psp);
}
else
{
psp.OrdinalValue = pieSlices.Count;
pieSlices.Add(psp);
}
GatherPieSlices(series, psp.SeriesPoints);
}
}
#endregion
#endregion
#endregion
#region UpdateSeriesOverlayValues
private void UpdateSeriesOverlayValues(PieSeries[] aseries)
{
for (int i = 0; i < aseries.Length; i++)
{
PieSeries series = aseries[i];
if (series.IsDisplayed == true)
UpdatePspOverlayValues(series, series.SeriesPoints.PieSlices);
}
}
#region UpdatePspOverlayValues
private void UpdatePspOverlayValues(PieSeries series, PieSeriesPointCollection spc)
{
if (spc != null && spc.Count > 0)
{
if (spc.PieOuterExtent != MaxPieOuterExtent)
{
spc.PieOuterExtent = MaxPieOuterExtent;
CalculateSliceValues(spc);
}
}
}
#endregion
#endregion
#region UpdateSeriesPalette
private void UpdateSeriesPalette(PieSeries series, ref int colorIndex)
{
if (series.UpdatePalette(this) == false)
{
foreach (PieRing pieRing in series.PieRings)
{
foreach (PieSeriesPoint psp in pieRing.Psps)
psp.DefaultPaletteColor = GetPaletteColor(colorIndex++);
}
}
}
#endregion
#endregion
#endregion
#region ArrangeOverride
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
{
int vmax = VScrollBar.LargeChange;
base.ArrangeOverride(layoutInfo);
if (VScrollBar.LargeChange != vmax)
SeriesPointCount++;
CalcPieCenter(layoutInfo);
if (RingWeightTotal > 0)
ArrangeSeries(layoutInfo);
SeriesLayoutCount++;
}
#region CalcPieCenter
private void CalcPieCenter(ChartLayoutInfo layoutInfo)
{
Rectangle bounds = ContentBoundsEx;
Point centerPos = Point.Empty;
centerPos.X = bounds.X + bounds.Width / 2;
centerPos.Y = bounds.Y + bounds.Height / 2;
if (CenterPos.X >= -1 && CenterPos.X <= 1)
{
if (CenterPos.X != 0.0)
centerPos.X += (int)(bounds.Width * CenterPos.X);
}
else
{
centerPos.X += (int)CenterPos.X;
}
if (CenterPos.Y >= -1 && CenterPos.Y <= 1)
{
if (CenterPos.Y != 0.0)
centerPos.Y += (int)(bounds.Height * CenterPos.Y);
}
else
{
centerPos.Y += (int)CenterPos.Y;
}
CenterPoint = centerPos;
}
#endregion
#region ArrangeSeries
private void ArrangeSeries(ChartLayoutInfo layoutInfo)
{
if (ChartSeries.Count > 0)
{
List<PieSeries> pieSeries = GetVisibleSeries();
if (pieSeries.Count > 0)
{
UpdatePieRingList();
PieChartVisualStyle pStyle = EffectiveChartStyle;
int innerRadius = (int)(ReverseRingOrder ? OuterRadiusEx : InnerRadiusEx);
int outerRadius = (int)(ReverseRingOrder ? InnerRadiusEx : OuterRadiusEx);
double ringWidth = Math.Max(0, (OuterRadiusEx - InnerRadiusEx));
double width = ringWidth;
int seriesMargin = GetSeriesMargin();
if (SeriesOverlayEnabled == false)
{
if (pieSeries.Count > 1)
width -= (pieSeries.Count - 1) * seriesMargin;
}
bool revOrder = (SeriesDisplayOrder == SeriesDisplayOrder.Reverse) ^ (ReverseRingOrder == true);
if (revOrder == true)
{
for (int i = pieSeries.Count - 1; i >= 0; i--)
ArrangeSeriesEx(layoutInfo, pieSeries[i], pStyle, ref outerRadius, width, seriesMargin);
}
else
{
for (int i = 0; i < pieSeries.Count; i++)
ArrangeSeriesEx(layoutInfo, pieSeries[i], pStyle, ref outerRadius, width, seriesMargin);
}
AdjustSeriesWidths(pieSeries, seriesMargin);
}
}
}
#region AdjustSeriesWidths
private void AdjustSeriesWidths(List<PieSeries> pieSeries, int seriesMargin)
{
int pieWidth = (int)(OuterRadiusEx - InnerRadiusEx);
if (SeriesOverlayEnabled == false)
pieWidth -= ((pieSeries.Count - 1) * seriesMargin);
int seriesWidth = 0;
foreach (PieSeries series in pieSeries)
{
seriesWidth += series.RingWeightEx;
if (SeriesOverlayEnabled == true)
break;
}
if (seriesWidth < pieWidth)
{
int n = 0;
int count = pieWidth - seriesWidth;
for (int i = 0; i < pieSeries.Count; i++)
{
PieSeries series = pieSeries[i];
if (i < count)
series.RingWeightEx++;
AdjustRingWidths(series, n);
if (i < count)
n++;
}
}
}
#region AdjustRingWidths
private void AdjustRingWidths(PieSeries series, int offset)
{
int seriesWidth = series.RingWeightEx;
int ringWidth = 0;
foreach (PieRing pieRing in series.PieRings)
ringWidth += (pieRing.OuterRadius - pieRing.InnerRadius);
int n = 0;
int count = seriesWidth - ringWidth;
if (ReverseRingOrder == true)
{
for (int i = series.PieRings.Count - 1; i >= 0; i--)
{
PieRing pieRing = series.PieRings[i];
pieRing.InnerRadius += offset;
pieRing.OuterRadius += offset;
if (n < count)
{
pieRing.InnerRadius += n;
pieRing.OuterRadius += (n + 1);
n++;
}
AdjustPspWidths(pieRing);
}
}
else
{
for (int i = 0; i < series.PieRings.Count; i++)
{
PieRing pieRing = series.PieRings[i];
pieRing.OuterRadius -= offset;
pieRing.InnerRadius -= offset;
if (n < count)
{
pieRing.OuterRadius -= n;
pieRing.InnerRadius -= (n + 1);
n++;
}
AdjustPspWidths(pieRing);
}
}
}
#region AdjustPspWidths
private void AdjustPspWidths(PieRing pieRing)
{
int ringWidth = (pieRing.OuterRadius - pieRing.InnerRadius);
foreach (PieSeriesPoint psp in pieRing.Psps)
{
psp.OuterRadius = pieRing.OuterRadius;
psp.InnerRadius = pieRing.InnerRadius;
}
}
#endregion
#endregion
#endregion
#region GetVisibleSeries
private List<PieSeries> GetVisibleSeries()
{
List<PieSeries> pieSeries = new List<PieSeries>();
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
pieSeries.Add(series);
}
return (pieSeries);
}
#endregion
#region UpdatePieRingList
private void UpdatePieRingList()
{
PieRing innerRing = null;
PieRing outerRing = null;
if (SeriesDisplayOrder == SeriesDisplayOrder.Reverse)
{
for (int i = ChartSeries.Count - 1; i >= 0; i--)
UpdatePieRingListEx(ChartSeries[i], ref innerRing, ref outerRing);
}
else
{
for (int i = 0; i < ChartSeries.Count; i++)
UpdatePieRingListEx(ChartSeries[i], ref innerRing, ref outerRing);
}
if (innerRing != null)
{
innerRing.IsInnerRing = true;
innerRing.ChartSeries.IsInnerRingSeries = true;
}
if (outerRing != null)
{
outerRing.IsOuterRing = true;
outerRing.ChartSeries.IsOuterRingSeries = true;
}
}
#region UpdatePieRingListEx
private void UpdatePieRingListEx(
PieSeries series, ref PieRing innerRing, ref PieRing outerRing)
{
if (series.IsDisplayed == true)
{
if (series.PieRings.Count > 0)
{
if (ReverseRingOrder == true)
{
if (outerRing == null)
outerRing = series.PieRings[series.PieRings.Count - 1];
innerRing = series.PieRings[0];
}
else
{
if (outerRing == null)
outerRing = series.PieRings[0];
innerRing = series.PieRings[series.PieRings.Count - 1];
}
series.IsInnerRingSeries = false;
series.IsOuterRingSeries = false;
for (int j = 0; j < series.PieRings.Count; j++)
{
PieRing pieRing = series.PieRings[j];
pieRing.IsOuterRing = false;
pieRing.IsInnerRing = false;
}
}
}
}
#endregion
#endregion
#region GetSeriesMargin
private int GetSeriesMargin()
{
//if (SeriesMargin <= 0)
// return (0);
if (Math.Abs(SeriesMargin) >= 1)
return ((int)SeriesMargin);
return (int)(SeriesMargin * (OuterRadiusEx - InnerRadiusEx));
}
#endregion
#region ArrangeSeriesEx
private void ArrangeSeriesEx(ChartLayoutInfo layoutInfo, PieSeries series,
PieChartVisualStyle pStyle, ref int outerRadius, double dwidth, int seriesMargin)
{
if (series.IsDisplayed == true)
{
series.Arrange(layoutInfo);
int width = (SeriesOverlayEnabled == false)
? (int)(dwidth * ((double)series.RingWeight / RingWeightTotal))
: (int)(dwidth);
ArrangePieSlices(series, outerRadius, width);
series.RingWeightEx = width;
if (SeriesOverlayEnabled == false)
{
if (ReverseRingOrder == true)
{
if (series.IsOuterRingSeries == false)
width += seriesMargin;
outerRadius += width;
}
else
{
if (series.IsInnerRingSeries == false)
width += seriesMargin;
outerRadius -= width;
}
}
}
}
#region ArrangePieSlices
private void ArrangePieSlices(PieSeries series, int outerRadius, int width)
{
series.IsOffset = false;
PieSeriesPointCollection spc = series.GetActiveSeriesPointCollection();
if (spc != null)
{
if (spc.PieSlices != null)
spc = spc.PieSlices;
if (spc != null && spc.Count > 0)
{
int sweepDir = GetSweepDirEx(series);
double sweepAngle = GetSweepAngle(series);
CalculateSweepAngles(spc, spc.PieTotal, sweepAngle, sweepDir);
double startAngle = GetStartAngle(series);
bool centerFirstSlice = GetCenterFirstSlice(series);
ArrangePieSlicesEx(series, spc,
outerRadius, width, startAngle, centerFirstSlice);
}
}
}
#region GetCenterFirstSlice
private bool GetCenterFirstSlice(PieSeries series)
{
Tbool centerSlice = series.CenterFirstSlice;
if (centerSlice == Tbool.NotSet)
centerSlice = CenterFirstSlice;
return (centerSlice == Tbool.True);
}
#endregion
#region GetSweepDirEx
internal int GetSweepDirEx(PieSeries series)
{
SweepDirection sweepDir = series.SubSliceVisualLayout.SweepDirection;
if (sweepDir == SweepDirection.NotSet)
sweepDir = SubSliceVisualLayout.SweepDirection;
return (sweepDir == SweepDirection.CounterClockwise) ? -1 : 1;
}
#endregion
#region GetSweepAngle
private double GetSweepAngle(PieSeries series)
{
double sweepAngle = series.SubSliceVisualLayout.SweepAngle;
if (double.IsNaN(sweepAngle) == false)
return (sweepAngle);
sweepAngle = SubSliceVisualLayout.SweepAngle;
return (double.IsNaN(sweepAngle) == false ? sweepAngle : 360d);
}
#endregion
#region GetStartAngle
private double GetStartAngle(PieSeries series)
{
double startAngle = series.SubSliceVisualLayout.StartAngle;
if (double.IsNaN(startAngle) == false)
return (startAngle);
startAngle = SubSliceVisualLayout.StartAngle;
return (double.IsNaN(startAngle) == false ? startAngle : 270d);
}
#endregion
#region CalculateSweepAngles
private void CalculateSweepAngles
(PieSeriesPointCollection spc, double pieTotal, double degrees, int sweepDir)
{
if (spc != null && spc.Count > 0)
{
if (pieTotal > 0)
{
foreach (PieSeriesPoint psp in spc)
{
psp.SweepAngleEx = 0;
psp.AngleMarginExx = 0;
if (double.IsNaN(psp.SweepAngle) == false)
psp.SweepAngleEx = psp.SweepAngle;
else
psp.SweepAngleEx = psp.SliceValue * degrees;
if (psp.AngleMarginEx > 0)
{
psp.AngleMarginExx = psp.AngleMarginEx;
if (psp.SweepAngleEx < (psp.AngleMarginEx * 2))
psp.AngleMarginExx = psp.SweepAngleEx / 2 - 1;
if (psp.AngleMarginExx > 0)
psp.SweepAngleEx -= (psp.AngleMarginExx * 2);
}
CalculateSweepAngles(
psp.SeriesPoints.PieSlices, psp.SeriesPoints.PieTotal, psp.SweepAngleEx, sweepDir);
psp.SweepAngleEx *= sweepDir;
}
}
}
}
#endregion
#region ArrangePieSlicesEx
private void ArrangePieSlicesEx(PieSeries series,
PieSeriesPointCollection spc, int outerRadius, int width, double sliceAngle, bool centerSlice)
{
if (spc.PieSlices != null)
spc = spc.PieSlices;
if (spc != null && spc.Count > 0)
{
if (series.ShowAllRingsEx(this) == true)
{
ArrangeAllPieRings(series,
spc, outerRadius, width, sliceAngle, centerSlice);
}
else
{
ArrangeSinglePieRing(series,
spc, outerRadius, width, sliceAngle, centerSlice);
}
}
}
#region ArrangeAllPieRings
private void ArrangeAllPieRings(PieSeries series,
PieSeriesPointCollection spc, int outerRadius, int width, double startAngle, bool centerSlice)
{
if (series.RingWeightTotal != 0)
{
if (spc.PieRing != null)
{
int awidth = (int)(width *
(double)spc.PieRing.RingWeight / series.RingWeightTotal);
int innerRadius = outerRadius - ((ReverseRingOrder == true) ? -awidth : awidth);
spc.PieRing.OuterRadius = (ReverseRingOrder == true) ? innerRadius : outerRadius;
spc.PieRing.InnerRadius = (ReverseRingOrder == true) ? outerRadius : innerRadius;
int sdir = GetSweepDirEx(series);
for (int i = 0; i < spc.Count; i++)
{
PieSeriesPoint psp = spc[i] as PieSeriesPoint;
if (psp != null)
{
psp.StartAngleEx = (startAngle + 360000) % 360;
startAngle += psp.SweepAngleEx;
if (double.IsNaN(psp.StartAngle) == false)
psp.StartAngleEx = psp.StartAngle;
if (centerSlice == true)
{
centerSlice = false;
startAngle -= (psp.SweepAngleEx / 2);
psp.StartAngleEx -= (int)((psp.SweepAngleEx + psp.AngleMarginExx * sdir) / 2);
}
if (psp.AngleMarginExx > 0)
{
double n = psp.AngleMarginExx * sdir;
startAngle += (n * 2);
psp.StartAngleEx += n;
}
psp.OuterRadius = spc.PieRing.OuterRadius;
psp.InnerRadius = spc.PieRing.InnerRadius;
int extentRadius = (int)psp.ExtentRadius;
if (extentRadius > spc.PieRing.ExtentRadius)
spc.PieRing.ExtentRadius = extentRadius;
PieSeriesPoint pspParent = spc.Parent as PieSeriesPoint;
if (pspParent == null)
{
psp.SliceCenter = GetSliceCenter(series, spc, psp);
}
else
{
psp.SliceCenter = pspParent.SliceCenter;
psp.IsOffset = pspParent.IsOffset;
double offset = GetDetachedOffset(psp);
if (offset > 0)
{
double centerAngle = psp.CenterAngle;
double radians = MathHelper.ToRadians(centerAngle);
Point pt = psp.SliceCenter;
pt.X += (int)(Math.Cos(radians) * offset);
pt.Y += (int)(Math.Sin(radians) * offset);
psp.SliceCenter = pt;
psp.IsOffset = psp.SliceCenter.Equals(CenterPoint);
}
}
ArrangePieSlicesEx(series,
psp.SeriesPoints, innerRadius, width, psp.StartAngleEx, false);
psp.PathBounds = Rectangle.Empty;
}
}
}
}
}
#endregion
#region ArrangeSinglePieRing
private int ArrangeSinglePieRing(PieSeries series,
PieSeriesPointCollection spc, int outerRadius, int width, double startAngle, bool centerSlice)
{
int innerRadius = outerRadius - ((ReverseRingOrder == true) ? -width : width);
bool isInnerRing = false;
bool isOuterRing = false;
GetRingBorderState(series, spc, ref isOuterRing, ref isInnerRing);
spc.PieRing.OuterRadius = (ReverseRingOrder == true) ? innerRadius : outerRadius;
spc.PieRing.InnerRadius = (ReverseRingOrder == true) ? outerRadius : innerRadius;
int vcount = spc.VisibleCount;
int sdir = GetSweepDirEx(series);
for (int i = 0; i < spc.Count; i++)
{
PieSeriesPoint psp = spc[i] as PieSeriesPoint;
if (psp != null)
{
psp.StartAngleEx = (startAngle + 360000) % 360;
startAngle += psp.SweepAngleEx;
if (double.IsNaN(psp.StartAngle) == false)
psp.StartAngleEx = psp.StartAngle;
if (centerSlice == true)
{
centerSlice = false;
startAngle -= (psp.SweepAngleEx / 2);
psp.StartAngleEx -= (int)((psp.SweepAngleEx + psp.AngleMarginExx * sdir) / 2);
}
if (psp.AngleMarginExx > 0)
{
double n = psp.AngleMarginExx * sdir;
startAngle += (n * 2);
psp.StartAngleEx += n;
}
psp.OuterRadius = spc.PieRing.OuterRadius;
psp.InnerRadius = spc.PieRing.InnerRadius;
psp.SliceCenter = GetSliceCenter(series, spc, psp);
spc.PieRing.OuterRadius = psp.OuterRadius;
spc.PieRing.InnerRadius = psp.InnerRadius;
int extentRadius = (int)psp.ExtentRadius;
if (extentRadius > spc.PieRing.ExtentRadius)
spc.PieRing.ExtentRadius = extentRadius;
psp.PathBounds = Rectangle.Empty;
}
}
return (Math.Abs(outerRadius - innerRadius));
}
#endregion
#region AdjustForAngleMargin
private void AdjustForAngleMargin(PieSeries series, PieSeriesPoint psp)
{
double angleMargin = psp.AngleMarginExx;
if (angleMargin != 0)
{
if (angleMargin != 0)
{
angleMargin *= GetSweepDirEx(series);
psp.StartAngleEx += (angleMargin);
psp.SweepAngleEx -= (angleMargin * 2);
}
}
}
#endregion
#region GetRingBorderState
private void GetRingBorderState(PieSeries series,
PieSeriesPointCollection spc, ref bool isOuterRing, ref bool isInnerRing)
{
if (series.IsInnerRingSeries == true)
{
if (series.ShowAllRingsEx(this) == true)
isInnerRing = spc.PieRing.IsInnerRing;
else
isInnerRing = true;
}
if (series.IsOuterRingSeries == true)
{
if (series.ShowAllRingsEx(this) == true)
isOuterRing = spc.PieRing.IsOuterRing;
else
isOuterRing = true;
}
}
#endregion
#region GetSliceCenter
private Point GetSliceCenter(PieSeries series,
PieSeriesPointCollection spc, PieSeriesPoint psp)
{
Point sliceCenter = CenterPoint;
if (IsExploded == false && psp.IsDetached == false)
return (sliceCenter);
double offset = GetPspOffset(series, psp);
psp.IsOffset = false;
if (offset > 0)
{
if (spc.Count > 1)
{
double centerAngle = psp.StartAngleEx + psp.SweepAngleEx / 2;
double radians = MathHelper.ToRadians(centerAngle);
sliceCenter.X += (int)(Math.Cos(radians) * offset);
sliceCenter.Y += (int)(Math.Sin(radians) * offset);
psp.IsOffset = true;
series.IsOffset = true;
}
else
{
psp.InnerRadius += (int)offset;
psp.OuterRadius += (int)offset;
}
}
return (sliceCenter);
}
#region GetPspOffset
internal double GetPspOffset(PieSeries series, PieSeriesPoint psp)
{
double offset = ExplodedOffsetEx + GetDetachedOffset(psp);
if (series.IsOuterRingSeries == false && IsExploded == true)
{
double expMargin = GetExplodedMargin(series);
offset -= expMargin;
}
return (offset);
}
#region GetExplodedMargin
internal double GetExplodedMargin(PieSeries series)
{
double margin = 0;
if (IsExploded == true)
{
for (int i = 0; i < ChartSeries.Count; i++)
{
PieSeries aseries = ChartSeries[i];
if (series.IsDisplayed == true)
{
if (aseries.IsOuterRingSeries == false)
{
if (aseries.IsDisplayed == true)
margin += GetExplodedMarginEx(aseries);
}
if (series == aseries)
break;
}
}
}
return (margin);
}
#region GetExplodedMarginEx
internal double GetExplodedMarginEx(PieSeries series)
{
if (IsExploded == true)
{
double margin = (double.IsNaN(series.ExplodedMargin) == false)
? series.ExplodedMargin : ExplodedMargin;
if (margin > 0)
{
if (margin >= 1)
return (margin);
return (OuterRadiusEx * margin);
}
}
return (0);
}
#endregion
#endregion
#region GetDetachedOffset
internal double GetDetachedOffset(PieSeriesPoint psp)
{
if (psp != null && psp.IsDetached == true)
{
double detachedOffset = double.IsNaN(psp.DetachedOffset) == false
? psp.DetachedOffset : DetachedOffset;
if (double.IsNaN(detachedOffset) == false)
{
if (Math.Abs(detachedOffset) >= 1)
return (detachedOffset);
return (OuterRadiusEx * detachedOffset);
}
}
return (0);
}
#endregion
#endregion
#endregion
#endregion
#endregion
#endregion
#endregion
#endregion
#region RenderOverride
protected override void RenderOverride(ChartRenderInfo renderInfo)
{
Graphics g = renderInfo.Graphics;
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
PieChartVisualStyle pStyle = EffectiveChartStyle;
ContainerVisualStyle cStyle = GetEffectiveContainerStyle();
Rectangle scFrameBounds = GetScrollBounds(FrameBounds);
Rectangle scContentBounds = GetScrollBounds(ContentBounds);
_RenderBounds = ContentBounds;
_RenderBounds.Location = GetGlobalAdjustedPoint(_RenderBounds.Location);
Rectangle scFigureBounds = GetFigureBounds(scFrameBounds, cStyle);
RenderFrameBackground(g, scFrameBounds, cStyle);
cStyle.RenderBackgroundFigure(g, scFigureBounds);
cStyle.RenderBorder(g, scFrameBounds);
Region clip = g.Clip;
g.SetClip(scContentBounds, CombineMode.Intersect);
Rectangle imageBounds = GetXyImageBounds(pStyle);
if (pStyle.ImageOverlay != ImageOverlay.Top && pStyle.ImageOverlay != ImageOverlay.Middle)
pStyle.RenderBackgroundFigure(g, scContentBounds, imageBounds);
Point cpt = Point.Empty;
Rectangle cbounds = Rectangle.Empty;
if (pStyle.ImageOverlay == ImageOverlay.Middle)
pStyle.RenderBackgroundFigure(g, scContentBounds, imageBounds);
if (InnerRadiusEx < OuterRadiusEx)
{
Point pt = GetLocalAdjustedPoint(Point.Empty);
if (pt.IsEmpty == false)
g.TranslateTransform(pt.X, pt.Y);
RenderContentBackground(renderInfo, scContentBounds, pStyle);
if (ShowGridOnTop == false)
RenderChartGrid(renderInfo, pStyle);
RenderChartContent(renderInfo, pStyle);
if (ShowGridOnTop == true)
RenderChartGrid(renderInfo, pStyle);
RenderChartOuterLabels(renderInfo, pStyle);
if (pt.IsEmpty == false)
g.ResetTransform();
}
g.Clip = clip;
pStyle.RenderBorder(g, scContentBounds);
if (pStyle.ImageOverlay == ImageOverlay.Top)
pStyle.RenderBackgroundFigure(g, scContentBounds, imageBounds);
RenderScrollbars(renderInfo);
if (pStyle.DropShadow.Enabled == Tbool.True)
pStyle.DropShadow.RenderDropShadow(g, scContentBounds, true, true);
if (cStyle.DropShadow.Enabled == Tbool.True)
cStyle.DropShadow.RenderDropShadow(g, scFrameBounds, true, true);
g.SmoothingMode = sm;
base.RenderOverride(renderInfo);
}
#region RenderChartOuterLabels
private void RenderChartOuterLabels(
ChartRenderInfo renderInfo, PieChartVisualStyle pstyle)
{
Graphics g = renderInfo.Graphics;
List<PieLabel> pieLabels = GetPieLabels(g);
if (pieLabels != null)
{
ChartControl chartControl = ChartControl;
using (StringFormat sf = new StringFormat())
{
foreach (PieLabel pl in pieLabels)
{
if (pl.Bounds.Height > 0 && pl.Bounds.Width > 0)
{
PieSeriesPoint psp = pl.PieSeriesPoint;
if (psp.ChartSeries.IsLabelDisplayed(this, psp) == true)
{
SliceOuterLabelVisualStyle lstyle =
psp.GetEffectiveSliceStyle(this, psp.ChartSeries).SliceOuterLabelStyle;
if (chartControl.DoRenderSliceOuterLabelEvent(g, this, psp, pl) == false)
{
RenderOuterLabelBackground(g, pl, lstyle);
RenderOuterLabelContent(g, pl, sf, lstyle);
RenderOuterLabelBorder(g, pl, lstyle);
RenderOuterLabelConnector(g, pl, lstyle);
}
}
}
}
}
}
}
#region GetPieLabels
private List<PieLabel> GetPieLabels(Graphics g)
{
if (_PieLabels == null)
{
if (SeriesOverlayEnabled == false)
{
PieSeries series = GetOuterSeries();
_PieLabels = GetPieLabelsEx(g, series);
}
else
{
_PieLabels = new List<PieLabel>();
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
{
List<PieLabel> pieLabels = GetPieLabelsEx(g, series);
if (pieLabels != null)
_PieLabels.AddRange(pieLabels);
}
}
}
}
return (_PieLabels);
}
#region GetPieLabelsEx
private List<PieLabel> GetPieLabelsEx(Graphics g, PieSeries series)
{
if (series != null && series.Visible == true)
{
List<PieLabel> pieLabels = series.GetPieLabels(g, this);
if (pieLabels != null)
{
ContainerVisualStyle cstyle = GetEffectiveContainerStyle();
Rectangle r = GetAdjustedBounds(ContentBoundsEx, cstyle.BorderThickness);
RadialAlign ralign = new RadialAlign(pieLabels);
ralign.Iterate(g, this, r);
}
return (pieLabels);
}
return (null);
}
#endregion
#region GetOuterSeries
private PieSeries GetOuterSeries()
{
if (ChartSeries.Count > 0)
{
if (ChartSeries.Count > 0)
{
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true && series.IsOuterRingSeries == true)
return (series);
}
}
}
return (null);
}
#endregion
#region GetInnerSeries
private PieSeries GetInnerSeries()
{
if (ChartSeries.Count > 0)
{
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true && series.IsInnerRingSeries == true)
return (series);
}
}
return (null);
}
#endregion
#endregion
#region RenderOuterLabelBackground
private void RenderOuterLabelBackground(
Graphics g, PieLabel pl, SliceOuterLabelVisualStyle lstyle)
{
if (lstyle.Background.IsEmpty == false)
{
using (Brush br = lstyle.Background.GetBrush(pl.Bounds))
g.FillRectangle(br, pl.Bounds);
}
}
#endregion
#region RenderOuterLabelContent
private void RenderOuterLabelContent(Graphics g,
PieLabel pl, StringFormat sf, SliceOuterLabelVisualStyle lstyle)
{
lstyle.GetStringFormatFlags(sf, false);
Rectangle r = GetAdjustedBounds(pl.Bounds, lstyle.Padding);
using (Brush br = new SolidBrush(lstyle.TextColor))
g.DrawString(pl.Label, lstyle.Font, br, r, sf);
}
#endregion
#region RenderOuterLabelBorder
private void RenderOuterLabelBorder(
Graphics g, PieLabel pl, SliceOuterLabelVisualStyle lstyle)
{
if (lstyle.Border.IsDisplayable == true)
{
using (Pen pen = new Pen(lstyle.Border.LineColor, Dpi.Width(lstyle.Border.LineWidth)))
{
if (lstyle.Border.LinePattern != LinePattern.NotSet)
pen.DashStyle = (DashStyle)lstyle.Border.LinePattern;
g.DrawRectangle(pen, pl.Bounds);
}
}
}
#endregion
#region RenderOuterLabelConnector
private void RenderOuterLabelConnector(
Graphics g, PieLabel pl, SliceOuterLabelVisualStyle lstyle)
{
if (lstyle.DrawConnector == Tbool.True)
{
if (lstyle.ConnectorColor.IsEmpty == false && lstyle.ConnectorThickness > 0 &&
lstyle.ConnectorPattern != LinePattern.None)
{
using (Pen pen = new Pen(lstyle.ConnectorColor, Dpi.Width(lstyle.ConnectorThickness)))
{
if (lstyle.ConnectorPattern != LinePattern.NotSet)
pen.DashStyle = (DashStyle)lstyle.ConnectorPattern;
g.DrawLines(pen,
new Point[] { pl.PtBoxEdge, pl.PtBoxBend, pl.PtSliceEdge });
}
}
}
}
#endregion
#endregion
#region RenderChartGrid
private void RenderChartGrid(ChartRenderInfo renderInfo, PieChartVisualStyle pstyle)
{
if (ShowPieGrid == true)
{
double startAngle = SubSliceVisualLayout.StartAngle;
double sweepAngle = SubSliceVisualLayout.SweepAngle;
if (double.IsNaN(startAngle) == true)
startAngle = 270;
if (double.IsNaN(sweepAngle) == true)
sweepAngle = 360;
if (sweepAngle > 0)
{
ChartControl chartControl = ChartControl;
if (GridMinValue != GridMaxValue && GridInterval != 0)
{
int dv = (int)Math.Ceiling((GridMaxValue - GridMinValue) / GridInterval);
if (dv > 0)
{
Graphics g = renderInfo.Graphics;
double exp = GetExplodedOffset();
int outerRadius = (int)(GridOuterRadiusEx + exp);
int innerRadius = (int)(GridInnerRadiusEx + exp);
if (chartControl.DoPreRenderRadialGridEvent(g, this, OuterRadiusExx, InnerRadiusEx, exp) == false)
{
int sdir = (SubSliceVisualLayout.SweepDirection == SweepDirection.CounterClockwise) ? -1 : 1;
double delta = (double)(outerRadius - innerRadius) / dv;
PieGridLineVisualStyle gstyle = pstyle.GridLineVisualStyle;
using (Pen pen = new Pen(gstyle.LineColor, Dpi.Width(gstyle.LineWidth)))
{
if (gstyle.LinePattern != LinePattern.NotSet)
pen.DashStyle = (DashStyle)gstyle.LinePattern;
if (UseAlternateGridBackground == false)
{
RenderChartGridLine(g, pen,
innerRadius, startAngle, sweepAngle, sdir, dv, delta);
}
else
{
RenderChartGridLinePath(g, pen,
innerRadius, startAngle, sweepAngle, sdir, dv, delta, pstyle);
}
if (ShowFullGrid == false && sweepAngle < 360)
{
RenderGridRay(g, pen, innerRadius, outerRadius, startAngle);
RenderGridRay(g, pen, innerRadius, outerRadius, startAngle + sweepAngle * sdir);
}
}
chartControl.DoPostRenderRadialGridEvent(g, this, OuterRadiusExx, InnerRadiusEx, exp);
}
}
}
}
}
}
#region RenderChartGridLine
private void RenderChartGridLine(Graphics g, Pen pen, int innerRadius,
double startAngle, double sweepAngle, int sdir, int dv, double delta)
{
Rectangle r = new Rectangle();
for (int i = 0; i <= dv; i++)
{
int n = (int)(innerRadius + delta * i);
if (n > 0)
{
r.Location = CenterPoint;
r.Size = Size.Empty;
r.Inflate(n, n);
if (ShowFullGrid == true || sweepAngle >= 360)
g.DrawEllipse(pen, r);
else
g.DrawArc(pen, r, (float)startAngle, (float)sweepAngle * sdir);
}
}
}
#endregion
#region RenderChartGridLinePath
private void RenderChartGridLinePath(Graphics g, Pen pen, int innerRadius,
double startAngle, double sweepAngle, int sdir, int dv, double delta, PieChartVisualStyle pstyle)
{
Rectangle r = new Rectangle();
using (GraphicsPath path = new GraphicsPath())
{
r.Location = CenterPoint;
r.Inflate((int)OuterRadiusEx, (int)OuterRadiusEx);
using (Brush br = pstyle.AlternateGridBackground.GetBrush(r))
{
for (int i = 0; i <= dv; i++)
{
int n = (int)(innerRadius + delta * i);
if (n > 0)
{
r.Location = CenterPoint;
r.Size = Size.Empty;
r.Inflate(n, n);
if (ShowFullGrid == true || sweepAngle >= 360)
{
path.AddEllipse(r);
}
else
{
if (i % 2 == 0)
path.AddArc(r, (float)startAngle, (float)sweepAngle * sdir);
else
path.AddArc(r, (float)(startAngle + sweepAngle * sdir), -(float)sweepAngle * sdir);
}
if (i % 2 == 1)
{
g.FillPath(br, path);
g.DrawPath(pen, path);
path.Reset();
}
}
}
if (path.PointCount > 0)
g.DrawPath(pen, path);
}
}
}
#endregion
#region RenderGridRay
private void RenderGridRay(Graphics g,
Pen pen, int innerRadius, int outerRadius, double angle)
{
double radians = MathHelper.ToRadians(angle);
int x = CenterPoint.X + (int)(Math.Cos(radians) * innerRadius);
int y = CenterPoint.Y + (int)(Math.Sin(radians) * innerRadius);
Point pt1 = new Point(x, y);
x = CenterPoint.X + (int)(Math.Cos(radians) * outerRadius);
y = CenterPoint.Y + (int)(Math.Sin(radians) * outerRadius);
Point pt2 = new Point(x, y);
g.DrawLine(pen, pt1, pt2);
}
#endregion
#endregion
#region RenderContentBackground
private void RenderContentBackground(
ChartRenderInfo renderInfo, Rectangle bounds, PieChartVisualStyle pstyle)
{
Graphics g = renderInfo.Graphics;
ChartControl chartControl = ChartControl;
if (chartControl.DoPreRenderContentBackgroundEvent(g, this, bounds) == false)
{
pstyle.RenderBackground(g, bounds);
Rectangle r = new Rectangle();
r.Location = CenterPoint;
r.Inflate((int)InnerRadiusEx, (int)InnerRadiusEx);
if (r.IntersectsWith(_RenderBounds) == true)
{
RenderPieCenter(g, pstyle);
if ((PieRingOutDisplayMode == PieRingOutDisplayMode.OnMouseOver && HitArea == ItemHitArea.InPieRingOut) ||
(PieRingOutDisplayMode == PieRingOutDisplayMode.Always && PresentRingOut() == true))
{
RenderPieRingOut(g, pstyle);
}
}
chartControl.DoPostRenderContentBackgroundEvent(g, this, bounds);
}
}
#region RenderPieCenter
private void RenderPieCenter(Graphics g, PieChartVisualStyle pstyle)
{
if ((CenterLabelVisibility == CenterLabelVisibility.Always) ||
(CenterLabelVisibility == CenterLabelVisibility.MouseOver && HitArea == ItemHitArea.InPieCenter))
{
int margin = (int)InnerMarginEx;
Rectangle rc = new Rectangle();
rc.Location = CenterPoint;
rc.Inflate((int)InnerRadiusEx - margin, (int)InnerRadiusEx - margin);
if (rc.Width > 0)
{
double hwidth = (double)rc.Width / 2;
int d = (int)Math.Sqrt((hwidth * hwidth) / 2);
Rectangle rt = new Rectangle();
rt.Location = CenterPoint;
rt.Inflate(d, d);
RenderPieCenterEx(g, pstyle, rc, rt);
}
}
}
#region RenderPieCenterEx
private void RenderPieCenterEx(Graphics g,
PieChartVisualStyle pstyle, Rectangle rc, Rectangle rt)
{
PieCenterVisualStyle cstyle = GetEffectivePieCenterStyle();
ChartLineVisualStyle border = cstyle.Border;
RenderPieCenterBackground(g, cstyle, rc, rt);
Rectangle rcSav = rc;
if (border.IsDisplayable == true)
{
int n = cstyle.Border.LineWidth / 2 + 1;
rc.Inflate(-n, -n);
rc.Width++;
rt.Inflate(-n, -n);
rc.Height++;
}
rc.Location = GetAdjustedPoint(rc.Location, cstyle.ImagePadding);
rt.Location = GetAdjustedPoint(rt.Location, cstyle.ImagePadding);
if (cstyle.ImageOverlay != ImageOverlay.Top)
RenderCenterFigure(g, rcSav, rc, rt, cstyle);
RenderPieCenterContent(g, cstyle, rc, rt);
if (cstyle.ImageOverlay == ImageOverlay.Top)
RenderCenterFigure(g, rcSav, rc, rt, cstyle);
if (border.IsDisplayable == true)
{
using (Pen pen = new Pen(border.LineColor, Dpi.Width(border.LineWidth)))
{
if (border.LinePattern != LinePattern.NotSet)
pen.DashStyle = (DashStyle)border.LinePattern;
g.DrawEllipse(pen, rcSav);
}
}
}
#region GetAdjustedPoint
private Point GetAdjustedPoint(Point pt, Thickness thickness)
{
if (thickness.IsEmpty == false)
{
pt.X += Dpi.Width(thickness.Left - thickness.Right);
pt.Y += Dpi.Height(thickness.Top - thickness.Bottom);
}
return (pt);
}
#endregion
#region RenderPieCenterBackground
private void RenderPieCenterBackground(
Graphics g, PieCenterVisualStyle cstyle, Rectangle rc, Rectangle rt)
{
ChartControl chartControl = ChartControl;
if (chartControl.DoPreRenderPieCenterBackgroundEvent(g, this, rc) == false)
{
if (cstyle.Background.IsEmpty == false)
{
using (Brush br = cstyle.Background.GetBrush(rc))
g.FillEllipse(br, rc);
}
chartControl.DoPostRenderPieCenterBackgroundEvent(g, this, rc);
}
}
#endregion
#region RenderPieCenterContent
private void RenderPieCenterContent(
Graphics g, PieCenterVisualStyle style, Rectangle rc, Rectangle rt)
{
ChartControl chartControl = ChartControl;
Rectangle r = (style.TextInscribed == Tbool.False) ? rc : rt;
r = GetAdjustedBounds(r, style.Padding);
if (r.Width > 0 && r.Height > 0)
{
string centerlabel = CenterLabel;
if (chartControl.DoPreRenderPieCenterContentEvent(g, this, r, centerlabel) == false)
{
if (string.IsNullOrEmpty(centerlabel) == false)
{
if (_CenterLabelMarkup != null)
{
RenderTextMarkup(g, _CenterLabelMarkup, style, r);
}
else
{
using (StringFormat sf = new StringFormat())
{
style.GetStringFormatFlags(sf);
using (Brush br = new SolidBrush(style.TextColor))
g.DrawString(centerlabel, style.Font, br, r, sf);
}
}
}
chartControl.DoPostRenderPieCenterContentEvent(g, this, r, centerlabel);
}
}
}
#region RenderTextMarkup
private void RenderTextMarkup(Graphics g,
BodyElement textMarkup, PieCenterVisualStyle style, Rectangle r)
{
MarkupDrawContext d =
new MarkupDrawContext(g, style.Font, style.TextColor, false);
textMarkup.Measure(r.Size, d);
textMarkup.Arrange(r, d);
Size size = textMarkup.Bounds.Size;
switch (style.Alignment)
{
case Alignment.MiddleLeft:
case Alignment.MiddleCenter:
case Alignment.MiddleRight:
if (r.Height > size.Height)
r.Y += (r.Height - size.Height) / 2;
break;
default:
if (r.Height > size.Height)
r.Y = r.Bottom - size.Height;
break;
}
textMarkup.Bounds = new Rectangle(r.Location, size);
Region oldClip = g.Clip;
try
{
g.SetClip(r, CombineMode.Intersect);
textMarkup.Render(d);
}
finally
{
g.Clip = oldClip;
}
}
#endregion
#endregion
#region RenderCenterFigure
private void RenderCenterFigure(Graphics g,
Rectangle rcSav, Rectangle rc, Rectangle rt, PieCenterVisualStyle cstyle)
{
object figure = cstyle.GetFigure();
if (figure != null)
{
int radius = rc.Width / 2;
Size fsize = cstyle.GetFigureSize(g);
Rectangle r = rc;
if (cstyle.ImageSizeMode == ImageSizeMode.Normal)
{
if (double.IsNaN(cstyle.ImageScale) == false)
{
if (cstyle.ImageScale != 1)
{
double d = (double)fsize.Height / fsize.Width;
fsize.Width = (int)(rt.Width * cstyle.ImageScale);
fsize.Height = (int)(fsize.Width * d);
cstyle.FigureSizeEx = fsize;
}
}
}
if (cstyle.ImageInscribed == Tbool.True)
r = GetFigureAlignment(radius, fsize, cstyle, rc, rt);
if (r.Width > 0 && r.Height > 0)
{
Region clip = g.Clip;
using (GraphicsPath path = new GraphicsPath())
{
rc.Inflate(1, 1);
path.AddEllipse(rcSav);
g.SetClip(path, CombineMode.Intersect);
cstyle.RenderBackgroundFigure(g, r);
g.Clip = clip;
}
}
}
}
#region GetFigureAlignment
private Rectangle GetFigureAlignment(int radius,
Size fsize, PieCenterVisualStyle cstyle, Rectangle rc, Rectangle rt)
{
Rectangle r = rc;
Alignment align = cstyle.ImageAlignment;
if (cstyle.ImageSizeMode == ImageSizeMode.Tile)
return (rc);
if (cstyle.ImageSizeMode == ImageSizeMode.Stretch)
return (rt);
if (cstyle.ImageSizeMode == ImageSizeMode.Zoom)
{
double ratio = (double)fsize.Height / fsize.Width;
int dx = (int)Math.Sqrt((radius * radius) / (1 + ratio * ratio));
int dy = (int)(dx * ratio);
r.X += ((r.Width / 2) - dx);
r.Width = dx * 2;
r.Y += ((r.Height / 2) - dy);
r.Height = dy * 2;
return (r);
}
if ((cstyle.ImageSizeMode == ImageSizeMode.Normal) &&
(align == Alignment.TopCenter || align == Alignment.BottomCenter ||
align == Alignment.MiddleLeft || align == Alignment.MiddleRight))
{
int height = fsize.Height / 2;
int width = fsize.Width / 2;
switch (align)
{
case Alignment.TopCenter:
if (radius > width)
{
int cy = (radius * radius) - (width * width);
int dy = radius - (int)Math.Sqrt(cy);
r.Y += dy;
}
if (r.Y > rt.Y)
r.Y = rt.Y;
r = GetAdjustedBounds(r, cstyle.ImagePadding);
break;
case Alignment.BottomCenter:
if (radius > width)
{
int cy = (radius * radius) - (width * width);
int dy = radius - (int)Math.Sqrt(cy);
r.Y -= dy;
if (r.Bottom < rt.Bottom)
r.Y = (rt.Bottom - r.Height);
r = GetAdjustedBounds(r, cstyle.ImagePadding);
}
break;
case Alignment.MiddleLeft:
if (radius > height)
{
int cx = (radius * radius) - (height * height);
int dx = radius - (int)Math.Sqrt(cx);
r.X += dx;
}
if (r.X > rt.X)
r.X = rt.X;
r = GetAdjustedBounds(r, cstyle.ImagePadding);
break;
case Alignment.MiddleRight:
if (radius > height)
{
int cx = (radius * radius) - (height * height);
int dx = radius - (int)Math.Sqrt(cx);
r.X -= dx;
}
if (r.Right < rt.Right)
r.X = (rt.Right - r.Width);
r = GetAdjustedBounds(r, cstyle.ImagePadding);
break;
}
return (r);
}
switch (align)
{
case Alignment.TopLeft:
r.X = rt.X;
r.Y = rt.Y;
break;
case Alignment.TopRight:
r.X = rt.Right - fsize.Width;
r.Y = rt.Y;
break;
case Alignment.TopCenter:
r.X = (r.X + r.Width / 2) - fsize.Width / 2;
r.Y = rt.Y;
break;
case Alignment.BottomLeft:
r.X = rt.X;
r.Y = (rt.Bottom - fsize.Height);
break;
case Alignment.BottomRight:
r.X = rt.Right - fsize.Width;
r.Y = (rt.Bottom - fsize.Height);
break;
case Alignment.BottomCenter:
r.X = (r.X + r.Width / 2) - fsize.Width / 2;
r.Y = (rt.Bottom - fsize.Height);
break;
default:
r.X = (r.X + r.Width / 2) - fsize.Width / 2;
r.Y = (r.Y + r.Height / 2) - fsize.Height / 2;
break;
}
r.Size = fsize;
return (r);
}
#endregion
#endregion
#endregion
#endregion
#region RenderPieRingOut
private void RenderPieRingOut(Graphics g, PieChartVisualStyle pstyle)
{
float n = RingOutRadius;
if (n > MinRingOutRadius)
{
Rectangle r = new Rectangle();
r.Location = CenterPoint;
r.Inflate((int)n, (int)n);
if (ChartControl.DoRenderPieRingOutEvent(g, this, r) == false)
{
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
using (Brush br = new SolidBrush(Color.FromArgb(30, Color.Black)))
g.FillEllipse(br, r);
if (_SymFontScale < 0)
{
_ScaleSymDef.SymbolSet = eSymbolSet.Awesome;
_ScaleSymDef.Symbol = "\uf060";
_ScaleSymDef.SymbolSize = n;
_SymFontScale = n / (_ScaleSymDef.SymbolFont.Height * .8f);
}
_ScaleSymDef.SymbolSize = n * _SymFontScale;
using (StringFormat sf = new StringFormat())
{
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
r.Y++;
using (Brush br = new SolidBrush(Color.FromArgb(130, Color.Black)))
g.DrawString(_ScaleSymDef.SymbolRealized, _ScaleSymDef.SymbolFont, br, r, sf);
}
g.SmoothingMode = sm;
}
}
}
#endregion
#endregion
#region GetXyImageBounds
private Rectangle GetXyImageBounds(PieChartVisualStyle pieStyle)
{
Rectangle scBbounds = GetScrollBounds(ScrollBounds);
scBbounds = GetAdjustedBounds(scBbounds, pieStyle.BorderThickness);
if (pieStyle.EnableImageScroll != Tbool.False)
{
scBbounds = GetScrollBounds(ScrollBoundsEx);
scBbounds = GetDisplayBounds(scBbounds);
}
if (HScrollBar.Visible == true)
scBbounds.Height -= HScrollBar.Height;
if (VScrollBar.Visible == true)
scBbounds.Width -= VScrollBar.Width;
return (scBbounds);
}
#endregion
#region GetFigureBounds
private Rectangle GetFigureBounds(Rectangle bounds, ContainerVisualStyle cStyle)
{
bounds = GetAdjustedBounds(bounds, cStyle.BorderThickness);
Rectangle scBounds = GetScrollBounds(bounds);
return (scBounds);
}
#endregion
#region RenderChartContent
protected virtual void RenderChartContent(
ChartRenderInfo renderInfo, PieChartVisualStyle pieStyle)
{
Graphics g = renderInfo.Graphics;
if (ChartSeries.Count > 0)
{
if (SeriesDisplayOrder == SeriesDisplayOrder.Reverse)
{
for (int i = ChartSeries.Count - 1; i >= 0; i--)
RenderSeries(renderInfo, ChartSeries[i]);
}
else
{
for (int i = 0; i < ChartSeries.Count; i++)
RenderSeries(renderInfo, ChartSeries[i]);
}
}
else
{
Rectangle scContentBounds = GetScrollBounds(ContentBounds);
Rectangle scDisplayBounds = GetDisplayBounds(scContentBounds);
RenderEmptyText(g, pieStyle, scDisplayBounds);
}
}
#region RenderSeries
private void RenderSeries(ChartRenderInfo renderInfo, PieSeries series)
{
if (Visible == true)
{
if (Legend.ItemCheckAction != ItemCheckAction.ShowItem || series.IsDisplayed == true)
series.Render(renderInfo);
}
}
#endregion
#endregion
#endregion
#region Markup support
private void MarkupCenterLabelChanged()
{
if (_CenterLabelMarkup != null)
_CenterLabelMarkup.HyperLinkClick -= CenterLabelMarkupLinkClick;
_CenterLabelMarkup = null;
if (EnableCenterLabelMarkup == true)
{
if (MarkupParser.IsMarkup(_CenterLabel) == true)
{
_CenterLabelMarkup = MarkupParser.Parse(_CenterLabel);
if (_CenterLabelMarkup != null)
_CenterLabelMarkup.HyperLinkClick += CenterLabelMarkupLinkClick;
}
}
else
{
if (_CenterLabelMarkup != null)
_CenterLabelMarkup.HyperLinkClick -= CenterLabelMarkupLinkClick;
}
}
protected virtual void CenterLabelMarkupLinkClick(object sender, EventArgs e)
{
HyperLink link = sender as HyperLink;
ChartControl.DoPieCenterMarkupLinkClickEvent(this, link);
InvalidatePieCenter();
}
/// <summary>
/// Gets plain CenterLabel text without text-markup (if text-markup is used in Text)
/// </summary>
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
public string PlainCenterlabelText
{
get { return (_CenterLabelMarkup != null ? _CenterLabelMarkup.PlainText : _CenterLabel); }
}
#endregion
#region Mouse Support
#region OnMouseDown
protected override bool OnMouseDown(MouseEventArgs e)
{
MouseDownHitArea = HitArea;
PieSeriesPoint psp = _HitPsp;
if (psp != null)
{
PieSeries series = psp.PieRing.ChartSeries;
if (series != null)
{
Capture = true;
return (series.ProcessMouseDown(e, this, psp));
}
}
else if (HitArea != ItemHitArea.InPieRingOut)
{
uint selCount = GlobalSelectionCount;
if (WhitespaceClickBehavior == WhitespaceClickBehavior.ClearSelection)
{
SetSelected(false);
if (GlobalSelectionCount != selCount)
ChartControl.DoPieSelectionChangedEvent(this, null, null, PieSelectionMode.None);
}
}
return (base.OnMouseDown(e));
}
#endregion
#region OnMouseUp
protected override bool OnMouseUp(MouseEventArgs e)
{
switch (MouseDownHitArea)
{
case ItemHitArea.InMarkup:
if (MouseDownHitArea == ItemHitArea.InMarkup)
{
if (e.Button == MouseButtons.Left)
DoMarkupClick(_CenterLabelMarkup);
}
break;
case ItemHitArea.InPieSeriesPoint:
if (_HitPsp != null)
_HitPsp.ChartSeries.ProcessMouseUp(e, this);
break;
case ItemHitArea.InPieRingOut:
ProcessRingOutClick();
break;
}
Capture = false;
return (base.OnMouseUp(e));
}
#region DoMarkupClick
private bool DoMarkupClick(BodyElement bodyElement)
{
if (bodyElement != null)
{
if (bodyElement.MouseOverElement != null)
{
bodyElement.Click(ChartControl);
ChartControl.Cursor = Cursors.Default;
return (true);
}
}
return (false);
}
#endregion
#region ProcessRingOutClick
private void ProcessRingOutClick()
{
List<PieSeriesPointCollection> spcs = GetSelectedSpcs();
if (spcs != null)
{
ChartControl chartControl = ChartControl;
foreach (PieSeriesPointCollection spc1 in spcs)
{
PieSeriesPoint psp = spc1.Parent as PieSeriesPoint;
if (psp != null)
{
PieSeriesPointCollection spc2 = psp.Parent as PieSeriesPointCollection;
if (chartControl.DoPieRingLevelChangingEvent(this, spc1, spc2) == false)
{
psp.ChartSeries.SetActiveSeriesPointCollection(spc2);
chartControl.DoPieRingLevelChangedEvent(this, spc1, spc2);
}
}
}
}
}
#region GetSelectedSpss
private List<PieSeriesPointCollection> GetSelectedSpcs()
{
List<PieSeriesPointCollection> list = new List<PieSeriesPointCollection>();
PieSeriesPointCollection dspc = null;
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
{
if (series.ShowAllRingsEx(this) == false)
{
PieSeriesPointCollection spc = series.GetActiveSeriesPointCollection();
if (SpcHasSelection(spc) == true)
list.Add(spc);
dspc = spc;
}
}
}
if (list.Count == 0 && dspc != null)
list.Add(dspc);
return (list);
}
#region SpcHasSelection
private bool SpcHasSelection(PieSeriesPointCollection spc)
{
if (spc.PieRing != null && spc.PieRing.Psps != null)
{
foreach (PieSeriesPoint psp in spc.PieRing.Psps)
{
if (psp.IsSelected == true)
return (true);
}
}
return (false);
}
#endregion
#endregion
#endregion
#endregion
#region OnMouseMove
protected override bool OnMouseMove(MouseEventArgs e)
{
if (Capture == false)
{
HitArea = GetHitItem(e.Location, out _HitPsp);
ChartControl.ChartCursor = Cursors.Default;
if (HitArea == ItemHitArea.InPieCenter)
{
if (_CenterLabelMarkup != null)
{
_CenterLabelMarkup.MouseMove(ChartControl, e);
if (_CenterLabelMarkup.MouseOverElement != null)
{
ChartControl.ChartCursor = Cursors.Hand;
HitArea = ItemHitArea.InMarkup;
}
}
}
if (_HitPsp != _LastHitPsp)
{
if (_LastHitPsp != null)
_LastHitPsp.ChartSeries.ProcessMouseLeave(EventArgs.Empty, this);
if (_HitPsp != null)
_HitPsp.ChartSeries.ProcessMouseEnter(EventArgs.Empty, this);
InvalidatePsp(_LastHitPsp);
InvalidatePsp(_HitPsp);
_LastHitPsp = _HitPsp;
}
if (HitArea != _LastHitArea)
{
if (HitArea == ItemHitArea.InPieCenter || _LastHitArea == ItemHitArea.InPieCenter)
InvalidatePieCenter();
else if (HitArea == ItemHitArea.InPieRingOut || _LastHitArea == ItemHitArea.InPieRingOut)
InvalidateRingOut();
}
_LastHitArea = HitArea;
}
if (_HitPsp != null)
_HitPsp.ChartSeries.ProcessMouseMove(e, this);
if (HitArea == ItemHitArea.None || HitArea == ItemHitArea.InContent)
return (base.OnMouseMove(e));
return (true);
}
#region GetHitArea
/// <summary>
/// Gets the hit area in the chart from the given point.
/// </summary>
/// <param name="pt"></param>
/// <returns>ItemHitArea</returns>
public override ItemHitArea GetHitArea(Point pt)
{
PieSeriesPoint psp;
return (GetHitItem(pt, out psp));
}
#endregion
#region GetHitItem
/// <summary>
/// Gets the hit item in the chart from the given point.
/// </summary>
/// <param name="pt"></param>
/// <param name="psp"></param>
/// <returns></returns>
public ItemHitArea GetHitItem(Point pt, out PieSeriesPoint psp)
{
Rectangle contentBounds = GetScrollBounds(ContentBounds);
if (contentBounds.Contains(pt))
{
psp = GetPspFromPoint(pt);
if (psp != null)
return (ItemHitArea.InPieSeriesPoint);
Point centerPoint = GetLocalAdjustedPoint(CenterPoint);
Point rpt = pt;
int radius = MathHelper.GetPointRadius(ref rpt, centerPoint);
if (radius <= RingOutRadius)
{
if (PresentRingOut() == true)
return (ItemHitArea.InPieRingOut);
}
if (radius <= InnerRadiusEx - InnerMarginEx)
return (ItemHitArea.InPieCenter);
return (ItemHitArea.InContent);
}
psp = null;
Rectangle frameBounds = GetScrollBounds(FrameBounds);
if (frameBounds.Contains(pt))
return (ItemHitArea.InFrame);
return (ItemHitArea.None);
}
#endregion
#region GetPspFromPoint
/// <summary>
/// Gets the psp at the given Point. Note that the order of
/// displayed/overlapping series is taken into account.
/// </summary>
/// <param name="pt"></param>
/// <returns>PieSeriesPoint or null.</returns>
public PieSeriesPoint GetPspFromPoint(Point pt)
{
if (_RenderBounds.Contains(GetGlobalAdjustedPoint(pt)) == true)
{
Point centerPoint = GetLocalAdjustedPoint(CenterPoint);
int radius, angle;
Point cpt = MathHelper.GetOffsetPoint(pt, centerPoint, out radius, out angle);
if (SeriesDisplayOrder == SeriesDisplayOrder.Forward)
{
for (int i = ChartSeries.Count - 1; i >= 0; i--)
{
PieSeriesPoint psp =
GetPspFromPoint(ChartSeries[i], pt, cpt, radius, angle);
if (psp != null)
return (psp);
}
}
else
{
for (int i = 0; i < ChartSeries.Count; i++)
{
PieSeriesPoint psp =
GetPspFromPoint(ChartSeries[i], pt, cpt, radius, angle);
if (psp != null)
return (psp);
}
}
}
return (null);
}
#region GetPspFromPoint (series)
private PieSeriesPoint GetPspFromPoint(
PieSeries series, Point pt, Point cpt, int radius, int angle)
{
if (series.IsDisplayed == true)
{
if (series.ShowAllRingsEx(this) == false)
{
PieSeriesPointCollection spc = series.GetActiveSeriesPointCollection();
if (spc != null)
{
if (spc.PieSlices != null)
spc = spc.PieSlices;
if (spc != null)
{
foreach (PieSeriesPoint psp in spc)
{
if (GetPspFromPointEx(series, psp, pt, radius, angle) == true)
return (psp);
}
}
}
}
else
{
foreach (PieRing pieRing in series.PieRings)
{
PieSeriesPoint psp = GetPspFromPoint(series, pieRing, pt, cpt, radius, angle);
if (psp != null)
return (psp);
}
}
}
return (null);
}
#region GetPspFromPoint (pieRing)
private PieSeriesPoint GetPspFromPoint(PieSeries series,
PieRing pieRing, Point pt, Point cpt, int cradius, int cangle)
{
if (series.IsOffset == false)
{
int innerRadius = pieRing.InnerRadius;
if (cradius < pieRing.InnerRadius || cradius > pieRing.OuterRadius)
return (null);
}
foreach (PieSeriesPoint psp in pieRing.Psps)
{
if (psp.IsInOtherEx == false)
{
if (GetPspFromPointEx(series, psp, pt, cradius, cangle) == true)
return (psp);
}
}
return (null);
}
#endregion
#region GetPspFromPointEx
private bool GetPspFromPointEx(PieSeries series,
PieSeriesPoint psp, Point pt, int cradius, int cangle)
{
if (psp.IsDisplayed == true)
{
int width = psp.OuterRadius - psp.InnerRadius;
if (width > 0)
{
PieSeriesPointCollection spc = psp.Parent as PieSeriesPointCollection;
if (spc != null)
{
int outerRadius = (psp.ShowSliceWhiteSpaceEx == true)
? psp.OuterRadius : (int)(psp.InnerRadius + psp.SliceExtent * width);
int innerRadius = psp.InnerRadius;
if (outerRadius - innerRadius > 0)
{
if (psp.IsOffset == false)
{
if (cradius >= innerRadius && cradius <= outerRadius)
{
int startAngle, endAngle;
NormalizePspAngles(psp, out startAngle, out endAngle);
if (IsAngleBetween(cangle, startAngle, endAngle) == true)
return (true);
}
}
else
{
Point scpt = GetLocalAdjustedPoint(psp.SliceCenter);
Point ppt = pt;
int pradius = MathHelper.GetPointRadius(ref ppt, scpt);
if (pradius >= innerRadius && pradius <= outerRadius)
{
int startAngle, endAngle;
NormalizePspAngles(psp, out startAngle, out endAngle);
int angle = MathHelper.GetPointAngle(ppt);
if (IsAngleBetween(angle, startAngle, endAngle) == true)
return (true);
}
}
}
}
}
}
return (false);
}
#region NormalizePspAngles
private void NormalizePspAngles(PieSeriesPoint psp, out int startAngle, out int endAngle)
{
startAngle = (int)psp.StartAngleEx;
endAngle = (int)(psp.StartAngleEx + psp.SweepAngleEx);
if (startAngle > endAngle)
{
int temp = startAngle;
startAngle = endAngle;
endAngle = temp;
}
}
#endregion
#region IsAngleBetween
private bool IsAngleBetween(int angle, int start, int end)
{
if (end - start >= 360)
return (true);
start = (3600000 + start) % 360;
end = (3600000 + end) % 360;
if (start <= end)
return (start <= angle && angle <= end);
return (start <= angle || angle <= end);
}
#endregion
#endregion
#endregion
#endregion
#region InvalidatePsp
private void InvalidatePsp(PieSeriesPoint psp)
{
if (psp != null)
{
PieSeries series = psp.ChartSeries;
PieSelectionMode psm = series.GetPieSelectionMode(this);
switch (psm)
{
case PieSelectionMode.Pie:
if (_LastHitPsp == null || _HitPsp == null)
InvalidateRender();
break;
case PieSelectionMode.Ring:
psp.PieRing.InvalidateRender(this);
break;
case PieSelectionMode.Series:
foreach (PieRing pieRing in series.PieRings)
pieRing.InvalidateRender(this);
break;
case PieSelectionMode.Slice:
PieSeriesPoint pspHit = psp;
if (series.ShowAllRingsEx(this) == true)
{
psp = psp.RootPsp;
InvalidateSlice(psp.SeriesPoints);
}
InvalidateRender(psp.PathBounds);
InvalidatePieLabel(psp);
InvalidateLegendItem(pspHit);
break;
case PieSelectionMode.Point:
InvalidateRender(psp.PathBounds);
InvalidatePieLabel(psp);
InvalidateLegendItem(psp);
break;
}
}
}
#region InvalidateSlice
private void InvalidateSlice(PieSeriesPointCollection spc)
{
if (spc != null)
{
foreach (PieSeriesPoint psp in spc)
{
InvalidateRender(psp.PathBounds);
InvalidatePieLabel(psp);
InvalidateLegendItem(psp);
InvalidateSlice(psp.SeriesPoints);
}
}
}
#endregion
#region InvalidateLegendItem
private void InvalidateLegendItem(PieSeriesPoint psp)
{
if (Legend.TrackingMode == LegendTrackingMode.ChartAndLegend ||
Legend.TrackingMode == LegendTrackingMode.Chart)
{
if (psp.LegendItem != null)
{
psp.LegendItem.LikeItem.IsHitItem = (psp == HitPsp);
psp.LegendItem.LikeItem.InvalidateRender();
}
}
}
#endregion
#region InvalidatePieLabel
private void InvalidatePieLabel(PieSeriesPoint psp)
{
if (psp.PieLabel != null)
{
if (psp.PieLabel.Bounds.IsEmpty == false)
{
InvalidateRender(psp.PieLabel.Bounds);
if (psp.PieLabel.ConnectorBounds.IsEmpty == false)
InvalidateRender(psp.PieLabel.ConnectorBounds);
}
}
}
#endregion
#endregion
#region InvalidatePieCenter
/// <summary>
/// Invalidates the Pie Center area (causing a repaint).
/// </summary>
public void InvalidatePieCenter()
{
int n = (int)InnerRadiusEx;
if (n > 0)
{
Rectangle r = new Rectangle();
r.Location = GetLocalAdjustedPoint(CenterPoint);
r.Inflate(n, n);
using (GraphicsPath path = new GraphicsPath())
{
path.AddEllipse(r);
using (Region rgn = new Region(path))
ChartControl.Invalidate(rgn);
}
}
}
#endregion
#region InvalidateRingOut
/// <summary>
/// Invalidates the 'Ring Out' area (causing a repaint).
/// </summary>
public void InvalidateRingOut()
{
int n = RingOutRadius;
if (n > MinRingOutRadius)
{
Rectangle r = new Rectangle();
r.Location = GetLocalAdjustedPoint(CenterPoint);
r.Inflate(n, n);
using (GraphicsPath path = new GraphicsPath())
{
path.AddEllipse(r);
using (Region rgn = new Region(path))
ChartControl.Invalidate(rgn);
}
}
}
#endregion
#endregion
#region OnMouseEnter
protected override bool OnMouseEnter(EventArgs e)
{
if (ShowSliceLabelsOnEntry == true)
InvalidateRender();
return (base.OnMouseEnter(e));
}
#endregion
#region OnMouseLeave
protected override bool OnMouseLeave(EventArgs e)
{
_HitPsp = null;
if (_LastHitArea == ItemHitArea.InPieSeriesPoint)
{
if (_LastHitPsp != null)
{
InvalidateRender(_LastHitPsp.PathBounds);
InvalidateLegendItem(_LastHitPsp);
if (_LastHitPsp != null)
_LastHitPsp.ChartSeries.ProcessMouseLeave(e, this);
_LastHitPsp = null;
IsDragging = false;
}
}
else if (_LastHitArea == ItemHitArea.InPieRingOut)
{
InvalidatePieCenter();
}
HitArea = ItemHitArea.None;
_LastHitArea = ItemHitArea.None;
if (ShowSliceLabelsOnEntry == true)
InvalidateRender();
return (base.OnMouseLeave(e));
}
#endregion
#region OnMouseDoubleClick
protected override bool OnMouseDoubleClick(MouseEventArgs e)
{
ChartControl chartControl = ChartControl;
PieSeriesPoint psp = _HitPsp;
ItemHitArea hitArea = HitArea;
ChartVisualElement hitElement = this;
object hitItem = psp;
if (hitArea == ItemHitArea.InPieSeriesPoint && psp != null)
hitElement = psp.ChartSeries;
if (chartControl.DoChartMouseDoubleClickEvent(this, hitArea, hitElement, hitItem, e) == false)
{
if (hitArea == ItemHitArea.InPieSeriesPoint && psp != null)
return (psp.ChartSeries.ProcessMouseDoubleClick(e, this, psp));
}
return (base.OnMouseDoubleClick(e));
}
#endregion
#endregion
#region PresentRingOut
private bool PresentRingOut()
{
if (PieRingOutDisplayMode == PieRingOutDisplayMode.Never)
return (false);
int inCount = 0;
int ringCount = 0;
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
{
if (series.ShowAllRingsEx(this) == false)
{
PieSeriesPointCollection spc = series.GetActiveSeriesPointCollection();
if (spc != null)
{
if (spc.Parent is PieSeries == false)
{
if (SpcHasSelection(spc) == true)
return (true);
inCount++;
}
ringCount++;
}
}
}
}
return (inCount == 1 && ringCount == 1);
}
#endregion
#region CancelCapture
/// <summary>
/// Cancels any inprogress operations that may have the mouse captured.
/// </summary>
public override void CancelCapture()
{
IsDragging = false;
PspDragType = PspDragType.None;
base.CancelCapture();
}
#endregion
#region SetSelected
/// <summary>
/// Set (or clears) all selected elements in the chart.
/// </summary>
/// <param name="select"></param>
public void SetSelected(bool select)
{
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
series.SetSelected(select);
}
}
/// <summary>
/// Set (or clears) all selected elements in the given series.
/// </summary>
/// <param name="series"></param>
/// <param name="select"></param>
public void SetSelected(PieSeries series, bool select)
{
if (series != null)
series.SetSelected(select);
}
/// <summary>
/// Set (or clears) the given series point.
/// </summary>
/// <param name="psp"></param>
/// <param name="select"></param>
public void SetSelected(PieSeriesPoint psp, bool select)
{
if (psp != null)
psp.IsSelected = select;
}
#endregion
#region GetVisibleSelectionCount
/// <summary>
/// Gets a count of the visible, selected pie series points.
/// </summary>
/// <returns></returns>
public int GetVisibleSelectionCount()
{
int count = 0;
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
count += series.GetVisibleSelectionCount();
}
return (count);
}
#endregion
#region GetVisibleSelectedPoints
/// <summary>
/// Gets a list of the currently Visible selected points.
/// </summary>
/// <returns></returns>
public List<PieSeriesPoint> GetVisibleSelectedPoints()
{
List<PieSeriesPoint> list = new List<PieSeriesPoint>();
foreach (PieSeries series in ChartSeries)
{
List<PieSeriesPoint> slist = series.GetVisibleSelectedPoints();
if (slist != null && slist.Count > 0)
list.AddRange(slist);
}
return (list);
}
#endregion
#region GetSelectionCount
/// <summary>
/// Gets a count of the selected pie series points.
/// </summary>
/// <returns></returns>
public int GetSelectionCount()
{
int count = 0;
foreach (PieSeries series in ChartSeries)
{
if (series.IsDisplayed == true)
count += series.GetSelectionCount();
}
return (count);
}
#endregion
#region GetSelectedPoints
/// <summary>
/// Gets a list of the currently selected points.
/// </summary>
/// <returns></returns>
public List<PieSeriesPoint> GetSelectedPoints()
{
List<PieSeriesPoint> list = new List<PieSeriesPoint>();
foreach (PieSeries series in ChartSeries)
{
List<PieSeriesPoint> slist = series.GetSelectedPoints();
if (slist != null && slist.Count > 0)
list.AddRange(slist);
}
return (list);
}
#endregion
#region GetLocalAdjustedPoint
/// <summary>
/// Gets the local, scroll adjusted point.
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
public Point GetLocalAdjustedPoint(Point pt)
{
pt.X -= ScrollOffset.X;
pt.X += (HScrollBar.Inverted == true ? HScrollOffset : -HScrollOffset);
pt.Y -= ScrollOffset.Y;
pt.Y += (VScrollBar.Inverted == true ? VScrollOffset : -VScrollOffset);
return (pt);
}
#endregion
#region GetGlobalAdjustedPoint
internal Point GetGlobalAdjustedPoint(Point pt)
{
pt.X -= (HScrollBar.Inverted == true ? HScrollOffset : -HScrollOffset);
pt.Y -= (VScrollBar.Inverted == true ? VScrollOffset : -VScrollOffset);
return (pt);
}
#endregion
#region GetRayEndPoint
/// <summary>
/// Gets the end Point for a ray, of the given angle (in degrees),
/// starting at the pie center and ending at the outer radius.
/// </summary>
/// <param name="angle"></param>
/// <returns></returns>
public Point GetRayEndPoint(double angle)
{
return (GetRayEndPoint(angle, OuterRadiusEx));
}
/// <summary>
/// Gets the end Point for a ray, of the given angle (in degrees),
/// starting at the pie center and ending at the specified radius.
/// </summary>
/// <param name="angle"></param>
/// <param name="radius"></param>
/// <returns></returns>
public Point GetRayEndPoint(double angle, double radius)
{
Point pt = CenterPoint;
double radians = MathHelper.ToRadians(angle);
pt.X += (int)(Math.Cos(radians) * radius);
pt.Y += (int)(Math.Sin(radians) * radius);
return (pt);
}
#endregion
#region OnSeriesCheckStateChanged
internal override void OnSeriesCheckStateChanged(string property)
{
SeriesRangeChanged = true;
InvalidateLayout();
base.OnSeriesCheckStateChanged(property);
}
#endregion
#region GetBaseSeries
internal override ChartBaseSeriesCollection GetBaseSeries()
{
ChartBaseSeriesCollection baseSeries = new ChartBaseSeriesCollection();
foreach (BaseSeries series in ChartSeries)
baseSeries.Add(series);
return (baseSeries);
}
#endregion
#region GetSeriesByName
/// <summary>
/// Gets the chart series with the given Name.
/// </summary>
/// <param name="name"></param>
/// <returns>PieSeries or null.</returns>
public PieSeries GetSeriesByName(string name)
{
if (String.IsNullOrEmpty(name) == true)
return (null);
foreach (PieSeries series in ChartSeries)
{
if (name.Equals(series.Name) == true)
return (series);
}
return (null);
}
#endregion
#region GetAutoGenSeriesType
internal override SeriesType GetAutoGenSeriesType()
{
return (SeriesType.Pie);
}
#endregion
#region GetAutoGenSeriesNameCount
internal override int GetAutoGenSeriesNameCount()
{
return (1);
}
#endregion
#region GetNewSeries
internal override BaseSeries GetNewSeries()
{
return (new PieSeries());
}
#endregion
#region AddChartSeries
internal override void AddChartSeries(BaseSeries series)
{
ChartSeries.Add((PieSeries)series);
}
#endregion
#region Style handling
#region GetEffectivePieCenterStyle
internal PieCenterVisualStyle GetEffectivePieCenterStyle()
{
StyleState state = GetPieCenterStyleState();
return (EffectivePieCenterStyle[state]);
}
#region GetPieCenterStyleState
private StyleState GetPieCenterStyleState()
{
StyleState state = StyleState.Default;
if (HitArea == ItemHitArea.InPieCenter || HitArea == ItemHitArea.InPieRingOut)
state |= StyleState.MouseOver;
return (state);
}
#endregion
#endregion
#region ApplyStyles
public override void ApplyStyles(BaseVisualStyle style)
{
base.ApplyStyles(style);
PieChartVisualStyle pstyle = style as PieChartVisualStyle;
if (pstyle != null)
{
ApplyParentStyles(pstyle, Parent as ChartContainer);
pstyle.ApplyStyle(_ChartVisualStyle);
}
}
#region ApplyParentStyles
private void ApplyParentStyles(PieChartVisualStyle pstyle, ChartContainer item)
{
if (item != null)
{
ApplyParentStyles(pstyle, item.Parent as ChartContainer);
ChartPanel panel = item as ChartPanel;
if (panel != null)
pstyle.ApplyStyle(panel.DefaultVisualStyles.PieChartVisualStyle);
}
else
{
ChartControl chartControl = ChartControl;
pstyle.ApplyStyle(chartControl.BaseVisualStyles.PieChartVisualStyle);
pstyle.ApplyStyle(chartControl.DefaultVisualStyles.PieChartVisualStyle);
}
}
#endregion
#endregion
#region ApplyStyles (StyleType)
public override void ApplyStyles(BaseVisualStyle style, StyleType cs)
{
base.ApplyStyles(style, cs);
PieCenterVisualStyle cstyle = style as PieCenterVisualStyle;
if (cstyle != null)
{
ApplyParentStyles(cstyle, Parent as ChartContainer, cs);
if (ChartVisualStyle.PieCenterVisualStyles != null)
cstyle.ApplyStyle(ChartVisualStyle.PieCenterVisualStyles[cs]);
}
}
#region ApplyParentStyles (PieCenterVisualStyle)
private void ApplyParentStyles(
PieCenterVisualStyle cstyle, ChartContainer item, StyleType cs)
{
if (item != null)
{
ApplyParentStyles(cstyle, item.Parent as ChartContainer, cs);
ChartPanel panel = item as ChartPanel;
if (panel != null)
{
if (panel.DefaultVisualStyles.PieChartVisualStyle.PieCenterVisualStyles != null)
cstyle.ApplyStyle(panel.DefaultVisualStyles.PieChartVisualStyle.PieCenterVisualStyles[cs]);
}
}
else
{
ChartControl chartControl = ChartControl;
if (chartControl.BaseVisualStyles.PieChartVisualStyle.PieCenterVisualStyles != null)
cstyle.ApplyStyle(ChartControl.BaseVisualStyles.PieChartVisualStyle.PieCenterVisualStyles[cs]);
if (chartControl.DefaultVisualStyles.PieChartVisualStyle.PieCenterVisualStyles != null)
cstyle.ApplyStyle(ChartControl.DefaultVisualStyles.PieChartVisualStyle.PieCenterVisualStyles[cs]);
}
}
#endregion
#endregion
#region ApplyDefaults
public override void ApplyDefaults(BaseVisualStyle style, StyleType cs)
{
PieCenterVisualStyle ctyle = style as PieCenterVisualStyle;
if (ctyle != null)
{
ctyle.ApplyDefaults();
}
else if (style is PieChartVisualStyle)
{
PieChartVisualStyle pstyle = (PieChartVisualStyle)style;
pstyle.ApplyDefaults();
}
base.ApplyDefaults(style, cs);
}
#endregion
#region ClearEffectiveStyles
protected override void ClearEffectiveStyles()
{
_EffectiveChartStyle = null;
base.ClearEffectiveStyles();
}
#endregion
#endregion
#region Copy/CopyTo
public override ChartVisualElement Copy()
{
PieChart copy = new PieChart();
CopyTo(copy);
return (copy);
}
public override void CopyTo(ChartVisualElement copy)
{
PieChart c = copy as PieChart;
if (c != null)
{
base.CopyTo(c);
c.CenterFirstSlice = CenterFirstSlice;
c.CenterLabel = CenterLabel;
c.CenterLabelVisibility = CenterLabelVisibility;
c.CenterPos = CenterPos;
foreach (PieSeries series in ChartSeries)
c.ChartSeries.Add((PieSeries)series.Copy());
c.ChartVisualStyle = (_ChartVisualStyle != null) ? ChartVisualStyle.Copy() : null;
c.DetachedOffset = DetachedOffset;
c.EnableDragDetach = EnableDragDetach;
c.EnableShiftDragExplode = EnableShiftDragExplode;
c.ExplodedMargin = ExplodedMargin;
c.ExplodedOffset = ExplodedOffset;
c.GridInnerRadius = GridInnerRadius;
c.GridInterval = GridInterval;
c.GridMaxValue = GridMaxValue;
c.GridMinValue = GridMinValue;
c.GridOuterRadius = GridOuterRadius;
c.InnerMargin = InnerMargin;
c.InnerRadius = InnerRadius;
c.IsExploded = IsExploded;
c.MaxDetachedOffset = MaxDetachedOffset;
c.MaxExplodedOffset = MaxExplodedOffset;
c.MaxRingOutRadius = MaxRingOutRadius;
c.MinOuterRadius = MinOuterRadius;
c.MinRingOutRadius = MinRingOutRadius;
c.MouseClickSliceAction = MouseClickSliceAction;
c.MouseDoubleClickSliceAction = MouseDoubleClickSliceAction;
c.MultiSelect = MultiSelect;
c.OuterMargin = OuterMargin;
c.OuterRadius = OuterRadius;
c.PieRingOutDisplayMode = PieRingOutDisplayMode;
c.PieSelectionMode = PieSelectionMode;
c.ReverseRingOrder = ReverseRingOrder;
c.SeriesMargin = SeriesMargin;
c.SeriesOverlayEnabled = SeriesOverlayEnabled;
c.ShowFullGrid = ShowFullGrid;
c.ShowGridOnTop = ShowGridOnTop;
c.ShowAllRings = ShowAllRings;
c.ShowOtherSlice = ShowOtherSlice;
c.ShowPieGrid = ShowPieGrid;
c.ShowSliceLabelsOnEntry = ShowSliceLabelsOnEntry;
c.SliceLabelOverlapMode = _SliceLabelOverlapMode;
c.SubSliceVisualLayout = (_SubSliceVisualLayout != null) ? SubSliceVisualLayout.Copy() : null;
c.UseAlternateGridBackground = UseAlternateGridBackground;
c.WhitespaceClickBehavior = WhitespaceClickBehavior;
}
}
#endregion
#region GetSerialData
internal override SerialElementCollection GetSerialData(string serialName)
{
SerialElementCollection sec = new SerialElementCollection();
if (serialName != null)
{
if (serialName.Equals("") == true)
serialName = "PieChart";
sec.AddStartElement(serialName);
}
sec.AddValue("CenterFirstSlice", CenterFirstSlice, Tbool.NotSet);
sec.AddValue("CenterLabel", CenterLabel, null);
sec.AddDataValue("CenterLabelVisibility", CenterLabelVisibility, CenterLabelVisibility.Always);
sec.AddValue("CenterPos", CenterPos, PointF.Empty);
if (ChartSeries.Count > 0)
{
sec.AddStartElement("ChartSeries count=\"" + ChartSeries.Count + "\"");
foreach (PieSeries series in ChartSeries)
sec.AddElement(series.GetSerialData("ChartSeries"));
sec.AddEndElement("ChartSeries");
}
if (_ChartVisualStyle != null && _ChartVisualStyle.IsEmpty == false)
sec.AddElement(_ChartVisualStyle.GetSerialData("ChartVisualStyle"));
sec.AddValue("EnableDragDetach", EnableDragDetach, Tbool.NotSet);
sec.AddValue("EnableShiftDragExplode", EnableShiftDragExplode, true);
sec.AddValue("ExplodedMargin", ExplodedMargin, .1d);
sec.AddValue("ExplodedOffset", ExplodedOffset, .05d);
sec.AddValue("GridInnerRadius", GridInnerRadius, 0d);
sec.AddValue("GridInterval", GridInterval, 10d);
sec.AddValue("GridMaxValue", GridMaxValue, 100d);
sec.AddValue("GridMinValue", GridMinValue, 0d);
sec.AddValue("GridOuterRadius", GridOuterRadius, 1d);
sec.AddValue("InnerMargin", InnerMargin, 3d);
sec.AddValue("InnerRadius", InnerRadius, 0d);
sec.AddValue("IsExploded", IsExploded, false);
sec.AddValue("MaxDetachedOffset", MaxDetachedOffset, 100);
sec.AddValue("MaxExplodedOffset", MaxExplodedOffset, 100);
sec.AddValue("MaxRingOutRadius", MaxRingOutRadius, 48);
sec.AddValue("MinOuterRadius", MinOuterRadius, 80);
sec.AddValue("MinRingOutRadius", MinRingOutRadius, 9);
sec.AddValue("MouseClickSliceAction", MouseClickSliceAction, MouseClickSliceAction.NotSet);
sec.AddValue("MouseDoubleClickSliceAction", MouseDoubleClickSliceAction, MouseDoubleClickSliceAction.NotSet);
sec.AddValue("MultiSelect", MultiSelect, true);
sec.AddValue("OuterMargin", OuterMargin, 0d);
sec.AddValue("PieRingOutDisplayMode", PieRingOutDisplayMode, PieRingOutDisplayMode.OnMouseOver);
sec.AddValue("PieSelectionMode", PieSelectionMode, PieSelectionMode.NotSet);
sec.AddValue("ReverseRingOrder", ReverseRingOrder, false);
sec.AddValue("SeriesMargin", SeriesMargin, 0d);
sec.AddValue("SeriesOverlayEnabled", SeriesOverlayEnabled, false);
sec.AddValue("ShowFullGrid", ShowFullGrid, false);
sec.AddValue("ShowGridOnTop", ShowGridOnTop, false);
sec.AddValue("ShowAllRings", ShowAllRings, Tbool.NotSet);
sec.AddValue("ShowOtherSlice", ShowOtherSlice, Tbool.NotSet);
sec.AddValue("ShowPieGrid", ShowPieGrid, false);
sec.AddValue("ShowSliceLabelsOnEntry", ShowSliceLabelsOnEntry, false);
sec.AddValue("ShowToolTips", ShowToolTips, false);
sec.AddValue("SliceLabelOverlapMode", SliceLabelOverlapMode, SliceLabelOverlapMode.NotSet);
if (_SubSliceVisualLayout != null)
sec.AddElement(_SubSliceVisualLayout.GetSerialData(true));
sec.AddValue("UseAlternateBackground", UseAlternateGridBackground, false);
sec.AddValue("WhitespaceClickBehavior", WhitespaceClickBehavior, WhitespaceClickBehavior.ClearSelection);
sec.AddElement(base.GetSerialData(null));
if (serialName != null)
sec.AddEndElement(serialName);
return (sec);
}
#endregion
#region PutSerialData
#region ProcessValue
internal override void ProcessValue(SerialElement se)
{
switch (se.Name)
{
case "CenterFirstSlice":
CenterFirstSlice = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "CenterLabel":
CenterLabel = se.StringValue;
break;
case "CenterLabelVisibility":
CenterLabelVisibility = (CenterLabelVisibility)se.GetValueEnum(typeof(CenterLabelVisibility));
break;
case "CenterPos":
CenterPos = se.GetValuePointF();
break;
case "EnableDragDetach":
EnableDragDetach = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "EnableShiftDragExplode":
EnableShiftDragExplode = bool.Parse(se.StringValue);
break;
case "ExplodedMargin":
ExplodedMargin = double.Parse(se.StringValue);
break;
case "ExplodedOffset":
ExplodedOffset = double.Parse(se.StringValue);
break;
case "GridInnerRadius":
GridInnerRadius = double.Parse(se.StringValue);
break;
case "GridInterval":
GridInterval = double.Parse(se.StringValue);
break;
case "GridMaxValue":
GridMaxValue = double.Parse(se.StringValue);
break;
case "GridMinValue":
GridMinValue = double.Parse(se.StringValue);
break;
case "GridOuterRadius":
GridOuterRadius = double.Parse(se.StringValue);
break;
case "InnerMargin":
InnerMargin = double.Parse(se.StringValue);
break;
case "InnerRadius":
InnerRadius = double.Parse(se.StringValue);
break;
case "IsExploded":
IsExploded = bool.Parse(se.StringValue);
break;
case "MaxDetachedOffset":
MaxDetachedOffset = int.Parse(se.StringValue);
break;
case "MaxExplodedOffset":
MaxExplodedOffset = int.Parse(se.StringValue);
break;
case "MaxRingOutRadius":
MaxRingOutRadius = int.Parse(se.StringValue);
break;
case "MinOuterRadius":
MinOuterRadius = int.Parse(se.StringValue);
break;
case "MinRingOutRadius":
MinRingOutRadius = int.Parse(se.StringValue);
break;
case "MouseClickSliceAction":
MouseClickSliceAction = (MouseClickSliceAction)se.GetValueEnum(typeof(MouseClickSliceAction));
break;
case "MouseDoubleClickSliceAction":
MouseDoubleClickSliceAction = (MouseDoubleClickSliceAction)se.GetValueEnum(typeof(MouseDoubleClickSliceAction));
break;
case "MultiSelect":
MultiSelect = bool.Parse(se.StringValue);
break;
case "OuterMargin":
OuterMargin = double.Parse(se.StringValue);
break;
case "PieRingOutDisplayMode":
PieRingOutDisplayMode = (PieRingOutDisplayMode)se.GetValueEnum(typeof(PieRingOutDisplayMode));
break;
case "PieSelectionMode":
PieSelectionMode = (PieSelectionMode)se.GetValueEnum(typeof(PieSelectionMode));
break;
case "ReverseRingOrder":
ReverseRingOrder = bool.Parse(se.StringValue);
break;
case "SeriesMargin":
SeriesMargin = double.Parse(se.StringValue);
break;
case "SeriesOverlayEnabled":
SeriesOverlayEnabled = bool.Parse(se.StringValue);
break;
case "ShowFullGrid":
ShowFullGrid = bool.Parse(se.StringValue);
break;
case "ShowGridOnTop":
ShowGridOnTop = bool.Parse(se.StringValue);
break;
case "ShowAllRings":
ShowAllRings = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "ShowOtherSlice":
ShowOtherSlice = (Tbool)se.GetValueEnum(typeof(Tbool));
break;
case "ShowPieGrid":
ShowPieGrid = bool.Parse(se.StringValue);
break;
case "ShowSliceLabelsOnEntry":
ShowSliceLabelsOnEntry = bool.Parse(se.StringValue);
break;
case "ShowToolTips":
ShowToolTips = bool.Parse(se.StringValue);
break;
case "SliceLabelOverlapMode":
SliceLabelOverlapMode = (SliceLabelOverlapMode)se.GetValueEnum(typeof(SliceLabelOverlapMode));
break;
case "UseAlternateBackground":
UseAlternateGridBackground = bool.Parse(se.StringValue);
break;
case "WhitespaceClickBehavior":
WhitespaceClickBehavior = (WhitespaceClickBehavior)se.GetValueEnum(typeof(WhitespaceClickBehavior));
break;
default:
base.ProcessValue(se);
break;
}
}
#endregion
#region ProcessCollection
internal override void ProcessCollection(SerialElement se)
{
SerialElementCollection sec = se.Sec;
switch (se.Name)
{
case "ChartSeries":
if (se.ArrayCount > 0)
{
sec.PutSerialData(this);
}
else
{
string name = sec.GetItemValue("Name");
PieSeries series = new PieSeries(name);
ChartSeries.Add(series);
sec.PutSerialData(series);
}
break;
case "ChartVisualStyle":
sec.PutSerialData(ChartVisualStyle);
break;
case "SliceVisualLayout":
sec.PutSerialData(SubSliceVisualLayout);
break;
default:
base.ProcessCollection(se);
break;
}
}
#endregion
#endregion
#region States
[Flags]
private enum States : uint
{
Exploded = (1U << 0),
ReverseRingOrder = (1U << 1),
MultiSelect = (1U << 2),
Dragging = (1U << 3),
EnableShiftDragExplode = (1U << 4),
EnableCenterLabelMarkup = (1U << 5),
ShowPieGrid = (1U << 6),
ShowGridOnTop = (1U << 7),
ShowFullGrid = (1U << 8),
ShowSliceLabelsOnEntry = (1U << 9),
ShowToolTips = (1U << 10),
UseAlternateGridBackground = (1U << 11),
SeriesOverlayEnabled = (1U << 12),
ShowPieRingsInLegend = (1U << 13),
ShowPieSeriesPointsInLegend = (1U << 14),
UpdatePaletteNeeded = (1U << 15),
}
#region TestState
private bool TestState(States state)
{
return ((_States & state) == state);
}
#endregion
#region SetState
private void SetState(States state, bool value)
{
if (value == true)
_States |= state;
else
_States &= ~state;
}
#endregion
#endregion
}
#region enums
#region LegendTrackingMode
/// <summary>
/// Defines the mode used to track mouse over interaction
/// between PieChart elements and associated Legend elements.
/// </summary>
public enum LegendTrackingMode
{
/// <summary>
/// NotSet
/// </summary>
NotSet,
/// <summary>
/// No tracking.
/// </summary>
None,
/// <summary>
/// Hit Chart elements are tracked in the Legend.
/// </summary>
Chart,
/// <summary>
/// Hit Legend elements are tracked in the Chart.
/// </summary>
Legend,
/// <summary>
/// Both hit Legend elements and Chart elements are tracked.
/// </summary>
ChartAndLegend,
}
#endregion
#region MouseClickSliceAction
/// <summary>
/// Defines the action taken when a user
/// clicks with the mouse in a pie slice..
/// </summary>
public enum MouseClickSliceAction
{
/// <summary>
/// NotSet
/// </summary>
NotSet,
/// <summary>
/// No action taken.
/// </summary>
None,
/// <summary>
/// Element select.
/// </summary>
Select,
/// <summary>
/// Element detach toggle.
/// </summary>
Detach,
/// <summary>
/// Pie Exploded.
/// </summary>
Explode,
}
#endregion
#region MouseDoubleClickSliceAction
/// <summary>
/// Defines the action taken when a user
/// double-clicks with the mouse in a pie slice.
/// </summary>
public enum MouseDoubleClickSliceAction
{
/// <summary>
/// NotSet
/// </summary>
NotSet,
/// <summary>
/// No action taken.
/// </summary>
None,
/// <summary>
/// Change Active Ring (used when ShowAllRings is set to false).
/// </summary>
ChangeActiveRing,
/// <summary>
/// Element detach toggle.
/// </summary>
Detach,
/// <summary>
/// Pie Exploded.
/// </summary>
Explode,
}
#endregion
#region OtherSliceMethod
/// <summary>
/// Defines the method used when determining
/// which slices are to be included in the 'Other' slice.
/// </summary>
public enum OtherSliceMethod
{
/// <summary>
/// Uses the percentage that is set by the OtherMinPercent property.
/// </summary>
MinPercent,
/// <summary>
/// Uses the count that is set by the OtherMaxSlices property.
/// </summary>
MaxSlices,
}
#endregion
#region PieRadiusScale
/// <summary>
/// Defines how the PieRadius values (InnerRadius,
/// OuterRadius, GridInnerRadius, and GridOuterRadius) values are interpreted).
/// </summary>
public enum PieRadiusScale
{
/// <summary>
/// Values are always taken as percentages of the content area.
/// </summary>
Percentage,
/// <summary>
/// Values > 1 are taken as pixel values.
/// </summary>
Pixel,
}
#endregion
#region PieSelectionMode
/// <summary>
/// Defines the selection mode used when the user
/// clicks on a pie element.
/// </summary>
public enum PieSelectionMode
{
/// <summary>
/// NotSet
/// </summary>
NotSet,
/// <summary>
/// No selection.
/// </summary>
None,
/// <summary>
/// Pie selection.
/// </summary>
Pie,
/// <summary>
/// Series selection.
/// </summary>
Series,
/// <summary>
/// Slice selection (includes nested PieSeriesPoints).
/// </summary>
Slice,
/// <summary>
/// Ring level selection.
/// </summary>
Ring,
/// <summary>
/// Individual PieSeriesPoint selection.
/// </summary>
Point,
}
#endregion
#region PspDragType
/// <summary>
/// Defines the drag type.
/// </summary>
internal enum PspDragType
{
None,
Explode,
Detach,
}
#endregion
#region PieRingOutDisplayMode
/// <summary>
/// Defines when the 'RingOut' indicator is displayed.
/// </summary>
public enum PieRingOutDisplayMode
{
/// <summary>
/// Always displayed (when appropriate).
/// </summary>
Always,
/// <summary>
/// Never displayed (user can go up a level by shift dbl-click).
/// </summary>
Never,
/// <summary>
/// Indicator shown when mouse is over ring area in center of Pie. (default)
/// </summary>
OnMouseOver,
}
#endregion
#region SliceLabelOverlapMode
/// <summary>
/// Specifies how overlapping outer slice Labels are resolved
/// </summary>
public enum SliceLabelOverlapMode
{
/// <summary>
/// Not set (default is None).
/// </summary>
NotSet = -1,
/// <summary>
/// Overlapping labels will be shown.
/// </summary>
ShowOverlapping,
/// <summary>
/// Overlapping labels will be hidden.
/// </summary>
HideOverlapping,
}
#endregion
#region SweepDirection
/// <summary>
/// Defines the sweep direction.
/// </summary>
public enum SweepDirection
{
/// <summary>
/// NotSet
/// </summary>
NotSet,
/// <summary>
/// Clockwise.
/// </summary>
Clockwise,
/// <summary>
/// CounterClockwise.
/// </summary>
CounterClockwise,
}
#endregion
#region WhitespaceClickBehavior
///<summary>
/// Specifies the resultant behavior
/// of clicking in the chart whitespace area.
///</summary>
public enum WhitespaceClickBehavior
{
///<summary>
/// No effect
///</summary>
None,
///<summary>
/// Current selection is cleared
///</summary>
ClearSelection,
}
#endregion
#endregion
}