6324 lines
		
	
	
		
			195 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			6324 lines
		
	
	
		
			195 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections;
 | |
| using System.Collections.Generic;
 | |
| using System.ComponentModel;
 | |
| using System.Drawing;
 | |
| using System.Drawing.Design;
 | |
| using System.Drawing.Drawing2D;
 | |
| using System.Drawing.Text;
 | |
| using System.Windows.Forms;
 | |
| using DevComponents.DotNetBar.Charts.Style;
 | |
| 
 | |
| namespace DevComponents.DotNetBar.Charts
 | |
| {
 | |
|     /// <summary>
 | |
|     /// Represents the collection of PieSeries.
 | |
|     /// </summary>
 | |
|     [Editor("DevComponents.Charts.Design.ChartSeriesCollectionEditor, DevComponents.Charts.Design, " +
 | |
|             "Version=14.1.0.37, Culture=neutral,  PublicKeyToken=90f470f34c89ccaf", typeof(UITypeEditor))]
 | |
|     public class ChartPieSeriesCollection : CustomNamedCollection<PieSeries>
 | |
|     {
 | |
|         #region GetUniqueName
 | |
| 
 | |
|         public string GetUniqueName()
 | |
|         {
 | |
|             return (GetUniqueName("Series"));
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
|     }
 | |
| 
 | |
|     [TypeConverter(typeof(PieSeriesConverter))]
 | |
|     public class PieSeries : BaseSeries, ISeriesPointContainer, ILegendItemEx
 | |
|     {
 | |
|         #region Private variables
 | |
| 
 | |
|         private States _States;
 | |
| 
 | |
|         private PieSeriesPointCollection _SeriesPoints;
 | |
| 
 | |
|         private double _ExplodedMargin = double.NaN;
 | |
| 
 | |
|         private Point _PieCenter;
 | |
|         private List<PieRing> _PieRings;
 | |
| 
 | |
|         private int _RingWeightTotal;
 | |
| 
 | |
|         private Tbool _CenterFirstSlice = Tbool.NotSet;
 | |
| 
 | |
|         private Tbool _ShowAllRings = Tbool.NotSet;
 | |
|         private Tbool _ShowOtherSlice = Tbool.NotSet;
 | |
| 
 | |
|         private PieSeriesPointCollection _ActiveSeriesPointSet;
 | |
| 
 | |
|         private MouseClickSliceAction _MouseClickSliceAction = MouseClickSliceAction.NotSet;
 | |
|         private MouseDoubleClickSliceAction _MouseDoubleClickSliceAction = MouseDoubleClickSliceAction.NotSet;
 | |
| 
 | |
|         private PieSelectionMode _PieSelectionMode = PieSelectionMode.NotSet;
 | |
| 
 | |
|         private PieSeriesPoint _MouseDownPsp;
 | |
|         private int _MouseDownRadius;
 | |
|         private int _MouseDownOffset;
 | |
| 
 | |
|         private Tbool _EnableDragDetach = Tbool.NotSet;
 | |
| 
 | |
|         private SymbolDef _ScaleSymDef = new SymbolDef();
 | |
|         private float _SymFontScale = -1;
 | |
| 
 | |
|         private SliceVisualLayout _SliceVisualLayout;
 | |
| 
 | |
|         private int _RingWeight = 100;
 | |
|         private int _RingWeightEx;
 | |
| 
 | |
|         private PaletteGroup _PaletteGroup = PaletteGroup.NotSet;
 | |
|         private Color[] _CustomPalette;
 | |
| 
 | |
|         private double _PieOuterExtent;
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Constructors
 | |
| 
 | |
|         public PieSeries()
 | |
|             : this(null)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         public PieSeries(string name)
 | |
|         {
 | |
|             Name = name;
 | |
|             SeriesType = SeriesType.Pie;
 | |
| 
 | |
|             InitDefaultStates();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region InitDefaultStates
 | |
| 
 | |
|         private void InitDefaultStates()
 | |
|         {
 | |
|             SetState(States.ShowInnerRingsEx, true);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Public properties
 | |
| 
 | |
|         #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 CustomPalette
 | |
| 
 | |
|         ///<summary>
 | |
|         /// Gets or sets the custom palette for the series.
 | |
|         ///</summary>
 | |
|         [DefaultValue(null), Category("Appearance")]
 | |
|         [Description("Indicates the custom palette for the series.")]
 | |
|         public Color[] CustomPalette
 | |
|         {
 | |
|             get { return (_CustomPalette); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 _CustomPalette = value;
 | |
| 
 | |
|                 OnPropertyChangedEx("CustomPalette", VisualChangeType.Layout);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region EnableDragDetach
 | |
| 
 | |
|         ///<summary>
 | |
|         /// Gets or sets whether the user can detach associated series elements by Click and drag.
 | |
|         /// Note that MouseClickSelect must not be set to None or NotSet.
 | |
|         ///</summary>
 | |
|         [DefaultValue(Tbool.NotSet), Category("Behavior")]
 | |
|         [Description("Indicates whether the user can detach associated series elements by Click and drag. Note that MouseClickSelect must not be set to None or NotSet.")]
 | |
|         public Tbool EnableDragDetach
 | |
|         {
 | |
|             get { return (_EnableDragDetach); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _EnableDragDetach)
 | |
|                 {
 | |
|                     _EnableDragDetach = value;
 | |
| 
 | |
|                     OnPropertyChangedEx("EnableDragDetach", VisualChangeType.Layout);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region GetEnableDragDetach
 | |
| 
 | |
|         internal bool GetEnableDragDetach(PieChart pieChart)
 | |
|         {
 | |
|             Tbool enable = EnableDragDetach;
 | |
| 
 | |
|             if (enable == Tbool.NotSet)
 | |
|                 enable = pieChart.EnableDragDetach;
 | |
| 
 | |
|             return (enable == Tbool.True);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ExplodedMargin
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the exploded Margin for the series when the pie
 | |
|         /// is Exploded. The Margin is is measured as a percentage of the pie
 | |
|         /// radius (if less than 1) or the absolute pixel amount (if greater than 1).
 | |
|         /// </summary>
 | |
|         [DefaultValue(double.NaN), Category("Layout")]
 | |
|         [Description("Indicates the exploded Margin for the 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).")]
 | |
|         public double ExplodedMargin
 | |
|         {
 | |
|             get { return (_ExplodedMargin); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _ExplodedMargin)
 | |
|                 {
 | |
|                     _ExplodedMargin = value;
 | |
| 
 | |
|                     OnPropertyChangedEx("ExplodedMargin", VisualChangeType.Layout);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region MouseClickSliceAction
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the action used when the user clicks on a pie slice.
 | |
|         /// </summary>
 | |
|         [DefaultValue(MouseClickSliceAction.NotSet), Category("Behavior")]
 | |
|         [Description("Indicates the action used when the user clicks on a pie slice.")]
 | |
|         public MouseClickSliceAction MouseClickSliceAction
 | |
|         {
 | |
|             get { return (_MouseClickSliceAction); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _MouseClickSliceAction)
 | |
|                 {
 | |
|                     _MouseClickSliceAction = value;
 | |
| 
 | |
|                     OnPropertyChanged("MouseClickSliceAction");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region GetMouseClickSliceAction
 | |
| 
 | |
|         private MouseClickSliceAction GetMouseClickSliceAction(PieChart pieChart)
 | |
|         {
 | |
|             MouseClickSliceAction mca =
 | |
|                 (MouseClickSliceAction != MouseClickSliceAction.NotSet)
 | |
|                 ? MouseClickSliceAction : pieChart.MouseClickSliceAction;
 | |
| 
 | |
|             return ((mca != MouseClickSliceAction.NotSet) ? mca : MouseClickSliceAction.None);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region MouseDoubleClickSliceAction
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the action used when the user double-clicks on a pie slice.
 | |
|         /// </summary>
 | |
|         [DefaultValue(MouseDoubleClickSliceAction.NotSet), Category("Behavior")]
 | |
|         [Description("Indicates the action used when the user clicks on a pie slice.")]
 | |
|         public MouseDoubleClickSliceAction MouseDoubleClickSliceAction
 | |
|         {
 | |
|             get { return (_MouseDoubleClickSliceAction); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _MouseDoubleClickSliceAction)
 | |
|                 {
 | |
|                     _MouseDoubleClickSliceAction = value;
 | |
| 
 | |
|                     OnPropertyChanged("MouseDoubleClickSliceAction");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region GetMouseDoubleClickSliceAction
 | |
| 
 | |
|         private MouseDoubleClickSliceAction GetMouseDoubleClickSliceAction(PieChart pieChart)
 | |
|         {
 | |
|             MouseDoubleClickSliceAction mca =
 | |
|                 (MouseDoubleClickSliceAction != MouseDoubleClickSliceAction.NotSet)
 | |
|                 ? MouseDoubleClickSliceAction : pieChart.MouseDoubleClickSliceAction;
 | |
| 
 | |
|             return ((mca != MouseDoubleClickSliceAction.NotSet) ? mca : MouseDoubleClickSliceAction.None);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PaletteGroup
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the palette color group to use (Light/Medium/Dark/Color1/MonoBlue/etc).
 | |
|         /// </summary>
 | |
|         [DefaultValue(PaletteGroup.NotSet), Category("Appearance")]
 | |
|         [Description("Indicates the palette color group to use (Light/Medium/Dark/Color1/MonoBlue/etc.).")]
 | |
|         public PaletteGroup PaletteGroup
 | |
|         {
 | |
|             get { return (_PaletteGroup); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _PaletteGroup)
 | |
|                 {
 | |
|                     _PaletteGroup = value;
 | |
| 
 | |
|                     OnPropertyChangedEx("PaletteGroup", VisualChangeType.Recalc);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PieSelectionMode
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the mode used to perfoem pie selections.
 | |
|         /// </summary>
 | |
|         [DefaultValue(PieSelectionMode.NotSet), Category("Behavior")]
 | |
|         [Description("Indicates the mode used to perform pie selections.")]
 | |
|         public PieSelectionMode PieSelectionMode
 | |
|         {
 | |
|             get { return (_PieSelectionMode); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _PieSelectionMode)
 | |
|                 {
 | |
|                     _PieSelectionMode = value;
 | |
| 
 | |
|                     OnPropertyChanged("PieSelectionMode");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region GetPieSelectionMode
 | |
| 
 | |
|         internal PieSelectionMode GetPieSelectionMode(PieChart pieChart)
 | |
|         {
 | |
|             PieSelectionMode psm = PieSelectionMode;
 | |
| 
 | |
|             if (psm == PieSelectionMode.NotSet)
 | |
|                 psm = pieChart.PieSelectionMode;
 | |
| 
 | |
|             return ((psm != PieSelectionMode.NotSet) ? psm : PieSelectionMode.Slice);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ReversePaletteColors
 | |
| 
 | |
|         ///<summary>
 | |
|         /// Gets or sets whether default palette colors are utilized in reverse order.
 | |
|         ///</summary>
 | |
|         [DefaultValue(false), Category("Behavior")]
 | |
|         [Description("Indicates whether default palette colors are utilized in reverse order.")]
 | |
|         public virtual bool ReversePaletteColors
 | |
|         {
 | |
|             get { return (TestState(States.ReversePaletteColors)); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != ReversePaletteColors)
 | |
|                 {
 | |
|                     SetState(States.ReversePaletteColors, value);
 | |
| 
 | |
|                     OnPropertyChangedEx("ReversePaletteColors", VisualChangeType.Layout);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RingWeight
 | |
| 
 | |
|         ///<summary>
 | |
|         /// Gets or sets the 'relative' total combined thickness of all series rings, as
 | |
|         /// compared to the relative thickness of other series combined rings.
 | |
|         /// rings.
 | |
|         ///</summary>
 | |
|         [DefaultValue(100), Category("Layout")]
 | |
|         [Description("Indicates the 'relative' total combined thickness of all series rings, as compared to the relative thickness of other series combined rings.. Default is 100.")]
 | |
|         public int RingWeight
 | |
|         {
 | |
|             get { return (_RingWeight); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _RingWeight)
 | |
|                 {
 | |
|                     _RingWeight = value;
 | |
| 
 | |
|                     OnPropertyChangedEx("RingWeight", Style.VisualChangeType.Recalc);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SeriesPoints
 | |
| 
 | |
|         ///<summary>
 | |
|         /// Gets or sets the series point data collection.
 | |
|         ///</summary>
 | |
|         [Category("Data")]
 | |
|         [Description("Indicates the series point data collection.")]
 | |
|         [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 | |
|         public PieSeriesPointCollection SeriesPoints
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (_SeriesPoints == null)
 | |
|                 {
 | |
|                     _SeriesPoints = new PieSeriesPointCollection();
 | |
| 
 | |
|                     _SeriesPoints.Parent = this;
 | |
| 
 | |
|                     _SeriesPoints.CollectionChanged += SeriesPoints_CollectionChanged;
 | |
|                 }
 | |
| 
 | |
|                 return (_SeriesPoints);
 | |
|             }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _SeriesPoints)
 | |
|                 {
 | |
|                     if (_SeriesPoints != null)
 | |
|                     {
 | |
|                         _SeriesPoints.Parent = null;
 | |
| 
 | |
|                         _SeriesPoints.CollectionChanged -= SeriesPoints_CollectionChanged;
 | |
|                     }
 | |
| 
 | |
|                     _SeriesPoints = value;
 | |
| 
 | |
|                     if (_SeriesPoints != null)
 | |
|                     {
 | |
|                         _SeriesPoints.Parent = this;
 | |
| 
 | |
|                         _SeriesPoints.CollectionChanged += SeriesPoints_CollectionChanged;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region SeriesPoints_CollectionChanged
 | |
| 
 | |
|         void SeriesPoints_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
 | |
|         {
 | |
|             SeriesRangeChanged = true;
 | |
| 
 | |
|             SetPointNotify(e.OldItems, false);
 | |
|             SetPointNotify(e.NewItems, true);
 | |
| 
 | |
|             InvalidateLayout();
 | |
|         }
 | |
| 
 | |
|         #region SetPointNotify
 | |
| 
 | |
|         private void SetPointNotify(IList list, bool notify)
 | |
|         {
 | |
|             if (list != null)
 | |
|             {
 | |
|                 for (int i = 0; i < list.Count; i++)
 | |
|                 {
 | |
|                     PieSeriesPoint psp = list[i] as PieSeriesPoint;
 | |
| 
 | |
|                     if (psp != null)
 | |
|                     {
 | |
|                         if (notify == true)
 | |
|                         {
 | |
|                             psp.Parent = SeriesPoints;
 | |
|                             psp.PropertyChanged += Sp_PropertyChanged;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             psp.Parent = null;
 | |
|                             psp.PropertyChanged -= Sp_PropertyChanged;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Sp_PropertyChanged
 | |
| 
 | |
|         void Sp_PropertyChanged(object sender, PropertyChangedEventArgs e)
 | |
|         {
 | |
|             VisualPropertyChangedEventArgs vce = e as VisualPropertyChangedEventArgs;
 | |
| 
 | |
|             if (vce != null)
 | |
|             {
 | |
|                 if (vce.ChangeType == VisualChangeType.Recalc)
 | |
|                 {
 | |
|                     InvalidateRecalc();
 | |
|                 }
 | |
|                 else if (vce.ChangeType == VisualChangeType.Layout)
 | |
|                 {
 | |
|                     InvalidateLayout();
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     PieSeriesPoint psp = sender as PieSeriesPoint;
 | |
| 
 | |
|                     if (psp != null)
 | |
|                     {
 | |
|                         InvalidateRender(psp.Bounds);
 | |
|                         InvalidateRender(psp.PathBounds);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         InvalidateRender();
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (ChartControl != null)
 | |
|                     ChartControl.GlobalUpdateCount++;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #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.        
 | |
|         /// </summary>
 | |
|         [DefaultValue(Tbool.NotSet), Category("Appearance")]
 | |
|         [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.")]
 | |
|         public Tbool ShowAllRings
 | |
|         {
 | |
|             get { return (_ShowAllRings); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _ShowAllRings)
 | |
|                 {
 | |
|                     _ShowAllRings = value;
 | |
| 
 | |
|                     OnPropertyChangedEx("ShowAllRings", VisualChangeType.Layout);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region ShowAllRingsEx
 | |
| 
 | |
|         internal bool ShowAllRingsEx(PieChart pieChart)
 | |
|         {
 | |
|             if (ShowAllRings != Tbool.NotSet)
 | |
|                 return (ShowAllRings != Tbool.False);
 | |
| 
 | |
|             return (pieChart.ShowAllRings != Tbool.False);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ShowOtherSlice
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets whether to consolidate smaller pie slices into a single slice that
 | |
|         /// represents 'other' data values, or whether to display those smaller slices
 | |
|         /// as separate pie slices.
 | |
|         /// </summary>
 | |
|         [DefaultValue(Tbool.NotSet), Category("Appearance")]
 | |
|         [Description("Indicates whether to consolidate smaller pie slices into a single slice that represents 'other' data values, or whether to display those smaller slices as separate pie slices.")]
 | |
|         public Tbool ShowOtherSlice
 | |
|         {
 | |
|             get { return (_ShowOtherSlice); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _ShowOtherSlice)
 | |
|                 {
 | |
|                     _ShowOtherSlice = value;
 | |
| 
 | |
|                     OnPropertyChangedEx("ShowOtherSlice", VisualChangeType.Layout);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region ShowOtherSliceEx
 | |
| 
 | |
|         internal bool ShowOtherSliceEx(PieChart pieChart)
 | |
|         {
 | |
|             if (ShowOtherSlice != Tbool.NotSet)
 | |
|                 return (ShowOtherSlice == Tbool.True);
 | |
| 
 | |
|             return (pieChart.ShowOtherSlice == Tbool.True);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SubSliceVisualLayout
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets the default layout of the subordinate or nested series slices.
 | |
|         /// </summary>
 | |
|         [Category("Layout")]
 | |
|         [Description("Indicates the default layout of the subordinate or nested series slices.")]
 | |
|         [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
 | |
|         public SliceVisualLayout SubSliceVisualLayout
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (_SliceVisualLayout == null)
 | |
|                     SubSliceVisualLayout = new SliceVisualLayout(this);
 | |
| 
 | |
|                 return (_SliceVisualLayout);
 | |
|             }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (value != _SliceVisualLayout)
 | |
|                 {
 | |
|                     if (_SliceVisualLayout != null)
 | |
|                         _SliceVisualLayout.PropertyChanged -= SliceVisualLayout_PropertyChanged;
 | |
| 
 | |
|                     _SliceVisualLayout = value;
 | |
| 
 | |
|                     if (_SliceVisualLayout != null)
 | |
|                         _SliceVisualLayout.PropertyChanged += SliceVisualLayout_PropertyChanged;
 | |
| 
 | |
|                     OnPropertyChangedEx("SliceVisualLayout", VisualChangeType.Recalc);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region SliceVisualLayout_PropertyChanged
 | |
| 
 | |
|         void SliceVisualLayout_PropertyChanged(object sender, PropertyChangedEventArgs e)
 | |
|         {
 | |
|             VisualPropertyChangedEventArgs vce = e as VisualPropertyChangedEventArgs;
 | |
| 
 | |
|             if (vce != null)
 | |
|             {
 | |
|                 OnPropertyChangedEx(vce.PropertyName, vce.ChangeType);
 | |
| 
 | |
|                 if (ChartControl != null)
 | |
|                     ChartControl.GlobalUpdateCount++;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Visible
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets or sets whether the series is visible or not.
 | |
|         /// </summary>
 | |
|         [DefaultValue(true), Category("Appearance")]
 | |
|         [Description("Indicates whether the series is visible or not.")]
 | |
|         public override bool Visible
 | |
|         {
 | |
|             get { return (base.Visible); }
 | |
| 
 | |
|             set
 | |
|             {
 | |
|                 if (Visible != value)
 | |
|                 {
 | |
|                     base.Visible = value;
 | |
| 
 | |
|                     SeriesRangeChanged = true;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Internal properties
 | |
| 
 | |
|         #region ActiveSeriesPointCollection
 | |
| 
 | |
|         internal PieSeriesPointCollection ActiveSeriesPointCollection
 | |
|         {
 | |
|             get { return (_ActiveSeriesPointSet); }
 | |
|             set { _ActiveSeriesPointSet = value; }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IsInnerRingSeries
 | |
| 
 | |
|         internal bool IsInnerRingSeries
 | |
|         {
 | |
|             get { return (TestState(States.IsInnerRingSeries)); }
 | |
|             set { SetState(States.IsInnerRingSeries, value); }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IsOffset
 | |
| 
 | |
|         internal bool IsOffset
 | |
|         {
 | |
|             get { return (TestState(States.IsOffset)); }
 | |
|             set { SetState(States.IsOffset, value); }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IsOuterRingSeries
 | |
| 
 | |
|         internal bool IsOuterRingSeries
 | |
|         {
 | |
|             get { return (TestState(States.IsOuterRingSeries)); }
 | |
|             set { SetState(States.IsOuterRingSeries, value); }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PieCenter
 | |
| 
 | |
|         internal Point PieCenter
 | |
|         {
 | |
|             get { return (_PieCenter); }
 | |
|             set { _PieCenter = value; }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PieOuterExtent
 | |
| 
 | |
|         internal double PieOuterExtent
 | |
|         {
 | |
|             get { return (_PieOuterExtent); }
 | |
|             set { _PieOuterExtent = value; }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PieRings
 | |
| 
 | |
|         internal List<PieRing> PieRings
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 if (_PieRings == null)
 | |
|                     _PieRings = new List<PieRing>();
 | |
| 
 | |
|                 return (_PieRings);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RingWeightTotal
 | |
| 
 | |
|         internal int RingWeightTotal
 | |
|         {
 | |
|             get { return (_RingWeightTotal); }
 | |
|             set { _RingWeightTotal = value; }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RingWeightEx
 | |
| 
 | |
|         internal int RingWeightEx
 | |
|         {
 | |
|             get { return (_RingWeightEx); }
 | |
|             set { _RingWeightEx = value; }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SymFontScale
 | |
| 
 | |
|         internal float SymFontScale
 | |
|         {
 | |
|             get { return (_SymFontScale); }
 | |
|             set { _SymFontScale = value; }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderOverride
 | |
| 
 | |
|         protected override void RenderOverride(ChartRenderInfo renderInfo)
 | |
|         {
 | |
|             if (SeriesPoints.Count > 0)
 | |
|             {
 | |
|                 PieChart pieChart = Parent as PieChart;
 | |
| 
 | |
|                 Point pt = pieChart.GetGlobalAdjustedPoint(pieChart.ContentBounds.Location);
 | |
|                 RenderBounds = new Rectangle(pt, pieChart.ContentBounds.Size);
 | |
| 
 | |
|                 if (RenderBounds.Width > 0 && RenderBounds.Height > 0)
 | |
|                     RenderPieSeries(renderInfo);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region RenderPieSeries
 | |
| 
 | |
|         private void RenderPieSeries(ChartRenderInfo renderInfo)
 | |
|         {
 | |
|             Graphics g = renderInfo.Graphics;
 | |
|             PieChart pieChart = Parent as PieChart;
 | |
| 
 | |
|             PieSeriesPointCollection spc = GetActiveSeriesPointCollection();
 | |
| 
 | |
|             RenderPieSeriesEx(g, renderInfo.ClipRectangle, pieChart, spc);
 | |
|         }
 | |
| 
 | |
|         #region RenderPieSeriesEx
 | |
| 
 | |
|         private void RenderPieSeriesEx(Graphics g,
 | |
|             Rectangle clip, PieChart pieChart, PieSeriesPointCollection spc)
 | |
|         {
 | |
|             if (spc != null)
 | |
|                 spc = spc.PieSlices;
 | |
| 
 | |
|             if (spc != null)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc)
 | |
|                 {
 | |
|                     if (psp.PieRing != null)
 | |
|                     {
 | |
|                         if (psp.PieRing.IsDisplayed == true)
 | |
|                             RenderSlice(g, clip, pieChart, spc, psp);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region RenderSlice
 | |
| 
 | |
|         private void RenderSlice(Graphics g, Rectangle clip,
 | |
|             PieChart pieChart, PieSeriesPointCollection spc, PieSeriesPoint psp)
 | |
|         {
 | |
|             if (PspNeedsDisplayed(pieChart, psp, clip) == true)
 | |
|             {
 | |
|                 Region rgn = null;
 | |
| 
 | |
|                 int outerRadius = (int)psp.OuterRadius;
 | |
|                 int innerRadius = (int)psp.InnerRadius;
 | |
| 
 | |
|                 ChartSliceVisualStyle sstyle = psp.GetEffectiveSliceStyle(pieChart, this);
 | |
| 
 | |
|                 if (psp.IsEmpty == false)
 | |
|                     RenderReferenceLines(g, pieChart, spc, psp, false);
 | |
| 
 | |
|                 RenderSliceEx(g, ref rgn, pieChart, 
 | |
|                     spc, psp, outerRadius, innerRadius, sstyle);
 | |
| 
 | |
|                 if (psp.IsEmpty == false)
 | |
|                 {
 | |
|                     if (psp.IsOther == true)
 | |
|                     {
 | |
|                         if (ShowAllRingsEx(pieChart) == true)
 | |
|                         {
 | |
|                             List<PieRing> pieRings = psp.PieRing.ChartSeries.PieRings;
 | |
| 
 | |
|                             outerRadius = innerRadius;
 | |
|                             innerRadius = pieRings[pieRings.Count - 1].InnerRadius;
 | |
| 
 | |
|                             RenderSliceOtherSpace(g, ref rgn,
 | |
|                                 pieChart, psp, outerRadius, innerRadius, sstyle);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 psp.PathBounds = (rgn != null)
 | |
|                     ? Rectangle.Ceiling(rgn.GetBounds(g)) : Rectangle.Empty;
 | |
| 
 | |
|                 if (psp.IsEmpty == false)
 | |
|                 {
 | |
|                     if (sstyle.ImageOverlay == ImageOverlay.Bottom)
 | |
|                         RenderSliceFigure(g, rgn, pieChart, psp, sstyle);
 | |
| 
 | |
|                     if ((sstyle.ImageOverlay == ImageOverlay.Middle) ||
 | |
|                         (sstyle.ImageOverlay == ImageOverlay.NotSet))
 | |
|                     {
 | |
|                         RenderSliceFigure(g, rgn, pieChart, psp, sstyle);
 | |
|                     }
 | |
| 
 | |
|                     RenderSliceLabel(g, pieChart, psp, sstyle);
 | |
| 
 | |
|                     if (sstyle.ImageOverlay == ImageOverlay.Top)
 | |
|                         RenderSliceFigure(g, rgn, pieChart, psp, sstyle);
 | |
| 
 | |
|                     RenderReferenceLines(g, pieChart, spc, psp, true);
 | |
|                 }
 | |
| 
 | |
|                 //using (StringFormat sf = new StringFormat())
 | |
|                 //{
 | |
|                 //    sf.Alignment = StringAlignment.Center;
 | |
|                 //    sf.LineAlignment = StringAlignment.Center;
 | |
| 
 | |
|                 //    g.DrawString(psp.RenderCount.ToString(),
 | |
|                 //        SystemFonts.DefaultFont, Brushes.Black, psp.PathBounds, sf);
 | |
|                 //}
 | |
| 
 | |
|                 //psp.RenderCount++;
 | |
|             }
 | |
| 
 | |
|             if (ShowAllRingsEx(pieChart) == true)
 | |
|             {
 | |
|                 if (psp.SeriesPoints != null)
 | |
|                     RenderPieSeriesEx(g, clip, pieChart, psp.SeriesPoints);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region PspNeedsDisplayed
 | |
| 
 | |
|         private bool PspNeedsDisplayed(PieChart pieChart, PieSeriesPoint psp, Rectangle clip)
 | |
|         {
 | |
|             if (psp.IsDisplayedEx == true)
 | |
|             {
 | |
|                 if (psp.SweepAngleEx != 0)
 | |
|                 {
 | |
|                     Rectangle r = psp.Bounds;
 | |
| 
 | |
|                     if (r.Width > 0 && r.Height > 0)
 | |
|                     {
 | |
|                         if (psp.InnerRadius < psp.OuterRadius)
 | |
|                         {
 | |
|                             if (psp.PathBounds.IsEmpty == true || clip.IntersectsWith(psp.PathBounds) == true)
 | |
|                                 return (true);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderSliceEx
 | |
| 
 | |
|         private void RenderSliceEx(Graphics g, ref Region rgn,
 | |
|             PieChart pieChart, PieSeriesPointCollection spc, PieSeriesPoint psp,
 | |
|             int outerRadius, int innerRadius, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             int width = outerRadius - innerRadius;
 | |
|             int extentWidth = (int)(psp.SliceExtent * width);
 | |
| 
 | |
|             bool renderShading = (sstyle.EnableShading == Tbool.True);
 | |
| 
 | |
|             SliceRenderType renderType = SliceRenderType.FullSlice;
 | |
| 
 | |
|             if (psp.HasExtent == true)
 | |
|             {
 | |
|                 int extentRadius = innerRadius + extentWidth;
 | |
| 
 | |
|                 if (extentWidth < width)
 | |
|                 {
 | |
|                     renderType = SliceRenderType.ExtentSlice;
 | |
| 
 | |
|                     if (psp.ShowSliceWhiteSpaceEx == true)
 | |
|                     {
 | |
|                         RenderSliceWhiteSpace(g, ref rgn, pieChart,
 | |
|                             psp, outerRadius, extentRadius, renderShading, sstyle);
 | |
| 
 | |
|                         renderShading = false;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 outerRadius = extentRadius;
 | |
|             }
 | |
| 
 | |
|             RenderSliceExtent(g, ref rgn, pieChart,
 | |
|                 psp, outerRadius, innerRadius, renderShading, renderType, sstyle);
 | |
|         }
 | |
| 
 | |
|         #region RenderSliceWhiteSpace
 | |
| 
 | |
|         private void RenderSliceWhiteSpace(Graphics g, ref Region rgn,
 | |
|             PieChart pieChart, PieSeriesPoint psp, int outerRadius,
 | |
|             int innerRadius, bool renderShading, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             Background background = sstyle.WhiteSpaceBackground;
 | |
|             ChartLineVisualStyle border = sstyle.WhiteSpaceBorder;
 | |
| 
 | |
|             GraphicsState gs = g.Save();
 | |
| 
 | |
|             g.TranslateTransform((float)psp.SliceCenter.X, (float)psp.SliceCenter.Y);
 | |
|             g.RotateTransform((float)(psp.CenterAngle) % 360);
 | |
| 
 | |
|             Rectangle r = new Rectangle();
 | |
| 
 | |
|             r.X = r.Y = -outerRadius;
 | |
|             r.Width = r.Height = (outerRadius * 2);
 | |
| 
 | |
|             float angle = (float)GetSweepAngle(psp);
 | |
| 
 | |
|             // Try to blend the edges of the slice better.
 | |
| 
 | |
|             //if (background.IsDisplayable == true && border.IsDisplayable == false)
 | |
|             //    angle += .1f;
 | |
| 
 | |
|             ChartControl chartControl = ChartControl;
 | |
| 
 | |
|             using (GraphicsPath path = new GraphicsPath())
 | |
|             {
 | |
|                 path.AddArc(r, -angle / 2, angle);
 | |
| 
 | |
|                 if (psp.SliceExtent == 0)
 | |
|                 {
 | |
|                     path.AddLine(Point.Empty, Point.Empty);
 | |
|                     path.CloseFigure();
 | |
| 
 | |
|                     if (chartControl.DoPreRenderSliceEvent(
 | |
|                         g, path, pieChart, this, psp, SliceRenderType.ExtentWhitespace) == false)
 | |
|                     {
 | |
|                         Rectangle pb = Rectangle.Truncate(path.GetBounds());
 | |
| 
 | |
|                         if (psp.IsEmpty == false)
 | |
|                         {
 | |
|                             if (background.IsDisplayable == true)
 | |
|                             {
 | |
|                                 using (Brush br = background.GetBrush(pb))
 | |
|                                     g.FillPath(br, path);
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         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.DrawPath(pen, path);
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         chartControl.DoPostRenderSliceEvent(
 | |
|                             g, path, pieChart, this, psp, SliceRenderType.ExtentWhitespace);
 | |
|                     }
 | |
| 
 | |
|                     if (psp.IsEmpty == false)
 | |
|                     {
 | |
|                         if (renderShading == true)
 | |
|                             RenderShading(g, psp, path);
 | |
|                     }
 | |
| 
 | |
|                     path.Transform(g.Transform);
 | |
| 
 | |
|                     if (rgn == null)
 | |
|                         rgn = new Region(path);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     int pcount = path.PointCount;
 | |
| 
 | |
|                     Rectangle t = new Rectangle();
 | |
|                     t.X = t.Y = (-innerRadius);
 | |
|                     t.Width = t.Height = (innerRadius * 2);
 | |
| 
 | |
|                     path.AddArc(t, angle / 2, -angle);
 | |
| 
 | |
|                     PointF ppt1 = path.PathPoints[pcount];
 | |
|                     PointF ppt2 = path.GetLastPoint();
 | |
| 
 | |
|                     path.CloseFigure();
 | |
| 
 | |
|                     if (chartControl.DoPreRenderSliceEvent(
 | |
|                         g, path, pieChart, this, psp, SliceRenderType.ExtentWhitespace) == false)
 | |
|                     {
 | |
|                         if (psp.IsEmpty == false)
 | |
|                         {
 | |
|                             if (background.IsDisplayable == true)
 | |
|                             {
 | |
|                                 t = Rectangle.Ceiling(path.GetBounds());
 | |
| 
 | |
|                                 Rectangle t2 = t;
 | |
|                                 t2.Width = outerRadius - (int)psp.InnerRadius;
 | |
|                                 t2.X = -t2.Width;
 | |
| 
 | |
|                                 using (Brush br = background.GetBrush(t2))
 | |
|                                     g.FillPath(br, path);
 | |
|                             }
 | |
| 
 | |
|                             if (renderShading == true)
 | |
|                                 RenderShading(g, psp, path);
 | |
|                         }
 | |
| 
 | |
|                         path.Transform(g.Transform);
 | |
| 
 | |
|                         if (rgn == null)
 | |
|                             rgn = new Region(path);
 | |
| 
 | |
|                         if (border.IsDisplayable == true)
 | |
|                         {
 | |
|                             path.Reset();
 | |
| 
 | |
|                             using (Pen pen = new Pen(border.LineColor, Dpi.Width(border.LineWidth)))
 | |
|                             {
 | |
|                                 if (border.LinePattern != LinePattern.NotSet)
 | |
|                                     pen.DashStyle = (DashStyle)border.LinePattern;
 | |
| 
 | |
|                                 path.AddLine(ppt2, ppt2);
 | |
|                                 path.AddArc(r, -angle / 2, angle);
 | |
|                                 path.AddLine(ppt1, ppt1);
 | |
| 
 | |
|                                 g.DrawPath(pen, path);
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         chartControl.DoPostRenderSliceEvent(
 | |
|                             g, path, pieChart, this, psp, SliceRenderType.ExtentWhitespace);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             g.Restore(gs);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderSliceExtent
 | |
| 
 | |
|         private void RenderSliceExtent(Graphics g, ref Region rgn,
 | |
|             PieChart pieChart, PieSeriesPoint psp, int outerRadius, int innerRadius, 
 | |
|             bool renderShading, SliceRenderType renderType, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             if (outerRadius - innerRadius > 0)
 | |
|             {
 | |
|                 GraphicsState gs = g.Save();
 | |
| 
 | |
|                 g.TranslateTransform((float)psp.SliceCenter.X, (float)psp.SliceCenter.Y);
 | |
|                 g.RotateTransform((float)(psp.CenterAngle) % 360);
 | |
| 
 | |
|                 Rectangle r = new Rectangle();
 | |
| 
 | |
|                 r.X = r.Y = -outerRadius;
 | |
|                 r.Width = r.Height = (outerRadius * 2);
 | |
| 
 | |
|                 float angle = (float)GetSweepAngle(psp);
 | |
| 
 | |
|                 using (GraphicsPath path = new GraphicsPath())
 | |
|                 {
 | |
|                     path.AddArc(r, -angle / 2, angle);
 | |
| 
 | |
|                     if (psp.InnerRadius == 0)
 | |
|                     {
 | |
|                         path.AddLine(Point.Empty, Point.Empty);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         Rectangle t = new Rectangle();
 | |
|                         t.X = t.Y = -innerRadius;
 | |
|                         t.Width = t.Height = innerRadius * 2;
 | |
| 
 | |
|                         path.AddArc(t, angle / 2, -angle);
 | |
|                     }
 | |
| 
 | |
|                     path.CloseFigure();
 | |
| 
 | |
|                     ChartControl chartControl = ChartControl;
 | |
| 
 | |
|                     if (chartControl.DoPreRenderSliceEvent(g, path, pieChart, this, psp, renderType) == false)
 | |
|                     {
 | |
|                         if (psp.IsEmpty == false)
 | |
|                         {
 | |
|                             if (sstyle.Background.IsDisplayable == true)
 | |
|                             {
 | |
|                                 r = Rectangle.Ceiling(path.GetBounds());
 | |
| 
 | |
|                                 if (psp.HasExtent == true)
 | |
|                                 {
 | |
|                                     switch (sstyle.ExtentFillRange)
 | |
|                                     {
 | |
|                                         case ExtentFillRange.ByRing:
 | |
|                                             r.Width = psp.PieRing.ExtentRadius - innerRadius;
 | |
|                                             break;
 | |
| 
 | |
|                                         case ExtentFillRange.BySlice:
 | |
|                                             PieSeriesPointCollection spc = psp.Parent as PieSeriesPointCollection;
 | |
| 
 | |
|                                             if (spc != null)
 | |
|                                             {
 | |
|                                                 double sliceExtent = spc.PieMaxExtent / spc.PieOuterExtent;
 | |
| 
 | |
|                                                 int width = (int)(psp.OuterRadius - psp.InnerRadius);
 | |
|                                                 int extentWidth = (int)(sliceExtent * width);
 | |
| 
 | |
|                                                 r.Width = extentWidth;
 | |
|                                             }
 | |
|                                             break;
 | |
|                                     }
 | |
|                                 }
 | |
| 
 | |
|                                 using (Brush br = sstyle.Background.GetBrush(r))
 | |
|                                     g.FillPath(br, path);
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         if (sstyle.Border.IsDisplayable == true)
 | |
|                         {
 | |
|                             using (Pen pen = new Pen(
 | |
|                                 sstyle.Border.LineColor, Dpi.Width(sstyle.Border.LineWidth)))
 | |
|                             {
 | |
|                                 if (sstyle.Border.LinePattern != LinePattern.NotSet)
 | |
|                                     pen.DashStyle = (DashStyle)sstyle.Border.LinePattern;
 | |
| 
 | |
|                                 g.DrawPath(pen, path);
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         chartControl.DoPostRenderSliceEvent(g, path, pieChart, this, psp, renderType);
 | |
|                     }
 | |
| 
 | |
|                     if (psp.IsEmpty == false)
 | |
|                     {
 | |
|                         if (renderShading == true)
 | |
|                             RenderShading(g, psp, path);
 | |
|                     }
 | |
| 
 | |
|                     path.Transform(g.Transform);
 | |
| 
 | |
|                     if (rgn == null)
 | |
|                         rgn = new Region(path);
 | |
|                     else
 | |
|                         rgn.Union(path);
 | |
| 
 | |
|                     g.Restore(gs);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region GetSweepAngle
 | |
| 
 | |
|         private double GetSweepAngle(PieSeriesPoint psp)
 | |
|         {
 | |
|             double sweepAngle = psp.SweepAngleEx;
 | |
| 
 | |
|             if (sweepAngle > 360)
 | |
|                 sweepAngle %= 360;
 | |
| 
 | |
|             return (sweepAngle);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderSliceOtherSpace
 | |
| 
 | |
|         private void RenderSliceOtherSpace(Graphics g,
 | |
|             ref Region rgn, PieChart pieChart, PieSeriesPoint psp,
 | |
|             int outerRadius, int innerRadius, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             if (outerRadius - innerRadius > 0)
 | |
|             {
 | |
|                 GraphicsState gs = g.Save();
 | |
| 
 | |
|                 g.TranslateTransform((float)psp.SliceCenter.X, (float)psp.SliceCenter.Y);
 | |
|                 g.RotateTransform((float)(psp.CenterAngle) % 360);
 | |
| 
 | |
|                 Rectangle r = new Rectangle();
 | |
| 
 | |
|                 r.X = r.Y = -outerRadius;
 | |
|                 r.Width = r.Height = (outerRadius * 2);
 | |
| 
 | |
|                 float angle = (float)GetSweepAngle(psp);
 | |
| 
 | |
|                 Background background = sstyle.WhiteSpaceBackground;
 | |
|                 ChartLineVisualStyle border = sstyle.WhiteSpaceBorder;
 | |
| 
 | |
|                 ChartControl chartControl = ChartControl;
 | |
| 
 | |
|                 using (GraphicsPath path = new GraphicsPath())
 | |
|                 {
 | |
|                     path.AddArc(r, -angle / 2, angle);
 | |
| 
 | |
|                     if (innerRadius == 0)
 | |
|                     {
 | |
|                         path.AddLine(Point.Empty, Point.Empty);
 | |
|                         path.CloseFigure();
 | |
| 
 | |
|                         if (chartControl.DoPreRenderSliceEvent(
 | |
|                             g, path, pieChart, this, psp, SliceRenderType.OtherWhitespace) == false)
 | |
|                         {
 | |
|                             Rectangle pb = Rectangle.Truncate(path.GetBounds());
 | |
| 
 | |
|                             if (background.IsEmpty == false)
 | |
|                             {
 | |
|                                 using (Brush br = background.GetBrush(pb))
 | |
|                                     g.FillPath(br, path);
 | |
|                             }
 | |
| 
 | |
|                             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.DrawPath(pen, path);
 | |
|                                 }
 | |
|                             }
 | |
| 
 | |
|                             chartControl.DoPostRenderSliceEvent(
 | |
|                                 g, path, pieChart, this, psp, SliceRenderType.OtherWhitespace);
 | |
|                         }
 | |
| 
 | |
|                         path.Transform(g.Transform);
 | |
| 
 | |
|                         if (rgn == null)
 | |
|                             rgn = new Region(path);
 | |
|                         else
 | |
|                             rgn.Union(path);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         int pcount = path.PointCount;
 | |
| 
 | |
|                         Rectangle t = new Rectangle();
 | |
| 
 | |
|                         t.X = t.Y = -innerRadius;
 | |
|                         t.Width = t.Height = (innerRadius * 2);
 | |
| 
 | |
|                         PointF ppt1 = path.PathPoints[0];
 | |
|                         PointF ppt2 = path.GetLastPoint();
 | |
| 
 | |
|                         path.AddArc(t, angle / 2, -angle);
 | |
|                         path.CloseFigure();
 | |
| 
 | |
|                         if (chartControl.DoPreRenderSliceEvent(
 | |
|                             g, path, pieChart, this, psp, SliceRenderType.OtherWhitespace) == false)
 | |
|                         {
 | |
|                             Rectangle pb = Rectangle.Ceiling(path.GetBounds());
 | |
| 
 | |
|                             if (background.IsEmpty == false)
 | |
|                             {
 | |
|                                 using (Brush br = background.GetBrush(pb))
 | |
|                                     g.FillPath(br, path);
 | |
|                             }
 | |
| 
 | |
|                             path.Transform(g.Transform);
 | |
| 
 | |
|                             if (rgn == null)
 | |
|                                 rgn = new Region(path);
 | |
|                             else
 | |
|                                 rgn.Union(path);
 | |
| 
 | |
|                             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;
 | |
| 
 | |
|                                     path.Reset();
 | |
| 
 | |
|                                     path.AddLine(ppt1, ppt1);
 | |
|                                     path.AddArc(t, -angle / 2, angle);
 | |
|                                     path.AddLine(ppt2, ppt2);
 | |
| 
 | |
|                                     g.DrawPath(pen, path);
 | |
|                                 }
 | |
|                             }
 | |
| 
 | |
|                             chartControl.DoPostRenderSliceEvent(
 | |
|                                 g, path, pieChart, this, psp, SliceRenderType.OtherWhitespace);
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             path.Transform(g.Transform);
 | |
| 
 | |
|                             if (rgn == null)
 | |
|                                 rgn = new Region(path);
 | |
|                             else
 | |
|                                 rgn.Union(path);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 g.Restore(gs);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderShading
 | |
| 
 | |
|         private void RenderShading(Graphics g, PieSeriesPoint psp, GraphicsPath path)
 | |
|         {
 | |
|             PieChart pieChart = Parent as PieChart;
 | |
| 
 | |
|             int radius = (int)((psp.HasExtent == true) ? psp.ExtentRadius : psp.OuterRadius);
 | |
| 
 | |
|             Rectangle r = new Rectangle();
 | |
|             r.Inflate(radius, radius);
 | |
| 
 | |
|             Region clip = g.Clip;
 | |
|             g.SetClip(path, CombineMode.Intersect);
 | |
| 
 | |
|             using (GraphicsPath path2 = new GraphicsPath())
 | |
|             {
 | |
|                 path2.AddEllipse(r);
 | |
| 
 | |
|                 PathGradientBrush pbr = new PathGradientBrush(path2);
 | |
| 
 | |
|                 ColorBlend cb = new ColorBlend(3);
 | |
| 
 | |
|                 Color[] colors = new Color[3];
 | |
| 
 | |
|                 colors[0] = Color.FromArgb(100, Color.Black);
 | |
|                 colors[1] = Color.Transparent;
 | |
|                 colors[2] = Color.Transparent;
 | |
| 
 | |
|                 cb.Colors = colors;
 | |
| 
 | |
|                 float[] cp = new float[3];
 | |
| 
 | |
|                 cp[0] = 0f;
 | |
|                 cp[1] = .07f;
 | |
|                 cp[2] = 1f;
 | |
| 
 | |
|                 cb.Positions = cp;
 | |
| 
 | |
|                 pbr.InterpolationColors = cb;
 | |
| 
 | |
|                 g.FillEllipse(pbr, r);
 | |
|             }
 | |
| 
 | |
|             g.Clip = clip;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderReferenceLines
 | |
| 
 | |
|         private void RenderReferenceLines(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPointCollection spc, PieSeriesPoint psp, bool onTop)
 | |
|         {
 | |
|             if (spc.PieOuterExtent > 0)
 | |
|             {
 | |
|                 ISeriesPointContainer ispc = spc.Parent;
 | |
| 
 | |
|                 if (ispc != null)
 | |
|                 {
 | |
|                     if (psp.ReferenceLineDisplayOnTopEx == onTop)
 | |
|                     {
 | |
|                         PieRefLineDisplayMode mode = psp.ReferenceLineDisplayModeEx;
 | |
| 
 | |
|                         if ((mode != PieRefLineDisplayMode.NotSet) &&
 | |
|                             ((mode & PieRefLineDisplayMode.None) != PieRefLineDisplayMode.None))
 | |
|                         {
 | |
|                             ChartSliceVisualStyle sstyle = psp.GetEffectiveSliceStyle(pieChart, this);
 | |
| 
 | |
|                             int width = psp.OuterRadius - psp.InnerRadius;
 | |
| 
 | |
|                             float start = (float)psp.StartAngleEx;
 | |
|                             float sweep = (float)psp.SweepAngleEx;
 | |
| 
 | |
|                             if ((mode & PieRefLineDisplayMode.ExtentAverage) == PieRefLineDisplayMode.ExtentAverage)
 | |
|                             {
 | |
|                                 int avg = (int)((spc.PieAverageExtent / spc.PieOuterExtent) * width);
 | |
| 
 | |
|                                 RenderReferenceLine(g, psp, start, sweep,
 | |
|                                     avg + psp.InnerRadius, sstyle.ExtentAverageRefLineStyle);
 | |
|                             }
 | |
| 
 | |
|                             if ((mode & PieRefLineDisplayMode.ExtentMinimum) == PieRefLineDisplayMode.ExtentMinimum)
 | |
|                             {
 | |
|                                 int min = (int)((spc.PieMinExtent / spc.PieOuterExtent) * width);
 | |
| 
 | |
|                                 RenderReferenceLine(g, psp, start, sweep,
 | |
|                                     min + psp.InnerRadius, sstyle.ExtentMinRefLineStyle);
 | |
|                             }
 | |
| 
 | |
|                             if ((mode & PieRefLineDisplayMode.ExtentMaximum) == PieRefLineDisplayMode.ExtentMaximum)
 | |
|                             {
 | |
|                                 int max = (int)((spc.PieMaxExtent / spc.PieOuterExtent) * width);
 | |
| 
 | |
|                                 RenderReferenceLine(g, psp, start, sweep,
 | |
|                                     max + psp.InnerRadius, sstyle.ExtentMaxRefLineStyle);
 | |
|                             }
 | |
| 
 | |
|                             if ((mode & PieRefLineDisplayMode.ExtentOuterRadius) == PieRefLineDisplayMode.ExtentOuterRadius)
 | |
|                             {
 | |
|                                 RenderReferenceLine(g, psp, start, sweep,
 | |
|                                     psp.OuterRadius, sstyle.ExtentOuterRefLineStyle);
 | |
|                             }
 | |
| 
 | |
|                             if ((mode & PieRefLineDisplayMode.UserDefined) == PieRefLineDisplayMode.UserDefined)
 | |
|                             {
 | |
|                                 List<PieReferenceLine> lines = psp.ReferenceLinesEx;
 | |
| 
 | |
|                                 if (lines.Count > 0)
 | |
|                                 {
 | |
|                                     foreach (PieReferenceLine line in lines)
 | |
|                                     {
 | |
|                                         if (line.Visible == true)
 | |
|                                         {
 | |
|                                             double radius = (line.Value / spc.PieOuterExtent) * width;
 | |
| 
 | |
|                                             RenderReferenceLine(g, psp, start, sweep,
 | |
|                                                 radius + psp.InnerRadius, line.EffectiveStyle);
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region RenderReferenceLine
 | |
| 
 | |
|         private void RenderReferenceLine(Graphics g, PieSeriesPoint psp,
 | |
|             float start, float sweep, double radius, PieReferenceLineVisualStyle rstyle)
 | |
|         {
 | |
|             if (radius > 0)
 | |
|             {
 | |
|                 if (rstyle.IsDisplayable == true)
 | |
|                 {
 | |
|                     Rectangle r = new Rectangle();
 | |
|                     r.Location = psp.SliceCenter;
 | |
| 
 | |
|                     r.Inflate((int)radius, (int)radius);
 | |
| 
 | |
|                     using (Pen pen = new Pen(rstyle.LineColor, rstyle.LineWidth))
 | |
|                     {
 | |
|                         if (rstyle.LinePattern != LinePattern.NotSet)
 | |
|                             pen.DashStyle = (DashStyle)rstyle.LinePattern;
 | |
| 
 | |
|                         g.DrawArc(pen, r, start, sweep);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderSliceFigure
 | |
| 
 | |
|         private void RenderSliceFigure(Graphics g, Region rgn,
 | |
|             PieChart pieChart, PieSeriesPoint psp, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             object figure = sstyle.GetFigure();
 | |
| 
 | |
|             if (figure != null)
 | |
|             {
 | |
|                 double radius = GetFigureRadius(psp, sstyle);
 | |
|                 double centerAngle = psp.CenterAngle;
 | |
| 
 | |
|                 double angle = GetImageAngle(psp, centerAngle, sstyle);
 | |
| 
 | |
|                 Point pt = psp.GetRayEndPoint(angle, radius);
 | |
|                 Size srcSize = sstyle.GetFigureSizeEx(g);
 | |
| 
 | |
|                 srcSize.Height = Dpi.DescaleHeight(srcSize.Height);
 | |
|                 srcSize.Width = Dpi.DescaleWidth(srcSize.Width);
 | |
| 
 | |
|                 Rectangle srcRect = new Rectangle(pt, Size.Empty);
 | |
|                 Rectangle destRect = srcRect;
 | |
| 
 | |
|                 double scaleFactor = GetImageSideFactor(psp, radius, srcSize);
 | |
| 
 | |
|                 Size destSize = srcRect.Size;
 | |
| 
 | |
|                 if (scaleFactor != 1)
 | |
|                 {
 | |
|                     double dh = (double)srcSize.Width / srcSize.Height;
 | |
|                     destSize = new Size((int)(dh * scaleFactor * 2), (int)scaleFactor * 2);
 | |
|                 }
 | |
| 
 | |
|                 srcRect.Inflate(srcSize.Width / 2, srcSize.Height / 2);
 | |
|                 destRect.Inflate(destSize.Width / 2, destSize.Height / 2);
 | |
| 
 | |
|                 bool scaleImage = (double.IsNaN(sstyle.ImageScale) == false);
 | |
| 
 | |
|                 Region clip = null;
 | |
| 
 | |
|                 if (scaleImage == false)
 | |
|                 {
 | |
|                     if (sstyle.ImageCropMode == SliceImageCropMode.ClipImage)
 | |
|                     {
 | |
|                         clip = g.Clip;
 | |
| 
 | |
|                         g.SetClip(rgn, CombineMode.Intersect);
 | |
|                     }
 | |
|                     else if (sstyle.ImageCropMode == SliceImageCropMode.HideImage)
 | |
|                     {
 | |
|                         if (destRect.Contains(srcRect) == false)
 | |
|                             return;
 | |
|                     }
 | |
| 
 | |
|                     destRect = srcRect;
 | |
|                 }
 | |
| 
 | |
|                 psp.PathBounds = Rectangle.Union(psp.PathBounds, destRect);
 | |
| 
 | |
|                 GraphicsState gState = null;
 | |
| 
 | |
|                 if (sstyle.ImageAutoRotate == Tbool.True || sstyle.ImageRotation != 0)
 | |
|                 {
 | |
|                     gState = g.Save();
 | |
| 
 | |
|                     destRect.X = -(destRect.Width / 2);
 | |
|                     destRect.Y = -(destRect.Height / 2);
 | |
| 
 | |
|                     g.TranslateTransform(pt.X, pt.Y);
 | |
| 
 | |
|                     if (sstyle.ImageAutoRotate == Tbool.True)
 | |
|                         g.RotateTransform((float)angle);
 | |
| 
 | |
|                     if (sstyle.ImageRotation != 0)
 | |
|                         g.RotateTransform((float)sstyle.ImageRotation);
 | |
|                 }
 | |
| 
 | |
|                 if (scaleImage == true)
 | |
|                 {
 | |
|                     if (sstyle.ImageScale != 1)
 | |
|                     {
 | |
|                         int width = (int)(destRect.Width * sstyle.ImageScale);
 | |
|                         int height = (int)(destRect.Height * sstyle.ImageScale);
 | |
| 
 | |
|                         destRect.X += (destRect.Width / 2);
 | |
|                         destRect.Y += (destRect.Height / 2);
 | |
|                         destRect.Size = Size.Empty;
 | |
| 
 | |
|                         destRect.Inflate(width / 2, height / 2);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (sstyle.IsSymbolFigure == true)
 | |
|                     RenderSliceSymbol(g, pieChart, (SymbolDef)figure, destRect, sstyle);
 | |
|                 else
 | |
|                     RenderSliceImage(g, (Image)figure, srcRect, destRect);
 | |
| 
 | |
|                 if (sstyle.ImageAutoRotate == Tbool.True || sstyle.ImageRotation != 0)
 | |
|                     g.Restore(gState);
 | |
| 
 | |
|                 if (clip != null)
 | |
|                     g.Clip = clip;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region GetImageAngle
 | |
| 
 | |
|         private double GetImageAngle(
 | |
|             PieSeriesPoint psp, double centerAngle, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             double offset = sstyle.ImageAngleOffset;
 | |
| 
 | |
|             if (offset == 0)
 | |
|                 return (centerAngle);
 | |
| 
 | |
|             if ((uint)offset < 1)
 | |
|                 return (centerAngle + offset * psp.SweepAngleEx);
 | |
| 
 | |
|             return (centerAngle + offset);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetImageSideFactor
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Calculates the max 'a' side of the image.
 | |
|         /// </summary>
 | |
|         /// <param name="psp"></param>
 | |
|         /// <param name="radius"></param>
 | |
|         /// <param name="size"></param>
 | |
|         /// <returns></returns>
 | |
|         private double GetImageSideFactor(
 | |
|             PieSeriesPoint psp, double radius, Size size)
 | |
|         {
 | |
|             double maxRadius = GetMaxImageRadius(psp, radius);
 | |
| 
 | |
|             double scaleFactor = (double)(size.Width * size.Width) / (size.Height * size.Height);
 | |
|             double side = Math.Sqrt((maxRadius * maxRadius) / (scaleFactor + 1));
 | |
| 
 | |
|             return (side);
 | |
|         }
 | |
| 
 | |
|         #region GetMaxImageRadius
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the max radius of a circle image at the given ray radius.
 | |
|         /// </summary>
 | |
|         /// <param name="psp"></param>
 | |
|         /// <param name="radius"></param>
 | |
|         /// <returns></returns>
 | |
|         private double GetMaxImageRadius(PieSeriesPoint psp, double radius)
 | |
|         {
 | |
|             double angle = psp.SweepAngleEx / 2;
 | |
| 
 | |
|             if (angle >= 90)
 | |
|                 return (radius);
 | |
| 
 | |
|             double radians = MathHelper.ToRadians(angle);
 | |
| 
 | |
|             double maxRad = radius * Math.Sin(radians);
 | |
| 
 | |
|             //double dr = (int)(radius * radius);
 | |
| 
 | |
|             //double maxRad = 2 * dr - 2 * (dr * Math.Cos(radians));
 | |
|             //maxRad = Math.Sqrt(maxRad);
 | |
| 
 | |
|             return (maxRad);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetFigureRadius
 | |
| 
 | |
|         private double GetFigureRadius(PieSeriesPoint psp, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             double radius = psp.OuterRadius - psp.InnerRadius;
 | |
|             double extentRadius = psp.InnerRadius + radius * psp.SliceExtent;
 | |
| 
 | |
|             double innerRadius = GetAnchorRadius(psp, extentRadius, sstyle.ImageInnerRadiusAnchor);
 | |
|             double outerRadius = GetAnchorRadius(psp, extentRadius, sstyle.ImageOuterRadiusAnchor);
 | |
| 
 | |
|             double delta = outerRadius - innerRadius;
 | |
| 
 | |
|             if (delta == 0)
 | |
|                 delta = radius;
 | |
| 
 | |
|             if (Math.Abs(sstyle.ImageRadiusOffset) <= 1)
 | |
|                 return (innerRadius + delta * sstyle.ImageRadiusOffset);
 | |
|             else
 | |
|                 return (innerRadius + sstyle.ImageRadiusOffset * (delta > 0 ? 1 : -1));
 | |
|         }
 | |
| 
 | |
|         #region GetAnchorRadius
 | |
| 
 | |
|         private double GetAnchorRadius(
 | |
|             PieSeriesPoint psp, double extentRadius, SliceImageRadiusAnchor anchor)
 | |
|         {
 | |
|             switch (anchor)
 | |
|             {
 | |
|                 case SliceImageRadiusAnchor.ExtentRadius:
 | |
|                     return (extentRadius);
 | |
| 
 | |
|                 case SliceImageRadiusAnchor.InnerRadius:
 | |
|                     return (psp.InnerRadius);
 | |
| 
 | |
|                 case SliceImageRadiusAnchor.OuterRadius:
 | |
|                     return (psp.OuterRadius);
 | |
|             }
 | |
| 
 | |
|             return (psp.InnerRadius);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderSliceSymbol
 | |
| 
 | |
|         private void RenderSliceSymbol(Graphics g,
 | |
|             PieChart pieChart, SymbolDef symDef, Rectangle destRect, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             TextRenderingHint hint = g.TextRenderingHint;
 | |
|             g.TextRenderingHint = TextRenderingHint.AntiAlias;
 | |
| 
 | |
|             if (double.IsNaN(sstyle.ImageScale) == true)
 | |
|             {
 | |
|                 using (StringFormat sf = new StringFormat())
 | |
|                 {
 | |
|                     sf.LineAlignment = StringAlignment.Center;
 | |
|                     sf.Alignment = StringAlignment.Center;
 | |
| 
 | |
|                     using (Brush br = new SolidBrush(symDef.SymbolColor))
 | |
|                         g.DrawString(symDef.SymbolRealized, symDef.SymbolFont, br, destRect, sf);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 float n = Math.Max(destRect.Width, destRect.Height);
 | |
| 
 | |
|                 destRect.Y += Dpi.Width4;
 | |
| 
 | |
|                 if (_SymFontScale <= 0)
 | |
|                 {
 | |
|                     _ScaleSymDef.SymbolSize = n;
 | |
|                     _ScaleSymDef.SymbolSet = symDef.SymbolSet;
 | |
| 
 | |
|                     _SymFontScale = n / _ScaleSymDef.SymbolFont.Height * .8f;
 | |
|                 }
 | |
| 
 | |
|                 float fn = _SymFontScale * n;
 | |
| 
 | |
|                 _ScaleSymDef.SymbolSize = fn;
 | |
|                 _ScaleSymDef.SymbolSet = symDef.SymbolSet;
 | |
| 
 | |
|                 using (StringFormat sf = new StringFormat())
 | |
|                 {
 | |
|                     sf.LineAlignment = StringAlignment.Center;
 | |
|                     sf.Alignment = StringAlignment.Center;
 | |
| 
 | |
|                     using (Brush br = new SolidBrush(symDef.SymbolColor))
 | |
|                         g.DrawString(symDef.SymbolRealized, _ScaleSymDef.SymbolFont, br, destRect, sf);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             g.TextRenderingHint = hint;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderSliceImage
 | |
| 
 | |
|         private void RenderSliceImage(Graphics g, Image image, Rectangle srcRect, Rectangle destRect)
 | |
|         {
 | |
|             g.DrawImage(image, destRect,
 | |
|                 new Rectangle(Point.Empty, srcRect.Size), GraphicsUnit.Pixel);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderSliceLabel
 | |
| 
 | |
|         internal void RenderSliceLabel(Graphics g,
 | |
|             PieChart pieChart, PieSeriesPoint psp, ChartSliceVisualStyle sstyle)
 | |
|         {
 | |
|             if (IsInnerSliceLabelVisible(pieChart, psp) == true)
 | |
|             {
 | |
|                 SliceInnerLabelVisualStyle lstyle = sstyle.SliceInnerLabelStyle;
 | |
| 
 | |
|                 psp.InnerLabelDisplayed = false;
 | |
| 
 | |
|                 string text = GetSliceLabel(pieChart, psp, true, psp.InnerSliceLabelEx);
 | |
| 
 | |
|                 ChartControl chartControl = ChartControl;
 | |
| 
 | |
|                 bool displayed = true;
 | |
| 
 | |
|                 if (chartControl.DoRenderSliceInnerLabelEvent(g, pieChart, psp, text, ref displayed) == false)
 | |
|                 {
 | |
|                     if (string.IsNullOrEmpty(text) == false)
 | |
|                     {
 | |
|                         double maxRadius = psp.OuterRadius;
 | |
| 
 | |
|                         if (lstyle.OuterRadiusOffsetBase == OuterRadiusOffsetBase.ExtentRadius)
 | |
|                             maxRadius = psp.InnerRadius + (psp.OuterRadius - psp.InnerRadius) * psp.SliceExtent;
 | |
| 
 | |
|                         SliceLabelOrientation orientation = psp.InnerLabelOrientationEx;
 | |
| 
 | |
|                         switch (orientation)
 | |
|                         {
 | |
|                             case SliceLabelOrientation.Adaptive:
 | |
|                                 psp.InnerLabelDisplayed =
 | |
|                                     RenderAdaptiveLabel(g, pieChart, psp, maxRadius, text, lstyle);
 | |
|                                 break;
 | |
| 
 | |
|                             case SliceLabelOrientation.Custom:
 | |
|                                 psp.InnerLabelDisplayed =
 | |
|                                     RenderCustomLabel(g, pieChart, psp, maxRadius, text, lstyle);
 | |
|                                 break;
 | |
| 
 | |
|                             case SliceLabelOrientation.Parallel:
 | |
|                                 psp.InnerLabelDisplayed =
 | |
|                                     RenderParallelLabel(g, pieChart, psp, maxRadius, text, lstyle);
 | |
|                                 break;
 | |
| 
 | |
|                             case SliceLabelOrientation.Perpendicular:
 | |
|                                 psp.InnerLabelDisplayed =
 | |
|                                     RenderPerpendicularLabel(g, pieChart, psp, maxRadius, text, lstyle);
 | |
|                                 break;
 | |
| 
 | |
|                             default:
 | |
|                                 psp.InnerLabelDisplayed =
 | |
|                                     RenderHorizontalLabel(g, pieChart, psp, maxRadius, text, lstyle);
 | |
|                                 break;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 psp.LastPathBounds = Rectangle.Empty;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region IsInnerSliceLabelVisible
 | |
| 
 | |
|         private bool IsInnerSliceLabelVisible(PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             switch (psp.SliceLabelDisplayModeEx)
 | |
|             {
 | |
|                 case SliceLabelDisplayMode.NotSet:
 | |
| 
 | |
|                 case SliceLabelDisplayMode.Inner:
 | |
|                 case SliceLabelDisplayMode.InnerAndOuter:
 | |
|                 case SliceLabelDisplayMode.InnerXorOuter:
 | |
|                     return (IsLabelDisplayed(pieChart, psp));
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region IsLabelDisplayed
 | |
| 
 | |
|         internal bool IsLabelDisplayed(PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             SliceLabelVisibility labVis = psp.SliceLabelVisibilityEx;
 | |
| 
 | |
|             if ((labVis == SliceLabelVisibility.NotSet) ||
 | |
|                 (labVis & SliceLabelVisibility.Always) == SliceLabelVisibility.Always)
 | |
|                 return (true);
 | |
| 
 | |
|             if ((labVis & SliceLabelVisibility.Never) == SliceLabelVisibility.Never)
 | |
|                 return (false);
 | |
| 
 | |
|             if (pieChart.ShowSliceLabelsOnEntry == true && pieChart.IsMouseOver == true)
 | |
|                 return (true);
 | |
| 
 | |
|             if ((labVis & SliceLabelVisibility.SliceMouseOver) == SliceLabelVisibility.SliceMouseOver)
 | |
|             {
 | |
|                 if (psp == pieChart.HitPsp)
 | |
|                     return (true);
 | |
|             }
 | |
| 
 | |
|             if (((labVis & SliceLabelVisibility.SelectionModeMouseOver) == SliceLabelVisibility.SelectionModeMouseOver) ||
 | |
|                 ((labVis & SliceLabelVisibility.SliceMouseOver) == SliceLabelVisibility.SliceMouseOver))
 | |
|             {
 | |
|                 if (IsHighLightedPsp(pieChart, psp) == true)
 | |
|                     return (true);
 | |
|             }
 | |
| 
 | |
|             if ((labVis & SliceLabelVisibility.SliceSelect) == SliceLabelVisibility.SliceSelect)
 | |
|             {
 | |
|                 if (psp.IsSelected == true)
 | |
|                     return (true);
 | |
|             }
 | |
| 
 | |
|             if ((labVis & SliceLabelVisibility.SliceDetach) == SliceLabelVisibility.SliceDetach)
 | |
|             {
 | |
|                 if (psp.IsDetached == true)
 | |
|                     return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderAdaptiveLabel
 | |
| 
 | |
|         internal bool RenderAdaptiveLabel(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, double maxRadius, string text, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double innerOffset = GetLableInnerOffset(psp, maxRadius, lstyle);
 | |
|             double outerOffset = GetLableOuterOffset(psp, maxRadius, lstyle);
 | |
| 
 | |
|             if (outerOffset - innerOffset > 0)
 | |
|             {
 | |
|                 double centerAngle = psp.CenterAngle % 360;
 | |
| 
 | |
|                 float fontAngle = 0;
 | |
| 
 | |
|                 if (lstyle.AutoOrientLabel != Tbool.False)
 | |
|                 {
 | |
|                     if (centerAngle < 180)
 | |
|                         fontAngle += 180;
 | |
|                 }
 | |
| 
 | |
|                 float c = (float)(Math.PI * outerOffset * 2);
 | |
| 
 | |
|                 if (c > 0)
 | |
|                 {
 | |
|                     RectangleF[] cBounds = GetAdaptiveCharBounds(g, psp, text, lstyle);
 | |
| 
 | |
|                     if (centerAngle < 180)
 | |
|                     {
 | |
|                         return (PaintAdaptiveFlipText(g, pieChart, psp,
 | |
|                             outerOffset, innerOffset, fontAngle, text, cBounds, lstyle));
 | |
|                     }
 | |
| 
 | |
|                     return (PaintAdaptiveText(g, pieChart, psp,
 | |
|                         outerOffset, innerOffset, fontAngle, text, cBounds, lstyle));
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region GetAdaptiveCharBounds
 | |
| 
 | |
|         private RectangleF[] GetAdaptiveCharBounds(Graphics g,
 | |
|             PieSeriesPoint psp, string text, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             RectangleF[] charBounds = psp.CharBounds;
 | |
| 
 | |
|             if (charBounds == null || charBounds.Length < text.Length)
 | |
|             {
 | |
|                 charBounds = new RectangleF[text.Length];
 | |
| 
 | |
|                 int n = (int)Math.Ceiling((double)text.Length / 32);
 | |
| 
 | |
|                 using (StringFormat sf = new StringFormat())
 | |
|                 {
 | |
|                     sf.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.MeasureTrailingSpaces;
 | |
| 
 | |
|                     for (int i = 0; i < text.Length; i += 32)
 | |
|                     {
 | |
|                         int len = 32;
 | |
| 
 | |
|                         if (i + len > text.Length)
 | |
|                             len = text.Length - i;
 | |
| 
 | |
|                         MeasureAdaptiveText(g, sf, text, i, len, charBounds, lstyle);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 psp.CharBounds = charBounds;
 | |
|             }
 | |
| 
 | |
|             return (charBounds); 
 | |
|         }
 | |
| 
 | |
|         #region MeasureAdaptiveText
 | |
| 
 | |
|         private void MeasureAdaptiveText(Graphics g, StringFormat sf,
 | |
|             string text, int index, int len, RectangleF[] charBounds, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             CharacterRange[] crs = new CharacterRange[len];
 | |
| 
 | |
|             string s = text.Substring(index, len);
 | |
| 
 | |
|             for (int j = 0; j < len; j++)
 | |
|                 crs[j] = new CharacterRange(j, 1);
 | |
| 
 | |
|             sf.SetMeasurableCharacterRanges(crs);
 | |
| 
 | |
|             Rectangle r = new Rectangle(0, 0, 5000, 5000);
 | |
|             Region[] rgns = g.MeasureCharacterRanges(s, lstyle.Font, r, sf);
 | |
| 
 | |
|             for (int i = 0; i < len; i++)
 | |
|                 charBounds[index + i] = rgns[i].GetBounds(g);
 | |
| 
 | |
|             if (index > 0)
 | |
|             {
 | |
|                 float dx = charBounds[index - 1].X + charBounds[index - 1].Width - charBounds[index].X;
 | |
| 
 | |
|                 for (int i = 0; i < len; i++)
 | |
|                     charBounds[index + i].X += dx;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PaintAdaptiveText
 | |
| 
 | |
|         private bool PaintAdaptiveText(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, double outerOffset, double innerOffset,
 | |
|             float fontAngle, string text, RectangleF[] cBounds, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             bool clipped;
 | |
|             List<WordPosLine> wpsLines =
 | |
|                 GetAdaptiveLines(psp, outerOffset, innerOffset, text, cBounds, out clipped, lstyle);
 | |
| 
 | |
|             if (wpsLines != null && wpsLines.Count > 0)
 | |
|             {
 | |
|                 psp.InnerLabelClipped = clipped;
 | |
| 
 | |
|                 if (clipped == true)
 | |
|                 {
 | |
|                     if (psp.SliceLabelCropModeEx == SliceLabelCropMode.Hide)
 | |
|                         return (false);
 | |
|                 }
 | |
| 
 | |
|                 double startAngle;
 | |
|                 double endAngle;
 | |
|                 NormalizeSliceAngles(psp, out startAngle, out endAngle);
 | |
| 
 | |
|                 double startRadians = MathHelper.ToRadians((float)(startAngle + lstyle.AngleMargin));
 | |
|                 double endRadians = MathHelper.ToRadians((float)(endAngle - lstyle.AngleMargin));
 | |
| 
 | |
|                 if (startRadians < endRadians)
 | |
|                 {
 | |
|                     TextRenderingHint renderingHint = g.TextRenderingHint;
 | |
|                     g.TextRenderingHint = TextRenderingHint.AntiAlias;
 | |
| 
 | |
|                     float height = cBounds[0].Height;
 | |
|                     float halfHeight = height / 2;
 | |
| 
 | |
|                     using (Brush br = new SolidBrush(lstyle.TextColor))
 | |
|                     {
 | |
|                         foreach (WordPosLine wpsLine in wpsLines)
 | |
|                         {
 | |
|                             double offset = wpsLine.Offset;
 | |
| 
 | |
|                             if (wpsLine.Wps.Count > 0)
 | |
|                             {
 | |
|                                 double dx = GetAlignmentOffset(wpsLine, cBounds, lstyle);
 | |
|                                 double xRadians = startRadians + (dx / offset);
 | |
| 
 | |
|                                 foreach (WordPos wp in wpsLine.Wps)
 | |
|                                 {
 | |
|                                     for (int j = 0; j < wp.Text.Length; j++)
 | |
|                                     {
 | |
|                                         RectangleF tf = cBounds[wp.Index + j];
 | |
| 
 | |
|                                         float cRadians = (float)(tf.Width / offset);
 | |
| 
 | |
|                                         if (xRadians + cRadians > (float)endRadians + .5)
 | |
|                                             break;
 | |
| 
 | |
|                                         xRadians += (cRadians / 2);
 | |
| 
 | |
|                                         float z = (float)(offset - halfHeight);
 | |
|                                         float y = (float)(psp.SliceCenter.Y + z * Math.Sin(xRadians));
 | |
|                                         float x = (float)(psp.SliceCenter.X + z * Math.Cos(xRadians));
 | |
| 
 | |
|                                         int n = (int)Math.Max(tf.Width, tf.Height);
 | |
| 
 | |
|                                         GraphicsState gState = g.Save();
 | |
| 
 | |
|                                         g.TranslateTransform(x, y);
 | |
|                                         g.RotateTransform(90 + (float)MathHelper.ToDegrees((float)xRadians));
 | |
| 
 | |
|                                         g.DrawString(wp.Text[j].ToString(), lstyle.Font, br, -tf.Width/2, -tf.Height / 2);
 | |
| 
 | |
|                                         g.Restore(gState);
 | |
| 
 | |
|                                         xRadians += (cRadians / 2);
 | |
|                                     }
 | |
| 
 | |
|                                     if (wp.Index + wp.Length < cBounds.Length)
 | |
|                                         xRadians += cBounds[wp.Index + wp.Length].Width / offset;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     if ((outerOffset > psp.OuterRadius) || 
 | |
|                         (wpsLines[wpsLines.Count - 1].Offset < psp.InnerRadius))
 | |
|                     {
 | |
|                         Rectangle t = GetBoundingArcRect(
 | |
|                             psp, startAngle, endAngle, outerOffset + height);
 | |
| 
 | |
|                         psp.PathBounds = Rectangle.Union(psp.PathBounds, t);
 | |
| 
 | |
|                         if (psp.PathBounds.Equals(psp.LastPathBounds) == false)
 | |
|                         {
 | |
|                             psp.LastPathBounds = psp.PathBounds;
 | |
| 
 | |
|                             InvalidateRender(psp.PathBounds);
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     g.TextRenderingHint = renderingHint;
 | |
| 
 | |
|                     return (true);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region GetBoundingArcRect
 | |
| 
 | |
|         private Rectangle GetBoundingArcRect(
 | |
|             PieSeriesPoint psp, double startAngle, double endAngle, double outerOffset)
 | |
|         {
 | |
|             Rectangle r = new Rectangle(psp.SliceCenter, Size.Empty);
 | |
| 
 | |
|             double n = startAngle;
 | |
| 
 | |
|             n += 89;
 | |
|             n = (int)(n / 90) * 90;
 | |
| 
 | |
|             while (n <= endAngle)
 | |
|             {
 | |
|                 UpdateAngleBounds(psp, n, outerOffset, ref r);
 | |
| 
 | |
|                 n += 90;
 | |
|             }
 | |
| 
 | |
|             if (startAngle % 90 != 0)
 | |
|                 UpdateAngleBounds(psp, startAngle, outerOffset, ref r);
 | |
| 
 | |
|             if (endAngle % 90 != 0)
 | |
|                 UpdateAngleBounds(psp, endAngle, outerOffset, ref r);
 | |
| 
 | |
|             return (r);
 | |
|         }
 | |
| 
 | |
|         #region UpdateAngleBounds
 | |
| 
 | |
|         private void UpdateAngleBounds(PieSeriesPoint psp,
 | |
|             double angle, double outerOffset, ref Rectangle r)
 | |
|         {
 | |
|             Point pts = psp.GetRayEndPoint(angle, outerOffset);
 | |
| 
 | |
|             if (pts.X < r.X)
 | |
|             {
 | |
|                 r.Width += (r.X - pts.X);
 | |
|                 r.X = pts.X;
 | |
|             }
 | |
|             else if (pts.X > r.Right)
 | |
|             {
 | |
|                 r.Width += (pts.X - r.Right);
 | |
|             }
 | |
| 
 | |
|             if (pts.Y < r.Y)
 | |
|             {
 | |
|                 r.Height += (r.Y - pts.Y);
 | |
|                 r.Y = pts.Y;
 | |
|             }
 | |
|             else if (pts.Y > r.Bottom)
 | |
|             {
 | |
|                 r.Height += (pts.Y - r.Bottom);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetAdaptiveLines
 | |
| 
 | |
|         private List<WordPosLine> GetAdaptiveLines(
 | |
|             PieSeriesPoint psp, double outerOffset, double innerOffset,
 | |
|             string text, RectangleF[] cBounds, out bool clipped, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             if (psp.WordPosLines == null)
 | |
|             {
 | |
|                 psp.WordPosLines =
 | |
|                     GetAdaptiveLinesEx(psp, outerOffset, innerOffset, text, cBounds, out clipped, lstyle);
 | |
| 
 | |
|                 psp.InnerLabelClipped = clipped;
 | |
|             }
 | |
| 
 | |
|             clipped = psp.InnerLabelClipped;
 | |
| 
 | |
|             return (psp.WordPosLines);
 | |
|         }
 | |
| 
 | |
|         #region GetAdaptiveLinesEx
 | |
| 
 | |
|         private List<WordPosLine> GetAdaptiveLinesEx(
 | |
|             PieSeriesPoint psp, double outerOffset, double innerOffset, string text,
 | |
|             RectangleF[] cBounds, out bool clipped, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             float height = cBounds[0].Height;
 | |
|             int maxLineCount = (int)((outerOffset - innerOffset) / height);
 | |
| 
 | |
|             SliceLabelCropMode cropMode = psp.SliceLabelCropModeEx;
 | |
| 
 | |
|             if (cropMode != SliceLabelCropMode.Hide)
 | |
|                 maxLineCount = 1000;
 | |
| 
 | |
|             if (lstyle.MaxLineCount >= 0)
 | |
|             {
 | |
|                 if (maxLineCount > lstyle.MaxLineCount)
 | |
|                     maxLineCount = lstyle.MaxLineCount;
 | |
|             }
 | |
| 
 | |
|             List<WordPosLine> wpsLines = null;
 | |
| 
 | |
|             if (maxLineCount > 0)
 | |
|             {
 | |
|                 List<WordPos> wps = GetWordWidths(text, cBounds);
 | |
| 
 | |
|                 double offset = outerOffset;
 | |
| 
 | |
|                 bool middle = false;
 | |
| 
 | |
|                 switch (lstyle.Alignment)
 | |
|                 {
 | |
|                     case SliceLabelAlignment.MiddleLeft:
 | |
|                     case SliceLabelAlignment.MiddleRight:
 | |
|                     case SliceLabelAlignment.MiddleCenter:
 | |
|                         offset = (outerOffset + innerOffset) / 2;
 | |
|                         middle = true;
 | |
|                         break;
 | |
| 
 | |
|                     case SliceLabelAlignment.InnerLeft:
 | |
|                     case SliceLabelAlignment.InnerRight:
 | |
|                     case SliceLabelAlignment.InnerCenter:
 | |
| 
 | |
|                         clipped = false;
 | |
| 
 | |
|                         while (offset > innerOffset)
 | |
|                         {
 | |
|                             List<WordPosLine> ilines = FitAdaptiveLines(psp,
 | |
|                                 offset, -height, cBounds, maxLineCount, wps, out clipped, lstyle);
 | |
| 
 | |
|                             if (ilines != null)
 | |
|                             {
 | |
|                                 if (wpsLines == null || clipped == false)
 | |
|                                     wpsLines = ilines;
 | |
| 
 | |
|                                 if (clipped == true)
 | |
|                                     break;
 | |
| 
 | |
|                                 wps = GetWordWidths(text, cBounds);
 | |
| 
 | |
|                                 offset -= height;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 break;
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         return (wpsLines);
 | |
| 
 | |
|                     default:
 | |
|                         List<WordPosLine> lines = FitAdaptiveLines(psp,
 | |
|                             offset, -height, cBounds, maxLineCount, wps, out clipped, lstyle);
 | |
| 
 | |
|                         return (lines);
 | |
|                 }
 | |
| 
 | |
|                 for (int i = 0; i < maxLineCount; i++)
 | |
|                 {
 | |
|                     List<WordPosLine> lines = FitAdaptiveLines(psp,
 | |
|                         offset, -height, cBounds, (i + 1), wps, out clipped, lstyle);
 | |
| 
 | |
|                     if (lines != null)
 | |
|                     {
 | |
|                         if (clipped == false)
 | |
|                             return (lines);
 | |
| 
 | |
|                         wpsLines = lines;
 | |
| 
 | |
|                         wps = GetWordWidths(text, cBounds);
 | |
| 
 | |
|                         if ((middle == false) || (i % 2 == 0))
 | |
|                             offset += height;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             clipped = false;
 | |
| 
 | |
|             return (wpsLines);
 | |
|         }
 | |
| 
 | |
|         #region FitAdaptiveLines
 | |
| 
 | |
|         private List<WordPosLine> FitAdaptiveLines(
 | |
|             PieSeriesPoint psp, double offset, float height, RectangleF[] cBounds,
 | |
|             int count, List<WordPos> wps, out bool clipped, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             List<WordPosLine> wpsLines = new List<WordPosLine>();
 | |
| 
 | |
|             int wordIndex = 0;
 | |
| 
 | |
|             while (wpsLines.Count < count)
 | |
|             {
 | |
|                 int lineWordCount = 0;
 | |
| 
 | |
|                 double arcWidth = GetArcWidth(psp, offset - cBounds[0].Height / 4, lstyle);
 | |
| 
 | |
|                 if (arcWidth <= 0)
 | |
|                     break;
 | |
| 
 | |
|                 WordPosLine wpsLine = new WordPosLine();
 | |
| 
 | |
|                 wpsLine.Offset = offset;
 | |
|                 wpsLine.ArcWidth = arcWidth;
 | |
| 
 | |
|                 while (wordIndex < wps.Count)
 | |
|                 {
 | |
|                     WordPos wp = wps[wordIndex];
 | |
| 
 | |
|                     double wordLength = GetWordLength(wp, cBounds, lineWordCount);
 | |
| 
 | |
|                     if (wp.Text.Equals("\n") == true)
 | |
|                     {
 | |
|                         if (wpsLine.Wps.Count == 0)
 | |
|                             wpsLine.Wps.Add(wp);
 | |
| 
 | |
|                         wordIndex++;
 | |
|                         break;
 | |
|                     }
 | |
| 
 | |
|                     if (wpsLine.ArcWidth - (wpsLine.LineWidth + wordLength) < 0)
 | |
|                     {
 | |
|                         if (lineWordCount == 0 || wpsLines.Count + 1 == count)
 | |
|                         {
 | |
|                             wpsLine = FitNonBrokenLine(psp, offset,
 | |
|                                 count - wpsLines.Count, wpsLines, wpsLine, wp, cBounds, height, out clipped, lstyle);
 | |
| 
 | |
|                             if (clipped == true || wpsLine == null)
 | |
|                             {
 | |
|                                 if (wpsLine != null && wpsLine.Wps.Count > 0)
 | |
|                                     wpsLines.Add(wpsLine);
 | |
| 
 | |
|                                 return (wpsLines);
 | |
|                             }
 | |
| 
 | |
|                             offset = wpsLine.Offset;
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             break;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         wpsLine.LineWidth += wordLength;
 | |
| 
 | |
|                         wpsLine.Wps.Add(wp);
 | |
|                     }
 | |
| 
 | |
|                     wordIndex++;
 | |
|                     lineWordCount++;
 | |
|                 }
 | |
| 
 | |
|                 if (wpsLine.Wps.Count > 0)
 | |
|                 {
 | |
|                     offset = wpsLine.Offset;
 | |
| 
 | |
|                     wpsLines.Add(wpsLine);
 | |
|                 }
 | |
| 
 | |
|                 if (wordIndex >= wps.Count)
 | |
|                     break;
 | |
| 
 | |
|                 offset += height;
 | |
|             }
 | |
| 
 | |
|             clipped = (wordIndex < wps.Count);
 | |
| 
 | |
|             return (wpsLines);
 | |
|         }
 | |
| 
 | |
|         #region FitNonBrokenLine
 | |
| 
 | |
|         private WordPosLine FitNonBrokenLine(PieSeriesPoint psp,
 | |
|             double offset, int maxCount, List<WordPosLine> wpsLines, WordPosLine wpsLine,
 | |
|             WordPos wp, RectangleF[] cBounds, float height, out bool clipped, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double length;
 | |
|             int count = GetNonBrokenCount(wpsLine, wp, cBounds, out length);
 | |
| 
 | |
|             clipped = true;
 | |
| 
 | |
|             if (length == 0)
 | |
|                 return (wpsLine);
 | |
| 
 | |
|             int rindex = wp.Index;
 | |
| 
 | |
|             while (count > 0)
 | |
|             {
 | |
|                 WordPos wp2 = new WordPos();
 | |
| 
 | |
|                 wp2.Index = wp.Index;
 | |
|                 wp2.Length = count;
 | |
|                 wp2.Text = wp.Text.Substring((wp.Index - rindex), count);
 | |
| 
 | |
|                 wpsLine.Wps.Add(wp2);
 | |
| 
 | |
|                 wp.Index += count;
 | |
|                 wp.Length -= count;
 | |
| 
 | |
|                 if (--maxCount <= 0)
 | |
|                     break;
 | |
| 
 | |
|                 if (wp.Length <= 0)
 | |
|                     break;
 | |
| 
 | |
|                 wpsLines.Add(wpsLine);
 | |
| 
 | |
|                 offset += height;
 | |
| 
 | |
|                 wpsLine = new WordPosLine();
 | |
|                 wpsLine.Offset = offset;
 | |
| 
 | |
|                 wpsLine.ArcWidth = GetArcWidth(psp, offset - cBounds[0].Height / 4, lstyle);
 | |
| 
 | |
|                 count = GetNonBrokenCount(wpsLine, wp, cBounds, out length);
 | |
|             }
 | |
| 
 | |
|             clipped = (wp.Length > 0);
 | |
| 
 | |
|             return (wpsLine);
 | |
|         }
 | |
| 
 | |
|         #region GetNonBrokenCount
 | |
| 
 | |
|         private int GetNonBrokenCount(
 | |
|             WordPosLine wpsLine, WordPos wp, RectangleF[] cBounds, out double length)
 | |
|         {
 | |
|             length = 0;
 | |
| 
 | |
|             if (wpsLine.Wps.Count > 0 && wp.Index > 0)
 | |
|             {
 | |
|                 double width = cBounds[wp.Index - 1].Width;
 | |
| 
 | |
|                 if (wpsLine.ArcWidth - (wpsLine.LineWidth + width) < 0)
 | |
|                     return (0);
 | |
| 
 | |
|                 wpsLine.LineWidth += width;
 | |
|                 length += width;
 | |
|             }
 | |
| 
 | |
|             for (int i = 0; i < wp.Length; i++)
 | |
|             {
 | |
|                 double width = cBounds[wp.Index + i].Width;
 | |
| 
 | |
|                 if (wpsLine.ArcWidth - (wpsLine.LineWidth + width) < 0)
 | |
|                     return (i);
 | |
| 
 | |
|                 wpsLine.LineWidth += width;
 | |
|                 length += width;
 | |
|             }
 | |
| 
 | |
|             return (wp.Length);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PaintAdaptiveFlipText
 | |
| 
 | |
|         private bool PaintAdaptiveFlipText(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, double outerOffset, double innerOffset, float fontAngle,
 | |
|             string text, RectangleF[] cBounds, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             bool clipped;
 | |
|             List<WordPosLine> wpsLines =
 | |
|                 GetAdaptiveFlipLines(psp, outerOffset, innerOffset, text, cBounds, out clipped, lstyle);
 | |
| 
 | |
|             if (wpsLines != null && wpsLines.Count > 0)
 | |
|             {
 | |
|                 if (clipped == true)
 | |
|                 {
 | |
|                     if (psp.SliceLabelCropModeEx == SliceLabelCropMode.Hide)
 | |
|                         return (false);
 | |
|                 }
 | |
| 
 | |
|                 double startAngle;
 | |
|                 double endAngle;
 | |
|                 NormalizeSliceAngles(psp, out startAngle, out endAngle);
 | |
| 
 | |
|                 double endRadians = MathHelper.ToRadians(startAngle + lstyle.AngleMargin);
 | |
|                 double startRadians = MathHelper.ToRadians(endAngle - lstyle.AngleMargin);
 | |
| 
 | |
|                 float height = cBounds[0].Height;
 | |
|                 float halfHeight = height / 2;
 | |
| 
 | |
|                 TextRenderingHint renderingHint = g.TextRenderingHint;
 | |
|                 g.TextRenderingHint = TextRenderingHint.AntiAlias;
 | |
| 
 | |
|                 using (Brush br = new SolidBrush(lstyle.TextColor))
 | |
|                 {
 | |
|                     foreach (WordPosLine wpsLine in wpsLines)
 | |
|                     {
 | |
|                         double offset = wpsLine.Offset;
 | |
| 
 | |
|                         if (wpsLine.Wps.Count > 0)
 | |
|                         {
 | |
|                             double dx = GetAlignmentOffset(wpsLine, cBounds, lstyle);
 | |
|                             double xRadians = startRadians - dx / offset;
 | |
| 
 | |
|                             foreach (WordPos wp in wpsLine.Wps)
 | |
|                             {
 | |
|                                 for (int j = 0; j < wp.Text.Length; j++)
 | |
|                                 {
 | |
|                                     if (xRadians < (float)endRadians)
 | |
|                                         break;
 | |
| 
 | |
|                                     RectangleF tf = cBounds[wp.Index + j];
 | |
| 
 | |
|                                     float cRadians = (float)(tf.Width / offset);
 | |
| 
 | |
|                                     xRadians -= (cRadians / 2);
 | |
| 
 | |
|                                     float z = (float)(offset - halfHeight);
 | |
|                                     float y = (float)((float)psp.SliceCenter.Y + z * Math.Sin(xRadians));
 | |
|                                     float x = (float)((float)psp.SliceCenter.X + z * Math.Cos(xRadians));
 | |
| 
 | |
|                                     GraphicsState gState = g.Save();
 | |
| 
 | |
|                                     g.TranslateTransform(x, y);
 | |
|                                     g.RotateTransform(-90 + (float)MathHelper.ToDegrees(xRadians));
 | |
| 
 | |
|                                     g.DrawString(wp.Text[j].ToString(), lstyle.Font, br, -tf.Width / 2, -tf.Height / 2);
 | |
| 
 | |
|                                     g.Restore(gState);
 | |
| 
 | |
|                                     xRadians -= (cRadians / 2);
 | |
|                                 }
 | |
| 
 | |
|                                 if (wp.Index + wp.Length < cBounds.Length)
 | |
|                                     xRadians -= cBounds[wp.Index + wp.Length].Width / offset;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if ((outerOffset > psp.OuterRadius) ||
 | |
|                     (wpsLines.Count > 0 && wpsLines[0].Offset < psp.InnerRadius))
 | |
|                 {
 | |
|                     Rectangle t = GetBoundingArcRect(
 | |
|                         psp, startAngle, endAngle, outerOffset + height);
 | |
| 
 | |
|                     psp.PathBounds = Rectangle.Union(psp.PathBounds, t);
 | |
| 
 | |
|                     if (psp.PathBounds.Equals(psp.LastPathBounds) == false)
 | |
|                     {
 | |
|                         psp.LastPathBounds = psp.PathBounds;
 | |
| 
 | |
|                         InvalidateRender(psp.PathBounds);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 g.TextRenderingHint = renderingHint;
 | |
| 
 | |
|                 return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region GetAdaptiveFlipLines
 | |
| 
 | |
|         private List<WordPosLine> GetAdaptiveFlipLines(
 | |
|             PieSeriesPoint psp, double outerOffset, double innerOffset,
 | |
|             string text, RectangleF[] cBounds, out bool clipped, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             if (psp.WordPosLines == null)
 | |
|             {
 | |
|                 psp.WordPosLines =
 | |
|                     GetAdaptiveFlipLinesEx(psp, outerOffset, innerOffset, text, cBounds, out clipped, lstyle);
 | |
| 
 | |
|                 psp.InnerLabelClipped = clipped;
 | |
|             }
 | |
| 
 | |
|             clipped = psp.InnerLabelClipped;
 | |
| 
 | |
|             return (psp.WordPosLines);
 | |
|         }
 | |
| 
 | |
|         #region GetAdaptiveFlipLinesEx
 | |
| 
 | |
|         private List<WordPosLine> GetAdaptiveFlipLinesEx(
 | |
|             PieSeriesPoint psp, double outerOffset, double innerOffset,
 | |
|             string text, RectangleF[] cBounds, out bool clipped, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             float height = cBounds[0].Height;
 | |
|             int maxLineCount = (int)Math.Abs((outerOffset - innerOffset) / height);
 | |
| 
 | |
|             SliceLabelCropMode cropMode = psp.SliceLabelCropModeEx;
 | |
| 
 | |
|             if (cropMode == SliceLabelCropMode.NoAction)
 | |
|                 maxLineCount = 1000;
 | |
| 
 | |
|             if (lstyle.MaxLineCount >= 0)
 | |
|             {
 | |
|                 if (maxLineCount > lstyle.MaxLineCount)
 | |
|                     maxLineCount = lstyle.MaxLineCount;
 | |
|             }
 | |
| 
 | |
|             List<WordPosLine> wpsLines = null;
 | |
| 
 | |
|             clipped = false;
 | |
| 
 | |
|             if (maxLineCount > 0)
 | |
|             {
 | |
|                 List<WordPos> wps = GetWordWidths(text, cBounds);
 | |
| 
 | |
|                 double offset = outerOffset;
 | |
| 
 | |
|                 bool middle = false;
 | |
| 
 | |
|                 switch (lstyle.Alignment)
 | |
|                 {
 | |
|                     case SliceLabelAlignment.MiddleLeft:
 | |
|                     case SliceLabelAlignment.MiddleRight:
 | |
|                     case SliceLabelAlignment.MiddleCenter:
 | |
|                         offset = (outerOffset + innerOffset) / 2;
 | |
|                         height = -height;
 | |
|                         middle = true;
 | |
|                         break;
 | |
| 
 | |
|                     case SliceLabelAlignment.InnerLeft:
 | |
|                     case SliceLabelAlignment.InnerRight:
 | |
|                     case SliceLabelAlignment.InnerCenter:
 | |
| 
 | |
|                         clipped = false;
 | |
| 
 | |
|                         offset = innerOffset;
 | |
| 
 | |
|                         while (offset < outerOffset)
 | |
|                         {
 | |
|                             List<WordPosLine> ilines = FitAdaptiveLines(psp,
 | |
|                                 offset, height, cBounds, maxLineCount, wps, out clipped, lstyle);
 | |
| 
 | |
|                             if (ilines != null && ilines.Count > 0)
 | |
|                                 return (ilines);
 | |
| 
 | |
|                             wps = GetWordWidths(text, cBounds);
 | |
| 
 | |
|                             offset += height;
 | |
|                         }
 | |
| 
 | |
|                         return (wpsLines);
 | |
| 
 | |
|                     default:
 | |
|                         height = -height;
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 for (int i = 0; i < maxLineCount; i++)
 | |
|                 {
 | |
|                     List<WordPosLine> lines = FitAdaptiveLines(psp,
 | |
|                         offset, Math.Abs(height), cBounds, i + 1, wps, out clipped, lstyle);
 | |
| 
 | |
|                     if (lines != null)
 | |
|                     {
 | |
|                         if (clipped == false)
 | |
|                             return (lines);
 | |
| 
 | |
|                         wpsLines = lines;
 | |
| 
 | |
|                         wps = GetWordWidths(text, cBounds);
 | |
| 
 | |
|                         if ((middle == false) || (i % 2 == 0))
 | |
|                             offset += height;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (wpsLines);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region NormalizeSliceAngles
 | |
| 
 | |
|         private void NormalizeSliceAngles(
 | |
|             PieSeriesPoint psp, out double startAngle, out double endAngle)
 | |
|         {
 | |
|             startAngle = psp.StartAngleEx;
 | |
|             endAngle = psp.StartAngleEx + psp.SweepAngleEx;
 | |
| 
 | |
|             if (startAngle > endAngle)
 | |
|             {
 | |
|                 double temp = startAngle;
 | |
|                 startAngle = endAngle;
 | |
|                 endAngle = temp;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetArcWidth
 | |
| 
 | |
|         private double GetArcWidth(
 | |
|             PieSeriesPoint psp, double offset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double margin = lstyle.AngleMargin * 2;
 | |
|             double sweep = Math.Abs(psp.SweepAngleEx);
 | |
| 
 | |
|             double width = offset * MathHelper.ToRadians(sweep - margin);
 | |
| 
 | |
|             return (width);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetWordLength
 | |
| 
 | |
|         private double GetWordLength(
 | |
|             WordPos wp, RectangleF[] cBounds, int lineWordCount)
 | |
|         {
 | |
|             double length = 0;
 | |
| 
 | |
|             if (lineWordCount > 0)
 | |
|                 length += cBounds[wp.Index - 1].Width;
 | |
| 
 | |
|             for (int i = 0; i < wp.Length; i++)
 | |
|                 length += cBounds[wp.Index + i].Width;
 | |
| 
 | |
|             return (length);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetWordWidths
 | |
| 
 | |
|         private List<WordPos> GetWordWidths(string text, RectangleF[] cBounds)
 | |
|         {
 | |
|             List<WordPos> wps = new List<WordPos>();
 | |
| 
 | |
|             int index = 0;
 | |
| 
 | |
|             while (index < text.Length)
 | |
|             {
 | |
|                 int length = GetNextWord(text, ref index);
 | |
| 
 | |
|                 if (length > 0)
 | |
|                 {
 | |
|                     WordPos wp = new WordPos();
 | |
| 
 | |
|                     wp.Index = index;
 | |
|                     wp.Length = length;
 | |
|                     wp.Text = text.Substring(index, length);
 | |
| 
 | |
|                     wps.Add(wp);
 | |
| 
 | |
|                     index += length;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (wps);
 | |
|         }
 | |
| 
 | |
|         #region GetNextWord
 | |
| 
 | |
|         private int GetNextWord(string text, ref int index)
 | |
|         {
 | |
|             while (index < text.Length)
 | |
|             {
 | |
|                 if (text[index] == '\n')
 | |
|                     return (1);
 | |
| 
 | |
|                 if (Char.IsWhiteSpace(text[index]) == false)
 | |
|                     break;
 | |
| 
 | |
|                 index++;
 | |
|             }
 | |
| 
 | |
|             int eindex = index;
 | |
| 
 | |
|             while (eindex < text.Length)
 | |
|             {
 | |
|                 if (Char.IsWhiteSpace(text[eindex]) == true)
 | |
|                     break;
 | |
| 
 | |
|                 eindex++;
 | |
|             }
 | |
| 
 | |
|             return (eindex - index);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetAlignmentOffset
 | |
| 
 | |
|         private double GetAlignmentOffset(
 | |
|             WordPosLine wpsLine, RectangleF[] tbounds, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             switch (lstyle.Alignment)
 | |
|             {
 | |
|                 case SliceLabelAlignment.OuterRight:
 | |
|                 case SliceLabelAlignment.MiddleRight:
 | |
|                 case SliceLabelAlignment.InnerRight:
 | |
|                     return (wpsLine.ArcWidth - wpsLine.LineWidth);
 | |
| 
 | |
|                 case SliceLabelAlignment.OuterCenter:
 | |
|                 case SliceLabelAlignment.MiddleCenter:
 | |
|                 case SliceLabelAlignment.InnerCenter:
 | |
|                     return ((wpsLine.ArcWidth - wpsLine.LineWidth) / 2);
 | |
| 
 | |
|                 default:
 | |
|                     return (0);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderCustomLabel
 | |
| 
 | |
|         internal bool RenderCustomLabel(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, double maxRadius, string text,SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double angle = GetCustomLabelAngle(psp, lstyle);
 | |
|             double offset = GetCustomLableOffset(psp, maxRadius, lstyle);
 | |
| 
 | |
|             Rectangle r = GetCustomLabelRect(psp, maxRadius, angle, offset, lstyle);
 | |
| 
 | |
|             angle += lstyle.CustomFontAngle;
 | |
| 
 | |
|             if (lstyle.AutoRotate != Tbool.True)
 | |
|                 angle -= (psp.CenterAngle - 90);
 | |
| 
 | |
|             angle = (angle + 360000) % 360;
 | |
| 
 | |
|             double fontAngle = 0;
 | |
| 
 | |
|             if (lstyle.AutoOrientLabel != Tbool.False)
 | |
|             {
 | |
|                 if (angle < 180)
 | |
|                     fontAngle += 180;
 | |
|             }
 | |
| 
 | |
|             r = GetSliceLabelBounds(g, pieChart, psp, text, r, lstyle);
 | |
| 
 | |
|             if (r.Width > 0 && r.Height > 0)
 | |
|             {
 | |
|                 GraphicsState gState = g.Save();
 | |
| 
 | |
|                 TextRenderingHint renderingHint = g.TextRenderingHint;
 | |
|                 g.TextRenderingHint = TextRenderingHint.AntiAlias;
 | |
| 
 | |
|                 using (StringFormat sf = new StringFormat())
 | |
|                 {
 | |
|                     lstyle.GetStringFormatFlags(sf, angle < 180);
 | |
| 
 | |
|                     g.TranslateTransform(r.X, r.Y);
 | |
|                     g.RotateTransform((float)(angle + fontAngle + 90));
 | |
| 
 | |
|                     r.X = -(int)(r.Width / 2);
 | |
|                     r.Y = -(int)(r.Height / 2);
 | |
| 
 | |
|                     if (lstyle.Background.IsEmpty == false)
 | |
|                     {
 | |
|                         using (Brush br = lstyle.Background.GetBrush(r))
 | |
|                             g.FillRectangle(br, r);
 | |
|                     }
 | |
| 
 | |
|                     using (Brush br = new SolidBrush(lstyle.TextColor))
 | |
|                         g.DrawString(text, lstyle.Font, br, r, sf);
 | |
| 
 | |
|                     if (ChartControl.DesignerHosted == true)
 | |
|                     {
 | |
|                         using (Pen pen = new Pen(Color.Plum))
 | |
|                         {
 | |
|                             pen.DashStyle = DashStyle.Dash;
 | |
| 
 | |
|                             g.DrawRectangle(pen, r);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 g.Restore(gState);
 | |
| 
 | |
|                 return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region GetCustomLabelRect
 | |
| 
 | |
|         private Rectangle GetCustomLabelRect(PieSeriesPoint psp,
 | |
|             double maxRadius, double angle, double offset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             Rectangle r = new Rectangle();
 | |
| 
 | |
|             r.Location = psp.GetRayEndPoint(angle, offset);
 | |
| 
 | |
|             r.Width = (int)GetCustomLabelWidth(psp, offset, lstyle);
 | |
|             r.Height = (int)GetCustomLabelHeight(psp, maxRadius, offset, lstyle);
 | |
| 
 | |
|             return (r);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetCustomLabelHeight
 | |
| 
 | |
|         private double GetCustomLabelHeight(PieSeriesPoint psp,
 | |
|             double maxRadius, double offset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double height = maxRadius - psp.InnerRadius;
 | |
| 
 | |
|             if (double.IsNaN(lstyle.CustomHeight) == false)
 | |
|             {
 | |
|                 if (Math.Abs(lstyle.CustomHeight) < 1)
 | |
|                     return (lstyle.CustomHeight * height);
 | |
| 
 | |
|                 return (lstyle.CustomHeight);
 | |
|             }
 | |
| 
 | |
|             return (height * .5);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetCustomLabelWidth
 | |
| 
 | |
|         private double GetCustomLabelWidth(
 | |
|             PieSeriesPoint psp, double offset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double width = GetArcWidth(psp, offset, lstyle);
 | |
| 
 | |
|             if (double.IsNaN(lstyle.CustomWidth) == false)
 | |
|             {
 | |
|                 if (Math.Abs(lstyle.CustomWidth) < 1)
 | |
|                     return (lstyle.CustomWidth * width);
 | |
| 
 | |
|                 return (lstyle.CustomWidth);
 | |
|             }
 | |
| 
 | |
|             return (width * .8);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetCustomLableOffset
 | |
| 
 | |
|         private double GetCustomLableOffset(
 | |
|             PieSeriesPoint psp, double maxRadius, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double offset = lstyle.CustomRadiusOffset;
 | |
| 
 | |
|             if (double.IsNaN(offset) == false)
 | |
|             {
 | |
|                 if (Math.Abs(offset) < 1)
 | |
|                     offset = (maxRadius - psp.InnerRadius) * offset;
 | |
| 
 | |
|                 return (psp.InnerRadius + offset);
 | |
|             }
 | |
| 
 | |
|             return (psp.InnerRadius + (maxRadius - psp.InnerRadius) * .7);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetCustomLabelAngle
 | |
| 
 | |
|         private double GetCustomLabelAngle(PieSeriesPoint psp, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double angle = (psp.StartAngleEx + psp.SweepAngleEx / 2) % 360;
 | |
| 
 | |
|             if (double.IsNaN(lstyle.CustomAngleOffset) == false)
 | |
|             {
 | |
|                 double offset = lstyle.CustomAngleOffset;
 | |
| 
 | |
|                 if (Math.Abs(offset) < 1)
 | |
|                     angle += (psp.SweepAngleEx * offset);
 | |
|                 else
 | |
|                     angle += offset;
 | |
|             }
 | |
| 
 | |
|             return (angle);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderParallelLabel
 | |
| 
 | |
|         internal bool RenderParallelLabel(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, double maxRadius, string text, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double centerAngle = psp.CenterAngle % 360;
 | |
| 
 | |
|             double innerOffset = GetLableInnerOffset(psp, maxRadius, lstyle);
 | |
|             double outerOffset = GetLableOuterOffset(psp, maxRadius, lstyle);
 | |
| 
 | |
|             float fontAngle = 0;
 | |
| 
 | |
|             if (lstyle.AutoOrientLabel != Tbool.False)
 | |
|             {
 | |
|                 if (centerAngle >= 90 && centerAngle < 270)
 | |
|                     fontAngle += 180;
 | |
|             }
 | |
| 
 | |
|             Point lpt = psp.GetRayEndPoint(
 | |
|                 centerAngle, (innerOffset + outerOffset) / 2);
 | |
| 
 | |
|             Rectangle r = new Rectangle();
 | |
| 
 | |
|             r.Location = lpt;
 | |
|             r.Width = (int)(outerOffset - innerOffset);
 | |
|             r.Height = (int)GetArcWidth(psp, innerOffset, lstyle);
 | |
| 
 | |
|             r = GetSliceLabelBounds(g, pieChart, psp, text, r, lstyle);
 | |
| 
 | |
|             if (r.Width > 0 && r.Height > 0)
 | |
|             {
 | |
|                 GraphicsState gState = g.Save();
 | |
| 
 | |
|                 TextRenderingHint renderingHint = g.TextRenderingHint;
 | |
|                 g.TextRenderingHint = TextRenderingHint.AntiAlias;
 | |
| 
 | |
|                 using (StringFormat sf = new StringFormat())
 | |
|                 {
 | |
|                     GetStringFormatFlags(lstyle, sf, fontAngle != 0);
 | |
| 
 | |
|                     r.X = -(int)(r.Width / 2);
 | |
|                     r.Y = -(int)(r.Height / 2);
 | |
| 
 | |
|                     g.TranslateTransform(lpt.X, lpt.Y);
 | |
|                     g.RotateTransform((float)centerAngle + fontAngle);
 | |
| 
 | |
|                     if (lstyle.Background.IsEmpty == false)
 | |
|                     {
 | |
|                         using (Brush br = lstyle.Background.GetBrush(r))
 | |
|                             g.FillRectangle(br, r);
 | |
|                     }
 | |
| 
 | |
|                     using (Brush br = new SolidBrush(lstyle.TextColor))
 | |
|                         g.DrawString(text, lstyle.Font, br, r, sf);
 | |
|                 }
 | |
| 
 | |
|                 g.Restore(gState);
 | |
| 
 | |
|                 return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region GetStringFormatFlags
 | |
| 
 | |
|         private void GetStringFormatFlags(
 | |
|             SliceInnerLabelVisualStyle lstyle, StringFormat sf, bool flip)
 | |
|         {
 | |
|             if (lstyle.AllowWrap == Tbool.False || lstyle.MaxLineCount == 1)
 | |
|                 sf.FormatFlags |= StringFormatFlags.NoWrap;
 | |
| 
 | |
|             sf.Trimming = StringTrimming.EllipsisCharacter;
 | |
| 
 | |
|             switch (lstyle.Alignment)
 | |
|             {
 | |
|                 case SliceLabelAlignment.OuterLeft:
 | |
|                     sf.Alignment = (flip ? StringAlignment.Near : StringAlignment.Far);     // Outer/inner
 | |
|                     sf.LineAlignment = (flip ? StringAlignment.Far : StringAlignment.Near); // Left/right
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.InnerLeft:
 | |
|                     sf.Alignment = (flip ? StringAlignment.Far : StringAlignment.Near);
 | |
|                     sf.LineAlignment = (flip ? StringAlignment.Far : StringAlignment.Near);
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.MiddleLeft:
 | |
|                     sf.Alignment = StringAlignment.Center;
 | |
|                     sf.LineAlignment = (flip ? StringAlignment.Far : StringAlignment.Near);
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.OuterRight:
 | |
|                     sf.Alignment = (flip ? StringAlignment.Near : StringAlignment.Far);
 | |
|                     sf.LineAlignment = (flip ? StringAlignment.Near : StringAlignment.Far);
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.InnerRight:
 | |
|                     sf.Alignment = (flip ? StringAlignment.Far : StringAlignment.Near);
 | |
|                     sf.LineAlignment = (flip ? StringAlignment.Near : StringAlignment.Far);
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.MiddleRight:
 | |
|                     sf.Alignment = StringAlignment.Center;
 | |
|                     sf.LineAlignment = (flip ? StringAlignment.Near : StringAlignment.Far);
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.OuterCenter:
 | |
|                     sf.Alignment = (flip ? StringAlignment.Near : StringAlignment.Far);
 | |
|                     sf.LineAlignment = StringAlignment.Center;
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.InnerCenter:
 | |
|                     sf.Alignment = (flip ? StringAlignment.Far : StringAlignment.Near);
 | |
|                     sf.LineAlignment = StringAlignment.Center;
 | |
|                     break;
 | |
| 
 | |
|                 case SliceLabelAlignment.NotSet:
 | |
|                 case SliceLabelAlignment.MiddleCenter:
 | |
|                     sf.Alignment = StringAlignment.Center;
 | |
|                     sf.LineAlignment = StringAlignment.Center;
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderPerpendicularLabel
 | |
| 
 | |
|         internal bool RenderPerpendicularLabel(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, double maxRadius, string text, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double innerOffset = GetLableInnerOffset(psp, maxRadius, lstyle);
 | |
|             double outerOffset = GetLableOuterOffset(psp, maxRadius, lstyle);
 | |
| 
 | |
|             if (outerOffset - innerOffset > 0)
 | |
|             {
 | |
|                 double centerAngle = psp.CenterAngle % 360;
 | |
| 
 | |
|                 Point lpt = psp.GetRayEndPoint(centerAngle, outerOffset);
 | |
| 
 | |
|                 float fontAngle = 0;
 | |
| 
 | |
|                 if (lstyle.AutoOrientLabel != Tbool.False)
 | |
|                 {
 | |
|                     if (centerAngle < 180)
 | |
|                         fontAngle += 180;
 | |
|                 }
 | |
| 
 | |
|                 Rectangle r = GetInscribedRectP(psp, maxRadius,
 | |
|                     centerAngle, outerOffset, innerOffset, lpt, lstyle);
 | |
| 
 | |
|                 r = GetSliceLabelBounds(g, pieChart, psp, text, r, lstyle);
 | |
| 
 | |
|                 if (r.Width > 0 && r.Height > 0)
 | |
|                 {
 | |
|                     GraphicsState gState = g.Save();
 | |
| 
 | |
|                     TextRenderingHint renderingHint = g.TextRenderingHint;
 | |
|                     g.TextRenderingHint = TextRenderingHint.AntiAlias;
 | |
| 
 | |
|                     g.TranslateTransform(lpt.X, lpt.Y);
 | |
|                     g.RotateTransform((float)((centerAngle + fontAngle + 90) % 360));
 | |
| 
 | |
|                     if (lstyle.Background.IsEmpty == false)
 | |
|                     {
 | |
|                         using (Brush br = lstyle.Background.GetBrush(r))
 | |
|                             g.FillRectangle(br, r);
 | |
|                     }
 | |
| 
 | |
|                     using (StringFormat sf = new StringFormat())
 | |
|                     {
 | |
|                         lstyle.GetStringFormatFlags(sf, (centerAngle < 180));
 | |
| 
 | |
|                         using (Brush br = new SolidBrush(lstyle.TextColor))
 | |
|                             g.DrawString(text, lstyle.Font, br, r, sf);
 | |
|                     }
 | |
| 
 | |
|                     g.Restore(gState);
 | |
| 
 | |
|                     return (true);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region GetInscribedRectP
 | |
| 
 | |
|         private Rectangle GetInscribedRectP(PieSeriesPoint psp, double maxRadius,
 | |
|             double centerAngle, double outerOffset, double innerOffset, Point lpt, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             if (psp.InscribedRectValid == false)
 | |
|             {
 | |
|                 double sweepAngle = psp.SweepAngleEx / 2 - lstyle.AngleMargin;
 | |
| 
 | |
|                 double b = (innerOffset * Math.Tan(MathHelper.ToRadians(sweepAngle)));
 | |
|                 double h = (outerOffset - innerOffset);
 | |
| 
 | |
|                 double maxb = Math.Sqrt(maxRadius * maxRadius - outerOffset * outerOffset);
 | |
| 
 | |
|                 if (b > maxb)
 | |
|                     b = maxb;
 | |
| 
 | |
|                 h = (h / lstyle.Font.Height) * lstyle.Font.Height;
 | |
| 
 | |
|                 Rectangle r = new Rectangle();
 | |
| 
 | |
|                 r.Location = new Point((int)-b, (centerAngle < 180) ? (int)-h : 0);
 | |
| 
 | |
|                 r.Width = (int)(b * 2);
 | |
|                 r.Height = (int)h;
 | |
| 
 | |
|                 psp.InscribedRect = r;
 | |
|             }
 | |
| 
 | |
|             return (psp.InscribedRect);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderHorizontalLabel
 | |
| 
 | |
|         internal bool RenderHorizontalLabel(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, double maxRadius, string text, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double innerOffset = GetLableInnerOffset(psp, maxRadius, lstyle);
 | |
| 
 | |
|             Rectangle r = GetInscribedRectH(g,
 | |
|                 psp, psp.CenterAngle % 360, maxRadius, innerOffset, lstyle);
 | |
| 
 | |
|             r = GetSliceLabelBounds(g, pieChart, psp, text, r, lstyle);
 | |
| 
 | |
|             if (r.Width > 0 && r.Height > 0)
 | |
|             {
 | |
|                 if (lstyle.Background.IsDisplayable == true)
 | |
|                 {
 | |
|                     using (Brush br = lstyle.Background.GetBrush(r))
 | |
|                         g.FillRectangle(br, r);
 | |
|                 }
 | |
| 
 | |
|                 using (StringFormat sf = new StringFormat())
 | |
|                 {
 | |
|                     lstyle.GetStringFormatFlags(sf, false);
 | |
| 
 | |
|                     using (Brush br = new SolidBrush(lstyle.TextColor))
 | |
|                         g.DrawString(text, lstyle.Font, br, r, sf);
 | |
|                 }
 | |
| 
 | |
|                 if (ChartControl.DesignerHosted == true)
 | |
|                 {
 | |
|                     using (Pen pen = new Pen(Color.Plum))
 | |
|                     {
 | |
|                         pen.DashStyle = DashStyle.Dash;
 | |
| 
 | |
|                         g.DrawRectangle(pen, r);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region GetInscribedRectH
 | |
| 
 | |
|         private Rectangle GetInscribedRectH(Graphics g, PieSeriesPoint psp,
 | |
|             double centerAngle, double outerOffset, double innerOffset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             if (psp.InscribedRectValid == false)
 | |
|             {
 | |
|                 double startAngle = psp.StartAngleEx % 360;
 | |
|                 double endAngle = startAngle + psp.SweepAngleEx;
 | |
| 
 | |
|                 if (psp.SweepAngleEx > 180)
 | |
|                 {
 | |
|                     startAngle = centerAngle - 88;
 | |
|                     endAngle = centerAngle + 88;
 | |
|                 }
 | |
| 
 | |
|                 Rectangle r;
 | |
| 
 | |
|                 if (centerAngle > 270)
 | |
|                 {
 | |
|                     r = GetInscribedRectQuad4(g, psp,
 | |
|                         startAngle, endAngle, centerAngle, outerOffset, innerOffset, lstyle);
 | |
|                 }
 | |
|                 else if (centerAngle > 180)
 | |
|                 {
 | |
|                     r = GetInscribedRectQuad3(g, psp,
 | |
|                         startAngle, endAngle, centerAngle, outerOffset, innerOffset, lstyle);
 | |
|                 }
 | |
|                 else if (centerAngle > 90)
 | |
|                 {
 | |
|                     r = GetInscribedRectQuad2(g, psp,
 | |
|                         startAngle, endAngle, centerAngle, outerOffset, innerOffset, lstyle);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     r = GetInscribedRectQuad1(g, psp,
 | |
|                         startAngle, endAngle, centerAngle, outerOffset, innerOffset, lstyle);
 | |
|                 }
 | |
| 
 | |
|                 r.Inflate(-2, -2);
 | |
| 
 | |
|                 psp.InscribedRect = r;
 | |
|             }
 | |
| 
 | |
|             return (psp.InscribedRect);
 | |
|         }
 | |
| 
 | |
|         #region GetInscribedRectQuad1
 | |
| 
 | |
|         private Rectangle GetInscribedRectQuad1(Graphics g,
 | |
|             PieSeriesPoint psp, double startAngle, double endAngle,
 | |
|             double centerAngle, double outerOffset, double innerOffset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             Point ptCenter = psp.SliceCenter;
 | |
| 
 | |
|             centerAngle = NormalizeCenterAngleQuad1(centerAngle, startAngle, endAngle);
 | |
| 
 | |
|             Point ptcInner = psp.GetRayEndPoint(centerAngle, innerOffset);
 | |
|             Point ptcOuter = psp.GetRayEndPoint(centerAngle, outerOffset);
 | |
| 
 | |
|             Point ptLeftRay = psp.GetRayEndPoint(startAngle, outerOffset);
 | |
|             Point ptRightRay = psp.GetRayEndPoint(endAngle, outerOffset);
 | |
| 
 | |
|             Point ptPie1, ptPie2;
 | |
|             int count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X + 1, ptcOuter.Y), out ptPie1, out ptPie2, true);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptLeftLower = new Point(ptPie1.X, ptcOuter.Y);
 | |
| 
 | |
|             Point pt1;
 | |
|             if (FindLineIntersect(ptcOuter, ptLeftLower, ptCenter, ptRightRay, out pt1) == true)
 | |
|             {
 | |
|                 if ((uint)(ptcOuter.X - pt1.X) < ptcOuter.X - ptLeftLower.X)
 | |
|                     ptLeftLower.X = pt1.X;
 | |
|             }
 | |
| 
 | |
|             Point ptPie3, ptPie4;
 | |
|             count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X, ptcOuter.Y + 10), out ptPie3, out ptPie4, false);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptRightUpper = new Point(ptcOuter.X, ptPie3.Y);
 | |
| 
 | |
|             if (FindLineIntersect(ptcOuter, new Point(ptcOuter.X, ptcOuter.Y + 10),
 | |
|                 ptCenter, ptLeftRay, out pt1) == true)
 | |
|             {
 | |
|                 if ((uint)(ptcOuter.Y - pt1.Y) < (ptcOuter.Y - ptRightUpper.Y))
 | |
|                     ptRightUpper.Y = pt1.Y;
 | |
|             }
 | |
| 
 | |
|             if (centerAngle < 40)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(0, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.X - ptcOuter.X) < Math.Abs(ptLeftLower.X - ptcOuter.X))
 | |
|                     ptLeftLower.X = ray.X;
 | |
|             }
 | |
|             else if (centerAngle > 50)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(90, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.Y - ptcOuter.Y) < Math.Abs(ptRightUpper.Y - ptcOuter.Y))
 | |
|                     ptRightUpper.Y = ray.Y;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (ptLeftLower.X < ptcInner.X)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptLeftRay, ptcInner,
 | |
|                         new Point(ptcInner.X, ptcInner.Y + 10), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptLeftLower.X - ptcOuter.X))
 | |
|                             ptLeftLower.X = pt1.X;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (ptRightUpper.Y <= ptcInner.Y)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptRightRay,
 | |
|                         ptcInner, new Point(ptcInner.X + 10, ptcInner.Y), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptRightUpper.Y - ptcOuter.Y))
 | |
|                             ptRightUpper.Y = pt1.Y;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (psp.SweepAngleEx < 180)
 | |
|             {
 | |
|                 if (FindLineIntersect(ptCenter, ptRightRay, ptRightUpper,
 | |
|                     new Point(ptRightUpper.X + 10, ptRightUpper.Y), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptLeftLower.X - ptcOuter.X))
 | |
|                         ptLeftLower.X = pt1.X;
 | |
|                 }
 | |
| 
 | |
|                 if (FindLineIntersect(ptCenter, ptLeftRay, ptLeftLower,
 | |
|                     new Point(ptLeftLower.X, ptLeftLower.Y + 10), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptRightUpper.Y - ptcOuter.Y))
 | |
|                         ptRightUpper.Y = pt1.Y;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Rectangle r = new Rectangle();
 | |
| 
 | |
|             r.Location = new Point(ptLeftLower.X, ptRightUpper.Y);
 | |
|             r.Width = ptcOuter.X - ptLeftLower.X;
 | |
|             r.Height = ptcOuter.Y - ptRightUpper.Y;
 | |
| 
 | |
|             return (r);
 | |
|         }
 | |
| 
 | |
|         #region NormalizeCenterAngleQuad1
 | |
| 
 | |
|         private double NormalizeCenterAngleQuad1(
 | |
|             double centerAngle, double startAngle, double endAngle)
 | |
|         {
 | |
|             if (centerAngle > 70)
 | |
|             {
 | |
|                 centerAngle -= (centerAngle - 70) / 2;
 | |
| 
 | |
|                 if (centerAngle - 2 < 0)
 | |
|                     centerAngle += 360;
 | |
| 
 | |
|                 if (centerAngle - 2 <= startAngle)
 | |
|                     centerAngle = (startAngle + 2) % 360;
 | |
|             }
 | |
|             else if (centerAngle < 20)
 | |
|             {
 | |
|                 centerAngle += (20 - centerAngle) / 2;
 | |
| 
 | |
|                 if (centerAngle + 2 >= endAngle)
 | |
|                     centerAngle = endAngle - 2;
 | |
|             }
 | |
| 
 | |
|             return (centerAngle);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetInscribedRectQuad2
 | |
| 
 | |
|         private Rectangle GetInscribedRectQuad2(Graphics g,
 | |
|             PieSeriesPoint psp, double startAngle, double endAngle,
 | |
|             double centerAngle, double outerOffset, double innerOffset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             Point ptCenter = psp.SliceCenter;
 | |
| 
 | |
|             centerAngle = NormalizeCenterAngleQuad2(centerAngle, startAngle, endAngle);
 | |
| 
 | |
|             Point ptcInner = psp.GetRayEndPoint(centerAngle, innerOffset);
 | |
|             Point ptcOuter = psp.GetRayEndPoint(centerAngle, outerOffset);
 | |
| 
 | |
|             Point ptLeftRay = psp.GetRayEndPoint(startAngle, outerOffset);
 | |
|             Point ptRightRay = psp.GetRayEndPoint(endAngle, outerOffset);
 | |
| 
 | |
|             Point ptPie1, ptPie2;
 | |
|             int count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X + 1, ptcOuter.Y), out ptPie1, out ptPie2, true);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptRightLower = new Point(ptPie2.X, ptcOuter.Y);
 | |
| 
 | |
|             Point pt1;
 | |
|             if (FindLineIntersect(ptcOuter, ptRightLower, ptCenter, ptLeftRay, out pt1) == true)
 | |
|             {
 | |
|                 if ((uint)(pt1.X - ptcOuter.X) < (ptRightLower.X - ptcOuter.X))
 | |
|                     ptRightLower.X = pt1.X;
 | |
|             }
 | |
| 
 | |
|             Point ptPie3, ptPie4;
 | |
|             count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X, ptcOuter.Y + 10), out ptPie3, out ptPie4, false);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptLeftUpper = new Point(ptcOuter.X, ptPie3.Y);
 | |
| 
 | |
|             if (FindLineIntersect(ptcOuter, new Point(ptcOuter.X, ptcOuter.Y + 10),
 | |
|                 ptCenter, ptRightRay, out pt1) == true)
 | |
|             {
 | |
|                 if ((uint)(ptcOuter.Y - pt1.Y) < (ptcOuter.Y - ptLeftUpper.Y))
 | |
|                     ptLeftUpper.Y = pt1.Y;
 | |
|             }
 | |
| 
 | |
|             if (centerAngle < 130)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(90, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.Y - ptcOuter.Y) < Math.Abs(ptLeftUpper.Y - ptcOuter.Y))
 | |
|                     ptLeftUpper.Y = ray.Y;
 | |
|             }
 | |
|             else if (centerAngle > 140)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(180, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.X - ptcOuter.X) < Math.Abs(ptRightLower.X - ptcOuter.X))
 | |
|                     ptRightLower.X = ray.X;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (ptRightLower.X > ptcInner.X)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptLeftRay, ptcInner,
 | |
|                         new Point(ptcInner.X, ptcInner.Y + 10), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptRightLower.X - ptcOuter.X))
 | |
|                             ptRightLower.X = pt1.X;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (ptLeftUpper.Y <= ptcInner.Y)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptRightRay,
 | |
|                         ptcInner, new Point(ptcInner.X + 10, ptcInner.Y), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptLeftUpper.Y - ptcOuter.Y))
 | |
|                             ptLeftUpper.Y = pt1.Y;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (psp.SweepAngleEx < 180)
 | |
|             {
 | |
|                 if (FindLineIntersect(ptCenter, ptRightRay, ptRightLower,
 | |
|                     new Point(ptRightLower.X, ptRightLower.Y + 10), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptLeftUpper.Y - ptcOuter.Y))
 | |
|                         ptLeftUpper.Y = pt1.Y;
 | |
|                 }
 | |
| 
 | |
|                 if (FindLineIntersect(ptCenter, ptLeftRay, ptLeftUpper,
 | |
|                     new Point(ptLeftUpper.X + 10, ptLeftUpper.Y), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptRightLower.X - ptcOuter.X))
 | |
|                         ptRightLower.X = pt1.X;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Rectangle r = new Rectangle();
 | |
| 
 | |
|             r.Location = ptLeftUpper;
 | |
|             r.Width = ptRightLower.X - ptcOuter.X;
 | |
|             r.Height = ptcOuter.Y - ptLeftUpper.Y;
 | |
| 
 | |
|             return (r);
 | |
|         }
 | |
| 
 | |
|         #region NormalizeCenterAngleQuad2
 | |
| 
 | |
|         private double NormalizeCenterAngleQuad2(
 | |
|             double centerAngle, double startAngle, double endAngle)
 | |
|         {
 | |
|             if (centerAngle > 160)
 | |
|             {
 | |
|                 centerAngle -= (centerAngle - 160) / 2;
 | |
| 
 | |
|                 if (centerAngle - 2 <= startAngle)
 | |
|                     centerAngle = startAngle + 2;
 | |
|             }
 | |
|             else if (centerAngle < 110)
 | |
|             {
 | |
|                 centerAngle += (110 - centerAngle) / 2;
 | |
| 
 | |
|                 if (centerAngle + 2 >= endAngle)
 | |
|                     centerAngle = endAngle - 2;
 | |
|             }
 | |
| 
 | |
|             return (centerAngle);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetInscribedRectQuad3
 | |
| 
 | |
|         private Rectangle GetInscribedRectQuad3(Graphics g,
 | |
|             PieSeriesPoint psp, double startAngle, double endAngle,
 | |
|             double centerAngle, double outerOffset, double innerOffset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             Point ptCenter = psp.SliceCenter;
 | |
| 
 | |
|             centerAngle = NormalizeCenterAngleQuad3(centerAngle, startAngle, endAngle);
 | |
| 
 | |
|             Point ptcInner = psp.GetRayEndPoint(centerAngle, innerOffset);
 | |
|             Point ptcOuter = psp.GetRayEndPoint(centerAngle, outerOffset);
 | |
| 
 | |
|             Point ptLeftRay = psp.GetRayEndPoint(startAngle, outerOffset);
 | |
|             Point ptRightRay = psp.GetRayEndPoint(endAngle, outerOffset);
 | |
| 
 | |
|             Point ptPie1, ptPie2;
 | |
| 
 | |
|             int count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X + 1, ptcOuter.Y), out ptPie1, out ptPie2, true);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptRightUpper = new Point(ptPie2.X, ptcOuter.Y);
 | |
| 
 | |
|             Point pt1;
 | |
|             if (FindLineIntersect(ptcOuter, ptRightUpper, ptCenter, ptRightRay, out pt1) == true)
 | |
|             {
 | |
|                 if (pt1.X - ptcOuter.X > 0)
 | |
|                 {
 | |
|                     if ((uint)(pt1.X - ptcOuter.X) < (ptRightUpper.X - ptcOuter.X))
 | |
|                         ptRightUpper.X = pt1.X;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Point ptPie3, ptPie4;
 | |
| 
 | |
|             count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X, ptcOuter.Y + 10), out ptPie3, out ptPie4, false);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptLeftLower = new Point(ptcOuter.X, ptPie4.Y);
 | |
| 
 | |
|             if (FindLineIntersect(ptcOuter, new Point(ptcOuter.X, ptcOuter.Y + 10),
 | |
|                 ptCenter, ptLeftRay, out pt1) == true)
 | |
|             {
 | |
|                 if (pt1.Y - ptcOuter.Y > 0)
 | |
|                 {
 | |
|                     if ((uint)(pt1.Y - ptcOuter.Y) < (ptLeftLower.Y - ptcOuter.Y))
 | |
|                         ptLeftLower.Y = pt1.Y;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (centerAngle < 220)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(180, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.X - ptcOuter.X) < Math.Abs(ptRightUpper.X - ptcOuter.X))
 | |
|                     ptRightUpper.X = ray.X;
 | |
|             }
 | |
|             else if (centerAngle > 230)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(270, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.Y - ptcOuter.Y) < Math.Abs(ptLeftLower.Y - ptcOuter.Y))
 | |
|                     ptLeftLower.Y = ray.Y;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (ptLeftLower.Y >= ptcInner.Y)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptLeftRay, ptcInner,
 | |
|                         new Point(ptcInner.X + 10, ptcInner.Y), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptLeftLower.Y - ptcOuter.Y))
 | |
|                             ptLeftLower.Y = pt1.Y;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (ptRightUpper.X > ptcInner.X)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptRightRay,
 | |
|                         ptcInner, new Point(ptcInner.X, ptcInner.Y + 10), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptRightUpper.X - ptcOuter.X))
 | |
|                             ptRightUpper.X = pt1.X;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (psp.SweepAngleEx < 180)
 | |
|             {
 | |
|                 if (FindLineIntersect(ptCenter, ptRightRay, ptLeftLower,
 | |
|                     new Point(ptLeftLower.X + 10, ptLeftLower.Y), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptRightUpper.X - ptcOuter.X))
 | |
|                         ptRightUpper.X = pt1.X;
 | |
|                 }
 | |
| 
 | |
|                 if (FindLineIntersect(ptCenter, ptLeftRay,
 | |
|                     ptRightUpper, new Point(ptRightUpper.X, ptRightUpper.Y + 10), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptLeftLower.Y - ptcOuter.Y))
 | |
|                         ptLeftLower.Y = pt1.Y;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Rectangle r = new Rectangle();
 | |
| 
 | |
|             r.Location = ptcOuter;
 | |
|             r.Width = ptRightUpper.X - ptcOuter.X;
 | |
|             r.Height = ptLeftLower.Y - ptcOuter.Y;
 | |
| 
 | |
|             return (r);
 | |
|         }
 | |
| 
 | |
|         #region NormalizeCenterAngleQuad3
 | |
| 
 | |
|         private double NormalizeCenterAngleQuad3(
 | |
|             double centerAngle, double startAngle, double endAngle)
 | |
|         {
 | |
|             if (centerAngle > 250)
 | |
|             {
 | |
|                 centerAngle -= (centerAngle - 250) / 2;
 | |
| 
 | |
|                 if (centerAngle - startAngle < 2)
 | |
|                     centerAngle = startAngle + 2;
 | |
|             }
 | |
|             else if (centerAngle < 200)
 | |
|             {
 | |
|                 centerAngle += (200 - centerAngle) / 2;
 | |
| 
 | |
|                 if (centerAngle + 2 >= endAngle)
 | |
|                     centerAngle = endAngle - 2;
 | |
|             }
 | |
| 
 | |
|             return (centerAngle);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetInscribedRectQuad4
 | |
| 
 | |
|         private Rectangle GetInscribedRectQuad4(Graphics g,
 | |
|             PieSeriesPoint psp, double startAngle, double endAngle,
 | |
|             double centerAngle, double outerOffset, double innerOffset, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             Point ptCenter = psp.SliceCenter;
 | |
| 
 | |
|             centerAngle = NormalizeCenterAngleQuad4(centerAngle, startAngle, endAngle);
 | |
| 
 | |
|             Point ptcInner = psp.GetRayEndPoint(centerAngle, innerOffset);
 | |
|             Point ptcOuter = psp.GetRayEndPoint(centerAngle, outerOffset);
 | |
| 
 | |
|             Point ptLeftRay = psp.GetRayEndPoint(startAngle, outerOffset);
 | |
|             Point ptRightRay = psp.GetRayEndPoint(endAngle, outerOffset);
 | |
| 
 | |
|             Point ptPie1, ptPie2;
 | |
|             int count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X + 1, ptcOuter.Y), out ptPie1, out ptPie2, true);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptLeftUpper = new
 | |
|                 Point((ptcOuter.Y < ptCenter.Y) ? ptPie1.X : ptPie2.X, ptcOuter.Y);
 | |
| 
 | |
|             Point pt1;
 | |
|             if (FindLineIntersect(ptcOuter, ptLeftUpper, ptCenter, ptLeftRay, out pt1) == true)
 | |
|             {
 | |
|                 if (ptcOuter.X - pt1.X > 0)
 | |
|                 {
 | |
|                     if ((uint)(ptcOuter.X - pt1.X) < ptcOuter.X - ptLeftUpper.X)
 | |
|                         ptLeftUpper.X = pt1.X;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Point ptPie3, ptPie4;
 | |
|             count = FindCircleIntersect(ptCenter, outerOffset, ptcOuter,
 | |
|                 new Point(ptcOuter.X, ptcOuter.Y + 10), out ptPie3, out ptPie4, false);
 | |
| 
 | |
|             if (count != 2)
 | |
|                 return (Rectangle.Empty);
 | |
| 
 | |
|             Point ptRightLower = new Point(ptcOuter.X,
 | |
|                 (ptcOuter.X < ptCenter.X) ? ptPie3.Y : ptPie4.Y);
 | |
| 
 | |
|             if (FindLineIntersect(ptcOuter, new Point(ptcOuter.X, ptcOuter.Y + 10),
 | |
|                 ptCenter, ptRightRay, out pt1) == true)
 | |
|             {
 | |
|                 if (pt1.Y - ptcOuter.Y > 0)
 | |
|                 {
 | |
|                     if ((uint)(pt1.Y - ptcOuter.Y) < (ptRightLower.Y - ptcOuter.Y))
 | |
|                         ptRightLower.Y = pt1.Y;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (centerAngle < 310)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(270, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.Y - ptcOuter.Y) < Math.Abs(ptRightLower.Y - ptcOuter.Y))
 | |
|                     ptRightLower.Y = ray.Y;
 | |
|             }
 | |
|             else if (centerAngle > 320)
 | |
|             {
 | |
|                 Point ray = psp.GetRayEndPoint(0, innerOffset);
 | |
| 
 | |
|                 if (Math.Abs(ray.X - ptcOuter.X) < Math.Abs(ptLeftUpper.X - ptcOuter.X))
 | |
|                     ptLeftUpper.X = ray.X;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (ptLeftUpper.X <= ptcInner.X)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptLeftRay, ptcInner,
 | |
|                         new Point(ptcInner.X, ptcInner.Y + 10), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptLeftUpper.X - ptcOuter.X))
 | |
|                             ptLeftUpper.X = pt1.X;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (ptRightLower.Y >= ptcInner.Y)
 | |
|                 {
 | |
|                     if (FindLineIntersect(ptCenter, ptRightRay,
 | |
|                         ptcInner, new Point(ptcInner.X + 10, ptcInner.Y), out pt1) == true)
 | |
|                     {
 | |
|                         if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptRightLower.Y - ptcOuter.Y))
 | |
|                             ptRightLower.Y = pt1.Y;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (psp.SweepAngleEx < 180)
 | |
|             {
 | |
|                 if (FindLineIntersect(ptCenter, ptRightRay, ptLeftUpper,
 | |
|                     new Point(ptLeftUpper.X, ptLeftUpper.Y + 10), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.Y - ptcOuter.Y) < Math.Abs(ptRightLower.Y - ptcOuter.Y))
 | |
|                         ptRightLower.Y = pt1.Y;
 | |
|                 }
 | |
| 
 | |
|                 if (FindLineIntersect(ptCenter, ptLeftRay,
 | |
|                     ptRightLower, new Point(ptRightLower.X + 10, ptRightLower.Y), out pt1) == true)
 | |
|                 {
 | |
|                     if (Math.Abs(pt1.X - ptcOuter.X) < Math.Abs(ptLeftUpper.X - ptcOuter.X))
 | |
|                         ptLeftUpper.X = pt1.X;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Rectangle r = new Rectangle();
 | |
| 
 | |
|             r.Location = ptLeftUpper;
 | |
|             r.Width = ptRightLower.X - ptLeftUpper.X;
 | |
|             r.Height = ptRightLower.Y - ptLeftUpper.Y;
 | |
| 
 | |
|             return (r);
 | |
|         }
 | |
| 
 | |
|         #region NormalizeCenterAngleQuad4
 | |
| 
 | |
|         private double NormalizeCenterAngleQuad4(
 | |
|             double centerAngle, double startAngle, double endAngle)
 | |
|         {
 | |
|             if (centerAngle > 340)
 | |
|             {
 | |
|                 centerAngle -= (centerAngle - 340) / 2;
 | |
| 
 | |
|                 if (centerAngle - 2 <= startAngle)
 | |
|                     centerAngle = startAngle + 2;
 | |
|             }
 | |
|             else if (centerAngle < 290)
 | |
|             {
 | |
|                 centerAngle += (290 - centerAngle) / 2;
 | |
| 
 | |
|                 if (centerAngle + 2 >= endAngle)
 | |
|                     centerAngle = endAngle - 2;
 | |
|             }
 | |
| 
 | |
|             return (centerAngle);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region FindLineIntersect
 | |
| 
 | |
|         private bool FindLineIntersect(
 | |
|             Point ps1, Point pe1, Point ps2, Point pe2, out Point ptOut)
 | |
|         {
 | |
|             float A1 = pe1.Y - ps1.Y;
 | |
|             float B1 = ps1.X - pe1.X;
 | |
|             float C1 = A1 * ps1.X + B1 * ps1.Y;
 | |
| 
 | |
|             float A2 = pe2.Y - ps2.Y;
 | |
|             float B2 = ps2.X - pe2.X;
 | |
|             float C2 = A2 * ps2.X + B2 * ps2.Y;
 | |
| 
 | |
|             float delta = A1 * B2 - A2 * B1;
 | |
| 
 | |
|             if (delta == 0)
 | |
|             {
 | |
|                 ptOut = Point.Empty;
 | |
| 
 | |
|                 return (false);
 | |
|             }
 | |
| 
 | |
|             ptOut = new Point(
 | |
|                 (int)((B2 * C1 - B1 * C2) / delta),
 | |
|                 (int)((A1 * C2 - A2 * C1) / delta));
 | |
| 
 | |
|             return (true);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region FindCircleIntersect
 | |
| 
 | |
|         private int FindCircleIntersect(Point ptc, double radius,
 | |
|             Point pt1, Point pt2, out Point ptOut1, out Point ptOut2, bool normx)
 | |
|         {
 | |
|             int dx = pt2.X - pt1.X;
 | |
|             int dy = pt2.Y - pt1.Y;
 | |
| 
 | |
|             int a = dx * dx + dy * dy;
 | |
|             int b = 2 * (dx * (pt1.X - ptc.X) + dy * (pt1.Y - ptc.Y));
 | |
| 
 | |
|             double c = (pt1.X - ptc.X) * (pt1.X - ptc.X) +
 | |
|                 (pt1.Y - ptc.Y) * (pt1.Y - ptc.Y) - radius * radius;
 | |
| 
 | |
|             double det = b * b - 4 * a * c;
 | |
| 
 | |
|             if ((a <= 0.0000001) || (det < 0))
 | |
|             {
 | |
|                 ptOut1 = Point.Empty;
 | |
|                 ptOut2 = Point.Empty;
 | |
| 
 | |
|                 return (0);
 | |
|             }
 | |
|             else if (det == 0)
 | |
|             {
 | |
|                 double t1 = -b / (2 * a);
 | |
| 
 | |
|                 ptOut1 = new Point((int)(pt1.X + t1 * dx), (int)(pt1.Y + t1 * dy));
 | |
|                 ptOut2 = Point.Empty;
 | |
| 
 | |
|                 return (1);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 double t2 = (float)((-b + Math.Sqrt(det)) / (2 * a));
 | |
|                 double t3 = (float)((-b - Math.Sqrt(det)) / (2 * a));
 | |
| 
 | |
|                 ptOut1 = new Point((int)(pt1.X + t2 * dx), (int)(pt1.Y + t2 * dy));
 | |
|                 ptOut2 = new Point((int)(pt1.X + t3 * dx), (int)(pt1.Y + t3 * dy));
 | |
| 
 | |
|                 if ((normx == true && ptOut1.X > ptOut2.X) ||
 | |
|                     (normx == false && ptOut1.Y > ptOut2.Y))
 | |
|                 {
 | |
|                     Point ptTemp = ptOut1;
 | |
| 
 | |
|                     ptOut1 = ptOut2;
 | |
|                     ptOut2 = ptTemp;
 | |
|                 }
 | |
| 
 | |
|                 return (2);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetLableInnerOffset
 | |
| 
 | |
|         internal double GetLableInnerOffset
 | |
|             (PieSeriesPoint psp, double maxRadius, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double offset;
 | |
| 
 | |
|             if (Math.Abs(lstyle.InnerRadiusOffset) >= 1)
 | |
|                 offset = lstyle.InnerRadiusOffset;
 | |
|             else
 | |
|                 offset = (maxRadius - psp.InnerRadius) * lstyle.InnerRadiusOffset;
 | |
| 
 | |
|             offset += psp.InnerRadius;
 | |
| 
 | |
|             if (lstyle.MaxLineCount >= 0)
 | |
|             {
 | |
|                 double outerOffset = psp.InnerRadius;
 | |
|                 
 | |
|                 if (lstyle.OuterRadiusOffset > -1 && lstyle.OuterRadiusOffset < 1)
 | |
|                     outerOffset += (lstyle.OuterRadiusOffset * maxRadius);
 | |
|                 else
 | |
|                     outerOffset += lstyle.OuterRadiusOffset;
 | |
| 
 | |
|                 double fh = lstyle.Font.GetHeight() * lstyle.MaxLineCount;
 | |
| 
 | |
|                 fh = outerOffset - fh;
 | |
| 
 | |
|                 if (fh > offset)
 | |
|                     offset = fh;
 | |
|             }
 | |
| 
 | |
|             return (offset);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetLableOuterOffset
 | |
| 
 | |
|         internal double GetLableOuterOffset(
 | |
|             PieSeriesPoint psp, double maxRadius, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double offset;
 | |
| 
 | |
|             if (Math.Abs(lstyle.OuterRadiusOffset) >= 1)
 | |
|                 offset = lstyle.OuterRadiusOffset;
 | |
|             else
 | |
|                 offset = (maxRadius * lstyle.OuterRadiusOffset);
 | |
| 
 | |
|             return (maxRadius + offset);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetSliceLabel
 | |
| 
 | |
|         internal string GetSliceLabel(
 | |
|             PieChart pieChart, PieSeriesPoint psp, bool inner, string label)
 | |
|         {
 | |
|             if (string.IsNullOrEmpty(label) == false)
 | |
|             {
 | |
|                 string text = (string)label.Clone();
 | |
| 
 | |
|                 if (ChartControl.DoGetSliceLabelEvent(pieChart, this, psp, inner, ref text) == false)
 | |
|                     text = psp.GetLabelText(text);
 | |
| 
 | |
|                 return (text);
 | |
|             }
 | |
| 
 | |
|             return (null);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetSliceLabelBounds
 | |
| 
 | |
|         private Rectangle GetSliceLabelBounds(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, string text, Rectangle r, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             if (r.Width > 0 && r.Height > 0)
 | |
|             {
 | |
|                 SizeF sz = g.MeasureString(text, lstyle.Font, r.Width);
 | |
|                 Size size = sz.ToSize();
 | |
| 
 | |
|                 psp.InnerLabelClipped = (size.Width > r.Width || size.Height > r.Height);
 | |
| 
 | |
|                 if (psp.InnerLabelClipped == true)
 | |
|                 {
 | |
|                     SliceLabelCropMode cropMode = psp.SliceLabelCropModeEx;
 | |
| 
 | |
|                     if (cropMode == SliceLabelCropMode.Hide)
 | |
|                         return (Rectangle.Empty);
 | |
| 
 | |
|                     else if (cropMode == SliceLabelCropMode.Clip)
 | |
|                     {
 | |
|                         int height = GetTruncatedHeight(r.Height, lstyle);
 | |
| 
 | |
|                         if (height > 0)
 | |
|                             r.Height = height;
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         r.Height = size.Height;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (r);
 | |
|         }
 | |
| 
 | |
|         #region GetTruncatedHeight
 | |
| 
 | |
|         private int GetTruncatedHeight(int height, SliceInnerLabelVisualStyle lstyle)
 | |
|         {
 | |
|             int n = (int)(height / lstyle.Font.Height);
 | |
| 
 | |
|             if (lstyle.MaxLineCount > 0)
 | |
|             {
 | |
|                 if (n > lstyle.MaxLineCount)
 | |
|                     n = lstyle.MaxLineCount;
 | |
|             }
 | |
| 
 | |
|             return (lstyle.Font.Height * n);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IsHighLightedPsp
 | |
| 
 | |
|         internal bool IsHighLightedPsp(PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             if (pieChart.Legend.TrackingMode == LegendTrackingMode.ChartAndLegend)
 | |
|             {
 | |
|                 if (LegendItem != null && LegendItem.IsLegendHitItem == true)
 | |
|                     return (true);
 | |
| 
 | |
|                 if (psp.LegendItem != null && psp.LegendItem.IsLegendHitItem == true)
 | |
|                     return (true);
 | |
|             }
 | |
| 
 | |
|             PieSeriesPoint hitPsp = pieChart.HitPsp;
 | |
| 
 | |
|             if (hitPsp != null)
 | |
|             {
 | |
|                 PieSelectionMode psm = GetPieSelectionMode(pieChart);
 | |
| 
 | |
|                 switch (psm)
 | |
|                 {
 | |
|                     case PieSelectionMode.Pie:
 | |
|                         return (true);
 | |
| 
 | |
|                     case PieSelectionMode.Ring:
 | |
|                         return (psp.PieRing == hitPsp.PieRing);
 | |
| 
 | |
|                     case PieSelectionMode.Series:
 | |
|                         return (psp.ChartSeries == hitPsp.ChartSeries);
 | |
| 
 | |
|                     case PieSelectionMode.Slice:
 | |
|                         if (ShowAllRingsEx(pieChart) == true)
 | |
|                             return (psp.RootPsp == hitPsp.RootPsp);
 | |
|                         else
 | |
|                             return (psp == hitPsp);
 | |
| 
 | |
|                     case PieSelectionMode.Point:
 | |
|                         return (psp == hitPsp);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Render
 | |
| 
 | |
|         internal override void Render(ChartRenderInfo renderInfo)
 | |
|         {
 | |
|             if (Displayed == true)
 | |
|             {
 | |
|                 Rectangle bounds = BoundsRelative;
 | |
| 
 | |
|                 if (renderInfo.ClipRectangle.IntersectsWith(bounds))
 | |
|                     RenderOverride(renderInfo);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region UpdatePalette
 | |
| 
 | |
|         internal bool UpdatePalette(PieChart pieChart)
 | |
|         {
 | |
|             if (PaletteGroup == PaletteGroup.NotSet)
 | |
|                 return (false);
 | |
| 
 | |
|             Color[] palette = (PaletteGroup == PaletteGroup.Custom)
 | |
|                 ? (CustomPalette.Length > 0 ? CustomPalette : pieChart.CustomPalette) 
 | |
|                 : BaseChart.PaletteGroups[(int)PaletteGroup];
 | |
| 
 | |
|             if (palette == null || palette.Length == 0)
 | |
|                 palette = BaseChart.PaletteColor1;
 | |
| 
 | |
|             int colorIndex = 0;
 | |
| 
 | |
|             DefaultPaletteColor =
 | |
|                 pieChart.GetPaletteColor(colorIndex++, palette, ReversePaletteColors);
 | |
| 
 | |
|             if (PieRings != null)
 | |
|             {
 | |
|                 foreach (PieRing pieRing in PieRings)
 | |
|                 {
 | |
|                     foreach (PieSeriesPoint psp in pieRing.Psps)
 | |
|                     {
 | |
|                         psp.DefaultPaletteColor = 
 | |
|                             pieChart.GetPaletteColor(colorIndex++, palette, ReversePaletteColors);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (true);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region AddSeriesPoint
 | |
| 
 | |
|         internal override void AddSeriesPoint(object valueX, object[] valuesY, object dataItem)
 | |
|         {
 | |
|             PieSeriesPoint sp = new PieSeriesPoint(valueX, valuesY);
 | |
| 
 | |
|             sp.DataItem = dataItem;
 | |
| 
 | |
|             SeriesPoints.Add(sp);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ClearSeriesPoints
 | |
| 
 | |
|         internal override void ClearSeriesPoints()
 | |
|         {
 | |
|             SeriesPoints.Clear();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetActiveSeriesPointCollection
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the current 'active' SeriesPointCollection (useful when
 | |
|         /// 'ShowInnerRings' is set to false).
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         public PieSeriesPointCollection GetActiveSeriesPointCollection()
 | |
|         {
 | |
|             PieChart pieChart = Parent as PieChart;
 | |
| 
 | |
|             if (pieChart != null)
 | |
|             {
 | |
|                 return ((ShowAllRingsEx(pieChart) == true)
 | |
|                     ? SeriesPoints : (ActiveSeriesPointCollection ?? SeriesPoints));
 | |
|             }
 | |
| 
 | |
|             return (null);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SetActiveSeriesPointCollection
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Sets the current 'active' SeriesPointCollection (useful when
 | |
|         /// 'ShowInnerRings' is set to false).
 | |
|         /// </summary>
 | |
|         /// <param name="spc"></param>
 | |
|         public void SetActiveSeriesPointCollection(PieSeriesPointCollection spc)
 | |
|         {
 | |
|             if (spc == null || ValidSeriesPointSet(SeriesPoints, spc) == true)
 | |
|                 ActiveSeriesPointCollection = spc;
 | |
|             else
 | |
|                 throw new Exception("Not a valid PieSeriesPointSet for the series.");
 | |
| 
 | |
|             InvalidateLayout();
 | |
|         }
 | |
| 
 | |
|         #region ValidSeriesPointSet
 | |
| 
 | |
|         private bool ValidSeriesPointSet(PieSeriesPointCollection spc, PieSeriesPointCollection aspc)
 | |
|         {
 | |
|             if (aspc == spc)
 | |
|                 return (true);
 | |
| 
 | |
|             if (spc.PieSlices != null)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc.PieSlices)
 | |
|                 {
 | |
|                     if (psp.SeriesPoints == aspc)
 | |
|                         return (true);
 | |
| 
 | |
|                     if (ValidSeriesPointSet(psp.SeriesPoints, aspc) == true)
 | |
|                         return (true);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetPieSeriesPointCollection
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the SeriesPointCollection containing the given PieSeriesPoint
 | |
|         /// </summary>
 | |
|         /// <param name="psp"></param>
 | |
|         /// <returns></returns>
 | |
|         public PieSeriesPointCollection GetPieSeriesPointCollection(PieSeriesPoint psp)
 | |
|         {
 | |
|             return (psp.Parent as PieSeriesPointCollection);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetPieLabels
 | |
| 
 | |
|         internal List<PieLabel> GetPieLabels(Graphics g, PieChart pieChart)
 | |
|         {
 | |
|             List<PieLabel> pieLabels = new List<PieLabel>();
 | |
| 
 | |
|             if (ShowAllRingsEx(pieChart) == true)
 | |
|             {
 | |
|                 PieRing pieRing = GetOuterRing(pieChart);
 | |
| 
 | |
|                 if (pieRing != null)
 | |
|                 {
 | |
|                     foreach (PieSeriesPoint psp in pieRing.Psps)
 | |
|                     {
 | |
|                         SetPieLabel(g, pieChart, psp);
 | |
| 
 | |
|                         if (psp.PieLabel != null)
 | |
|                             pieLabels.Add(psp.PieLabel);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 PieSeriesPointCollection spc = GetActiveSeriesPointCollection();
 | |
| 
 | |
|                 if (spc != null)
 | |
|                 {
 | |
|                     foreach (PieSeriesPoint psp in spc)
 | |
|                     {
 | |
|                         SetPieLabel(g, pieChart, psp);
 | |
| 
 | |
|                         if (psp.PieLabel != null)
 | |
|                             pieLabels.Add(psp.PieLabel);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (pieLabels);
 | |
|         }
 | |
| 
 | |
|         #region SetPieLabel
 | |
| 
 | |
|         private void SetPieLabel(
 | |
|             Graphics g, PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             psp.PieLabel = null;
 | |
| 
 | |
|             if (psp.IsDisplayed == true && psp.SweepAngleEx != 0 &&
 | |
|                 psp.IsInOtherEx == false && psp.IsEmpty == false)
 | |
|             {
 | |
|                 ChartSliceVisualStyle sstyle = psp.GetEffectiveSliceStyle(pieChart, this);
 | |
| 
 | |
|                 if (IsOuterSliceLabelVisible(pieChart, psp) == true)
 | |
|                 {
 | |
|                     SliceOuterLabelVisualStyle lstyle = sstyle.SliceOuterLabelStyle;
 | |
|                     SliceLabelDisplayMode displayMode = psp.SliceLabelDisplayModeEx;
 | |
| 
 | |
|                     if (displayMode == SliceLabelDisplayMode.Outer ||
 | |
|                         displayMode == SliceLabelDisplayMode.InnerAndOuter ||
 | |
|                         displayMode == SliceLabelDisplayMode.NotSet)
 | |
|                     {
 | |
|                         string outerlabel = psp.OuterSliceLabelEx;
 | |
| 
 | |
|                         if (string.IsNullOrEmpty(outerlabel) == false)
 | |
|                             SetPieLabelEx(g, pieChart, psp, outerlabel, lstyle);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         if (psp.InnerLabelDisplayed == false)
 | |
|                         {
 | |
|                             string outerlabel = psp.OuterSliceLabelEx;
 | |
| 
 | |
|                             if (string.IsNullOrEmpty(outerlabel) == false)
 | |
|                             {
 | |
|                                 SetPieLabelEx(g, pieChart, psp, outerlabel, lstyle);
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 string innerlabel = psp.InnerSliceLabelEx;
 | |
| 
 | |
|                                 if (string.IsNullOrEmpty(innerlabel) == false)
 | |
|                                     SetPieLabelEx(g, pieChart, psp, innerlabel, lstyle);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetOuterRing
 | |
| 
 | |
|         private PieRing GetOuterRing(PieChart pieChart)
 | |
|         {
 | |
|             if (ShowAllRingsEx(pieChart) == false)
 | |
|             {
 | |
|                 PieSeriesPointCollection spc = (ActiveSeriesPointCollection ?? SeriesPoints);
 | |
| 
 | |
|                 return (spc.PieRing);
 | |
|             }
 | |
| 
 | |
|             if (PieRings.Count > 0)
 | |
|             {
 | |
|                 foreach (PieRing pieRing in PieRings)
 | |
|                 {
 | |
|                     if (pieRing.IsOuterRing == true)
 | |
|                         return (pieRing);
 | |
|                 }
 | |
| 
 | |
|                 return (PieRings[0]);
 | |
|             }
 | |
| 
 | |
|             return (null);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region IsOuterSliceLabelVisible
 | |
| 
 | |
|         private bool IsOuterSliceLabelVisible(PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             if (psp.SliceLabelVisibilityEx == SliceLabelVisibility.Never)
 | |
|                 return (false);
 | |
| 
 | |
|             switch (psp.SliceLabelDisplayModeEx)
 | |
|             {
 | |
|                 case SliceLabelDisplayMode.Outer:
 | |
|                 case SliceLabelDisplayMode.InnerAndOuter:
 | |
|                 case SliceLabelDisplayMode.InnerXorOuter:
 | |
|                     return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SetPieLabelEx
 | |
| 
 | |
|         private void SetPieLabelEx(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, string text, SliceOuterLabelVisualStyle lstyle)
 | |
|         {
 | |
|             string s = GetSliceLabel(pieChart, psp, false, text);
 | |
| 
 | |
|             if (String.IsNullOrEmpty(s) == false)
 | |
|             {
 | |
|                 PieLabel pl = new PieLabel(psp, s);
 | |
| 
 | |
|                 pl.LabelSize = MeasurePieLabel(g, pieChart, psp, pl, 0, lstyle);
 | |
| 
 | |
|                 psp.PieLabel = pl;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region MeasurePieLabel
 | |
| 
 | |
|         internal Size MeasurePieLabel(Graphics g, PieChart pieChart,
 | |
|             PieSeriesPoint psp, PieLabel pl, int cwidth, SliceOuterLabelVisualStyle lstyle)
 | |
|         {
 | |
|             float fheight = lstyle.Font.GetHeight();
 | |
| 
 | |
|             int maxWidth = GetMaxPieTextWidth(g, pieChart, lstyle);
 | |
|             int maxHeight = GetMaxPieTextHeight(g, pieChart, fheight, lstyle);
 | |
| 
 | |
|             int minWidth = GetMinPieTextWidth(g, pieChart, lstyle);
 | |
|             int minHeight = GetMinPieTextHeight(g, pieChart, fheight, lstyle);
 | |
| 
 | |
|             using (StringFormat sf = new StringFormat())
 | |
|             {
 | |
|                 lstyle.GetStringFormatFlags(sf, false);
 | |
| 
 | |
|                 if (cwidth != 0)
 | |
|                     cwidth -= Dpi.Width(lstyle.Padding.Horizontal);
 | |
| 
 | |
|                 Size size = g.MeasureString(pl.Label,
 | |
|                     lstyle.Font, cwidth != 0 ? cwidth : maxWidth, sf).ToSize();
 | |
| 
 | |
|                 size.Width += Dpi.Width1;
 | |
| 
 | |
|                 size = AdjustForPadding(pieChart, psp, size);
 | |
| 
 | |
|                 size.Height = MathHelper.Clamp(size.Height, minHeight, maxHeight);
 | |
|                 size.Width = MathHelper.Clamp(size.Width, minWidth, maxWidth);
 | |
| 
 | |
|                 if (lstyle.MaxLineCount > 1)
 | |
|                 {
 | |
|                     int lineHeight = (int)(Math.Ceiling(fheight)) * lstyle.MaxLineCount;
 | |
| 
 | |
|                     if (size.Height > lineHeight)
 | |
|                         size.Height = lineHeight;
 | |
|                 }
 | |
| 
 | |
|                 return (size);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region GetMaxPieTextWidth
 | |
| 
 | |
|         private int GetMaxPieTextWidth(
 | |
|             Graphics g, PieChart pieChart, SliceOuterLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double maxWidth = lstyle.MaxLabelWidth;
 | |
| 
 | |
|             if (double.IsNaN(maxWidth) == false)
 | |
|             {
 | |
|                 if (Math.Abs(maxWidth) >= 1)
 | |
|                     return ((int)maxWidth);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 maxWidth = .5;
 | |
|             }
 | |
| 
 | |
|             return ((int)(pieChart.ContentBoundsEx.Width * maxWidth));
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetMaxPieTextHeight
 | |
| 
 | |
|         private int GetMaxPieTextHeight(
 | |
|             Graphics g, PieChart pieChart, float fheight, SliceOuterLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double maxHeight = lstyle.MaxLabelHeight;
 | |
| 
 | |
|             if (double.IsNaN(maxHeight) == false)
 | |
|             {
 | |
|                 if (Math.Abs(maxHeight) >= 1)
 | |
|                     return ((int)maxHeight);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 maxHeight = .5;
 | |
|             }
 | |
| 
 | |
|             double height = pieChart.ContentBoundsEx.Height * maxHeight;
 | |
| 
 | |
|             int n = (int)(height / fheight);
 | |
| 
 | |
|             return ((int)(fheight * n));
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetMinPieTextWidth
 | |
| 
 | |
|         private int GetMinPieTextWidth(
 | |
|             Graphics g, PieChart pieChart, SliceOuterLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double minWidth = lstyle.MinLabelWidth;
 | |
| 
 | |
|             if (double.IsNaN(minWidth) == false)
 | |
|             {
 | |
|                 if (Math.Abs(minWidth) >= 1)
 | |
|                     return ((int)minWidth);
 | |
| 
 | |
|                 return ((int)(pieChart.ContentBoundsEx.Width * minWidth));
 | |
|             }
 | |
| 
 | |
|             return (0);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetMinPieTextHeight
 | |
| 
 | |
|         private int GetMinPieTextHeight(
 | |
|             Graphics g, PieChart pieChart, float fheight, SliceOuterLabelVisualStyle lstyle)
 | |
|         {
 | |
|             double minHeight = lstyle.MinLabelHeight;
 | |
| 
 | |
|             if (double.IsNaN(minHeight) == false)
 | |
|             {
 | |
|                 if (Math.Abs(minHeight) >= 1)
 | |
|                     return ((int)minHeight);
 | |
| 
 | |
|                 double height = pieChart.ContentBoundsEx.Height * minHeight;
 | |
| 
 | |
|                 int n = (int)(height / fheight);
 | |
| 
 | |
|                 return ((int)(fheight * n));
 | |
|             }
 | |
| 
 | |
|             return ((int)fheight);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region AdjustForPadding
 | |
| 
 | |
|         private Size AdjustForPadding(PieChart pieChart, PieSeriesPoint psp, Size size)
 | |
|         {
 | |
|             SliceOuterLabelVisualStyle sstyle =
 | |
|                 psp.GetEffectiveSliceStyle(pieChart, psp.ChartSeries).SliceOuterLabelStyle;
 | |
| 
 | |
|             size.Width += Dpi.Width(sstyle.Padding.Horizontal);
 | |
|             size.Height += Dpi.Width(sstyle.Padding.Vertical);
 | |
| 
 | |
|             return (size);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetOtherPieSeriesPoint
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the 'Other' PieSeriesPoint
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         public PieSeriesPoint GetOtherPieSeriesPoint()
 | |
|         {
 | |
|             return (SeriesPoints.OtherSlicePsp);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Mouse support
 | |
| 
 | |
|         #region ProcessMouseEnter
 | |
| 
 | |
|         internal void ProcessMouseEnter(EventArgs e, PieChart pieChart)
 | |
|         {
 | |
|             SetToolTip(pieChart.ShowToolTips ? GetToolTipText(pieChart) : string.Empty);
 | |
|         }
 | |
| 
 | |
|         #region SetToolTip
 | |
| 
 | |
|         private static string _toolTipText;
 | |
| 
 | |
|         private void SetToolTip(string toolTipText)
 | |
|         {
 | |
|             ChartControl chartControl = ChartControl;
 | |
| 
 | |
|             if (chartControl != null)
 | |
|             {
 | |
|                 if (chartControl.ToolTipText != _toolTipText)
 | |
|                     chartControl.ToolTip.Hide(chartControl);
 | |
| 
 | |
|                 chartControl.ToolTipText = toolTipText;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetToolTipText
 | |
| 
 | |
|         private string GetToolTipText(PieChart pieChart)
 | |
|         {
 | |
|             PieSeriesPoint psp = pieChart.HitPsp;
 | |
| 
 | |
|             if (psp == null || "".Equals(psp.ToolTipText))
 | |
|                 return (string.Empty);
 | |
| 
 | |
|             if (_toolTipText == null)
 | |
|             {
 | |
|                 ChartControl chartControl = ChartControl;
 | |
| 
 | |
|                 string s = "";
 | |
| 
 | |
|                 if (chartControl.DoGetToolTipEvent(pieChart, this, psp, ref s) == false)
 | |
|                     s = psp.ToolTipTextEx;
 | |
| 
 | |
|                 _toolTipText = psp.FormatItemText(s);
 | |
|             }
 | |
| 
 | |
|             return (_toolTipText);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessMouseLeave
 | |
| 
 | |
|         internal void ProcessMouseLeave(EventArgs e, PieChart pieChart)
 | |
|         {
 | |
|             ChartControl chartControl = ChartControl;
 | |
| 
 | |
|             if (chartControl != null)
 | |
|                 chartControl.ToolTipText = "";
 | |
| 
 | |
|             _toolTipText = null;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessMouseDown
 | |
| 
 | |
|         internal bool ProcessMouseDown(
 | |
|             MouseEventArgs e, PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             pieChart.IsDragging = false;
 | |
|             pieChart.PspDragType = PspDragType.None;
 | |
| 
 | |
|             if ((Control.MouseButtons & MouseButtons.Left) == MouseButtons.Left)
 | |
|             {
 | |
|                 _MouseDownPsp = psp;
 | |
| 
 | |
|                 Point cpt = pieChart.GetLocalAdjustedPoint(pieChart.CenterPoint);
 | |
| 
 | |
|                 Point rpt = e.Location;
 | |
|                 _MouseDownRadius = MathHelper.GetPointRadius(ref rpt, cpt);
 | |
| 
 | |
|                 if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
 | |
|                 {
 | |
|                     _MouseDownOffset = (int)pieChart.ExplodedOffsetEx;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     PieSeriesPoint rootPsp = (ShowAllRingsEx(pieChart) == true)
 | |
|                         ? psp.RootPsp : psp;
 | |
| 
 | |
|                     _MouseDownOffset = (double.IsNaN(rootPsp.DetachedOffset) == false)
 | |
|                         ? (int)rootPsp.DetachedOffset : 0;
 | |
|                 }
 | |
| 
 | |
|                 MouseClickSliceAction mca = GetMouseClickSliceAction(pieChart);
 | |
| 
 | |
|                 switch (mca)
 | |
|                 {
 | |
|                     case MouseClickSliceAction.Explode:
 | |
|                     case MouseClickSliceAction.Detach:
 | |
|                         InitPspDrag(pieChart, psp);
 | |
|                         break;
 | |
| 
 | |
|                     case MouseClickSliceAction.Select:
 | |
|                         ProcessSliceSelect(e, pieChart, psp);
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region InitPspDrag
 | |
| 
 | |
|         private bool InitPspDrag(PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
 | |
|             {
 | |
|                 if (pieChart.EnableShiftDragExplode == true)
 | |
|                 {
 | |
|                     pieChart.PspDragType = PspDragType.Explode;
 | |
| 
 | |
|                     return (true);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (GetEnableDragDetach(pieChart) == true)
 | |
|                 {
 | |
|                     pieChart.PspDragType = PspDragType.Detach;
 | |
| 
 | |
|                     return (psp.IsSelected);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessSliceSelect
 | |
| 
 | |
|         private void ProcessSliceSelect(
 | |
|             MouseEventArgs e, PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             bool select = true;
 | |
| 
 | |
|             if ((pieChart.MultiSelect == true) &&
 | |
|                 (Control.ModifierKeys & Keys.Control) == Keys.Control)
 | |
|             {
 | |
|                 select = !psp.IsSelected;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (InitPspDrag(pieChart, psp) == true)
 | |
|                     return;
 | |
| 
 | |
|                 int selCount = pieChart.GetSelectionCount();
 | |
| 
 | |
|                 if (selCount != 1 || psp.IsSelected == false)
 | |
|                     pieChart.SetSelected(false);
 | |
|             }
 | |
| 
 | |
|             ProcessSliceSelectEx(pieChart, psp, select);
 | |
|         }
 | |
| 
 | |
|         #region ProcessSliceSelectEx
 | |
| 
 | |
|         private void ProcessSliceSelectEx(
 | |
|             PieChart pieChart, PieSeriesPoint psp, bool select)
 | |
|         {
 | |
|             PieSelectionMode psm = GetPieSelectionMode(pieChart);
 | |
| 
 | |
|             switch (psm)
 | |
|             {
 | |
|                 case PieSelectionMode.Pie:
 | |
|                     pieChart.SetSelected(select);
 | |
|                     break;
 | |
| 
 | |
|                 case PieSelectionMode.Series:
 | |
|                     SelectPspSeries(SeriesPoints, true, select);
 | |
|                     break;
 | |
| 
 | |
|                 case PieSelectionMode.Ring:
 | |
|                     SelectPspRing(psp, select);
 | |
|                     break;
 | |
| 
 | |
|                 case PieSelectionMode.Slice:
 | |
|                     SelectPspSlice(pieChart, psp, select);
 | |
|                     break;
 | |
| 
 | |
|                 case PieSelectionMode.Point:
 | |
|                     psp.IsSelected = select;
 | |
|                     break;
 | |
|             }
 | |
| 
 | |
|             ChartControl.DoPieSelectionChangedEvent(pieChart, this, psp, psm);
 | |
|         }
 | |
| 
 | |
|         #region SelectPspSeries
 | |
| 
 | |
|         private void SelectPspSeries(
 | |
|             PieSeriesPointCollection spc, bool showInner, bool select)
 | |
|         {
 | |
|             if (spc != null)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc)
 | |
|                 {
 | |
|                     if (psp.AllowSelect == true)
 | |
|                     {
 | |
|                         psp.IsSelected = select;
 | |
| 
 | |
|                         if (showInner == true)
 | |
|                             SelectPspSeries(psp.SeriesPoints, true, select);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SelectPspRing
 | |
| 
 | |
|         private void SelectPspRing(PieSeriesPoint psp, bool select)
 | |
|         {
 | |
|             if (psp.PieRing != null)
 | |
|             {
 | |
|                 if (psp.PieRing.AllowSelect == true)
 | |
|                 {
 | |
|                     foreach (PieSeriesPoint rpsp in psp.PieRing.Psps)
 | |
|                     {
 | |
|                         if (rpsp.AllowSelect == true)
 | |
|                             rpsp.IsSelected = select;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SelectPspSlice
 | |
| 
 | |
|         private void SelectPspSlice(
 | |
|             PieChart pieChart, PieSeriesPoint psp, bool select)
 | |
|         {
 | |
|             PieSeriesPoint rootPsp = (ShowAllRingsEx(pieChart) == true)
 | |
|                 ? psp.RootPsp : psp;
 | |
| 
 | |
|             if (rootPsp != null)
 | |
|             {
 | |
|                 if (rootPsp.AllowSelect == true)
 | |
|                 {
 | |
|                     rootPsp.IsSelected = select;
 | |
| 
 | |
|                     SelectPspSliceEx(rootPsp.SeriesPoints, select);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region SelectPspSliceEx
 | |
| 
 | |
|         private void SelectPspSliceEx(PieSeriesPointCollection spc, bool select)
 | |
|         {
 | |
|             if (spc != null)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc)
 | |
|                 {
 | |
|                     if (psp.AllowSelect == true)
 | |
|                     {
 | |
|                         psp.IsSelected = select;
 | |
| 
 | |
|                         SelectPspSliceEx(psp.SeriesPoints, select);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessMouseMove
 | |
| 
 | |
|         internal void ProcessMouseMove(MouseEventArgs e, PieChart pieChart)
 | |
|         {
 | |
|             if (IsMouseDown == true && _MouseDownPsp != null)
 | |
|                 ProcessMouseDownMove(e, pieChart);
 | |
|         }
 | |
| 
 | |
|         #region ProcessMouseDownMove
 | |
| 
 | |
|         private bool ProcessMouseDownMove(MouseEventArgs e, PieChart pieChart)
 | |
|         {
 | |
|             Point pt = e.Location;
 | |
| 
 | |
|             if (pieChart.IsDragging == false)
 | |
|             {
 | |
|                 if (Math.Abs(MouseDownPoint.X - pt.X) > 3 ||
 | |
|                     Math.Abs(MouseDownPoint.Y - pt.Y) > 3)
 | |
|                 {
 | |
|                     pieChart.IsDragging = true;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 int deltaOffset = GetDeltaOffset(pieChart, pt);
 | |
| 
 | |
|                 MouseClickSliceAction mca = GetMouseClickSliceAction(pieChart);
 | |
| 
 | |
|                 switch (pieChart.PspDragType)
 | |
|                 {
 | |
|                     case PspDragType.Detach:
 | |
|                         if (GetEnableDragDetach(pieChart) == true)
 | |
|                             DetachSelectedPsps(pieChart, mca, deltaOffset);
 | |
|                         break;
 | |
| 
 | |
|                     case PspDragType.Explode:
 | |
|                         if (pieChart.EnableShiftDragExplode == true)
 | |
|                             ExplodePie(pieChart, deltaOffset);
 | |
|                         break;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (true);
 | |
|         }
 | |
| 
 | |
|         #region GetDeltaOffset
 | |
| 
 | |
|         private int GetDeltaOffset(PieChart pieChart, Point pt)
 | |
|         {
 | |
|             PieSeriesPoint psp = pieChart.HitPsp;
 | |
| 
 | |
|             if (psp != null)
 | |
|             {
 | |
|                 Point cpt = pieChart.GetLocalAdjustedPoint(pieChart.CenterPoint);
 | |
| 
 | |
|                 Point rpt = pt;
 | |
|                 double radius = MathHelper.GetPointRadius(ref rpt, cpt);
 | |
| 
 | |
|                 if (ShowAllRingsEx(pieChart) == true)
 | |
|                 {
 | |
|                     double pspAngle = MathHelper.GetPointAngle(rpt);
 | |
| 
 | |
|                     double angle = psp.CenterAngle - pspAngle;
 | |
|                     double delta = Math.Cos(MathHelper.ToRadians(angle)) * radius;
 | |
| 
 | |
|                     return ((int)delta);
 | |
|                 }
 | |
| 
 | |
|                 return ((int)radius);
 | |
|             }
 | |
| 
 | |
|             return (0);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region DetachSelectedPsps
 | |
| 
 | |
|         private void DetachSelectedPsps(
 | |
|             PieChart pieChart, MouseClickSliceAction mca, int deltaOffset)
 | |
|         {
 | |
|             int offset = Math.Max(0, deltaOffset - _MouseDownRadius + _MouseDownOffset);
 | |
|             offset = Math.Min(offset, pieChart.MaxDetachedOffset);
 | |
| 
 | |
|             PieSeriesPoint pspRoot =
 | |
|                 ShowAllRingsEx(pieChart) ? _MouseDownPsp.RootPsp : _MouseDownPsp;
 | |
| 
 | |
|             PieSelectionMode psm = GetPieSelectionMode(pieChart);
 | |
| 
 | |
|             bool detachChange = false;
 | |
| 
 | |
|             switch (psm)
 | |
|             {
 | |
|                 case PieSelectionMode.Pie:
 | |
|                     foreach (PieSeries series in pieChart.ChartSeries)
 | |
|                     {
 | |
|                         if (series.IsDisplayed == true)
 | |
|                         {
 | |
|                             foreach (PieSeriesPoint psp in series.SeriesPoints)
 | |
|                                 detachChange |= DetachPsp(psp, offset);
 | |
|                         }
 | |
|                     }
 | |
|                     break;
 | |
| 
 | |
|                 case PieSelectionMode.Series:
 | |
|                 case PieSelectionMode.Ring:
 | |
|                     if (pspRoot.PieRing.AllowDetach == true)
 | |
|                     {
 | |
|                         foreach (PieSeriesPoint psp in pspRoot.PieRing.Psps)
 | |
|                             detachChange |= DetachPsp(psp, offset);
 | |
|                     }
 | |
|                     break;
 | |
| 
 | |
|                 case PieSelectionMode.Slice:
 | |
|                 case PieSelectionMode.Point:
 | |
|                     if (mca == MouseClickSliceAction.Select)
 | |
|                     {
 | |
|                         if (pspRoot.PieRing.AllowDetach == true)
 | |
|                         {
 | |
|                             foreach (PieSeriesPoint psp in pspRoot.PieRing.Psps)
 | |
|                             {
 | |
|                                 if (psp.IsSelected == true)
 | |
|                                     detachChange |= DetachPsp(psp, offset);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         detachChange |= DetachPsp(pspRoot, offset);
 | |
|                     }
 | |
|                     break;
 | |
|             }
 | |
| 
 | |
|             ChartControl.DoPieDetachChangedEvent(pieChart, this, psm);
 | |
|         }
 | |
| 
 | |
|         #region DetachPsp
 | |
| 
 | |
|         private void DetachPsp(PieSeriesPoint psp)
 | |
|         {
 | |
|             DetachPsp(psp, psp.DetachedOffset);
 | |
|         }
 | |
| 
 | |
|         private bool DetachPsp(PieSeriesPoint psp, double offset)
 | |
|         {
 | |
|             if (psp.AllowDetach == true)
 | |
|             {
 | |
|                 if (psp.DetachedOffset != offset || psp.IsDetached != (offset > 0))
 | |
|                 {
 | |
|                     psp.DetachedOffset = offset;
 | |
|                     psp.IsDetached = (offset > 0);
 | |
| 
 | |
|                     return (true);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ExplodePie
 | |
| 
 | |
|         private void ExplodePie(PieChart pieChart, int deltaOffset)
 | |
|         {
 | |
|             int offset = Math.Max(0, deltaOffset - _MouseDownRadius + _MouseDownOffset);
 | |
| 
 | |
|             offset = Math.Min(offset, pieChart.MaxExplodedOffset);
 | |
| 
 | |
|             if (pieChart.ExplodedOffset != offset || pieChart.IsExploded != (offset > 0))
 | |
|             {
 | |
|                 pieChart.IsExploded = (offset > 0);
 | |
|                 pieChart.ExplodedOffset = offset;
 | |
| 
 | |
|                 ChartControl.DoPieExplodeChangedEvent(pieChart, this);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessMouseUp
 | |
| 
 | |
|         internal void ProcessMouseUp(MouseEventArgs e, PieChart pieChart)
 | |
|         {
 | |
|             if (pieChart.IsDragging == false)
 | |
|             {
 | |
|                 PieSeriesPoint psp = pieChart.HitPsp;
 | |
| 
 | |
|                 if (psp != null && psp == _MouseDownPsp)
 | |
|                 {
 | |
|                     ChartControl chartControl = ChartControl;
 | |
| 
 | |
|                     if (chartControl.DoChartMouseClickEvent(pieChart, psp, e) == false)
 | |
|                     {
 | |
|                         MouseClickSliceAction mca = GetMouseClickSliceAction(pieChart);
 | |
| 
 | |
|                         switch (mca)
 | |
|                         {
 | |
|                             case MouseClickSliceAction.Explode:
 | |
|                                 pieChart.IsExploded = !pieChart.IsExploded;
 | |
|                                 break;
 | |
| 
 | |
|                             case MouseClickSliceAction.Detach:
 | |
|                                 DetachPsp(ShowAllRingsEx(pieChart) ? psp.RootPsp : psp);
 | |
|                                 break;
 | |
| 
 | |
|                             case MouseClickSliceAction.Select:
 | |
|                                 if ((Control.ModifierKeys & Keys.Control) == Keys.None)
 | |
|                                 {
 | |
|                                     int selCount = pieChart.GetSelectionCount();
 | |
| 
 | |
|                                     if (selCount != 1 || psp.IsSelected == false)
 | |
|                                         pieChart.SetSelected(false);
 | |
| 
 | |
|                                     ProcessSliceSelectEx(pieChart, psp, true);
 | |
|                                 }
 | |
|                                 break;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessMouseDoubleClick
 | |
| 
 | |
|         internal bool ProcessMouseDoubleClick(
 | |
|             MouseEventArgs e, PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             if (e.Button == MouseButtons.Left)
 | |
|             {
 | |
|                 MouseDoubleClickSliceAction mdca = GetMouseDoubleClickSliceAction(pieChart);
 | |
| 
 | |
|                 switch (mdca)
 | |
|                 {
 | |
|                     case MouseDoubleClickSliceAction.Detach:
 | |
|                         psp.IsDetached = !psp.IsDetached;
 | |
|                         break;
 | |
| 
 | |
|                     case MouseDoubleClickSliceAction.Explode:
 | |
|                         pieChart.IsExploded = !pieChart.IsExploded;
 | |
|                         break;
 | |
| 
 | |
|                     case MouseDoubleClickSliceAction.ChangeActiveRing:
 | |
|                         Keys keys = Control.ModifierKeys;
 | |
| 
 | |
|                         if ((keys & Keys.Shift) == Keys.Shift)
 | |
|                             ProcessPieDrillUp(pieChart, psp);
 | |
| 
 | |
|                         else if ((keys & Keys.Control) == Keys.None)
 | |
|                             ProcessPieDrillDown(pieChart, psp);
 | |
|                         break;
 | |
|                 }
 | |
| 
 | |
|                 return (true);
 | |
|             }
 | |
| 
 | |
|             return (false);
 | |
|         }
 | |
| 
 | |
|         #region ProcessPieDrillUp
 | |
| 
 | |
|         private void ProcessPieDrillUp(PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             PieSeriesPointCollection spc1 = psp.Parent as PieSeriesPointCollection;
 | |
| 
 | |
|             if (spc1 != null)
 | |
|             {
 | |
|                 PieSeriesPoint psp2 = spc1.Parent as PieSeriesPoint;
 | |
| 
 | |
|                 if (psp2 != null)
 | |
|                 {
 | |
|                     PieSeriesPointCollection spc2 = GetPieSeriesPointCollection(psp2);
 | |
| 
 | |
|                     if (spc2 != null)
 | |
|                     {
 | |
|                         ChartControl chartControl = ChartControl;
 | |
| 
 | |
|                         if (chartControl.DoPieRingLevelChangingEvent(pieChart, spc1, spc2) == false)
 | |
|                         {
 | |
|                             SetActiveSeriesPointCollection(spc2);
 | |
| 
 | |
|                             chartControl.DoPieRingLevelChangedEvent(pieChart, spc1, spc2);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessPieDrillDown
 | |
| 
 | |
|         private void ProcessPieDrillDown(PieChart pieChart, PieSeriesPoint psp)
 | |
|         {
 | |
|             if (psp.ChartSeries.ShowAllRingsEx(pieChart) == false)
 | |
|             {
 | |
|                 PieSeriesPointCollection spc1 = psp.Parent as PieSeriesPointCollection;
 | |
| 
 | |
|                 if (psp.SeriesPoints.Count > 0)
 | |
|                 {
 | |
|                     ChartControl chartControl = ChartControl;
 | |
|                     PieSeriesPointCollection spc2 = psp.SeriesPoints;
 | |
| 
 | |
|                     if (chartControl.DoPieRingLevelChangingEvent(pieChart, spc1, spc2) == false)
 | |
|                     {
 | |
|                         SetActiveSeriesPointCollection(psp.SeriesPoints);
 | |
| 
 | |
|                         chartControl.DoPieRingLevelChangedEvent(pieChart, spc1, spc2);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region SetSelected
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Selects or clears all series PieSeriesPoints.
 | |
|         /// </summary>
 | |
|         /// <param name="select"></param>
 | |
|         public void SetSelected(bool select)
 | |
|         {
 | |
|             PieSeriesPointCollection spc = SeriesPoints;
 | |
| 
 | |
|             spc.SetSelected(select);
 | |
| 
 | |
|             if (spc.OtherSlicePsp != null)
 | |
|                 spc.OtherSlicePsp.IsSelected = select;
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetVisibleSelectionCount
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets the count of the currently Visible selected pie series points.
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         public int GetVisibleSelectionCount()
 | |
|         {
 | |
|             int count = GetVisibleSelectionCountEx(SeriesPoints);
 | |
| 
 | |
|             return (count);
 | |
|         }
 | |
| 
 | |
|         #region GetVisibleSelectionCountEx
 | |
| 
 | |
|         private int GetVisibleSelectionCountEx(PieSeriesPointCollection spc)
 | |
|         {
 | |
|             int count = 0;
 | |
| 
 | |
|             if (spc != null && spc.Count > 0)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc)
 | |
|                 {
 | |
|                     if (psp.IsSelected == true && psp.Visible == true)
 | |
|                         count++;
 | |
| 
 | |
|                     count += GetVisibleSelectionCountEx(psp.SeriesPoints);
 | |
|                 }
 | |
| 
 | |
|                 if (spc.OtherSlicePsp != null)
 | |
|                 {
 | |
|                     if (spc.OtherSlicePsp.IsSelected == true && spc.OtherSlicePsp.Visible == true)
 | |
|                         count++;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (count);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetVisibleSelectedPoints
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets a list of the currently Visible selected pie series points.
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         public List<PieSeriesPoint> GetVisibleSelectedPoints()
 | |
|         {
 | |
|             List<PieSeriesPoint> list = new List<PieSeriesPoint>();
 | |
| 
 | |
|             GetVisibleSelectedPointsEx(list, SeriesPoints);
 | |
| 
 | |
|             return (list);
 | |
|         }
 | |
| 
 | |
|         #region GetVisibleSelectedPointsEx
 | |
| 
 | |
|         private void GetVisibleSelectedPointsEx(
 | |
|             List<PieSeriesPoint> list, PieSeriesPointCollection spc)
 | |
|         {
 | |
|             if (spc != null && spc.Count > 0)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc)
 | |
|                 {
 | |
|                     if (psp.IsSelected == true && psp.Visible == true)
 | |
|                         list.Add(psp);
 | |
| 
 | |
|                     GetVisibleSelectedPointsEx(list, psp.SeriesPoints);
 | |
|                 }
 | |
| 
 | |
|                 if (spc.OtherSlicePsp != null)
 | |
|                 {
 | |
|                     if (spc.OtherSlicePsp.IsSelected == true && spc.OtherSlicePsp.Visible == true)
 | |
|                         list.Add(spc.OtherSlicePsp);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetSelectionCount
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets a count of the selected pie series points.
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         public int GetSelectionCount()
 | |
|         {
 | |
|             int count = GetSelectionCountEx(SeriesPoints);
 | |
| 
 | |
|             return (count);
 | |
|         }
 | |
| 
 | |
|         #region GetSelectionCountEx
 | |
| 
 | |
|         private int GetSelectionCountEx(PieSeriesPointCollection spc)
 | |
|         {
 | |
|             int count = 0;
 | |
| 
 | |
|             if (spc != null && spc.Count > 0)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc)
 | |
|                 {
 | |
|                     if (psp.IsSelected == true)
 | |
|                         count++;
 | |
| 
 | |
|                     count += GetSelectionCountEx(psp.SeriesPoints);
 | |
|                 }
 | |
| 
 | |
|                 if (spc.OtherSlicePsp != null)
 | |
|                 {
 | |
|                     if (spc.OtherSlicePsp.IsSelected == true )
 | |
|                         count++;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (count);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetSelectedPoints
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets a list of the currently selected pie series points.
 | |
|         /// </summary>
 | |
|         /// <returns></returns>
 | |
|         public List<PieSeriesPoint> GetSelectedPoints()
 | |
|         {
 | |
|             List<PieSeriesPoint> list = new List<PieSeriesPoint>();
 | |
| 
 | |
|             GetSelectedPointsEx(list, SeriesPoints);
 | |
| 
 | |
|             return (list);
 | |
|         }
 | |
| 
 | |
|         #region GetSelectedPointsEx
 | |
| 
 | |
|         private void GetSelectedPointsEx(
 | |
|             List<PieSeriesPoint> list, PieSeriesPointCollection spc)
 | |
|         {
 | |
|             if (spc != null && spc.Count > 0)
 | |
|             {
 | |
|                 foreach (PieSeriesPoint psp in spc)
 | |
|                 {
 | |
|                     if (psp.IsSelected == true)
 | |
|                         list.Add(psp);
 | |
| 
 | |
|                     GetSelectedPointsEx(list, psp.SeriesPoints);
 | |
|                 }
 | |
| 
 | |
|                 if (spc.OtherSlicePsp != null)
 | |
|                 {
 | |
|                     if (spc.OtherSlicePsp.IsSelected == true)
 | |
|                         list.Add(spc.OtherSlicePsp);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Style handling
 | |
| 
 | |
|         #region StyleChanged
 | |
| 
 | |
|         protected override void StyleChanged(object sender, PropertyChangedEventArgs e)
 | |
|         {
 | |
|             base.StyleChanged(sender, e);
 | |
| 
 | |
|             if (sender is ChartLegendItemVisualStyles && LegendItem != null)
 | |
|                 InvalidateRender(LegendItem.Bounds);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region InvalidateRender
 | |
| 
 | |
|         public override void InvalidateRender()
 | |
|         {
 | |
|             BaseChart chart = Parent as BaseChart;
 | |
| 
 | |
|             if (chart != null)
 | |
|                 chart.InvalidateRender();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region InvalidateRecalc
 | |
| 
 | |
|         internal override void InvalidateRecalc()
 | |
|         {
 | |
|             SeriesRangeChanged = true;
 | |
| 
 | |
|             base.InvalidateRecalc();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ILegendItem
 | |
| 
 | |
|         #region GetLegendItem
 | |
| 
 | |
|         public override ChartLegendItem GetLegendItem()
 | |
|         {
 | |
|             LegendItem = null;
 | |
| 
 | |
|             if (ShowInLegend == true)
 | |
|             {
 | |
|                 PieChart pieChart = Parent as PieChart;
 | |
| 
 | |
|                 if (pieChart != null)
 | |
|                 {
 | |
|                     if (pieChart.VisibleSeriesCount > 1)
 | |
|                     {
 | |
|                         if (pieChart.Legend.ShowPieSeriesInLegend == true)
 | |
|                         {
 | |
|                             LegendItem = base.GetLegendItem();
 | |
| 
 | |
|                             LegendItem.ShowCheckBox = pieChart.Legend.ShowPieSeriesCheckBoxes;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (LegendItem);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region AddSubLegendItems
 | |
| 
 | |
|         internal override void AddSubLegendItems(List<ChartLegendItem> list)
 | |
|         {
 | |
|             PieChart pieChart = Parent as PieChart;
 | |
| 
 | |
|             if (pieChart != null)
 | |
|             {
 | |
|                 if (ShowInLegend == true)
 | |
|                 {
 | |
|                     ChartLegend legend = pieChart.Legend;
 | |
| 
 | |
|                     if (ShowAllRingsEx(pieChart) == true)
 | |
|                     {
 | |
|                         if (PieRings != null && PieRings.Count > 0)
 | |
|                         {
 | |
|                             bool addRings =
 | |
|                                 ((PieRings.Count > 1) && 
 | |
|                                  (pieChart.Legend.ShowPieRingsInLegend == true));
 | |
| 
 | |
|                             foreach (PieRing pieRing in PieRings)
 | |
|                             {
 | |
|                                 if (addRings == true)
 | |
|                                 {
 | |
|                                     ChartLegendItem litem = pieRing.GetLegendItem();
 | |
| 
 | |
|                                     if (litem != null)
 | |
|                                     {
 | |
|                                         litem.ShowCheckBox = legend.ShowPieRingCheckBoxes;
 | |
|                                         list.Add(litem);
 | |
|                                     }
 | |
|                                 }
 | |
| 
 | |
|                                 if (legend.ShowPieSeriesPointsInLegend == true)
 | |
|                                     AddSubLegendItemsEx(legend, list, pieRing.GetLegendItems());
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         PieSeriesPointCollection spc = GetActiveSeriesPointCollection();
 | |
| 
 | |
|                         if (spc != null)
 | |
|                         {
 | |
|                             if (spc.PieSlices != null)
 | |
|                                 spc = spc.PieSlices;
 | |
| 
 | |
|                             if (spc != null)
 | |
|                             {
 | |
|                                 foreach (PieSeriesPoint psp in spc)
 | |
|                                 {
 | |
|                                     if (psp.IsDisplayable == true)
 | |
|                                         AddSubLegendItemsEx(legend, list, psp.GetLegendItems());
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region AddSubLegendItemsEx
 | |
| 
 | |
|         private void AddSubLegendItemsEx(ChartLegend legend,
 | |
|             List<ChartLegendItem> list, List<ChartLegendItem> items)
 | |
|         {
 | |
|             if (items != null && items.Count > 0)
 | |
|             {
 | |
|                 foreach (ChartLegendItem item in items)
 | |
|                 {
 | |
|                     item.ShowCheckBox = legend.ShowPieSeriesPointCheckBoxes;
 | |
| 
 | |
|                     if (legend.CombineLikeItems == true)
 | |
|                     {
 | |
|                         ChartLegendItem likeItem = FindLikeItems(list, item);
 | |
| 
 | |
|                         if (likeItem == null)
 | |
|                         {
 | |
|                             item.ChartControl = ChartControl;
 | |
| 
 | |
|                             likeItem = new ChartLegendItem();
 | |
| 
 | |
|                             likeItem.Parent = legend;
 | |
|                             likeItem.ChartControl = ChartControl;
 | |
| 
 | |
|                             likeItem.Name = item.Name;
 | |
|                             likeItem.ItemText = item.ItemText;
 | |
|                             likeItem.IsEnabled = item.IsEnabled;
 | |
| 
 | |
|                             list.Add(likeItem);
 | |
|                         }
 | |
| 
 | |
|                         item.LikeItem = likeItem;
 | |
| 
 | |
|                         likeItem.ChartItems.AddRange(item.ChartItems);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         list.Add(item);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #region FindLikeItems
 | |
| 
 | |
|         private ChartLegendItem FindLikeItems(List<ChartLegendItem> list, ChartLegendItem item)
 | |
|         {
 | |
|             string itemName = item.Name ?? item.ItemText;
 | |
| 
 | |
|             if (String.IsNullOrEmpty(itemName) == false)
 | |
|             {
 | |
|                 foreach (ChartLegendItem likeItem in list)
 | |
|                 {
 | |
|                     string likeName = likeItem.Name ?? likeItem.ItemText;
 | |
| 
 | |
|                     if (String.IsNullOrEmpty(likeName) == false)
 | |
|                     {
 | |
|                         if (likeName.Equals(itemName) == true)
 | |
|                             return (likeItem);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (null);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetLegendItemColorEx
 | |
| 
 | |
|         internal override Color GetLegendItemColorEx()
 | |
|         {
 | |
|             return (Color.Empty);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region RenderLegendItemMarkerEx
 | |
| 
 | |
|         internal override void RenderLegendItemMarkerEx(
 | |
|             Graphics g, ChartLegendItem litem, ChartLegendItemVisualStyle style)
 | |
|         {
 | |
|             Rectangle bounds = litem.MarkerBounds;
 | |
| 
 | |
|             bounds.Width--;
 | |
|             bounds.Height--;
 | |
| 
 | |
|             Color color = GetLegendItemColor();
 | |
| 
 | |
|             using (GraphicsPath path = new GraphicsPath())
 | |
|             {
 | |
|                 path.AddEllipse(bounds);
 | |
| 
 | |
|                 using (Brush br = new SolidBrush(color))
 | |
|                     g.FillPath(br, path);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region TrackLegendItem
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Gets whether legend item tracking is enabled.
 | |
|         /// </summary>
 | |
|         [Browsable(false)]
 | |
|         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 | |
|         public bool TrackLegendItem
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 PieChart pieChart = Parent as PieChart;
 | |
| 
 | |
|                 if (pieChart != null)
 | |
|                 {
 | |
|                     return (pieChart.Legend.TrackingMode == LegendTrackingMode.ChartAndLegend ||
 | |
|                         pieChart.Legend.TrackingMode == LegendTrackingMode.Legend);
 | |
|                 }
 | |
| 
 | |
|                 return (false);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region FormatItemText
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Formats the provided item text.
 | |
|         /// </summary>
 | |
|         [Browsable(false)]
 | |
|         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 | |
|         public string FormatItemText(string text)
 | |
|         {
 | |
|             return (text);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region OnCheckStateChanged
 | |
| 
 | |
|         internal override void OnCheckStateChanged()
 | |
|         {
 | |
|             if (LegendItem != null)
 | |
|                 LegendItem.UpdateCheckState();
 | |
| 
 | |
|             foreach (PieRing pieRing in PieRings)
 | |
|             {
 | |
|                 if (pieRing.LegendItem != null)
 | |
|                 {
 | |
|                     pieRing.LegendItem.IsEnabled = pieRing.IsEnabled;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     foreach (PieSeriesPoint psp in pieRing.Psps)
 | |
|                     {
 | |
|                         if (psp.LegendItem != null)
 | |
|                             psp.LegendItem.IsEnabled = psp.IsEnabled;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             base.OnCheckStateChanged();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Copy/CopyTo
 | |
| 
 | |
|         public override ChartVisualElement Copy()
 | |
|         {
 | |
|             ChartSeries copy = new ChartSeries();
 | |
| 
 | |
|             CopyTo(copy);
 | |
| 
 | |
|             return (copy);
 | |
|         }
 | |
| 
 | |
|         public override void CopyTo(ChartVisualElement copy)
 | |
|         {
 | |
|             PieSeries c = copy as PieSeries;
 | |
| 
 | |
|             if (c != null)
 | |
|             {
 | |
|                 base.CopyTo(c);
 | |
| 
 | |
|                 c.CenterFirstSlice = CenterFirstSlice;
 | |
| 
 | |
|                 if (_CustomPalette != null)
 | |
|                 {
 | |
|                     c.CustomPalette = new Color[CustomPalette.Length];
 | |
| 
 | |
|                     CustomPalette.CopyTo(c.CustomPalette, 0);
 | |
|                 }
 | |
| 
 | |
|                 c.EnableDragDetach = EnableDragDetach;
 | |
|                 c.ExplodedMargin = ExplodedMargin;
 | |
| 
 | |
|                 c.MouseClickSliceAction = MouseClickSliceAction;
 | |
|                 c.MouseDoubleClickSliceAction = MouseDoubleClickSliceAction;
 | |
| 
 | |
|                 c.PaletteGroup = PaletteGroup;
 | |
|                 c.PieSelectionMode = PieSelectionMode;
 | |
|                 c.ReversePaletteColors = ReversePaletteColors;
 | |
|                 c.RingWeight = RingWeight;
 | |
| 
 | |
|                 c.SubSliceVisualLayout = (_SliceVisualLayout != null) ? _SliceVisualLayout.Copy() : null;
 | |
| 
 | |
|                 foreach (PieSeriesPoint psp in SeriesPoints)
 | |
|                     c.SeriesPoints.Add(psp.Copy());
 | |
| 
 | |
|                 c.ShowAllRings = ShowAllRings;
 | |
|                 c.ShowOtherSlice = ShowOtherSlice;
 | |
| 
 | |
|                 c.SubSliceVisualLayout = (_SliceVisualLayout != null) ? SubSliceVisualLayout.Copy() : null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region GetSerialData
 | |
| 
 | |
|         internal override SerialElementCollection GetSerialData(string serialName)
 | |
|         {
 | |
|             SerialElementCollection sec = new SerialElementCollection();
 | |
| 
 | |
|             if (serialName != null)
 | |
|             {
 | |
|                 if (serialName.Equals("") == true)
 | |
|                     serialName = "PieSeries";
 | |
| 
 | |
|                 sec.AddStartElement(serialName);
 | |
|             }
 | |
| 
 | |
|             sec.AddValue("CenterFirstSlice", CenterFirstSlice, Tbool.NotSet);
 | |
| 
 | |
|             if (_CustomPalette != null && _CustomPalette.Length > 0)
 | |
|             {
 | |
|                 sec.AddStartElement("CustomPalette count=\"" + _CustomPalette.Length + "\"");
 | |
| 
 | |
|                 foreach (Color color in _CustomPalette)
 | |
|                     sec.AddValue("PaletteColor", color);
 | |
| 
 | |
|                 sec.AddEndElement("CustomPalette");
 | |
|             }
 | |
| 
 | |
|             sec.AddValue("EnableDragDetach", EnableDragDetach, Tbool.NotSet);
 | |
|             sec.AddValue("ExplodedMargin", ExplodedMargin, double.NaN);
 | |
| 
 | |
|             sec.AddValue("MouseClickSliceAction", MouseClickSliceAction, MouseClickSliceAction.NotSet);
 | |
|             sec.AddValue("MouseDoubleClickSliceAction", MouseDoubleClickSliceAction, MouseDoubleClickSliceAction.NotSet);
 | |
| 
 | |
|             sec.AddValue("PaletteGroup", PaletteGroup, PaletteGroup.NotSet);
 | |
|             sec.AddValue("PieSelectionMode", PieSelectionMode, PieSelectionMode.NotSet);
 | |
|             sec.AddValue("ReversePaletteColors", ReversePaletteColors, false);
 | |
|             sec.AddValue("RingWeight", RingWeight, 100);
 | |
| 
 | |
|             if (_SeriesPoints != null)
 | |
|             {
 | |
|                 PieSeriesPointCollection spc = _SeriesPoints;
 | |
| 
 | |
|                 if (spc.Count > 0)
 | |
|                 {
 | |
|                     sec.AddStartElement("SeriesPoints count=\"" + spc.Count + "\"");
 | |
| 
 | |
|                     foreach (PieSeriesPoint psp in spc)
 | |
|                         sec.AddElement(psp.GetSerialData());
 | |
| 
 | |
|                     sec.AddEndElement("SeriesPoints");
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             sec.AddValue("ShowAllRings", ShowAllRings, Tbool.NotSet);
 | |
|             sec.AddValue("ShowOtherSlice", ShowOtherSlice, Tbool.NotSet);
 | |
| 
 | |
|             if (_SliceVisualLayout != null)
 | |
|                 sec.AddElement(_SliceVisualLayout.GetSerialData(true));
 | |
| 
 | |
|             sec.AddElement(base.GetSerialData(null));
 | |
| 
 | |
|             if (serialName != null)
 | |
|                 sec.AddEndElement(serialName);
 | |
| 
 | |
|             return (sec);
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region PutSerialData
 | |
| 
 | |
|         #region ProcessValue
 | |
| 
 | |
|         internal override void ProcessValue(SerialElement se)
 | |
|         {
 | |
|             ChartXy chartXy = Parent as ChartXy;
 | |
| 
 | |
|             switch (se.Name)
 | |
|             {
 | |
|                 case "CenterFirstSlice":
 | |
|                     CenterFirstSlice = (Tbool)se.GetValueEnum(typeof(Tbool));
 | |
|                     break;
 | |
| 
 | |
|                 case "EnableDragDetach":
 | |
|                     EnableDragDetach = (Tbool)se.GetValueEnum(typeof(Tbool));
 | |
|                     break;
 | |
| 
 | |
|                 case "ExplodedMargin":
 | |
|                     ExplodedMargin = double.Parse(se.StringValue);
 | |
|                     break;
 | |
| 
 | |
|                 case "MouseClickSliceAction":
 | |
|                     MouseClickSliceAction = (MouseClickSliceAction)se.GetValueEnum(typeof(MouseClickSliceAction));
 | |
|                     break;
 | |
| 
 | |
|                 case "MouseDoubleClickSliceAction":
 | |
|                     MouseDoubleClickSliceAction = (MouseDoubleClickSliceAction)se.GetValueEnum(typeof(MouseDoubleClickSliceAction));
 | |
|                     break;
 | |
| 
 | |
|                 case "PaletteColor":
 | |
|                     CustomPalette[se.ValueIndex] = se.GetValueColor();
 | |
|                     break;
 | |
| 
 | |
|                 case "PaletteGroup":
 | |
|                     PaletteGroup = (PaletteGroup)se.GetValueEnum(typeof(PaletteGroup));
 | |
|                     break;
 | |
| 
 | |
|                 case "PieSelectionMode":
 | |
|                     PieSelectionMode = (PieSelectionMode)se.GetValueEnum(typeof(PieSelectionMode));
 | |
|                     break;
 | |
| 
 | |
|                 case "ReversePaletteColors":
 | |
|                     ReversePaletteColors = bool.Parse(se.StringValue);
 | |
|                     break;
 | |
| 
 | |
|                 case "RingWeight":
 | |
|                     RingWeight = int.Parse(se.StringValue);
 | |
|                     break;
 | |
| 
 | |
|                 case "ShowAllRings":
 | |
|                     ShowAllRings = (Tbool)se.GetValueEnum(typeof(Tbool));
 | |
|                     break;
 | |
| 
 | |
|                 case "ShowOtherSlice":
 | |
|                     ShowOtherSlice = (Tbool)se.GetValueEnum(typeof(Tbool));
 | |
|                     break;
 | |
| 
 | |
|                 default:
 | |
|                     base.ProcessValue(se);
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region ProcessCollection
 | |
| 
 | |
|         internal override void ProcessCollection(SerialElement se)
 | |
|         {
 | |
|             SerialElementCollection sec = se.Sec;
 | |
| 
 | |
|             switch (se.Name)
 | |
|             {
 | |
|                 case "CustomPalette":
 | |
|                     if (se.ArrayCount > 0)
 | |
|                     {
 | |
|                         CustomPalette = new Color[se.ArrayCount];
 | |
| 
 | |
|                         sec.PutSerialData(this);
 | |
|                     }
 | |
|                     break;
 | |
| 
 | |
|                 case "SeriesPoint":
 | |
|                     PieSeriesPoint psp = new PieSeriesPoint();
 | |
| 
 | |
|                     sec.PutSerialData(psp);
 | |
| 
 | |
|                     SeriesPoints.Add(psp);
 | |
|                     break;
 | |
| 
 | |
|                 case "SeriesPoints":
 | |
|                     if (se.ArrayCount > 0)
 | |
|                     {
 | |
|                         SeriesPoints = new PieSeriesPointCollection();
 | |
| 
 | |
|                         sec.PutSerialData(this);
 | |
|                     }
 | |
|                     break;
 | |
| 
 | |
|                 case "SliceVisualLayout":
 | |
|                     sec.PutSerialData(SubSliceVisualLayout);
 | |
|                     break;
 | |
| 
 | |
|                 default:
 | |
|                     base.ProcessCollection(se);
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #endregion
 | |
| 
 | |
|         #region Series States
 | |
| 
 | |
|         [Flags]
 | |
|         private enum States : uint
 | |
|         {
 | |
|             FilterIgnoreMatchCase = (1U << 0),
 | |
| 
 | |
|             IsSorted = (1U << 1),
 | |
|             IsRotated = (1U << 2),
 | |
| 
 | |
|             StackQualitativePoints = (1U << 3),
 | |
|             DisplayLinePointsOnTop = (1U << 4),
 | |
| 
 | |
|             EnableEmptyValues = (1U << 5),
 | |
|             ShowEmptyLines = (1U << 6),
 | |
|             ShowEmptyPoints = (1U << 7),
 | |
|             ShowOriginValueLabels = (1U << 8),
 | |
|             ShowHiLoBarMedianLines = (1U << 9),
 | |
| 
 | |
|             NeedToUpdateBindings = (1U << 10),
 | |
| 
 | |
|             IsInnerRingSeries = (1U << 11),
 | |
|             IsOuterRingSeries = (1U << 12),
 | |
| 
 | |
|             IsOffset = (1U << 13),
 | |
|             IsDetached = (1U << 14),
 | |
| 
 | |
|             ShowInnerRingsEx = (1U << 15),
 | |
|             ReversePaletteColors = (1U << 16),
 | |
|         }
 | |
| 
 | |
|         #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 IDisposable
 | |
| 
 | |
|         public override void Dispose()
 | |
|         {
 | |
|             Visible = false;
 | |
| 
 | |
|             SeriesPoints = null;
 | |
|             SubSliceVisualLayout = null;
 | |
| 
 | |
|             base.Dispose();
 | |
|         }
 | |
| 
 | |
|         #endregion
 | |
|     }
 | |
| 
 | |
|     #region WordPos
 | |
| 
 | |
|     internal class WordPos
 | |
|     {
 | |
|         public string Text;
 | |
| 
 | |
|         public int Index;
 | |
|         public int Length;
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #region WordPosLine
 | |
| 
 | |
|     internal class WordPosLine
 | |
|     {
 | |
|         public double ArcWidth;
 | |
|         public double LineWidth;
 | |
|         public double Offset;
 | |
| 
 | |
|         public List<WordPos> Wps = new List<WordPos>();
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #region enums
 | |
| 
 | |
|     #region SliceRenderType
 | |
| 
 | |
|     public enum SliceRenderType
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// Full slice.
 | |
|         /// </summary>
 | |
|         FullSlice,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extent slice (partial slice).
 | |
|         /// </summary>
 | |
|         ExtentSlice,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extentwhitespace.
 | |
|         /// </summary>
 | |
|         ExtentWhitespace,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// 'Other' slice whitespace.
 | |
|         /// </summary>
 | |
|         OtherWhitespace,
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #region ExtentFillRange
 | |
| 
 | |
|     public enum ExtentFillRange
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// Not set (default is ByPoint)
 | |
|         /// </summary>
 | |
|         NotSet = 0,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extents are filled according to each individual
 | |
|         /// PieSeriesPoint extent value.
 | |
|         /// </summary>
 | |
|         ByPoint,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extents are filled according to the slice
 | |
|         /// maximum extent value.
 | |
|         /// </summary>
 | |
|         BySlice,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extents are filled according to the associated
 | |
|         /// PieRing maximum extent value.
 | |
|         /// </summary>
 | |
|         ByRing,
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #region SliceImageCropMode
 | |
| 
 | |
|     public enum SliceImageCropMode
 | |
|     {
 | |
|         NotSet = -1,
 | |
| 
 | |
|         NoAction,
 | |
|         ClipImage,
 | |
|         HideImage,
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #region SliceImageRadiusAnchor
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Defines the anchor for the slice image (ie. the image's bounding edge).
 | |
|     /// </summary>
 | |
|     public enum SliceImageRadiusAnchor
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// NotSet
 | |
|         /// </summary>
 | |
|         NotSet = -1,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The pie InnerRadius will be the anchor. 
 | |
|         /// </summary>
 | |
|         InnerRadius,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The pie ExtentRadius will be the anchor. The 'ExtentRadius' denotes
 | |
|         /// how far the slice extends out from the slice center - which may not
 | |
|         /// be as far as the OuterRadius (specified by the ValuesY[1] value).
 | |
|         /// </summary>
 | |
|         ExtentRadius,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The pie OuterRadius will be the anchor. 
 | |
|         /// </summary>
 | |
|         OuterRadius,
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #region PieRefLineDisplayMode
 | |
| 
 | |
|     [Flags]
 | |
|     /// <summary>
 | |
|     /// Defines the type of ReferenceLine to display.
 | |
|     /// </summary>
 | |
|     public enum PieRefLineDisplayMode
 | |
|     {
 | |
|         /// <summary>
 | |
|         /// NotSet
 | |
|         /// </summary>
 | |
|         NotSet = 0,
 | |
| 
 | |
|         /// <summary>
 | |
|         /// No Reference lines
 | |
|         /// </summary>
 | |
|         None = (1 << 0),
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extent Average Line. 
 | |
|         /// </summary>
 | |
|         ExtentAverage = (1 << 3),
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extent Minimum Line.
 | |
|         /// </summary>
 | |
|         ExtentMaximum = (1 << 2),
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Extent Minimum Line.
 | |
|         /// </summary>
 | |
|         ExtentMinimum = (1 << 1),
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Outer Extent Line.
 | |
|         /// </summary>
 | |
|         ExtentOuterRadius = (1 << 4),
 | |
| 
 | |
|         /// <summary>
 | |
|         /// All User defined Lines.
 | |
|         /// </summary>
 | |
|         UserDefined = (1 << 5),
 | |
|     }
 | |
| 
 | |
|     #endregion
 | |
| 
 | |
|     #endregion
 | |
| }
 |