1 //-------------------------------------------------------------
2 // <copyright company=�Microsoft Corporation�>
3 //   Copyright � Microsoft Corporation. All Rights Reserved.
4 // </copyright>
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 //  File:		Axis.cs
9 //
10 //  Namespace:	System.Web.UI.WebControls[Windows.Forms].Charting
11 //
12 //	Classes:	Axis
13 //
14 //  Purpose:	Axis related properties and methods. Axis class gives
15 //				information to Common.Chart series about
16 //				position in the Common.Chart area and keeps all necessary
17 //				information about axes.
18 //
19 //	Reviewed:	GS - August 6, 2002
20 //				AG - August 7, 2002
21 //
22 //===================================================================
23 
24 #region Used namespace
25 using System;
26 using System.Collections;
27 using System.Collections.Specialized;
28 using System.ComponentModel;
29 using System.ComponentModel.Design;
30 using System.Data;
31 using System.Drawing;
32 using System.Drawing.Design;
33 using System.Drawing.Text;
34 using System.Drawing.Drawing2D;
35 using System.Diagnostics.CodeAnalysis;
36 #if Microsoft_CONTROL
37 	using System.Windows.Forms.DataVisualization.Charting;
38 	using System.Windows.Forms.DataVisualization.Charting.Data;
39 	using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
40 	using System.Windows.Forms.DataVisualization.Charting.Utilities;
41 	using System.Windows.Forms.DataVisualization.Charting.Borders3D;
42 
43 #else
44 using System.Web;
45 using System.Web.UI;
46 using System.Web.UI.DataVisualization.Charting;
47 using System.Web.UI.DataVisualization.Charting.Data;
48 using System.Web.UI.DataVisualization.Charting.Utilities;
49 using System.Web.UI.DataVisualization.Charting.ChartTypes;
50 #endif
51 
52 
53 #endregion
54 
55 #if Microsoft_CONTROL
56 	namespace System.Windows.Forms.DataVisualization.Charting
57 #else
58 namespace System.Web.UI.DataVisualization.Charting
59 
60 #endif
61 {
62     #region Axis name enumeration
63 
64     /// <summary>
65     /// An enumeration of auto-fitting styles of the axis labels.
66     /// </summary>
67     [Flags]
68     public enum LabelAutoFitStyles
69     {
70         /// <summary>
71         /// No auto-fitting.
72         /// </summary>
73         None = 0,
74         /// <summary>
75         /// Allow font size increasing.
76         /// </summary>
77         IncreaseFont = 1,
78         /// <summary>
79         /// Allow font size decreasing.
80         /// </summary>
81         DecreaseFont = 2,
82         /// <summary>
83         /// Allow using staggered labels.
84         /// </summary>
85         StaggeredLabels = 4,
86         /// <summary>
87         /// Allow changing labels angle using values of 0, 30, 60 and 90 degrees.
88         /// </summary>
89         LabelsAngleStep30 = 8,
90         /// <summary>
91         /// Allow changing labels angle using values of 0, 45, 90 degrees.
92         /// </summary>
93         LabelsAngleStep45 = 16,
94         /// <summary>
95         /// Allow changing labels angle using values of 0 and 90 degrees.
96         /// </summary>
97         LabelsAngleStep90 = 32,
98         /// <summary>
99         /// Allow replacing spaces with the new line character.
100         /// </summary>
101         WordWrap = 64,
102     }
103 
104     /// <summary>
105     /// An enumeration of axis names.
106     /// </summary>
107     public enum AxisName
108     {
109         /// <summary>
110         /// Primary X Axis.
111         /// </summary>
112 
113         [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "X")]
114         X = 0,
115         /// <summary>
116         /// Primary Y Axis.
117         /// </summary>
118         [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Y")]
119         Y = 1,
120         /// <summary>
121         /// Secondary X Axis.
122         /// </summary>
123         X2 = 2,
124         /// <summary>
125         /// Secondary Y Axis.
126         /// </summary>
127         Y2 = 3
128     }
129 
130     #endregion
131 
132     /// <summary>
133     /// The Axis class gives information to the Common.Chart series
134     /// about positions in the Common.Chart area and keeps all of
135     ///	the data about the axis.
136     /// </summary>
137     [
138         SRDescription("DescriptionAttributeAxis_Axis"),
139         DefaultProperty("Enabled"),
140     ]
141 #if ASPPERM_35
142 	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
143     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
144 #endif
145 #if Microsoft_CONTROL
146     public partial class Axis :  ChartNamedElement
147 #else
148 	public partial class Axis :  ChartNamedElement, IChartMapArea
149 #endif
150     {
151         #region Axis fields
152 
153         /// <summary>
154         /// Plot area position
155         /// </summary>
156         internal ElementPosition PlotAreaPosition;
157 
158         // This field synchronies Store and Reset temporary values
159         private bool _storeValuesEnabled = true;
160 
161         private FontCache _fontCache = new FontCache();
162         private Font  _titleFont;
163         private Color _titleForeColor = Color.Black;
164         private StringAlignment _titleAlignment = StringAlignment.Center;
165         private string _title = "";
166         private int _lineWidth = 1;
167         private ChartDashStyle _lineDashStyle = ChartDashStyle.Solid;
168         private Color _lineColor = Color.Black;
169         private bool _isLabelAutoFit = true;
170         private AxisArrowStyle _arrowStyle = AxisArrowStyle.None;
171         private StripLinesCollection _stripLines = null;
172         private bool _isMarksNextToAxis = true;
173 
174         // Default text orientation
175         private TextOrientation _textOrientation = TextOrientation.Auto;
176 
177         // Size of the axis elements in percentage
178         internal float titleSize = 0F;
179         internal float labelSize = 0F;
180         internal float labelNearOffset = 0F;
181         internal float labelFarOffset = 0F;
182         internal float unRotatedLabelSize = 0F;
183         internal float markSize = 0F;
184         internal float scrollBarSize = 0F;
185         internal float totlaGroupingLabelsSize = 0F;
186         internal float[] groupingLabelSizes = null;
187         internal float totlaGroupingLabelsSizeAdjustment = 0f;
188         private LabelAutoFitStyles _labelAutoFitStyle = LabelAutoFitStyles.DecreaseFont |
189                                                             LabelAutoFitStyles.IncreaseFont |
190                                                             LabelAutoFitStyles.LabelsAngleStep30 |
191                                                             LabelAutoFitStyles.StaggeredLabels |
192                                                             LabelAutoFitStyles.WordWrap;
193 
194         // Auto calculated font for labels
195         internal Font autoLabelFont = null;
196         internal int autoLabelAngle = -1000;
197         internal int autoLabelOffset = -1;
198 
199         // Labels auto fitting constants
200         private float _aveLabelFontSize = 10F;
201         private float _minLabelFontSize = 5F;
202         // Determines maximum label size of the chart area.
203         private float _maximumAutoSize = 75f;
204 
205         // Chart title position rectangle
206         private RectangleF _titlePosition = RectangleF.Empty;
207 
208         // Element spacing size
209         internal const float elementSpacing = 1F;
210 
211         // Maximum total size of the axis's elements in percentage
212         private const float maxAxisElementsSize = 75F;
213 
214         // Maximum size of the axis title in percentage
215         private const float maxAxisTitleSize = 20F;
216 
217         // Maximum size of the axis second row of labels in percentage
218         // of the total labels size
219         private const float maxAxisLabelRow2Size = 45F;
220 
221         // Maximum size of the axis tick marks in percentage
222         private const float maxAxisMarkSize = 20F;
223 
224         // Minimum cached value from data series.
225         internal double minimumFromData = double.NaN;
226 
227         // Maximum cached value from data series.
228         internal double maximumFromData = double.NaN;
229 
230         // Flag, which tells to Set Data method to take, again values from
231         // data source and not to use cached values.
232         internal bool refreshMinMaxFromData = true;
233 
234         // Flag, which tells to Set Data method to take, again values from
235         // data source and not to use cached values.
236         internal int numberOfPointsInAllSeries = 0;
237 
238         // Original axis scaleView position
239         private double _originalViewPosition = double.NaN;
240 
241 
242         /// <summary>
243         /// Indicates that isInterlaced strip lines will be displayed for the axis.
244         /// </summary>
245         private bool _isInterlaced = false;
246 
247         /// <summary>
248         /// Color used to draw isInterlaced strip lines for the axis.
249         /// </summary>
250         private Color _interlacedColor = Color.Empty;
251 
252         /// <summary>
253         /// Axis interval offset.
254         /// </summary>
255         private double _intervalOffset = 0;
256 
257         /// <summary>
258         /// Axis interval.
259         /// </summary>
260         internal double interval = 0;
261 
262         /// <summary>
263         /// Axis interval units type.
264         /// </summary>
265         internal DateTimeIntervalType intervalType = DateTimeIntervalType.Auto;
266 
267         /// <summary>
268         /// Axis interval offset units type.
269         /// </summary>
270         internal DateTimeIntervalType intervalOffsetType = DateTimeIntervalType.Auto;
271 
272         /// <summary>
273 		/// Minimum font size that can be used by the labels auto-fitting algorithm.
274 		/// </summary>
275 		internal int					labelAutoFitMinFontSize = 6;
276 
277 		/// <summary>
278 		/// Maximum font size that can be used by the labels auto-fitting algorithm.
279 		/// </summary>
280 		internal int					labelAutoFitMaxFontSize = 10;
281 
282 		/// <summary>
283 		/// Axis tooltip
284 		/// </summary>
285 		private	string					_toolTip = String.Empty;
286 
287         /// <summary>
288         /// Axis HREF
289         /// </summary>
290         private string _url = String.Empty;
291 
292 #if !Microsoft_CONTROL
293 
294 
295         /// <summary>
296 		/// Axis map area attributes
297 		/// </summary>
298 		private	string					_mapAreaAttributes = String.Empty;
299 
300         private string _postbackValue = String.Empty;
301 
302 #endif
303 
304         #endregion
305 
306         #region Axis constructor and initialization
307 
308         /// <summary>
309         /// Default constructor of Axis.
310         /// </summary>
Axis()311         public Axis()
312             : base(null, GetName(AxisName.X))
313         {
314             Initialize(AxisName.X);
315         }
316 
317         /// <summary>
318         /// Axis constructor.
319         /// </summary>
320         /// <param name="chartArea">The chart area the axis belongs to.</param>
321         /// <param name="axisTypeName">The type of the axis.</param>
Axis(ChartArea chartArea, AxisName axisTypeName)322         public Axis(ChartArea chartArea, AxisName axisTypeName)
323             : base(chartArea, GetName(axisTypeName))
324         {
325             Initialize(axisTypeName);
326         }
327 
328         /// <summary>
329         /// Initialize axis class
330         /// </summary>
331         /// <param name="axisTypeName">Name of the axis type.</param>
Initialize(AxisName axisTypeName)332         private void Initialize(AxisName axisTypeName)
333         {
334             // DT: Axis could be already created. Don't recreate new labelstyle and other objects.
335             // Initialize axis labels
336             if (labelStyle == null)
337             {
338                 labelStyle = new LabelStyle(this);
339             }
340             if (_customLabels == null)
341             {
342                 _customLabels = new CustomLabelsCollection(this);
343             }
344             if (_scaleView == null)
345             {
346                 // Create axis data scaleView object
347                 _scaleView = new AxisScaleView(this);
348             }
349 #if Microsoft_CONTROL
350             if (scrollBar == null)
351             {
352                 // Create axis croll bar class
353                 scrollBar = new AxisScrollBar(this);
354             }
355 #endif // Microsoft_CONTROL
356 
357             this.axisType = axisTypeName;
358 
359             // Create grid & tick marks objects
360             if (minorTickMark == null)
361             {
362                 minorTickMark = new TickMark(this, false);
363             }
364             if (majorTickMark == null)
365             {
366                 majorTickMark = new TickMark(this, true);
367                 majorTickMark.Interval = double.NaN;
368                 majorTickMark.IntervalOffset = double.NaN;
369                 majorTickMark.IntervalType = DateTimeIntervalType.NotSet;
370                 majorTickMark.IntervalOffsetType = DateTimeIntervalType.NotSet;
371             }
372             if (minorGrid == null)
373             {
374                 minorGrid = new Grid(this, false);
375             }
376             if (majorGrid == null)
377             {
378                 majorGrid = new Grid(this, true);
379                 majorGrid.Interval = double.NaN;
380                 majorGrid.IntervalOffset = double.NaN;
381                 majorGrid.IntervalType = DateTimeIntervalType.NotSet;
382                 majorGrid.IntervalOffsetType = DateTimeIntervalType.NotSet;
383             }
384             if (this._stripLines == null)
385             {
386                 this._stripLines = new StripLinesCollection(this);
387             }
388 
389             if (_titleFont == null)
390             {
391                 _titleFont = _fontCache.DefaultFont;
392             }
393 #if SUBAXES
394 			if(this.subAxes == null)
395 			{
396 				this.subAxes = new SubAxisCollection(this);
397 			}
398 #endif // SUBAXES
399 
400 #if Microsoft_CONTROL
401 
402             // Initialize axis scroll bar class
403             this.ScrollBar.Initialize();
404 
405 #endif // Microsoft_CONTROL
406 
407             // Create collection of scale segments
408             if (this.scaleSegments == null)
409             {
410                 this.scaleSegments = new AxisScaleSegmentCollection(this);
411             }
412 
413             // Create scale break style
414             if (this.axisScaleBreakStyle == null)
415             {
416                 this.axisScaleBreakStyle = new AxisScaleBreakStyle(this);
417             }
418         }
419 
420         /// <summary>
421         /// Initialize axis class
422         /// </summary>
423         /// <param name="chartArea">Chart area that the axis belongs.</param>
424         /// <param name="axisTypeName">Axis type.</param>
Initialize(ChartArea chartArea, AxisName axisTypeName)425         internal void Initialize(ChartArea chartArea, AxisName axisTypeName)
426         {
427             this.Initialize(axisTypeName);
428             this.Parent = chartArea;
429             this.Name = GetName(axisTypeName);
430         }
431 
432         /// <summary>
433         /// Set Axis Name
434         /// </summary>
GetName(AxisName axisName)435         internal static string GetName(AxisName axisName)
436         {
437             // Set axis name.
438             // NOTE: Strings below should neber be localized. Name properties in the chart are never localized
439             // and represent consisten object name in all locales.
440             switch (axisName)
441             {
442                 case (AxisName.X):
443                     return "X axis";
444                 case (AxisName.Y):
445                     return "Y (Value) axis";
446                 case (AxisName.X2):
447                     return "Secondary X axis";
448                 case (AxisName.Y2):
449                     return "Secondary Y (Value) axis";
450             }
451             return null;
452         }
453 
454         #endregion
455 
456         #region Axis properies
457 
458         // Internal
459         internal ChartArea ChartArea
460         {
461             get { return Parent as ChartArea; }
462         }
463 
464         /// <summary>
465         /// Text orientation.
466         /// </summary>
467         [
468         SRCategory("CategoryAttributeTitle"),
469         Bindable(true),
470         DefaultValue(TextOrientation.Auto),
471         SRDescription("DescriptionAttribute_TextOrientation"),
472         NotifyParentPropertyAttribute(true),
473 #if !Microsoft_CONTROL
474 		PersistenceMode(PersistenceMode.Attribute)
475 #endif
476 ]
477         public TextOrientation TextOrientation
478         {
479             get
480             {
481                 return this._textOrientation;
482             }
483             set
484             {
485                 this._textOrientation = value;
486                 this.Invalidate();
487             }
488         }
489 
490         /// <summary>
491         /// Returns sub-axis name.
492         /// </summary>
493         virtual internal string SubAxisName
494         {
495             get
496             {
497                 return string.Empty;
498             }
499         }
500 
501 #if SUBAXES
502 
503 		/// <summary>
504 		/// Indicates if this axis object present the main or sub axis.
505 		/// </summary>
506 		virtual internal bool IsSubAxis
507 		{
508 			get
509 			{
510 				return false;
511 			}
512 		}
513 
514 		private SubAxisCollection subAxes = null;
515 
516 		/// <summary>
517 		/// Sub-axes collection.
518 		/// </summary>
519 		[
520 		SRCategory("CategoryAttributeSubAxes"),
521 		Bindable(true),
522 		SRDescription("DescriptionAttributeSubAxes"),
523 #if Microsoft_CONTROL
524 		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
525 #else
526 		PersistenceMode(PersistenceMode.InnerProperty),
527 #endif
528         Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
529 		]
530 		virtual public SubAxisCollection SubAxes
531 		{
532 			get
533 			{
534 				return this.subAxes;
535 			}
536 		}
537 
538 #endif // SUBAXES
539 
540         /// <summary>
541         /// Gets or sets a flag which indicates whether interlaced strip lines will be displayed for the axis.
542         /// </summary>
543         [
544         SRCategory("CategoryAttributeAppearance"),
545         Bindable(true),
546         DefaultValue(false),
547         SRDescription("DescriptionAttributeInterlaced"),
548 #if !Microsoft_CONTROL
549  PersistenceMode(PersistenceMode.Attribute),
550 #endif
551  NotifyParentPropertyAttribute(true),
552         ]
553         public bool IsInterlaced
554         {
555             get
556             {
557                 return _isInterlaced;
558             }
559             set
560             {
561                 _isInterlaced = value;
562                 this.Invalidate();
563             }
564         }
565 
566         /// <summary>
567         /// Gets or sets the color used to draw interlaced strip lines for the axis.
568         /// </summary>
569         [
570         SRCategory("CategoryAttributeAppearance"),
571         Bindable(true),
572         DefaultValue(typeof(Color), ""),
573         SRDescription("DescriptionAttributeInterlacedColor"),
574         NotifyParentPropertyAttribute(true),
575         TypeConverter(typeof(ColorConverter)),
576         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
577 #if !Microsoft_CONTROL
578  PersistenceMode(PersistenceMode.Attribute)
579 #endif
580 ]
581         public Color InterlacedColor
582         {
583             get
584             {
585                 return _interlacedColor;
586             }
587             set
588             {
589                 _interlacedColor = value;
590                 this.Invalidate();
591             }
592         }
593 
594         /// <summary>
595         /// Axis name. This field is reserved for internal use only.
596         /// </summary>
597         [
598         SRCategory("CategoryAttributeAppearance"),
599         Bindable(true),
600         Browsable(false),
601         DefaultValue(""),
602         SRDescription("DescriptionAttributeAxis_Name"),
603 #if !Microsoft_CONTROL
604  PersistenceMode(PersistenceMode.Attribute),
605 #endif
606  DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
607         SerializationVisibilityAttribute(SerializationVisibility.Hidden)
608         ]
609         public override string Name
610         {
611             get
612             {
613                 return base.Name;
614             }
615             set
616             {
617                 base.Name = value;
618             }
619         }
620 
621         /// <summary>
622         /// Axis name. This field is reserved for internal use only.
623         /// </summary>
624         [
625         SRCategory("CategoryAttributeAppearance"),
626         Bindable(true),
627         Browsable(false),
628         DefaultValue(""),
629         SRDescription("DescriptionAttributeType"),
630 #if !Microsoft_CONTROL
631  PersistenceMode(PersistenceMode.Attribute),
632 #endif
633  DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
634         SerializationVisibilityAttribute(SerializationVisibility.Hidden)
635         ]
636         virtual public AxisName AxisName
637         {
638             get
639             {
640                 return axisType;
641             }
642         }
643 
644         /// <summary>
645         /// Gets or sets the arrow style used for the axis.
646         /// </summary>
647         [
648         SRCategory("CategoryAttributeAppearance"),
649         Bindable(true),
650         DefaultValue(AxisArrowStyle.None),
651         NotifyParentPropertyAttribute(true),
652         SRDescription("DescriptionAttributeArrows"),
653 #if !Microsoft_CONTROL
654  PersistenceMode(PersistenceMode.Attribute)
655 #endif
656 ]
657         public AxisArrowStyle ArrowStyle
658         {
659             get
660             {
661                 return _arrowStyle;
662             }
663             set
664             {
665                 _arrowStyle = value;
666                 this.Invalidate();
667             }
668         }
669 
670         /// <summary>
671         /// Gets or sets the properties used for the major gridlines.
672         /// </summary>
673         [
674         SRCategory("CategoryAttributeGridTickMarks"),
675         Bindable(true),
676         NotifyParentPropertyAttribute(true),
677         SRDescription("DescriptionAttributeMajorGrid"),
678 #if Microsoft_CONTROL
679 		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
680 #else
681  PersistenceMode(PersistenceMode.InnerProperty),
682 #endif
683  TypeConverter(typeof(NoNameExpandableObjectConverter))
684         ]
685         public Grid MajorGrid
686         {
687             get
688             {
689                 return majorGrid;
690             }
691             set
692             {
693                 majorGrid = value;
694                 majorGrid.Axis = this;
695                 majorGrid.majorGridTick = true;
696 
697                 if (!majorGrid.intervalChanged)
698                     majorGrid.Interval = double.NaN;
699                 if (!majorGrid.intervalOffsetChanged)
700                     majorGrid.IntervalOffset = double.NaN;
701                 if (!majorGrid.intervalTypeChanged)
702                     majorGrid.IntervalType = DateTimeIntervalType.NotSet;
703                 if (!majorGrid.intervalOffsetTypeChanged)
704                     majorGrid.IntervalOffsetType = DateTimeIntervalType.NotSet;
705 
706                 this.Invalidate();
707             }
708         }
709 
710         /// <summary>
711         /// Gets or sets the properties used for the minor gridlines.
712         /// </summary>
713         [
714         SRCategory("CategoryAttributeGridTickMarks"),
715         Bindable(true),
716         NotifyParentPropertyAttribute(true),
717         SRDescription("DescriptionAttributeMinorGrid"),
718 #if Microsoft_CONTROL
719 		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
720 #else
721  PersistenceMode(PersistenceMode.InnerProperty),
722 #endif
723  TypeConverter(typeof(NoNameExpandableObjectConverter))
724         ]
725         public Grid MinorGrid
726         {
727             get
728             {
729                 return minorGrid;
730             }
731             set
732             {
733                 minorGrid = value;
734                 minorGrid.Initialize(this, false);
735                 this.Invalidate();
736             }
737         }
738 
739         /// <summary>
740         /// Gets or sets the properties used for the major tick marks.
741         /// </summary>
742         [
743         SRCategory("CategoryAttributeGridTickMarks"),
744         Bindable(true),
745         NotifyParentPropertyAttribute(true),
746         SRDescription("DescriptionAttributeMajorTickMark"),
747 #if Microsoft_CONTROL
748 		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
749 #else
750  PersistenceMode(PersistenceMode.InnerProperty),
751 #endif
752  TypeConverter(typeof(NoNameExpandableObjectConverter))
753         ]
754         public TickMark MajorTickMark
755         {
756             get
757             {
758                 return majorTickMark;
759             }
760             set
761             {
762                 majorTickMark = value;
763                 majorTickMark.Axis = this;
764                 majorTickMark.majorGridTick = true;
765 
766                 if (!majorTickMark.intervalChanged)
767                     majorTickMark.Interval = double.NaN;
768                 if (!majorTickMark.intervalOffsetChanged)
769                     majorTickMark.IntervalOffset = double.NaN;
770                 if (!majorTickMark.intervalTypeChanged)
771                     majorTickMark.IntervalType = DateTimeIntervalType.NotSet;
772                 if (!majorTickMark.intervalOffsetTypeChanged)
773                     majorTickMark.IntervalOffsetType = DateTimeIntervalType.NotSet;
774 
775                 this.Invalidate();
776             }
777         }
778 
779         /// <summary>
780         /// Gets or sets the properties used for the minor tick marks.
781         /// </summary>
782         [
783         SRCategory("CategoryAttributeGridTickMarks"),
784         Bindable(true),
785         NotifyParentPropertyAttribute(true),
786         SRDescription("DescriptionAttributeMinorTickMark"),
787 #if Microsoft_CONTROL
788 		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
789 #else
790  PersistenceMode(PersistenceMode.InnerProperty),
791 #endif
792  TypeConverter(typeof(NoNameExpandableObjectConverter))
793         ]
794         public TickMark MinorTickMark
795         {
796             get
797             {
798                 return minorTickMark;
799             }
800             set
801             {
802                 minorTickMark = value;
803                 minorTickMark.Initialize(this, false);
804                 this.Invalidate();
805             }
806         }
807 
808         /// <summary>
809         /// Gets or sets a flag which indicates whether auto-fitting of labels is enabled.
810         /// </summary>
811         [
812         SRCategory("CategoryAttributeLabels"),
813         Bindable(true),
814         DefaultValue(true),
815         SRDescription("DescriptionAttributeLabelsAutoFit"),
816         NotifyParentPropertyAttribute(true),
817 #if !Microsoft_CONTROL
818  PersistenceMode(PersistenceMode.Attribute),
819 #endif
820  RefreshPropertiesAttribute(RefreshProperties.All)
821         ]
822         public bool IsLabelAutoFit
823         {
824             get
825             {
826                 return _isLabelAutoFit;
827             }
828             set
829             {
830                 _isLabelAutoFit = value;
831                 this.Invalidate();
832             }
833         }
834 
835 
836 
837 		/// <summary>
838         /// Gets or sets the minimum font size that can be used by
839         /// the label auto-fitting algorithm.
840 		/// </summary>
841 		[
842 		SRCategory("CategoryAttributeLabels"),
843 		Bindable(true),
844 		DefaultValue(6),
845 		SRDescription("DescriptionAttributeLabelsAutoFitMinFontSize"),
846 		NotifyParentPropertyAttribute(true),
847 #if !Microsoft_CONTROL
848 		PersistenceMode(PersistenceMode.Attribute),
849 #endif
850 		RefreshPropertiesAttribute(RefreshProperties.All)
851 		]
852 		public int LabelAutoFitMinFontSize
853 		{
854 			get
855 			{
856 				return this.labelAutoFitMinFontSize;
857 			}
858 			set
859 			{
860 				// Font size cannot be less than 5
861 				if(value < 5)
862 				{
863                     throw (new InvalidOperationException(SR.ExceptionAxisLabelsAutoFitMinFontSizeValueInvalid));
864 				}
865 
866 				this.labelAutoFitMinFontSize = value;
867 				this.Invalidate();
868 			}
869 		}
870 
871 		/// <summary>
872         /// Gets or sets the maximum font size that can be used by
873         /// the label auto-fitting algorithm.
874 		/// </summary>
875 		[
876 		SRCategory("CategoryAttributeLabels"),
877 		Bindable(true),
878 		DefaultValue(10),
879 		SRDescription("DescriptionAttributeLabelsAutoFitMaxFontSize"),
880 		NotifyParentPropertyAttribute(true),
881 #if !Microsoft_CONTROL
882 		PersistenceMode(PersistenceMode.Attribute),
883 #endif
884 		RefreshPropertiesAttribute(RefreshProperties.All)
885 		]
886 		public int LabelAutoFitMaxFontSize
887 		{
888 			get
889 			{
890 				return this.labelAutoFitMaxFontSize;
891 			}
892 			set
893 			{
894 				// Font size cannot be less than 5
895 				if(value < 5)
896 				{
897                     throw (new InvalidOperationException(SR.ExceptionAxisLabelsAutoFitMaxFontSizeInvalid));
898 				}
899 
900 				this.labelAutoFitMaxFontSize = value;
901 				this.Invalidate();
902 			}
903 		}
904 
905 
906 
907         /// <summary>
908         /// Gets or sets the auto-fitting style used for the labels.
909         /// IsLabelAutoFit must be set to true.
910         /// </summary>
911         [
912         SRCategory("CategoryAttributeLabels"),
913         Bindable(true),
914         DefaultValue(LabelAutoFitStyles.DecreaseFont | LabelAutoFitStyles.IncreaseFont | LabelAutoFitStyles.LabelsAngleStep30 | LabelAutoFitStyles.StaggeredLabels | LabelAutoFitStyles.WordWrap),
915         SRDescription("DescriptionAttributeLabelsAutoFitStyle"),
916         NotifyParentPropertyAttribute(true),
917         Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base),
918 #if !Microsoft_CONTROL
919  PersistenceMode(PersistenceMode.Attribute),
920 #endif
921 ]
922         public LabelAutoFitStyles LabelAutoFitStyle
923         {
924             get
925             {
926                 return this._labelAutoFitStyle;
927             }
928             set
929             {
930                 this._labelAutoFitStyle = value;
931                 this.Invalidate();
932             }
933         }
934 
935         /// <summary>
936         /// Gets or sets a flag which indicates whether
937         /// tick marks and labels move with the axis when
938         /// the crossing value changes.
939         /// </summary>
940         [
941         SRCategory("CategoryAttributeAppearance"),
942         Bindable(true),
943         DefaultValue(true),
944         SRDescription("DescriptionAttributeMarksNextToAxis"),
945         NotifyParentPropertyAttribute(true),
946 #if !Microsoft_CONTROL
947  PersistenceMode(PersistenceMode.Attribute)
948 #endif
949 ]
950         virtual public bool IsMarksNextToAxis
951         {
952             get
953             {
954                 return _isMarksNextToAxis;
955             }
956             set
957             {
958                 _isMarksNextToAxis = value;
959                 this.Invalidate();
960             }
961         }
962 
963         /// <summary>
964         /// Gets or sets the axis title.
965         /// </summary>
966         [
967         SRCategory("CategoryAttributeTitle"),
968         Bindable(true),
969         DefaultValue(""),
970         SRDescription("DescriptionAttributeTitle6"),
971         NotifyParentPropertyAttribute(true),
972 #if !Microsoft_CONTROL
973  PersistenceMode(PersistenceMode.Attribute)
974 #endif
975 ]
976         public string Title
977         {
978             get
979             {
980                 return _title;
981             }
982             set
983             {
984                 _title = value;
985                 this.Invalidate();
986             }
987         }
988 
989         /// <summary>
990         /// Gets or sets the color of the axis title.
991         /// </summary>
992         [
993         SRCategory("CategoryAttributeTitle"),
994         Bindable(true),
995         DefaultValue(typeof(Color), "Black"),
996         SRDescription("DescriptionAttributeTitleColor"),
997         NotifyParentPropertyAttribute(true),
998         TypeConverter(typeof(ColorConverter)),
999         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
1000 #if !Microsoft_CONTROL
1001  PersistenceMode(PersistenceMode.Attribute)
1002 #endif
1003 ]
1004         public Color TitleForeColor
1005         {
1006             get
1007             {
1008                 return _titleForeColor;
1009             }
1010             set
1011             {
1012                 _titleForeColor = value;
1013                 this.Invalidate();
1014             }
1015         }
1016 
1017         /// <summary>
1018         /// Gets or sets the alignment of the axis title.
1019         /// </summary>
1020         [
1021         SRCategory("CategoryAttributeTitle"),
1022         Bindable(true),
1023         DefaultValue(typeof(StringAlignment), "Center"),
1024         SRDescription("DescriptionAttributeTitleAlignment"),
1025         NotifyParentPropertyAttribute(true),
1026 #if !Microsoft_CONTROL
1027  PersistenceMode(PersistenceMode.Attribute)
1028 #endif
1029 ]
1030         public StringAlignment TitleAlignment
1031         {
1032             get
1033             {
1034                 return _titleAlignment;
1035             }
1036             set
1037             {
1038                 _titleAlignment = value;
1039                 this.Invalidate();
1040             }
1041         }
1042 
1043         /// <summary>
1044         /// Gets or sets the font used for the axis title.
1045         /// </summary>
1046         [
1047         SRCategory("CategoryAttributeTitle"),
1048         Bindable(true),
1049         DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
1050         SRDescription("DescriptionAttributeTitleFont"),
1051         NotifyParentPropertyAttribute(true),
1052 #if !Microsoft_CONTROL
1053  PersistenceMode(PersistenceMode.Attribute)
1054 #endif
1055 ]
1056         public Font TitleFont
1057         {
1058             get
1059             {
1060                 return _titleFont;
1061             }
1062             set
1063             {
1064                 _titleFont = value;
1065                 this.Invalidate();
1066             }
1067         }
1068 
1069         /// <summary>
1070         /// Gets or sets the line color of the axis.
1071         /// </summary>
1072         [
1073         SRCategory("CategoryAttributeAppearance"),
1074         Bindable(true),
1075         DefaultValue(typeof(Color), "Black"),
1076         SRDescription("DescriptionAttributeLineColor"),
1077         NotifyParentPropertyAttribute(true),
1078         TypeConverter(typeof(ColorConverter)),
1079         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
1080 #if !Microsoft_CONTROL
1081  PersistenceMode(PersistenceMode.Attribute)
1082 #endif
1083 ]
1084         public Color LineColor
1085         {
1086             get
1087             {
1088                 return _lineColor;
1089             }
1090             set
1091             {
1092                 _lineColor = value;
1093                 this.Invalidate();
1094             }
1095         }
1096 
1097         /// <summary>
1098         /// Gets or sets the line width of the axis.
1099         /// </summary>
1100         [
1101         SRCategory("CategoryAttributeAppearance"),
1102         Bindable(true),
1103         DefaultValue(1),
1104         SRDescription("DescriptionAttributeLineWidth"),
1105         NotifyParentPropertyAttribute(true),
1106 #if !Microsoft_CONTROL
1107  PersistenceMode(PersistenceMode.Attribute)
1108 #endif
1109 ]
1110         public int LineWidth
1111         {
1112             get
1113             {
1114                 return _lineWidth;
1115             }
1116             set
1117             {
1118                 if (value < 0)
1119                 {
1120                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionAxisWidthIsNegative));
1121                 }
1122                 _lineWidth = value;
1123                 this.Invalidate();
1124             }
1125         }
1126 
1127         /// <summary>
1128         /// Gets or sets the line style of the axis.
1129         /// </summary>
1130         [
1131         SRCategory("CategoryAttributeAppearance"),
1132         Bindable(true),
1133         DefaultValue(ChartDashStyle.Solid),
1134         SRDescription("DescriptionAttributeLineDashStyle"),
1135         NotifyParentPropertyAttribute(true),
1136 #if !Microsoft_CONTROL
1137  PersistenceMode(PersistenceMode.Attribute)
1138 #endif
1139 ]
1140         public ChartDashStyle LineDashStyle
1141         {
1142             get
1143             {
1144                 return _lineDashStyle;
1145             }
1146             set
1147             {
1148                 _lineDashStyle = value;
1149                 this.Invalidate();
1150             }
1151         }
1152 
1153         /// <summary>
1154         /// The collection of strip lines of the axis.
1155         /// </summary>
1156         [
1157         SRCategory("CategoryAttributeAppearance"),
1158         Bindable(true),
1159         SRDescription("DescriptionAttributeStripLines"),
1160 #if Microsoft_CONTROL
1161 		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
1162 #else
1163  PersistenceMode(PersistenceMode.InnerProperty),
1164 #endif
1165         Editor(Editors.ChartCollectionEditor.Editor, Editors.ChartCollectionEditor.Base)
1166         ]
1167         public StripLinesCollection StripLines
1168         {
1169             get
1170             {
1171                 return _stripLines;
1172             }
1173         }
1174 
1175 
1176         /// <summary>
1177         /// Gets or sets the maximum size (in percentage) of the axis used in the automatic layout algorithm.
1178         /// </summary>
1179         /// <remarks>
1180         /// This property determines the maximum size of the axis, measured as a percentage of the chart area.
1181         /// </remarks>
1182         [
1183         SRCategory("CategoryAttributeLabels"),
1184         DefaultValue(75f),
1185         SRDescription("DescriptionAttributeAxis_MaxAutoSize"),
1186         ]
1187         public float MaximumAutoSize
1188         {
1189             get
1190             {
1191                 return this._maximumAutoSize;
1192             }
1193             set
1194             {
1195                 if (value < 0f || value > 100f)
1196                 {
1197                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionValueMustBeInRange("MaximumAutoSize", "0", "100")));
1198                 }
1199                 this._maximumAutoSize = value;
1200                 this.Invalidate();
1201             }
1202         }
1203         #endregion
1204 
1205         #region	IMapAreaAttributes Properties implementation
1206 
1207 		/// <summary>
1208 		/// Tooltip of the axis.
1209 		/// </summary>
1210 		[
1211 		SRCategory("CategoryAttributeMapArea"),
1212 		Bindable(true),
1213 		SRDescription("DescriptionAttributeToolTip"),
1214 		DefaultValue(""),
1215 		]
1216 		public string ToolTip
1217 		{
1218 			set
1219 			{
1220 				this._toolTip = value;
1221 			}
1222 			get
1223 			{
1224 				return this._toolTip;
1225 			}
1226 		}
1227 
1228 #if !Microsoft_CONTROL
1229 
1230 		/// <summary>
1231 		/// URL target of the axis.
1232 		/// </summary>
1233 		[
1234 		SRCategory("CategoryAttributeMapArea"),
1235 		Bindable(true),
1236 		SRDescription("DescriptionAttributeUrl"),
1237 		DefaultValue(""),
1238 		PersistenceMode(PersistenceMode.Attribute),
1239         Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base)
1240 		]
1241 		public string Url
1242 		{
1243 			set
1244 			{
1245 				this._url = value;
1246 			}
1247 			get
1248 			{
1249                 return this._url;
1250 			}
1251 		}
1252 
1253 
1254 		/// <summary>
1255 		/// Gets or sets the map area attributes.
1256 		/// </summary>
1257 		[
1258 		SRCategory("CategoryAttributeMapArea"),
1259 		Bindable(true),
1260 		SRDescription("DescriptionAttributeMapAreaAttributes"),
1261 		DefaultValue(""),
1262 		PersistenceMode(PersistenceMode.Attribute)
1263 		]
1264 		public string MapAreaAttributes
1265 		{
1266 			set
1267 			{
1268 				this._mapAreaAttributes = value;
1269 			}
1270 			get
1271 			{
1272                 return this._mapAreaAttributes;
1273 			}
1274 		}
1275 
1276         /// <summary>
1277         /// Gets or sets the postback value which can be processed on click event.
1278         /// </summary>
1279         /// <value>The value which is passed to click event as argument.</value>
1280         [DefaultValue("")]
1281         [SRCategory(SR.Keys.CategoryAttributeMapArea)]
1282         [SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
1283         public string PostBackValue
1284         {
1285             get
1286             {
1287                 return this._postbackValue;
1288             }
1289             set
1290             {
1291                 this._postbackValue = value;
1292             }
1293         }
1294 
1295 
1296 #endif // !Microsoft_CONTROL
1297 
1298 
1299 
1300         #endregion
1301 
1302         #region Axis Interavl properies
1303 
1304         /// <summary>
1305         /// Axis interval size.
1306         /// </summary>
1307         [
1308         SRCategory("CategoryAttributeInterval"),
1309         Bindable(true),
1310         DefaultValue(0.0),
1311         SRDescription("DescriptionAttributeInterval4"),
1312         RefreshPropertiesAttribute(RefreshProperties.All),
1313         TypeConverter(typeof(AxisIntervalValueConverter)),
1314 #if !Microsoft_CONTROL
1315  PersistenceMode(PersistenceMode.Attribute),
1316 #endif
1317 ]
1318         public double Interval
1319         {
1320             get
1321             {
1322                 return interval;
1323             }
1324             set
1325             {
1326                 // Axis interval properties must be set
1327                 if (double.IsNaN(value))
1328                 {
1329                     interval = 0;
1330                 }
1331                 else
1332                 {
1333                     interval = value;
1334                 }
1335 
1336                 // Reset initial values
1337                 majorGrid.interval = tempMajorGridInterval;
1338                 majorTickMark.interval = tempMajorTickMarkInterval;
1339                 minorGrid.interval = tempMinorGridInterval;
1340                 minorTickMark.interval = tempMinorTickMarkInterval;
1341                 labelStyle.interval = tempLabelInterval;
1342 
1343                 this.Invalidate();
1344             }
1345         }
1346 
1347         /// <summary>
1348         /// Axis interval offset.
1349         /// </summary>
1350         [
1351         SRCategory("CategoryAttributeInterval"),
1352         Bindable(true),
1353         DefaultValue(0.0),
1354         SRDescription("DescriptionAttributeIntervalOffset6"),
1355 #if !Microsoft_CONTROL
1356  PersistenceMode(PersistenceMode.Attribute),
1357 #endif
1358  RefreshPropertiesAttribute(RefreshProperties.All),
1359         TypeConverter(typeof(AxisIntervalValueConverter))
1360         ]
1361         public double IntervalOffset
1362         {
1363             get
1364             {
1365                 return _intervalOffset;
1366             }
1367             set
1368             {
1369                 // Axis interval properties must be set
1370                 if (double.IsNaN(value))
1371                 {
1372                     _intervalOffset = 0;
1373                 }
1374                 else
1375                 {
1376                     _intervalOffset = value;
1377                 }
1378 
1379                 this.Invalidate();
1380             }
1381         }
1382 
1383         /// <summary>
1384         /// Axis interval type.
1385         /// </summary>
1386         [
1387         SRCategory("CategoryAttributeInterval"),
1388         Bindable(true),
1389         DefaultValue(DateTimeIntervalType.Auto),
1390         SRDescription("DescriptionAttributeIntervalType4"),
1391         RefreshPropertiesAttribute(RefreshProperties.All),
1392 #if !Microsoft_CONTROL
1393  PersistenceMode(PersistenceMode.Attribute)
1394 #endif
1395 ]
1396         public DateTimeIntervalType IntervalType
1397         {
1398             get
1399             {
1400                 return intervalType;
1401             }
1402             set
1403             {
1404                 // Axis interval properties must be set
1405                 if (value == DateTimeIntervalType.NotSet)
1406                 {
1407                     intervalType = DateTimeIntervalType.Auto;
1408                 }
1409                 else
1410                 {
1411                     intervalType = value;
1412                 }
1413 
1414                 // Reset initial values
1415                 majorGrid.intervalType = tempGridIntervalType;
1416                 majorTickMark.intervalType = tempTickMarkIntervalType;
1417                 labelStyle.intervalType = tempLabelIntervalType;
1418 
1419                 this.Invalidate();
1420             }
1421         }
1422 
1423         /// <summary>
1424         /// Axis interval offset type.
1425         /// </summary>
1426         [
1427         SRCategory("CategoryAttributeInterval"),
1428         Bindable(true),
1429         DefaultValue(DateTimeIntervalType.Auto),
1430         SRDescription("DescriptionAttributeIntervalOffsetType4"),
1431         RefreshPropertiesAttribute(RefreshProperties.All),
1432 #if !Microsoft_CONTROL
1433  PersistenceMode(PersistenceMode.Attribute)
1434 #endif
1435 ]
1436         public DateTimeIntervalType IntervalOffsetType
1437         {
1438             get
1439             {
1440                 return intervalOffsetType;
1441             }
1442             set
1443             {
1444                 // Axis interval properties must be set
1445                 if (value == DateTimeIntervalType.NotSet)
1446                 {
1447                     intervalOffsetType = DateTimeIntervalType.Auto;
1448                 }
1449                 else
1450                 {
1451                     intervalOffsetType = value;
1452                 }
1453 
1454                 this.Invalidate();
1455             }
1456         }
1457 
1458         #endregion
1459 
1460         #region Axis painting methods
1461 
1462         /// <summary>
1463         /// Checks if Common.Chart axis title is drawn vertically.
1464         /// Note: From the drawing perspective stacked text orientation is not vertical.
1465         /// </summary>
1466         /// <returns>True if text is vertical.</returns>
1467         private bool IsTextVertical
1468         {
1469             get
1470             {
1471                 TextOrientation currentTextOrientation = this.GetTextOrientation();
1472                 return currentTextOrientation == TextOrientation.Rotated90 || currentTextOrientation == TextOrientation.Rotated270;
1473             }
1474         }
1475 
1476         /// <summary>
1477         /// Returns axis title text orientation. If set to Auto automatically determines the
1478         /// orientation based on the axis position.
1479         /// </summary>
1480         /// <returns>Current text orientation.</returns>
GetTextOrientation()1481         private TextOrientation GetTextOrientation()
1482         {
1483             if (this.TextOrientation == TextOrientation.Auto)
1484             {
1485                 if (this.AxisPosition == AxisPosition.Left)
1486                 {
1487                     return TextOrientation.Rotated270;
1488                 }
1489                 else if (this.AxisPosition == AxisPosition.Right)
1490                 {
1491                     return TextOrientation.Rotated90;
1492                 }
1493                 return TextOrientation.Horizontal;
1494             }
1495             return this.TextOrientation;
1496         }
1497 
1498         /// <summary>
1499         /// Paint Axis elements on the back of the 3D scene.
1500         /// </summary>
1501         /// <param name="graph">Reference to the Chart Graphics object</param>
PrePaint(ChartGraphics graph)1502         internal void PrePaint(ChartGraphics graph)
1503         {
1504             if (enabled != false)
1505             {
1506                 // draw axis hot region
1507                 DrawAxisLineHotRegion(graph, true);
1508 
1509                 // Paint Major Tick Marks
1510                 majorTickMark.Paint(graph, true);
1511 
1512                 // Paint Minor Tick Marks
1513                 minorTickMark.Paint(graph, true);
1514 
1515                 // Draw axis line
1516                 DrawAxisLine(graph, true);
1517 
1518                 // Paint Labels
1519                 labelStyle.Paint(graph, true);
1520             }
1521 
1522 #if SUBAXES
1523 			// Process all sub-axis
1524 			if(!ChartArea.Area3DStyle.Enable3D &&
1525 				!ChartArea.chartAreaIsCurcular)
1526 			{
1527 				foreach(SubAxis subAxis in this.SubAxes)
1528 				{
1529 					subAxis.PrePaint( graph );
1530 				}
1531 			}
1532 #endif // SUBAXES
1533         }
1534 
1535         /// <summary>
1536         /// Paint Axis
1537         /// </summary>
1538         /// <param name="graph">Reference to the Chart Graphics object</param>
Paint(ChartGraphics graph)1539         internal void Paint(ChartGraphics graph)
1540         {
1541             // Only Y axis is drawn in the circular Common.Chart area
1542             if (ChartArea != null && ChartArea.chartAreaIsCurcular)
1543             {
1544                 // Y circular axes
1545                 if (this.axisType == AxisName.Y && enabled != false)
1546                 {
1547                     ICircularChartType chartType = ChartArea.GetCircularChartType();
1548                     if (chartType != null)
1549                     {
1550                         Matrix oldMatrix = graph.Transform;
1551                         float[] axesLocation = chartType.GetYAxisLocations(ChartArea);
1552                         bool drawLabels = true;
1553                         foreach (float curentSector in axesLocation)
1554                         {
1555                             // Set graphics rotation matrix
1556                             Matrix newMatrix = oldMatrix.Clone();
1557                             newMatrix.RotateAt(
1558                                 curentSector,
1559                                 graph.GetAbsolutePoint(ChartArea.circularCenter));
1560                             graph.Transform = newMatrix;
1561 
1562                             // draw axis hot region
1563                             DrawAxisLineHotRegion(graph, false);
1564 
1565                             // Paint Minor Tick Marks
1566                             minorTickMark.Paint(graph, false);
1567 
1568                             // Paint Major Tick Marks
1569                             majorTickMark.Paint(graph, false);
1570 
1571                             // Draw axis line
1572                             DrawAxisLine(graph, false);
1573 
1574                             // Only first Y axis has labels
1575                             if (drawLabels)
1576                             {
1577                                 drawLabels = false;
1578 
1579                                 // Save current font angle
1580                                 int currentAngle = labelStyle.Angle;
1581 
1582                                 // Set labels text angle
1583                                 if (labelStyle.Angle == 0)
1584                                 {
1585                                     if (curentSector >= 45f && curentSector <= 180f)
1586                                     {
1587                                         labelStyle.angle = -90;
1588                                     }
1589                                     else if (curentSector > 180f && curentSector <= 315f)
1590                                     {
1591                                         labelStyle.angle = 90;
1592                                     }
1593                                 }
1594 
1595                                 // Draw labels
1596                                 labelStyle.Paint(graph, false);
1597 
1598                                 // Restore font angle
1599                                 labelStyle.angle = currentAngle;
1600                             }
1601                         }
1602 
1603                         graph.Transform = oldMatrix;
1604                     }
1605                 }
1606 
1607                 // X circular axes
1608                 if (this.axisType == AxisName.X && enabled != false)
1609                 {
1610                     labelStyle.PaintCircular(graph);
1611                 }
1612 
1613                 DrawAxisTitle(graph);
1614 
1615                 return;
1616             }
1617 
1618             // If axis is disabled draw only Title
1619             if (enabled != false)
1620             {
1621 
1622                 // draw axis hot region
1623                 DrawAxisLineHotRegion(graph, false);
1624 
1625                 // Paint Minor Tick Marks
1626                 minorTickMark.Paint(graph, false);
1627 
1628                 // Paint Major Tick Marks
1629                 majorTickMark.Paint(graph, false);
1630 
1631                 // Draw axis line
1632                 DrawAxisLine(graph, false);
1633 
1634                 // Paint Labels
1635                 labelStyle.Paint(graph, false);
1636 
1637 #if Microsoft_CONTROL
1638 
1639                 // Scroll bar is supoorted only in 2D charts
1640                 if (ChartArea != null && ChartArea.Area3DStyle.Enable3D == false)
1641                 {
1642                     // Draw axis scroll bar
1643                     ScrollBar.Paint(graph);
1644                 }
1645 #endif // Microsoft_CONTROL
1646 
1647             }
1648 
1649             // Draw axis title
1650             this.DrawAxisTitle(graph);
1651 
1652 #if SUBAXES
1653 			// Process all sub-axis
1654 			if(ChartArea.IsSubAxesSupported)
1655 			{
1656 				foreach(SubAxis subAxis in this.SubAxes)
1657 				{
1658 					subAxis.Paint( graph );
1659 				}
1660 			}
1661 #endif // SUBAXES
1662 
1663             // Reset temp axis offset for side-by-side charts like column
1664             this.ResetTempAxisOffset();
1665         }
1666 
1667 
1668 
1669 		/// <summary>
1670 		/// Paint Axis element when segmented axis scale feature is used.
1671 		/// </summary>
1672 		/// <param name="graph">Reference to the Chart Graphics object</param>
PaintOnSegmentedScalePassOne( ChartGraphics graph )1673 		internal void PaintOnSegmentedScalePassOne( ChartGraphics graph )
1674 		{
1675 			// If axis is disabled draw only Title
1676 			if( enabled != false )
1677 			{
1678 				// Paint Minor Tick Marks
1679 				minorTickMark.Paint( graph, false );
1680 
1681 				// Paint Major Tick Marks
1682 				majorTickMark.Paint( graph, false );
1683             }
1684 
1685 #if SUBAXES
1686 			// Process all sub-axis
1687 			if(ChartArea.IsSubAxesSupported)
1688 			{
1689 				foreach(SubAxis subAxis in this.SubAxes)
1690 				{
1691 					subAxis.PaintOnSegmentedScalePassOne( graph );
1692 				}
1693 			}
1694 #endif // SUBAXES
1695 
1696         }
1697 
1698 		/// <summary>
1699 		/// Paint Axis element when segmented axis scale feature is used.
1700 		/// </summary>
1701 		/// <param name="graph">Reference to the Chart Graphics object</param>
PaintOnSegmentedScalePassTwo( ChartGraphics graph )1702 		internal void PaintOnSegmentedScalePassTwo( ChartGraphics graph )
1703 		{
1704 			// If axis is disabled draw only Title
1705 			if( enabled != false )
1706 			{
1707 				// Draw axis line
1708 				DrawAxisLine( graph, false );
1709 
1710 				// Paint Labels
1711 				labelStyle.Paint( graph, false);
1712 			}
1713 
1714 			// Draw axis title
1715 			this.DrawAxisTitle( graph );
1716 
1717 			// Reset temp axis offset for side-by-side charts like column
1718 			this.ResetTempAxisOffset();
1719 
1720 #if SUBAXES
1721 			// Process all sub-axis
1722 			if(ChartArea.IsSubAxesSupported)
1723 			{
1724 				foreach(SubAxis subAxis in this.SubAxes)
1725 				{
1726 					subAxis.PaintOnSegmentedScalePassTwo( graph );
1727 				}
1728 			}
1729 #endif // SUBAXES
1730 
1731         }
1732 
1733         /// <summary>
1734         /// Draw axis title
1735         /// </summary>
1736         /// <param name="graph">Reference to the Chart Graphics object</param>
DrawAxisTitle(ChartGraphics graph)1737         private void DrawAxisTitle(ChartGraphics graph)
1738         {
1739             if (!this.enabled)
1740                 return;
1741 
1742             // Draw axis title
1743             if (this.Title.Length > 0)
1744             {
1745                 Matrix oldTransform = null;
1746 
1747                 // Draw title in 3D
1748                 if (ChartArea.Area3DStyle.Enable3D && !ChartArea.chartAreaIsCurcular)
1749                 {
1750                     DrawAxis3DTitle(graph);
1751                     return;
1752                 }
1753 
1754                 string axisTitle = this.Title;
1755 
1756                 //******************************************************
1757                 //** Check axis position
1758                 //******************************************************
1759                 float axisPosition = (float)this.GetAxisPosition();
1760                 if (this.AxisPosition == AxisPosition.Bottom)
1761                 {
1762                     if (!this.GetIsMarksNextToAxis())
1763                     {
1764                         axisPosition = ChartArea.PlotAreaPosition.Bottom;
1765                     }
1766                     axisPosition = ChartArea.PlotAreaPosition.Bottom - axisPosition;
1767                 }
1768                 else if (this.AxisPosition == AxisPosition.Top)
1769                 {
1770                     if (!this.GetIsMarksNextToAxis())
1771                     {
1772                         axisPosition = ChartArea.PlotAreaPosition.Y;
1773                     }
1774                     axisPosition = axisPosition - ChartArea.PlotAreaPosition.Y;
1775                 }
1776                 else if (this.AxisPosition == AxisPosition.Right)
1777                 {
1778                     if (!this.GetIsMarksNextToAxis())
1779                     {
1780                         axisPosition = ChartArea.PlotAreaPosition.Right;
1781                     }
1782                     axisPosition = ChartArea.PlotAreaPosition.Right - axisPosition;
1783                 }
1784                 else if (this.AxisPosition == AxisPosition.Left)
1785                 {
1786                     if (!this.GetIsMarksNextToAxis())
1787                     {
1788                         axisPosition = ChartArea.PlotAreaPosition.X;
1789                     }
1790                     axisPosition = axisPosition - ChartArea.PlotAreaPosition.X;
1791                 }
1792 
1793                 //******************************************************
1794                 //** Adjust axis elements size with axis position
1795                 //******************************************************
1796                 // Calculate total size of axis elements
1797                 float axisSize = this.markSize + this.labelSize;
1798                 axisSize -= axisPosition;
1799                 if (axisSize < 0)
1800                 {
1801                     axisSize = 0;
1802                 }
1803                 // Set title alignment
1804                 using (StringFormat format = new StringFormat())
1805                 {
1806                     format.Alignment = this.TitleAlignment;
1807                     format.Trimming = StringTrimming.EllipsisCharacter;
1808                     // VSTS #144398
1809                     // We need to have the StringFormatFlags set to FitBlackBox as othwerwise axis titles using Fonts like
1810                     // "Algerian" or "Forte" are completly clipped (= not drawn) due to the fact that MeasureString returns
1811                     // a bounding rectangle that is too small.
1812                     format.FormatFlags |= StringFormatFlags.FitBlackBox;
1813 
1814                     // Calculate title rectangle
1815                     _titlePosition = ChartArea.PlotAreaPosition.ToRectangleF();
1816                     float titleSizeWithoutSpacing = this.titleSize - elementSpacing;
1817                     if (this.AxisPosition == AxisPosition.Left)
1818                     {
1819                         _titlePosition.X = ChartArea.PlotAreaPosition.X - titleSizeWithoutSpacing - axisSize;
1820                         _titlePosition.Y = ChartArea.PlotAreaPosition.Y;
1821 
1822                         if (!this.IsTextVertical)
1823                         {
1824                             SizeF axisTitleSize = new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height);
1825                             _titlePosition.Width = axisTitleSize.Width;
1826                             _titlePosition.Height = axisTitleSize.Height;
1827 
1828                             format.Alignment = StringAlignment.Center;
1829                             if (this.TitleAlignment == StringAlignment.Far)
1830                             {
1831                                 format.LineAlignment = StringAlignment.Near;
1832                             }
1833                             else if (this.TitleAlignment == StringAlignment.Near)
1834                             {
1835                                 format.LineAlignment = StringAlignment.Far;
1836                             }
1837                             else
1838                             {
1839                                 format.LineAlignment = StringAlignment.Center;
1840                             }
1841                         }
1842                         else
1843                         {
1844                             SizeF axisTitleSize = graph.GetAbsoluteSize(new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height));
1845                             axisTitleSize = graph.GetRelativeSize(new SizeF(axisTitleSize.Height, axisTitleSize.Width));
1846 
1847 							_titlePosition.Width = axisTitleSize.Width;
1848 							_titlePosition.Height = axisTitleSize.Height;
1849 
1850                             _titlePosition.Y += ChartArea.PlotAreaPosition.Height / 2f - _titlePosition.Height / 2f;
1851 							_titlePosition.X += titleSizeWithoutSpacing / 2f - _titlePosition.Width / 2f;
1852 
1853                             // Set graphics rotation transformation
1854                             oldTransform = this.SetRotationTransformation(graph, _titlePosition);
1855 
1856                             // Set alignment
1857                             format.LineAlignment = StringAlignment.Center;
1858                         }
1859                     }
1860                     else if (this.AxisPosition == AxisPosition.Right)
1861                     {
1862                         _titlePosition.X = ChartArea.PlotAreaPosition.Right + axisSize;
1863                         _titlePosition.Y = ChartArea.PlotAreaPosition.Y;
1864 
1865                         if (!this.IsTextVertical)
1866                         {
1867                             SizeF axisTitleSize = new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height);
1868                             _titlePosition.Width = axisTitleSize.Width;
1869                             _titlePosition.Height = axisTitleSize.Height;
1870 
1871                             format.Alignment = StringAlignment.Center;
1872                             if (this.TitleAlignment == StringAlignment.Far)
1873                             {
1874                                 format.LineAlignment = StringAlignment.Near;
1875                             }
1876                             else if (this.TitleAlignment == StringAlignment.Near)
1877                             {
1878                                 format.LineAlignment = StringAlignment.Far;
1879                             }
1880                             else
1881                             {
1882                                 format.LineAlignment = StringAlignment.Center;
1883                             }
1884                         }
1885                         else
1886                         {
1887                             SizeF axisTitleSize = graph.GetAbsoluteSize(new SizeF(titleSizeWithoutSpacing, ChartArea.PlotAreaPosition.Height));
1888                             axisTitleSize = graph.GetRelativeSize(new SizeF(axisTitleSize.Height, axisTitleSize.Width));
1889 
1890 							_titlePosition.Width = axisTitleSize.Width;
1891 							_titlePosition.Height = axisTitleSize.Height;
1892 
1893                             _titlePosition.Y += ChartArea.PlotAreaPosition.Height / 2f - _titlePosition.Height / 2f;
1894 							_titlePosition.X += titleSizeWithoutSpacing / 2f - _titlePosition.Width / 2f;
1895 
1896                             // Set graphics rotation transformation
1897                             oldTransform = this.SetRotationTransformation(graph, _titlePosition);
1898 
1899                             // Set alignment
1900                             format.LineAlignment = StringAlignment.Center;
1901                         }
1902                     }
1903                     else if (this.AxisPosition == AxisPosition.Top)
1904                     {
1905                         _titlePosition.Y = ChartArea.PlotAreaPosition.Y - titleSizeWithoutSpacing - axisSize;
1906                         _titlePosition.Height = titleSizeWithoutSpacing;
1907                         _titlePosition.X = ChartArea.PlotAreaPosition.X;
1908                         _titlePosition.Width = ChartArea.PlotAreaPosition.Width;
1909 
1910                         if (this.IsTextVertical)
1911                         {
1912                             // Set graphics rotation transformation
1913                             oldTransform = this.SetRotationTransformation(graph, _titlePosition);
1914                         }
1915 
1916                         // Set alignment
1917                         format.LineAlignment = StringAlignment.Center;
1918                     }
1919                     else if (this.AxisPosition == AxisPosition.Bottom)
1920                     {
1921                         _titlePosition.Y = ChartArea.PlotAreaPosition.Bottom + axisSize;
1922                         _titlePosition.Height = titleSizeWithoutSpacing;
1923                         _titlePosition.X = ChartArea.PlotAreaPosition.X;
1924                         _titlePosition.Width = ChartArea.PlotAreaPosition.Width;
1925 
1926                         if (this.IsTextVertical)
1927                         {
1928                             // Set graphics rotation transformation
1929                             oldTransform = this.SetRotationTransformation(graph, _titlePosition);
1930                         }
1931 
1932                         // Set alignment
1933                         format.LineAlignment = StringAlignment.Center;
1934                     }
1935 
1936 #if DEBUG
1937                     // TESTING CODE: Shows labels rectangle position.
1938 					//				RectangleF rr = graph.GetAbsoluteRectangle(_titlePosition);
1939 					//				graph.DrawRectangle(Pens.Blue, rr.X, rr.Y, rr.Width, rr.Height);
1940 #endif // DEBUG
1941 
1942                     // Draw title
1943                     using (Brush brush = new SolidBrush(this.TitleForeColor))
1944                     {
1945                         graph.DrawStringRel(
1946                             axisTitle.Replace("\\n", "\n"),
1947                             this.TitleFont,
1948                             brush,
1949                             _titlePosition,
1950                             format,
1951                             this.GetTextOrientation());
1952                     }
1953                 }
1954 
1955                 // Process selection regions
1956                 if (this.Common.ProcessModeRegions)
1957                 {
1958                     // NOTE: Solves Issue #4423
1959                     // Transform title position coordinates using curent Graphics matrix
1960                     RectangleF transformedTitlePosition = graph.GetAbsoluteRectangle(_titlePosition);
1961                     PointF[] rectPoints = new PointF[] {
1962 						new PointF(transformedTitlePosition.X, transformedTitlePosition.Y),
1963 						new PointF(transformedTitlePosition.Right, transformedTitlePosition.Bottom) };
1964                     graph.Transform.TransformPoints(rectPoints);
1965                     transformedTitlePosition = new RectangleF(
1966                         rectPoints[0].X,
1967                         rectPoints[0].Y,
1968                         rectPoints[1].X - rectPoints[0].X,
1969                         rectPoints[1].Y - rectPoints[0].Y);
1970                     if (transformedTitlePosition.Width < 0)
1971                     {
1972                         transformedTitlePosition.Width = Math.Abs(transformedTitlePosition.Width);
1973                         transformedTitlePosition.X -= transformedTitlePosition.Width;
1974                     }
1975                     if (transformedTitlePosition.Height < 0)
1976                     {
1977                         transformedTitlePosition.Height = Math.Abs(transformedTitlePosition.Height);
1978                         transformedTitlePosition.Y -= transformedTitlePosition.Height;
1979                     }
1980 
1981                     // Add hot region
1982                     this.Common.HotRegionsList.AddHotRegion(
1983                         transformedTitlePosition, this, ChartElementType.AxisTitle, false, false);
1984                 }
1985 
1986                 // Restore old transformation
1987                 if (oldTransform != null)
1988                 {
1989                     graph.Transform = oldTransform;
1990                 }
1991             }
1992         }
1993 
1994         /// <summary>
1995         /// Helper method which sets 90 or -90 degrees transformation in the middle of the
1996         /// specified rectangle. It is used to draw title text rotated 90 or 270 degrees.
1997         /// </summary>
1998         /// <param name="graph">Chart graphics to apply transformation for.</param>
1999         /// <param name="titlePosition">Title position.</param>
2000         /// <returns>Old graphics transformation matrix.</returns>
SetRotationTransformation(ChartGraphics graph, RectangleF titlePosition)2001         private Matrix SetRotationTransformation(ChartGraphics graph, RectangleF titlePosition)
2002         {
2003             // Save old graphics transformation
2004             Matrix oldTransform = graph.Transform.Clone();
2005 
2006             // Rotate left tile 90 degrees at center
2007             PointF center = PointF.Empty;
2008             center.X = titlePosition.X + titlePosition.Width / 2F;
2009             center.Y = titlePosition.Y + titlePosition.Height / 2F;
2010 
2011             // Create and set new transformation matrix
2012             float angle = (this.GetTextOrientation() == TextOrientation.Rotated90) ? 90f : -90f;
2013             Matrix newMatrix = graph.Transform.Clone();
2014             newMatrix.RotateAt(angle, graph.GetAbsolutePoint(center));
2015             graph.Transform = newMatrix;
2016 
2017             return oldTransform;
2018         }
2019 
2020 
2021         /// <summary>
2022         /// Draws a radial line in circular Common.Chart area.
2023         /// </summary>
2024         /// <param name="obj">Object requesting the painting.</param>
2025         /// <param name="graph">Graphics path.</param>
2026         /// <param name="color">Line color.</param>
2027         /// <param name="width">Line width.</param>
2028         /// <param name="style">Line style.</param>
2029         /// <param name="position">X axis circular position.</param>
DrawRadialLine( object obj, ChartGraphics graph, Color color, int width, ChartDashStyle style, double position)2030         internal void DrawRadialLine(
2031             object obj,
2032             ChartGraphics graph,
2033             Color color,
2034             int width,
2035             ChartDashStyle style,
2036             double position)
2037         {
2038             // Create circle position rectangle
2039             RectangleF rect = ChartArea.PlotAreaPosition.ToRectangleF();
2040             rect = graph.GetAbsoluteRectangle(rect);
2041 
2042             // Make sure the rectangle width equals rectangle height for the circle
2043             if (rect.Width != rect.Height)
2044             {
2045                 if (rect.Width > rect.Height)
2046                 {
2047                     rect.X += (rect.Width - rect.Height) / 2f;
2048                     rect.Width = rect.Height;
2049                 }
2050                 else
2051                 {
2052                     rect.Y += (rect.Height - rect.Width) / 2f;
2053                     rect.Height = rect.Width;
2054                 }
2055             }
2056 
2057             // Convert axis position to angle
2058             float angle = ChartArea.CircularPositionToAngle(position);
2059 
2060             // Set clipping region to the polygon
2061             Region oldRegion = null;
2062             if (ChartArea.CircularUsePolygons)
2063             {
2064                 oldRegion = graph.Clip;
2065                 graph.Clip = new Region(graph.GetPolygonCirclePath(rect, ChartArea.CircularSectorsNumber));
2066             }
2067 
2068             // Get center point
2069             PointF centerPoint = graph.GetAbsolutePoint(ChartArea.circularCenter);
2070 
2071             // Set graphics rotation matrix
2072             Matrix oldMatrix = graph.Transform;
2073             Matrix newMatrix = oldMatrix.Clone();
2074             newMatrix.RotateAt(
2075                 angle,
2076                 centerPoint);
2077             graph.Transform = newMatrix;
2078 
2079             // Draw Line
2080             PointF endPoint = new PointF(rect.X + rect.Width / 2f, rect.Y);
2081             graph.DrawLineAbs(color, width, style, centerPoint, endPoint);
2082 
2083             // Process selection regions
2084             if (this.Common.ProcessModeRegions)
2085             {
2086                 using (GraphicsPath path = new GraphicsPath())
2087                 {
2088                     path.AddLine(centerPoint, endPoint);
2089                     path.Transform(newMatrix);
2090                     try
2091                     {
2092                         using (Pen pen = new Pen(Color.Black, width + 2))
2093                         {
2094                             path.Widen(pen);
2095                             this.Common.HotRegionsList.AddHotRegion(path, false, ChartElementType.Gridlines, obj);
2096                         }
2097                     }
2098                     catch (OutOfMemoryException)
2099                     {
2100                         // GraphicsPath.Widen incorrectly throws OutOfMemoryException
2101                         // catching here and reacting by not widening
2102                     }
2103                     catch (ArgumentException)
2104                     {
2105                     }
2106                 }
2107             }
2108 
2109             // Restore graphics
2110             graph.Transform = oldMatrix;
2111             newMatrix.Dispose();
2112 
2113             // Restore clip region
2114             if (ChartArea.CircularUsePolygons)
2115             {
2116                 graph.Clip = oldRegion;
2117             }
2118 
2119         }
2120 
2121         /// <summary>
2122         /// Draws a circular line in circular Common.Chart area.
2123         /// </summary>
2124         /// <param name="obj">Object requesting the painting.</param>
2125         /// <param name="graph">Graphics path.</param>
2126         /// <param name="color">Line color.</param>
2127         /// <param name="width">Line width.</param>
2128         /// <param name="style">Line style.</param>
2129         /// <param name="position">Line position.</param>
DrawCircularLine( object obj, ChartGraphics graph, Color color, int width, ChartDashStyle style, float position )2130         internal void DrawCircularLine(
2131             object obj,
2132             ChartGraphics graph,
2133             Color color,
2134             int width,
2135             ChartDashStyle style,
2136             float position
2137             )
2138         {
2139             // Create circle position rectangle
2140             RectangleF rect = ChartArea.PlotAreaPosition.ToRectangleF();
2141             rect = graph.GetAbsoluteRectangle(rect);
2142 
2143             // Make sure the rectangle width equals rectangle height for the circle
2144             if (rect.Width != rect.Height)
2145             {
2146                 if (rect.Width > rect.Height)
2147                 {
2148                     rect.X += (rect.Width - rect.Height) / 2f;
2149                     rect.Width = rect.Height;
2150                 }
2151                 else
2152                 {
2153                     rect.Y += (rect.Height - rect.Width) / 2f;
2154                     rect.Height = rect.Width;
2155                 }
2156             }
2157 
2158             // Inflate rectangle
2159             PointF absPoint = graph.GetAbsolutePoint(new PointF(position, position));
2160             float rectInflate = absPoint.Y - rect.Top;
2161             rect.Inflate(-rectInflate, -rectInflate);
2162 
2163             // Create circle pen
2164             Pen circlePen = new Pen(color, width);
2165             circlePen.DashStyle = graph.GetPenStyle(style);
2166 
2167             // Draw circle
2168             if (ChartArea.CircularUsePolygons)
2169             {
2170                 // Draw eaqula sides polygon
2171                 graph.DrawCircleAbs(circlePen, null, rect, ChartArea.CircularSectorsNumber, false);
2172             }
2173             else
2174             {
2175                 graph.DrawEllipse(circlePen, rect);
2176             }
2177 
2178             // Process selection regions
2179             if (this.Common.ProcessModeRegions)
2180             {
2181                 // Bounding rectangle must be more than 1 pixel by 1 pixel
2182                 if (rect.Width >= 1f && rect.Height > 1)
2183                 {
2184                     GraphicsPath path = null;
2185                     try
2186                     {
2187                         if (ChartArea.CircularUsePolygons)
2188                         {
2189                             path = graph.GetPolygonCirclePath(rect, ChartArea.CircularSectorsNumber);
2190                         }
2191                         else
2192                         {
2193                             path = new GraphicsPath();
2194                             path.AddEllipse(rect);
2195                         }
2196                         circlePen.Width += 2;
2197                         path.Widen(circlePen);
2198                         this.Common.HotRegionsList.AddHotRegion(path, false, ChartElementType.Gridlines, obj);
2199                     }
2200                     catch (OutOfMemoryException)
2201                     {
2202                         // GraphicsPath.Widen incorrectly throws OutOfMemoryException
2203                         // catching here and reacting by not widening
2204                     }
2205                     catch (ArgumentException)
2206                     {
2207                     }
2208                     finally
2209                     {
2210                         path.Dispose();
2211                     }
2212                 }
2213             }
2214 
2215         }
2216 
2217         /// <summary>
2218         /// Draw axis title in 3D.
2219         /// </summary>
2220         /// <param name="graph">Reference to the Chart Graphics object</param>
DrawAxis3DTitle(ChartGraphics graph)2221         private void DrawAxis3DTitle(ChartGraphics graph)
2222         {
2223             // Do not draw title if axis is not enabled
2224             if (!this.enabled)
2225             {
2226                 return;
2227             }
2228 
2229             string axisTitle = this.Title;
2230 
2231             // Draw axis title
2232             PointF rotationCenter = PointF.Empty;
2233             int angle = 0;
2234 
2235             // Set title alignment
2236             using (StringFormat format = new StringFormat())
2237             {
2238                 format.Alignment = this.TitleAlignment;
2239                 format.Trimming = StringTrimming.EllipsisCharacter;
2240                 format.FormatFlags |= StringFormatFlags.LineLimit;
2241 
2242                 // Measure title size for non-centered aligment
2243                 SizeF realTitleSize = graph.MeasureString(axisTitle.Replace("\\n", "\n"), this.TitleFont, new SizeF(10000f, 10000f), format, this.GetTextOrientation());
2244                 SizeF axisTitleSize = SizeF.Empty;
2245                 if (format.Alignment != StringAlignment.Center)
2246                 {
2247                     axisTitleSize = realTitleSize;
2248                     if (this.IsTextVertical)
2249                     {
2250                         // Switch height and width for vertical axis
2251                         float tempValue = axisTitleSize.Height;
2252                         axisTitleSize.Height = axisTitleSize.Width;
2253                         axisTitleSize.Width = tempValue;
2254                     }
2255 
2256                     // Get relative size
2257                     axisTitleSize = graph.GetRelativeSize(axisTitleSize);
2258 
2259                     // Change format aligment for the reversed mode
2260                     if (ChartArea.ReverseSeriesOrder)
2261                     {
2262                         if (format.Alignment == StringAlignment.Near)
2263                         {
2264                             format.Alignment = StringAlignment.Far;
2265                         }
2266                         else
2267                         {
2268                             format.Alignment = StringAlignment.Near;
2269                         }
2270                     }
2271                 }
2272 
2273                 // Set text rotation angle based on the text orientation
2274                 if (this.GetTextOrientation() == TextOrientation.Rotated90)
2275                 {
2276                     angle = 90;
2277                 }
2278                 else if (this.GetTextOrientation() == TextOrientation.Rotated270)
2279                 {
2280                     angle = -90;
2281                 }
2282 
2283                 // Calculate title center point on the axis
2284                 if (this.AxisPosition == AxisPosition.Left)
2285                 {
2286                     rotationCenter = new PointF(ChartArea.PlotAreaPosition.X, ChartArea.PlotAreaPosition.Y + ChartArea.PlotAreaPosition.Height / 2f);
2287                     if (format.Alignment == StringAlignment.Near)
2288                     {
2289                         rotationCenter.Y = ChartArea.PlotAreaPosition.Bottom - axisTitleSize.Height / 2f;
2290                     }
2291                     else if (format.Alignment == StringAlignment.Far)
2292                     {
2293                         rotationCenter.Y = ChartArea.PlotAreaPosition.Y + axisTitleSize.Height / 2f;
2294                     }
2295                 }
2296                 else if (this.AxisPosition == AxisPosition.Right)
2297                 {
2298                     rotationCenter = new PointF(ChartArea.PlotAreaPosition.Right, ChartArea.PlotAreaPosition.Y + ChartArea.PlotAreaPosition.Height / 2f);
2299                     if (format.Alignment == StringAlignment.Near)
2300                     {
2301                         rotationCenter.Y = ChartArea.PlotAreaPosition.Bottom - axisTitleSize.Height / 2f;
2302                     }
2303                     else if (format.Alignment == StringAlignment.Far)
2304                     {
2305                         rotationCenter.Y = ChartArea.PlotAreaPosition.Y + axisTitleSize.Height / 2f;
2306                     }
2307                 }
2308                 else if (this.AxisPosition == AxisPosition.Top)
2309                 {
2310                     rotationCenter = new PointF(ChartArea.PlotAreaPosition.X + ChartArea.PlotAreaPosition.Width / 2f, ChartArea.PlotAreaPosition.Y);
2311                     if (format.Alignment == StringAlignment.Near)
2312                     {
2313                         rotationCenter.X = ChartArea.PlotAreaPosition.X + axisTitleSize.Width / 2f;
2314                     }
2315                     else if (format.Alignment == StringAlignment.Far)
2316                     {
2317                         rotationCenter.X = ChartArea.PlotAreaPosition.Right - axisTitleSize.Width / 2f;
2318                     }
2319                 }
2320                 else if (this.AxisPosition == AxisPosition.Bottom)
2321                 {
2322                     rotationCenter = new PointF(ChartArea.PlotAreaPosition.X + ChartArea.PlotAreaPosition.Width / 2f, ChartArea.PlotAreaPosition.Bottom);
2323                     if (format.Alignment == StringAlignment.Near)
2324                     {
2325                         rotationCenter.X = ChartArea.PlotAreaPosition.X + axisTitleSize.Width / 2f;
2326                     }
2327                     else if (format.Alignment == StringAlignment.Far)
2328                     {
2329                         rotationCenter.X = ChartArea.PlotAreaPosition.Right - axisTitleSize.Width / 2f;
2330                     }
2331                 }
2332 
2333                 // Transform center of title coordinates and calculate axis angle
2334                 bool isOnEdge = false;
2335                 float zPosition = this.GetMarksZPosition(out isOnEdge);
2336                 Point3D[] rotationCenterPoints = null;
2337                 float angleAxis = 0;
2338                 if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
2339                 {
2340                     rotationCenterPoints = new Point3D[] {
2341 					new Point3D(rotationCenter.X, rotationCenter.Y, zPosition),
2342 					new Point3D(rotationCenter.X - 20f, rotationCenter.Y, zPosition) };
2343 
2344                     // Transform coordinates of text rotation point
2345                     ChartArea.matrix3D.TransformPoints(rotationCenterPoints);
2346                     rotationCenter = rotationCenterPoints[0].PointF;
2347 
2348                     // Get absolute coordinates
2349                     rotationCenterPoints[0].PointF = graph.GetAbsolutePoint(rotationCenterPoints[0].PointF);
2350                     rotationCenterPoints[1].PointF = graph.GetAbsolutePoint(rotationCenterPoints[1].PointF);
2351 
2352                     // Calculate X axis angle
2353                     angleAxis = (float)Math.Atan(
2354                         (rotationCenterPoints[1].Y - rotationCenterPoints[0].Y) /
2355                         (rotationCenterPoints[1].X - rotationCenterPoints[0].X));
2356                 }
2357                 else
2358                 {
2359                     rotationCenterPoints = new Point3D[] {
2360 					new Point3D(rotationCenter.X, rotationCenter.Y, zPosition),
2361 					new Point3D(rotationCenter.X, rotationCenter.Y - 20f, zPosition) };
2362 
2363                     // Transform coordinates of text rotation point
2364                     ChartArea.matrix3D.TransformPoints(rotationCenterPoints);
2365                     rotationCenter = rotationCenterPoints[0].PointF;
2366 
2367                     // Get absolute coordinates
2368                     rotationCenterPoints[0].PointF = graph.GetAbsolutePoint(rotationCenterPoints[0].PointF);
2369                     rotationCenterPoints[1].PointF = graph.GetAbsolutePoint(rotationCenterPoints[1].PointF);
2370 
2371                     // Calculate Y axis angle
2372                     if (rotationCenterPoints[1].Y != rotationCenterPoints[0].Y)
2373                     {
2374                         angleAxis = -(float)Math.Atan(
2375                             (rotationCenterPoints[1].X - rotationCenterPoints[0].X) /
2376                             (rotationCenterPoints[1].Y - rotationCenterPoints[0].Y));
2377                     }
2378                 }
2379                 angle += (int)Math.Round(angleAxis * 180f / (float)Math.PI);
2380 
2381 
2382                 // Calculate title center offset from the axis line
2383                 float offset = this.labelSize + this.markSize + this.titleSize / 2f;
2384                 float dX = 0f, dY = 0f;
2385 
2386 
2387                 // Adjust center of title with labels, marker and title size
2388                 if (this.AxisPosition == AxisPosition.Left)
2389                 {
2390                     dX = (float)(offset * Math.Cos(angleAxis));
2391                     rotationCenter.X -= dX;
2392                 }
2393                 else if (this.AxisPosition == AxisPosition.Right)
2394                 {
2395                     dX = (float)(offset * Math.Cos(angleAxis));
2396                     rotationCenter.X += dX;
2397                 }
2398                 else if (this.AxisPosition == AxisPosition.Top)
2399                 {
2400                     dY = (float)(offset * Math.Cos(angleAxis));
2401                     dX = (float)(offset * Math.Sin(angleAxis));
2402                     rotationCenter.Y -= dY;
2403                     if (dY > 0)
2404                     {
2405                         rotationCenter.X += dX;
2406                     }
2407                     else
2408                     {
2409                         rotationCenter.X -= dX;
2410                     }
2411                 }
2412                 else if (this.AxisPosition == AxisPosition.Bottom)
2413                 {
2414                     dY = (float)(offset * Math.Cos(angleAxis));
2415                     dX = (float)(offset * Math.Sin(angleAxis));
2416                     rotationCenter.Y += dY;
2417                     if (dY > 0)
2418                     {
2419                         rotationCenter.X -= dX;
2420                     }
2421                     else
2422                     {
2423                         rotationCenter.X += dX;
2424                     }
2425                 }
2426 
2427 
2428                 // Always align text in the center
2429                 format.LineAlignment = StringAlignment.Center;
2430                 format.Alignment = StringAlignment.Center;
2431                 // SQL VSTS Fix #259954, Dev10: 591135 Windows 7 crashes on empty transformation.
2432                 if (rotationCenter.IsEmpty || float.IsNaN(rotationCenter.X) || float.IsNaN(rotationCenter.Y))
2433                 {
2434                     return;
2435                 }
2436 
2437                 // Draw 3D title
2438                 using (Brush brush = new SolidBrush(this.TitleForeColor))
2439                 {
2440                     graph.DrawStringRel(
2441                         axisTitle.Replace("\\n", "\n"),
2442                         this.TitleFont,
2443                         brush,
2444                         rotationCenter,
2445                         format,
2446                         angle,
2447                         this.GetTextOrientation());
2448                 }
2449 
2450                 // Add hot region
2451                 if (Common.ProcessModeRegions)
2452                 {
2453                     using (GraphicsPath hotPath = graph.GetTranformedTextRectPath(rotationCenter, realTitleSize, angle))
2454                     {
2455                         this.Common.HotRegionsList.AddHotRegion(hotPath, false, ChartElementType.AxisTitle, this);
2456                     }
2457                 }
2458             }
2459 
2460         }
2461 
2462         /// <summary>
2463         /// Select Axis line
2464         /// </summary>
2465         /// <param name="graph">Reference to the Chart Graphics</param>
2466         /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
DrawAxisLine(ChartGraphics graph, bool backElements)2467         internal void DrawAxisLine(ChartGraphics graph, bool backElements)
2468         {
2469             Axis opositeAxis;
2470             ArrowOrientation arrowOrientation = ArrowOrientation.Top;
2471             PointF first = Point.Empty;
2472             PointF second = Point.Empty;
2473 
2474             // Set the position of axis
2475             switch (AxisPosition)
2476             {
2477 
2478                 case AxisPosition.Left:
2479 
2480                     first.X = (float)GetAxisPosition();
2481                     first.Y = PlotAreaPosition.Bottom;
2482                     second.X = (float)GetAxisPosition();
2483                     second.Y = PlotAreaPosition.Y;
2484                     if (isReversed)
2485                         arrowOrientation = ArrowOrientation.Bottom;
2486                     else
2487                         arrowOrientation = ArrowOrientation.Top;
2488 
2489                     break;
2490 
2491                 case AxisPosition.Right:
2492 
2493                     first.X = (float)GetAxisPosition();
2494                     first.Y = PlotAreaPosition.Bottom;
2495                     second.X = (float)GetAxisPosition();
2496                     second.Y = PlotAreaPosition.Y;
2497                     if (isReversed)
2498                         arrowOrientation = ArrowOrientation.Bottom;
2499                     else
2500                         arrowOrientation = ArrowOrientation.Top;
2501 
2502                     break;
2503 
2504                 case AxisPosition.Bottom:
2505 
2506                     first.X = PlotAreaPosition.X;
2507                     first.Y = (float)GetAxisPosition();
2508                     second.X = PlotAreaPosition.Right;
2509                     second.Y = (float)GetAxisPosition();
2510                     if (isReversed)
2511                         arrowOrientation = ArrowOrientation.Left;
2512                     else
2513                         arrowOrientation = ArrowOrientation.Right;
2514 
2515                     break;
2516 
2517                 case AxisPosition.Top:
2518 
2519                     first.X = PlotAreaPosition.X;
2520                     first.Y = (float)GetAxisPosition();
2521                     second.X = PlotAreaPosition.Right;
2522                     second.Y = (float)GetAxisPosition();
2523                     if (isReversed)
2524                         arrowOrientation = ArrowOrientation.Left;
2525                     else
2526                         arrowOrientation = ArrowOrientation.Right;
2527 
2528                     break;
2529 
2530             }
2531 
2532             // Update axis line position for circular area
2533             if (ChartArea.chartAreaIsCurcular)
2534             {
2535                 first.Y = PlotAreaPosition.Y + PlotAreaPosition.Height / 2f;
2536             }
2537 
2538 
2539             if (Common.ProcessModePaint)
2540             {
2541                 if (!ChartArea.Area3DStyle.Enable3D || ChartArea.chartAreaIsCurcular)
2542                 {
2543 
2544 					// Start Svg/Flash Selection mode
2545 					graph.StartHotRegion( this._url, _toolTip );
2546 
2547                     // Draw the line
2548                     graph.DrawLineRel(_lineColor, _lineWidth, _lineDashStyle, first, second);
2549 
2550 					// End Svg/Flash Selection mode
2551 					graph.EndHotRegion( );
2552 
2553                     // Opposite axis. Arrow uses this axis to find
2554                     // a shift from Common.Chart area border. This shift
2555                     // depend on Tick mark size.
2556                     switch (arrowOrientation)
2557                     {
2558                         case ArrowOrientation.Left:
2559                             opositeAxis = ChartArea.AxisX;
2560                             break;
2561                         case ArrowOrientation.Right:
2562                             opositeAxis = ChartArea.AxisX2;
2563                             break;
2564                         case ArrowOrientation.Top:
2565                             opositeAxis = ChartArea.AxisY2;
2566                             break;
2567                         case ArrowOrientation.Bottom:
2568                             opositeAxis = ChartArea.AxisY;
2569                             break;
2570                         default:
2571                             opositeAxis = ChartArea.AxisX;
2572                             break;
2573                     }
2574 
2575                     // Draw arrow
2576                     PointF arrowPosition;
2577                     if (isReversed)
2578                         arrowPosition = first;
2579                     else
2580                         arrowPosition = second;
2581 
2582                     // Draw Arrow
2583                     graph.DrawArrowRel(arrowPosition, arrowOrientation, _arrowStyle, _lineColor, _lineWidth, _lineDashStyle, opositeAxis.majorTickMark.Size, _lineWidth);
2584                 }
2585                 else
2586                 {
2587                     Draw3DAxisLine(graph, first, second, (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom), backElements);
2588                 }
2589             }
2590 
2591         }
2592 
2593 
2594         /// <summary>
2595         /// Draws the axis line hot region.
2596         /// </summary>
2597         /// <param name="graph">The graph.</param>
2598         /// <param name="backElements">set to <c>true</c> if we draw back elements.</param>
DrawAxisLineHotRegion(ChartGraphics graph, bool backElements)2599         private void DrawAxisLineHotRegion(ChartGraphics graph, bool backElements)
2600         {
2601             if (Common.ProcessModeRegions)
2602             {
2603                 //VSTS #229835: During the 3D rendering the axis is drawn twice:
2604                 //1. In PrePaint() both axis and backelements (labels) are drawn.
2605                 //2. In Paint() the axis is redrawn without labels and as a result it creates a second hot region which covered the labels' hotregions.
2606                 //In order to avoid this we have to suppress the hotregion drawing in the Paint using the backElements flag (it's false during the Paint)
2607                 //The circular charts and 2D charts are drawn only once in Paint() so we draw the hot regions.
2608                 if (backElements || !ChartArea.Area3DStyle.Enable3D || ChartArea.chartAreaIsCurcular)
2609                 {
2610                     DrawAxisLineHotRegion(graph);
2611                 }
2612             }
2613 
2614         }
2615 
2616         /// <summary>
2617         /// Adds the axis hot region
2618         /// </summary>
2619         /// <param name="graph">The chart graphics instance.</param>
DrawAxisLineHotRegion(ChartGraphics graph)2620         private void DrawAxisLineHotRegion(ChartGraphics graph)
2621         {
2622             using (GraphicsPath path = new GraphicsPath())
2623             {
2624                 // Find the topLeft(first) and bottomRight(second) points of the hotregion rectangle
2625                 PointF first = PointF.Empty;
2626                 PointF second = PointF.Empty;
2627                 float axisPosition = (float)GetAxisPosition();
2628 
2629                 switch (this.AxisPosition)
2630                 {
2631                     case AxisPosition.Left:
2632                         first.X = axisPosition - (labelSize + markSize);
2633                         first.Y = PlotAreaPosition.Y;
2634                         second.X = axisPosition;
2635                         second.Y = PlotAreaPosition.Bottom;
2636                         break;
2637 
2638                     case AxisPosition.Right:
2639                         first.X = axisPosition;
2640                         first.Y = PlotAreaPosition.Y;
2641                         second.X = axisPosition + labelSize + markSize;
2642                         second.Y = PlotAreaPosition.Bottom;
2643                         break;
2644 
2645                     case AxisPosition.Bottom:
2646                         first.X = PlotAreaPosition.X;
2647                         first.Y = axisPosition;
2648                         second.X = PlotAreaPosition.Right;
2649                         second.Y = axisPosition + labelSize + markSize;
2650                         break;
2651 
2652                     case AxisPosition.Top:
2653                         first.X = PlotAreaPosition.X;
2654                         first.Y = axisPosition - (labelSize + markSize);
2655                         second.X = PlotAreaPosition.Right;
2656                         second.Y = axisPosition;
2657                         break;
2658                 }
2659 
2660                 // Update axis line position for circular area
2661                 if (ChartArea.chartAreaIsCurcular)
2662                 {
2663                     second.Y = PlotAreaPosition.Y + PlotAreaPosition.Height / 2f;
2664                 }
2665 
2666                 // Create rectangle and inflate it
2667                 RectangleF rect = new RectangleF(first.X, first.Y, second.X - first.X, second.Y - first.Y);
2668                 SizeF size = graph.GetRelativeSize(new SizeF(3, 3));
2669 
2670                 if (AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom)
2671                 {
2672                     rect.Inflate(2, size.Height);
2673                 }
2674                 else
2675                 {
2676                     rect.Inflate(size.Width, 2);
2677                 }
2678 
2679                 // Get the rectangle points
2680                 PointF[] points = new PointF[] {
2681                     new PointF(rect.Left, rect.Top),
2682                     new PointF(rect.Right, rect.Top),
2683                     new PointF(rect.Right, rect.Bottom),
2684                     new PointF(rect.Left, rect.Bottom)};
2685 
2686                 // If we are dealing with the 3D - transform the rectangle
2687                 if (ChartArea.Area3DStyle.Enable3D && !ChartArea.chartAreaIsCurcular)
2688                 {
2689                     Boolean axisOnEdge = false;
2690                     float zPositon = GetMarksZPosition(out axisOnEdge);
2691 
2692                     // Convert points to 3D
2693                     Point3D[] points3D = new Point3D[points.Length];
2694                     for (int i = 0; i < points.Length; i++)
2695                     {
2696                         points3D[i] = new Point3D(points[i].X, points[i].Y, zPositon);
2697                     }
2698 
2699                     // Transform
2700                     ChartArea.matrix3D.TransformPoints(points3D);
2701 
2702                     // Convert to 2D
2703                     for (int i = 0; i < points3D.Length; i++)
2704                     {
2705                         points[i] = points3D[i].PointF;
2706                     }
2707                 }
2708 
2709                 // Transform points to absolute cooordinates
2710                 for (int i = 0; i < points.Length; i++)
2711                 {
2712                     points[i] = graph.GetAbsolutePoint(points[i]);
2713                 }
2714 
2715                 // Add the points to the path
2716                 path.AddPolygon(points);
2717 
2718 
2719 #if Microsoft_CONTROL
2720 				Common.HotRegionsList.AddHotRegion(
2721 					graph,
2722 					path,
2723 					false,
2724 					this._toolTip,
2725 					string.Empty,
2726 					string.Empty,
2727 					string.Empty,
2728 					this,
2729 					ChartElementType.Axis);
2730 #else
2731                 Common.HotRegionsList.AddHotRegion(
2732                     graph,
2733                     path,
2734                     false,
2735                     this._toolTip,
2736                     this._url,
2737                     this._mapAreaAttributes,
2738                     this.PostBackValue,
2739                     this,
2740                     ChartElementType.Axis);
2741 #endif
2742 
2743             }
2744         }
2745 
2746 
2747         /// <summary>
2748         /// Draws axis line in 3D space.
2749         /// </summary>
2750         /// <param name="graph">Reference to the Chart Graphics object.</param>
2751         /// <param name="point1">First line point.</param>
2752         /// <param name="point2">Second line point.</param>
2753         /// <param name="horizontal">Indicates that tick mark line is horizontal</param>
2754         /// <param name="backElements">Only back elements of axis should be drawn.</param>
Draw3DAxisLine( ChartGraphics graph, PointF point1, PointF point2, bool horizontal, bool backElements )2755         private void Draw3DAxisLine(
2756             ChartGraphics graph,
2757             PointF point1,
2758             PointF point2,
2759             bool horizontal,
2760             bool backElements
2761             )
2762         {
2763             // Check if axis is positioned on the plot area adge
2764             bool onEdge = this.IsAxisOnAreaEdge;
2765 
2766             // Check if axis tick marks are drawn inside plotting area
2767             bool tickMarksOnEdge = onEdge;
2768             if (tickMarksOnEdge &&
2769                 this.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
2770                 this.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea ||
2771                 this.MinorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis ||
2772                 this.MinorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
2773             {
2774                 tickMarksOnEdge = false;
2775             }
2776 
2777             // Make sure first point of axis coordinates has smaller values
2778             if ((horizontal && point1.X > point2.X) ||
2779                 (!horizontal && point1.Y > point2.Y))
2780             {
2781                 PointF tempPoint = new PointF(point1.X, point1.Y);
2782                 point1.X = point2.X;
2783                 point1.Y = point2.Y;
2784                 point2 = tempPoint;
2785             }
2786 
2787             // Check if the front/back wall is on the top drawing layer
2788             float zPositon = ChartArea.IsMainSceneWallOnFront() ? ChartArea.areaSceneDepth : 0f;
2789             SurfaceNames surfName = ChartArea.IsMainSceneWallOnFront() ? SurfaceNames.Front : SurfaceNames.Back;
2790             if (ChartArea.ShouldDrawOnSurface(SurfaceNames.Back, backElements, tickMarksOnEdge))
2791             {
2792 
2793 				// Start Svg Selection mode
2794 				graph.StartHotRegion( this._url, _toolTip );
2795 
2796                 // Draw axis line on the back/front wall
2797                 graph.Draw3DLine(
2798                     ChartArea.matrix3D,
2799                     _lineColor, _lineWidth, _lineDashStyle,
2800                     new Point3D(point1.X, point1.Y, zPositon),
2801                     new Point3D(point2.X, point2.Y, zPositon),
2802                     Common,
2803                     this,
2804                     ChartElementType.Nothing
2805                     );
2806 
2807 				// End Svg Selection mode
2808 				graph.EndHotRegion();
2809 
2810             }
2811 
2812             // Check if the back wall is on the top drawing layer
2813             zPositon = ChartArea.IsMainSceneWallOnFront() ? 0f : ChartArea.areaSceneDepth;
2814             surfName = ChartArea.IsMainSceneWallOnFront() ? SurfaceNames.Back : SurfaceNames.Front;
2815             if (ChartArea.ShouldDrawOnSurface(surfName, backElements, tickMarksOnEdge))
2816             {
2817                 // Draw axis line on the front wall
2818                 if (!onEdge ||
2819                     (this.AxisPosition == AxisPosition.Bottom && ChartArea.IsBottomSceneWallVisible()) ||
2820                     (this.AxisPosition == AxisPosition.Left && ChartArea.IsSideSceneWallOnLeft()) ||
2821                     (this.AxisPosition == AxisPosition.Right && !ChartArea.IsSideSceneWallOnLeft()))
2822                 {
2823 
2824 					// Start Svg Selection mode
2825 					graph.StartHotRegion( this._url, _toolTip );
2826 
2827                     graph.Draw3DLine(
2828                         ChartArea.matrix3D,
2829                         _lineColor, _lineWidth, _lineDashStyle,
2830                         new Point3D(point1.X, point1.Y, zPositon),
2831                         new Point3D(point2.X, point2.Y, zPositon),
2832                         Common,
2833                         this,
2834                         ChartElementType.Nothing
2835                         );
2836 
2837 					// End Svg Selection mode
2838 					graph.EndHotRegion();
2839 
2840                 }
2841             }
2842 
2843             // Check if the left/top wall is on the top drawing layer
2844             SurfaceNames surfaceName = (this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? SurfaceNames.Top : SurfaceNames.Left;
2845             if (ChartArea.ShouldDrawOnSurface(surfaceName, backElements, tickMarksOnEdge))
2846             {
2847                 // Draw axis line on the left/top side walls
2848                 if (!onEdge ||
2849                     (this.AxisPosition == AxisPosition.Bottom && (ChartArea.IsBottomSceneWallVisible() || ChartArea.IsSideSceneWallOnLeft())) ||
2850                     (this.AxisPosition == AxisPosition.Left && ChartArea.IsSideSceneWallOnLeft()) ||
2851                     (this.AxisPosition == AxisPosition.Right && !ChartArea.IsSideSceneWallOnLeft()) ||
2852                     (this.AxisPosition == AxisPosition.Top && ChartArea.IsSideSceneWallOnLeft()))
2853                 {
2854 
2855 					// Start Svg Selection mode
2856 					graph.StartHotRegion( this._url, _toolTip );
2857 
2858                     graph.Draw3DLine(
2859                         ChartArea.matrix3D,
2860                         _lineColor, _lineWidth, _lineDashStyle,
2861                         new Point3D(point1.X, point1.Y, ChartArea.areaSceneDepth),
2862                         new Point3D(point1.X, point1.Y, 0f),
2863                         Common,
2864                         this,
2865                         ChartElementType.Nothing
2866                     );
2867 
2868 					// End Svg Selection mode
2869 					graph.EndHotRegion( );
2870 
2871                 }
2872             }
2873 
2874             // Check if the right/bottom wall is on the top drawing layer
2875             surfaceName = (this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? SurfaceNames.Bottom : SurfaceNames.Right;
2876             if (ChartArea.ShouldDrawOnSurface(surfaceName, backElements, tickMarksOnEdge))
2877             {
2878                 // Draw axis line on the bottom/right side walls
2879                 if (!onEdge ||
2880                     (this.AxisPosition == AxisPosition.Bottom && (ChartArea.IsBottomSceneWallVisible() || !ChartArea.IsSideSceneWallOnLeft())) ||
2881                     (this.AxisPosition == AxisPosition.Left && (ChartArea.IsSideSceneWallOnLeft() || ChartArea.IsBottomSceneWallVisible())) ||
2882                     (this.AxisPosition == AxisPosition.Right && (!ChartArea.IsSideSceneWallOnLeft() || ChartArea.IsBottomSceneWallVisible())) ||
2883                     (this.AxisPosition == AxisPosition.Top && !ChartArea.IsSideSceneWallOnLeft())
2884                     )
2885                 {
2886 
2887 					// Start Svg Selection mode
2888 					graph.StartHotRegion( this._url, _toolTip );
2889 
2890                     graph.Draw3DLine(
2891                         ChartArea.matrix3D,
2892                         _lineColor, _lineWidth, _lineDashStyle,
2893                         new Point3D(point2.X, point2.Y, ChartArea.areaSceneDepth),
2894                         new Point3D(point2.X, point2.Y, 0f),
2895                         Common,
2896                         this,
2897                         ChartElementType.Nothing
2898                         );
2899 
2900 					// End Svg Selection mode
2901 					graph.EndHotRegion();
2902 
2903                 }
2904             }
2905 
2906         }
2907 
2908         /// <summary>
2909         /// Gets Z position of axis tick marks and labels.
2910         /// </summary>
2911         /// <param name="axisOnEdge">Returns true if axis is on the edge.</param>
2912         /// <returns>Marks Z position.</returns>
GetMarksZPosition(out bool axisOnEdge)2913         internal float GetMarksZPosition(out bool axisOnEdge)
2914         {
2915             axisOnEdge = this.IsAxisOnAreaEdge;
2916             if (!this.GetIsMarksNextToAxis())
2917             {
2918                 // Marks are forced to be on the area edge
2919                 axisOnEdge = true;
2920             }
2921             float wallZPosition = 0f;
2922             if (this.AxisPosition == AxisPosition.Bottom && (ChartArea.IsBottomSceneWallVisible() || !axisOnEdge))
2923             {
2924                 wallZPosition = ChartArea.areaSceneDepth;
2925             }
2926             if (this.AxisPosition == AxisPosition.Left && (ChartArea.IsSideSceneWallOnLeft() || !axisOnEdge))
2927             {
2928                 wallZPosition = ChartArea.areaSceneDepth;
2929             }
2930             if (this.AxisPosition == AxisPosition.Right && (!ChartArea.IsSideSceneWallOnLeft() || !axisOnEdge))
2931             {
2932                 wallZPosition = ChartArea.areaSceneDepth;
2933             }
2934             if (this.AxisPosition == AxisPosition.Top && !axisOnEdge)
2935             {
2936                 wallZPosition = ChartArea.areaSceneDepth;
2937             }
2938 
2939             // Check if front wall is shown
2940             if (ChartArea.IsMainSceneWallOnFront())
2941             {
2942                 // Switch Z position of tick mark
2943                 wallZPosition = (wallZPosition == 0f) ? ChartArea.areaSceneDepth : 0f;
2944             }
2945 
2946             return wallZPosition;
2947         }
2948 
2949         /// <summary>
2950         /// Paint Axis Grid lines
2951         /// </summary>
2952         /// <param name="graph">Reference to the Chart Graphics object</param>
PaintGrids(ChartGraphics graph)2953         internal void PaintGrids(ChartGraphics graph)
2954         {
2955             object obj;
2956 
2957             PaintGrids(graph, out obj);
2958 
2959         }
2960 
2961         /// <summary>
2962         /// Paint Axis Grid lines or
2963         /// hit test function for grid lines
2964         /// </summary>
2965         /// <param name="graph">Reference to the Chart Graphics object</param>
2966         /// <param name="obj">Returns selected grid object</param>
PaintGrids(ChartGraphics graph, out object obj)2967         internal void PaintGrids(ChartGraphics graph, out object obj)
2968         {
2969             obj = null;
2970 
2971 #if SUBAXES
2972 			// Paint grids of sub-axis
2973 			if(!ChartArea.Area3DStyle.Enable3D &&
2974 				!ChartArea.chartAreaIsCurcular)
2975 			{
2976 				foreach(SubAxis subAxis in this.SubAxes)
2977 				{
2978 					subAxis.PaintGrids( graph, out obj);
2979 				}
2980 			}
2981 #endif // SUBAXES
2982 
2983             // Axis is disabled
2984             if (enabled == false)
2985                 return;
2986 
2987             // Paint Minor grid lines
2988             minorGrid.Paint(graph);
2989 
2990             // Paint Major grid lines
2991             majorGrid.Paint(graph);
2992         }
2993 
2994         /// <summary>
2995         /// Paint Axis Strip lines
2996         /// </summary>
2997         /// <param name="graph">Reference to the Chart Graphics object</param>
2998         /// <param name="drawLinesOnly">Indicates if Lines or Stripes should be drawn.</param>
PaintStrips(ChartGraphics graph, bool drawLinesOnly)2999         internal void PaintStrips(ChartGraphics graph, bool drawLinesOnly)
3000         {
3001             object obj;
3002             PaintStrips(graph, false, 0, 0, out obj, drawLinesOnly);
3003         }
3004 
3005         /// <summary>
3006         /// Paint Axis Strip lines or
3007         /// hit test function for Strip lines
3008         /// </summary>
3009         /// <param name="graph">Reference to the Chart Graphics object</param>
3010         /// <param name="selectionMode">The selection mode is active</param>
3011         /// <param name="x">X coordinate</param>
3012         /// <param name="y">Y coordinate</param>
3013         /// <param name="obj">Returns selected grid object</param>
3014         /// <param name="drawLinesOnly">Indicates if Lines or Stripes should be drawn.</param>
3015         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "y"),
3016         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "x"),
3017         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "selectionMode")]
PaintStrips(ChartGraphics graph, bool selectionMode, int x, int y, out object obj, bool drawLinesOnly)3018         internal void PaintStrips(ChartGraphics graph, bool selectionMode, int x, int y, out object obj, bool drawLinesOnly)
3019         {
3020             obj = null;
3021 
3022 #if SUBAXES
3023 			// Paint strips of sub-axis
3024 			if(ChartArea.IsSubAxesSupported)
3025 			{
3026 				foreach(SubAxis subAxis in this.SubAxes)
3027 				{
3028 					subAxis.PaintStrips( graph, selectionMode, x, y, out obj, drawLinesOnly);
3029 				}
3030 			}
3031 #endif // SUBAXES
3032 
3033             // Axis is disabled
3034             if (enabled == false)
3035                 return;
3036 
3037             // Add axis isInterlaced strip lines into the collection
3038             bool interlacedStripAdded = AddInterlacedStrip();
3039 
3040             // Draw axis strips and lines
3041             foreach (StripLine strip in this.StripLines)
3042             {
3043                 strip.Paint(graph, this.Common, drawLinesOnly);
3044             }
3045 
3046             // Remove axis isInterlaced strip line from the collection after drawing
3047             if (interlacedStripAdded)
3048             {
3049                 // Remove isInterlaced strips which always is the first strip line
3050                 this.StripLines.RemoveAt(0);
3051             }
3052 
3053         }
3054 
3055         /// <summary>
3056         /// Helper function which adds temp. strip lines into the collection
3057         /// to display isInterlaced lines in axis.
3058         /// </summary>
AddInterlacedStrip()3059         private bool AddInterlacedStrip()
3060         {
3061             bool addStrip = false;
3062             if (this.IsInterlaced)
3063             {
3064                 StripLine stripLine = new StripLine();
3065                 stripLine.interlaced = true;
3066                 // VSTS fix of 164115 IsInterlaced StripLines with no border are rendered with black border, regression of VSTS 136763
3067                 stripLine.BorderColor = Color.Empty;
3068 
3069                 // Get interval from grid lines, tick marks or labels
3070                 if (this.MajorGrid.Enabled && this.MajorGrid.GetInterval() != 0.0)
3071                 {
3072                     addStrip = true;
3073                     stripLine.Interval = this.MajorGrid.GetInterval() * 2.0;
3074                     stripLine.IntervalType = this.MajorGrid.GetIntervalType();
3075                     stripLine.IntervalOffset = this.MajorGrid.GetIntervalOffset();
3076                     stripLine.IntervalOffsetType = this.MajorGrid.GetIntervalOffsetType();
3077                     stripLine.StripWidth = this.MajorGrid.GetInterval();
3078                     stripLine.StripWidthType = this.MajorGrid.GetIntervalType();
3079                 }
3080                 else if (this.MajorTickMark.Enabled && this.MajorTickMark.GetInterval() != 0.0)
3081                 {
3082                     addStrip = true;
3083                     stripLine.Interval = this.MajorTickMark.GetInterval() * 2.0;
3084                     stripLine.IntervalType = this.MajorTickMark.GetIntervalType();
3085                     stripLine.IntervalOffset = this.MajorTickMark.GetIntervalOffset();
3086                     stripLine.IntervalOffsetType = this.MajorTickMark.GetIntervalOffsetType();
3087                     stripLine.StripWidth = this.MajorTickMark.GetInterval();
3088                     stripLine.StripWidthType = this.MajorTickMark.GetIntervalType();
3089                 }
3090                 else if (this.LabelStyle.Enabled && this.LabelStyle.GetInterval() != 0.0)
3091                 {
3092                     addStrip = true;
3093                     stripLine.Interval = this.LabelStyle.GetInterval() * 2.0;
3094                     stripLine.IntervalType = this.LabelStyle.GetIntervalType();
3095                     stripLine.IntervalOffset = this.LabelStyle.GetIntervalOffset();
3096                     stripLine.IntervalOffsetType = this.LabelStyle.GetIntervalOffsetType();
3097                     stripLine.StripWidth = this.LabelStyle.GetInterval();
3098                     stripLine.StripWidthType = this.LabelStyle.GetIntervalType();
3099                 }
3100 
3101                 // Insert item into the strips collection
3102                 if (addStrip)
3103                 {
3104                     // Define stip color
3105                     if (this.InterlacedColor != Color.Empty)
3106                     {
3107                         stripLine.BackColor = this.InterlacedColor;
3108                     }
3109                     else
3110                     {
3111                         // If isInterlaced strips color is not set - use darker color of the area
3112                         if (ChartArea.BackColor == Color.Empty)
3113                         {
3114                             stripLine.BackColor = (ChartArea.Area3DStyle.Enable3D) ? Color.DarkGray : Color.LightGray;
3115                         }
3116                         else if (ChartArea.BackColor == Color.Transparent)
3117                         {
3118                             if (Common.Chart.BackColor != Color.Transparent && Common.Chart.BackColor != Color.Black)
3119                             {
3120                                 stripLine.BackColor = ChartGraphics.GetGradientColor(Common.Chart.BackColor, Color.Black, 0.2);
3121                             }
3122                             else
3123                             {
3124                                 stripLine.BackColor = Color.LightGray;
3125                             }
3126                         }
3127                         else
3128                         {
3129                             stripLine.BackColor = ChartGraphics.GetGradientColor(ChartArea.BackColor, Color.Black, 0.2);
3130                         }
3131                     }
3132 
3133                     // Insert strip
3134                     this.StripLines.Insert(0, stripLine);
3135                 }
3136             }
3137 
3138             return addStrip;
3139         }
3140 
3141         #endregion
3142 
3143         #region Axis parameters recalculation and resizing methods
3144 
3145         /// <summary>
3146         /// This method will calculate the maximum and minimum values
3147         /// using interval on the X axis automatically. It will make a gap between
3148         /// data points and border of the Common.Chart area.
3149         /// Note that this method can only be called for primary or secondary X axes.
3150         /// </summary>
RoundAxisValues()3151         public void RoundAxisValues()
3152         {
3153             this.roundedXValues = true;
3154         }
3155 
3156         /// <summary>
3157         /// RecalculateAxesScale axis.
3158         /// </summary>
3159         /// <param name="position">Plotting area position.</param>
ReCalc(ElementPosition position)3160         internal void ReCalc(ElementPosition position)
3161         {
3162             PlotAreaPosition = position;
3163 
3164 #if SUBAXES
3165 
3166 			// Recalculate all sub-axis
3167 			foreach(SubAxis subAxis in this.SubAxes)
3168 			{
3169 				subAxis.ReCalc( position );
3170 			}
3171 #endif // SUBAXES
3172         }
3173 
3174         /// <summary>
3175         /// This method store Axis values as minimum, maximum,
3176         /// crossing, etc. Axis auto algorithm changes these
3177         /// values and they have to be set to default values
3178         /// after painting.
3179         /// </summary>
StoreAxisValues()3180         internal void StoreAxisValues()
3181         {
3182             tempLabels = new CustomLabelsCollection(this);
3183             foreach (CustomLabel label in CustomLabels)
3184             {
3185                 tempLabels.Add(label.Clone());
3186             }
3187 
3188             paintMode = true;
3189 
3190             // This field synchronies the Storing and
3191             // resetting of temporary values
3192             if (_storeValuesEnabled)
3193             {
3194 
3195                 tempMaximum = maximum;
3196                 tempMinimum = minimum;
3197                 tempCrossing = crossing;
3198                 tempAutoMinimum = _autoMinimum;
3199                 tempAutoMaximum = _autoMaximum;
3200 
3201                 tempMajorGridInterval = majorGrid.interval;
3202                 tempMajorTickMarkInterval = majorTickMark.interval;
3203 
3204                 tempMinorGridInterval = minorGrid.interval;
3205                 tempMinorTickMarkInterval = minorTickMark.interval;
3206 
3207 
3208                 tempGridIntervalType = majorGrid.intervalType;
3209                 tempTickMarkIntervalType = majorTickMark.intervalType;
3210 
3211 
3212                 tempLabelInterval = labelStyle.interval;
3213                 tempLabelIntervalType = labelStyle.intervalType;
3214 
3215                 // Remember original ScaleView Position
3216                 this._originalViewPosition = this.ScaleView.Position;
3217 
3218                 // This field synchronies the Storing and
3219                 // resetting of temporary values
3220                 _storeValuesEnabled = false;
3221             }
3222 
3223 #if SUBAXES
3224 
3225 			// Store values of all sub-axis
3226 			if(ChartArea.IsSubAxesSupported)
3227 			{
3228 				foreach(SubAxis subAxis in this.SubAxes)
3229 				{
3230 					subAxis.StoreAxisValues( );
3231 				}
3232 			}
3233 #endif // SUBAXES
3234 
3235         }
3236 
3237 
3238         /// <summary>
3239         /// This method reset Axis values as minimum, maximum,
3240         /// crossing, etc. Axis auto algorithm changes these
3241         /// values and they have to be set to default values
3242         /// after painting.
3243         /// </summary>
ResetAxisValues()3244         internal void ResetAxisValues()
3245         {
3246             // Paint mode is finished
3247             paintMode = false;
3248 
3249 #if Microsoft_CONTROL
3250 			if(Common.Chart == null)
3251 			{
3252 #if SUBAXES
3253 				else if(this is SubAxis)
3254 				{
3255 					if( ((SubAxis)this).parentAxis != null)
3256 					{
3257 						this.Common = ((SubAxis)this).parentAxis.Common;
3258 						Common.Chart = ((SubAxis)this).parentAxis.Common.Chart;
3259 					}
3260 				}
3261 #endif // SUBAXES
3262             }
3263 			if(Common.Chart != null && Common.Chart.Site != null && Common.Chart.Site.DesignMode)
3264 			{
3265 				ResetAutoValues();
3266 			}
3267 #else
3268             ResetAutoValues();
3269 #endif
3270 
3271             // Reset back original custom labels
3272             if (tempLabels != null)
3273             {
3274                 CustomLabels.Clear();
3275                 foreach (CustomLabel label in tempLabels)
3276                 {
3277                     CustomLabels.Add(label.Clone());
3278                 }
3279 
3280                 tempLabels = null;
3281             }
3282 
3283 #if SUBAXES
3284 
3285 			// Reset values of all sub-axis
3286 			if(ChartArea.IsSubAxesSupported)
3287 			{
3288 				foreach(SubAxis subAxis in this.SubAxes)
3289 				{
3290 					subAxis.ResetAxisValues( );
3291 				}
3292 			}
3293 #endif // SUBAXES
3294         }
3295 
3296 
3297         /// <summary>
3298         /// Reset auto calculated axis values
3299         /// </summary>
ResetAutoValues()3300         internal void ResetAutoValues()
3301         {
3302             refreshMinMaxFromData = true;
3303             maximum = tempMaximum;
3304             minimum = tempMinimum;
3305             crossing = tempCrossing;
3306             _autoMinimum = tempAutoMinimum;
3307             _autoMaximum = tempAutoMaximum;
3308 
3309             majorGrid.interval = tempMajorGridInterval;
3310             majorTickMark.interval = tempMajorTickMarkInterval;
3311 
3312             minorGrid.interval = tempMinorGridInterval;
3313             minorTickMark.interval = tempMinorTickMarkInterval;
3314 
3315 
3316             labelStyle.interval = tempLabelInterval;
3317             majorGrid.intervalType = tempGridIntervalType;
3318             majorTickMark.intervalType = tempTickMarkIntervalType;
3319             labelStyle.intervalType = tempLabelIntervalType;
3320 
3321             // Restore original ScaleView Position
3322             if (Common.Chart != null)
3323             {
3324                 if (!Common.Chart.serializing)
3325                 {
3326                     this.ScaleView.Position = this._originalViewPosition;
3327                 }
3328             }
3329 
3330             // This field synchronies the Storing and
3331             // resetting of temporary values
3332             _storeValuesEnabled = true;
3333 
3334 #if SUBAXES
3335 
3336 			// Reset auto values of all sub-axis
3337 			if(ChartArea.IsSubAxesSupported)
3338 			{
3339 				foreach(SubAxis subAxis in this.SubAxes)
3340 				{
3341 					subAxis.ResetAutoValues( );
3342 				}
3343 			}
3344 #endif // SUBAXES
3345 
3346         }
3347 
3348         /// <summary>
3349         /// Calculate size of the axis elements like title, labels and marks.
3350         /// </summary>
3351         /// <param name="chartGraph">Chart graphics object.</param>
3352         /// <param name="chartAreaPosition">The Chart area position.</param>
3353         /// <param name="plotArea">Plotting area size.</param>
3354         /// <param name="axesNumber">Number of axis of the same orientation.</param>
3355         /// <param name="autoPlotPosition">Indicates that inner plot position is automatic.</param>
Resize( ChartGraphics chartGraph, ElementPosition chartAreaPosition, RectangleF plotArea, float axesNumber, bool autoPlotPosition)3356         virtual internal void Resize(
3357             ChartGraphics chartGraph,
3358             ElementPosition chartAreaPosition,
3359             RectangleF plotArea,
3360             float axesNumber,
3361             bool autoPlotPosition)
3362         {
3363 #if SUBAXES
3364 			// Resize all sub-axis
3365 			if(ChartArea.IsSubAxesSupported)
3366 			{
3367 				foreach(SubAxis subAxis in this.SubAxes)
3368 				{
3369 					subAxis.Resize(chartGraph, chartAreaPosition, plotArea, axesNumber, autoPlotPosition);
3370 				}
3371 			}
3372 #endif // SUBAXES
3373 
3374 
3375 #if Microsoft_CONTROL
3376             // Disable Common.Chart invalidation
3377             bool oldDisableInvalidates = Common.Chart.disableInvalidates;
3378 			Common.Chart.disableInvalidates = true;
3379 #endif //Microsoft_CONTROL
3380 
3381             // Set Common.Chart area position
3382             PlotAreaPosition = chartAreaPosition;
3383 
3384             // Initialize plot area size
3385             PlotAreaPosition.FromRectangleF(plotArea);
3386 
3387             //******************************************************
3388             //** Calculate axis title size
3389             //******************************************************
3390             this.titleSize = 0F;
3391             if (this.Title.Length > 0)
3392             {
3393                 // Measure axis title
3394                 SizeF titleStringSize = chartGraph.MeasureStringRel(this.Title.Replace("\\n", "\n"), this.TitleFont, new SizeF(10000f, 10000f), StringFormat.GenericTypographic, this.GetTextOrientation());
3395 
3396                 // Switch Width & Heigth for vertical axes
3397                 // If axis is horizontal
3398                 float maxTitlesize = 0;
3399                 if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3400                 {
3401                     maxTitlesize = (plotArea.Height / 100F) * (Axis.maxAxisTitleSize / axesNumber);
3402                     if (this.IsTextVertical)
3403                     {
3404                         this.titleSize = Math.Min(titleStringSize.Width, maxTitlesize);
3405                     }
3406                     else
3407                     {
3408                         this.titleSize = Math.Min(titleStringSize.Height, maxTitlesize);
3409                     }
3410                 }
3411                 // If axis is vertical
3412                 else
3413                 {
3414 					titleStringSize = chartGraph.GetAbsoluteSize(titleStringSize);
3415 					titleStringSize = chartGraph.GetRelativeSize(new SizeF(titleStringSize.Height, titleStringSize.Width));
3416 					maxTitlesize = (plotArea.Width / 100F) * (Axis.maxAxisTitleSize / axesNumber);
3417                     if (this.IsTextVertical)
3418                     {
3419 						this.titleSize = Math.Min(titleStringSize.Width, maxTitlesize);
3420                     }
3421                     else
3422                     {
3423                         this.titleSize = Math.Min(titleStringSize.Height, maxTitlesize);
3424                     }
3425                 }
3426             }
3427             if (this.titleSize > 0)
3428             {
3429                 this.titleSize += elementSpacing;
3430             }
3431 
3432             //*********************************************************
3433             //** Get arrow size of the opposite axis
3434             //*********************************************************
3435             float arrowSize = 0F;
3436             SizeF arrowSizePrimary = SizeF.Empty;
3437             SizeF arrowSizeSecondary = SizeF.Empty;
3438             ArrowOrientation arrowOrientation = ArrowOrientation.Bottom;
3439             if (this.axisType == AxisName.X || this.axisType == AxisName.X2)
3440             {
3441                 if (ChartArea.AxisY.ArrowStyle != AxisArrowStyle.None)
3442                 {
3443                     arrowSizePrimary = ChartArea.AxisY.GetArrowSize(out arrowOrientation);
3444                     if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
3445                     {
3446                         arrowSizePrimary = SizeF.Empty;
3447                     }
3448                 }
3449 
3450                 if (ChartArea.AxisY2.ArrowStyle != AxisArrowStyle.None)
3451                 {
3452                     arrowSizeSecondary = ChartArea.AxisY2.GetArrowSize(out arrowOrientation);
3453                     if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
3454                     {
3455                         arrowSizeSecondary = SizeF.Empty;
3456                     }
3457                 }
3458             }
3459             else
3460             {
3461                 if (ChartArea.AxisX.ArrowStyle != AxisArrowStyle.None)
3462                 {
3463                     arrowSizePrimary = ChartArea.AxisX.GetArrowSize(out arrowOrientation);
3464                     if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
3465                     {
3466                         arrowSizePrimary = SizeF.Empty;
3467                     }
3468                 }
3469 
3470                 if (ChartArea.AxisX2.ArrowStyle != AxisArrowStyle.None)
3471                 {
3472                     arrowSizeSecondary = ChartArea.AxisX2.GetArrowSize(out arrowOrientation);
3473                     if (!IsArrowInAxis(arrowOrientation, this.AxisPosition))
3474                     {
3475                         arrowSizeSecondary = SizeF.Empty;
3476                     }
3477                 }
3478             }
3479 
3480             // If axis is horizontal
3481             if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3482             {
3483                 arrowSize = Math.Max(arrowSizePrimary.Height, arrowSizeSecondary.Height);
3484             }
3485             // If axis is vertical
3486             else
3487             {
3488                 arrowSize = Math.Max(arrowSizePrimary.Width, arrowSizeSecondary.Width);
3489             }
3490 
3491             //*********************************************************
3492             //** Calculate axis tick marks, axis thickness, arrow size
3493             //** and scroll bar size
3494             //*********************************************************
3495             this.markSize = 0F;
3496 
3497             // Get major and minor tick marks sizes
3498             float majorTickSize = 0;
3499             if (this.MajorTickMark.Enabled && this.MajorTickMark.TickMarkStyle != TickMarkStyle.None)
3500             {
3501                 if (this.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
3502                 {
3503                     majorTickSize = 0F;
3504                 }
3505                 else if (this.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
3506                 {
3507                     majorTickSize = this.MajorTickMark.Size / 2F;
3508                 }
3509                 else if (this.MajorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
3510                 {
3511                     majorTickSize = this.MajorTickMark.Size;
3512                 }
3513             }
3514 
3515             float minorTickSize = 0;
3516             if (this.MinorTickMark.Enabled && this.MinorTickMark.TickMarkStyle != TickMarkStyle.None && this.MinorTickMark.GetInterval() != 0)
3517             {
3518                 if (this.MinorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
3519                 {
3520                     minorTickSize = 0F;
3521                 }
3522                 else if (this.MinorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
3523                 {
3524                     minorTickSize = this.MinorTickMark.Size / 2F;
3525                 }
3526                 else if (this.MinorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
3527                 {
3528                     minorTickSize = this.MinorTickMark.Size;
3529                 }
3530             }
3531 
3532             this.markSize += (float)Math.Max(majorTickSize, minorTickSize);
3533 
3534 
3535             // Add axis line size
3536             SizeF borderSize = chartGraph.GetRelativeSize(new SizeF(this.LineWidth, this.LineWidth));
3537 
3538             // If axis is horizontal
3539             if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3540             {
3541                 this.markSize += borderSize.Height / 2f;
3542                 this.markSize = Math.Min(this.markSize, (plotArea.Height / 100F) * (Axis.maxAxisMarkSize / axesNumber));
3543             }
3544             // If axis is vertical
3545             else
3546             {
3547                 this.markSize += borderSize.Width / 2f;
3548                 this.markSize = Math.Min(this.markSize, (plotArea.Width / 100F) * (Axis.maxAxisMarkSize / axesNumber));
3549             }
3550 
3551             // Add axis scroll bar size (if it's visible)
3552             this.scrollBarSize = 0f;
3553 
3554 #if Microsoft_CONTROL
3555 
3556             if (this.ScrollBar.IsVisible &&
3557                 (this.IsAxisOnAreaEdge || !this.IsMarksNextToAxis))
3558             {
3559                 if (this.ScrollBar.IsPositionedInside)
3560                 {
3561                     this.markSize += (float)this.ScrollBar.GetScrollBarRelativeSize();
3562                 }
3563                 else
3564                 {
3565                     this.scrollBarSize = (float)this.ScrollBar.GetScrollBarRelativeSize();
3566                 }
3567             }
3568 
3569 #endif // Microsoft_CONTROL
3570 
3571 
3572             //*********************************************************
3573             //** Adjust mark size using area scene wall width
3574             //*********************************************************
3575             if (ChartArea.Area3DStyle.Enable3D &&
3576                 !ChartArea.chartAreaIsCurcular &&
3577                 ChartArea.BackColor != Color.Transparent &&
3578                 ChartArea.Area3DStyle.WallWidth > 0)
3579             {
3580                 SizeF areaWallSize = chartGraph.GetRelativeSize(new SizeF(ChartArea.Area3DStyle.WallWidth, ChartArea.Area3DStyle.WallWidth));
3581                 if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3582                 {
3583                     this.markSize += areaWallSize.Height;
3584                 }
3585                 else
3586                 {
3587                     this.markSize += areaWallSize.Width;
3588                 }
3589 
3590                 // Ignore Max marks size for the 3D wall size.
3591                 //this.markSize = Math.Min(this.markSize, (plotArea.Width / 100F) * (Axis.maxAxisMarkSize / axesNumber));
3592             }
3593 
3594             //*********************************************************
3595             //** Adjust title size and mark size using arrow size
3596             //*********************************************************
3597             if (arrowSize > (this.markSize + this.scrollBarSize + this.titleSize))
3598             {
3599                 this.markSize = Math.Max(this.markSize, arrowSize - (this.markSize + this.scrollBarSize + this.titleSize));
3600                 this.markSize = Math.Min(this.markSize, (plotArea.Width / 100F) * (Axis.maxAxisMarkSize / axesNumber));
3601             }
3602 
3603             //*********************************************************
3604             //** Calculate max label size
3605             //*********************************************************
3606             float maxLabelSize = 0;
3607 
3608             if (!autoPlotPosition)
3609             {
3610                 if (this.GetIsMarksNextToAxis())
3611                 {
3612                     if (this.AxisPosition == AxisPosition.Top)
3613                         maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.Y;
3614                     else if (this.AxisPosition == AxisPosition.Bottom)
3615                         maxLabelSize = ChartArea.Position.Bottom - (float)GetAxisPosition();
3616                     if (this.AxisPosition == AxisPosition.Left)
3617                         maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.X;
3618                     else if (this.AxisPosition == AxisPosition.Right)
3619                         maxLabelSize = ChartArea.Position.Right - (float)GetAxisPosition();
3620                 }
3621                 else
3622                 {
3623                     if (this.AxisPosition == AxisPosition.Top)
3624                         maxLabelSize = plotArea.Y - ChartArea.Position.Y;
3625                     else if (this.AxisPosition == AxisPosition.Bottom)
3626                         maxLabelSize = ChartArea.Position.Bottom - plotArea.Bottom;
3627                     if (this.AxisPosition == AxisPosition.Left)
3628                         maxLabelSize = plotArea.X - ChartArea.Position.X;
3629                     else if (this.AxisPosition == AxisPosition.Right)
3630                         maxLabelSize = ChartArea.Position.Right - plotArea.Right;
3631                 }
3632 
3633                 maxLabelSize *= 2F;
3634             }
3635             else
3636             {
3637                 if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3638                     maxLabelSize = plotArea.Height * (_maximumAutoSize / 100f);
3639                 else
3640                     maxLabelSize = plotArea.Width * (_maximumAutoSize / 100f);
3641             }
3642 
3643 
3644 
3645             //******************************************************
3646             //** First try to select the interval that will
3647             //** generate best fit labels.
3648             //******************************************************
3649 
3650 
3651 
3652 			// Make sure the variable interval mode is enabled and
3653 			// no custom label interval used.
3654 			if( this.Enabled != AxisEnabled.False &&
3655 				this.LabelStyle.Enabled &&
3656 				this.IsVariableLabelCountModeEnabled() )
3657 			{
3658 				// Increase font by several points when height of the font is the most important
3659 				// dimension. Use original size whenwidth is the most important size.
3660 				float extraSize = 3f;
3661 				if( (this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) &&
3662 					(this.LabelStyle.Angle == 90 || this.LabelStyle.Angle == -90) )
3663 				{
3664 					extraSize = 0f;
3665 				}
3666 				if( (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom) &&
3667 					(this.LabelStyle.Angle == 180 || this.LabelStyle.Angle == 0) )
3668 				{
3669 					extraSize = 0f;
3670 				}
3671 
3672 				// If 3D Common.Chart is used make the measurements with font several point larger
3673 				if(ChartArea.Area3DStyle.Enable3D)
3674 				{
3675 					extraSize += 1f;
3676 				}
3677 
3678 				this.autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(this.LabelStyle.Font.FontFamily,
3679 					this.LabelStyle.Font.Size + extraSize,
3680 					this.LabelStyle.Font.Style,
3681 					GraphicsUnit.Point);
3682 
3683 				// Reset angle and stagged flag used in the auto-fitting algorithm
3684 				this.autoLabelAngle = this.LabelStyle.Angle;
3685 				this.autoLabelOffset = (this.LabelStyle.IsStaggered) ? 1 : 0;
3686 
3687 				// Adjust interval
3688 				this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, false);
3689 			}
3690 
3691 
3692 
3693             //******************************************************
3694             //** Automatically calculate the best font size, angle
3695             //** and try to use offset labels.
3696             //******************************************************
3697             // Reset all automatic label properties
3698             autoLabelFont = null;
3699             autoLabelAngle = -1000;
3700             autoLabelOffset = -1;
3701 
3702             // For circular Common.Chart area process auto-fitting for Y Axis only
3703             if (this.IsLabelAutoFit &&
3704                 this.LabelAutoFitStyle != LabelAutoFitStyles.None &&
3705                 !ChartArea.chartAreaIsCurcular)
3706             {
3707                 bool fitDone = false;
3708                 bool noWordWrap = false;
3709 
3710                 // Set default font angle and labels offset flag
3711                 autoLabelAngle = 0;
3712                 autoLabelOffset = 0;
3713 
3714                 // Original labels collection
3715                 CustomLabelsCollection originalLabels = null;
3716 
3717                 // Pick up maximum font size
3718                 float size = 8f;
3719 				size = (float)Math.Max(this.LabelAutoFitMaxFontSize, this.LabelAutoFitMinFontSize);
3720 				_minLabelFontSize = Math.Min(this.LabelAutoFitMinFontSize, this.LabelAutoFitMaxFontSize);
3721 				_aveLabelFontSize = _minLabelFontSize + Math.Abs(size - _minLabelFontSize)/2f;
3722 
3723 
3724                 // Check if common font size should be used
3725                 if (ChartArea.IsSameFontSizeForAllAxes)
3726                 {
3727                     size = (float)Math.Min(size, ChartArea.axesAutoFontSize);
3728                 }
3729 
3730                 //Set new font
3731                 autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(this.LabelStyle.Font.FontFamily,
3732                     size,
3733                     this.LabelStyle.Font.Style,
3734 					GraphicsUnit.Point
3735                 );
3736 
3737                 // Check if we allowed to increase font size while auto-fitting
3738                 if ((this.LabelAutoFitStyle & LabelAutoFitStyles.IncreaseFont) != LabelAutoFitStyles.IncreaseFont)
3739                 {
3740                     // Use axis labels font as starting point
3741                     autoLabelFont = this.LabelStyle.Font;
3742                 }
3743 
3744                 // Loop while labels do not fit
3745                 float spacer = 0f;
3746                 while (!fitDone)
3747                 {
3748                     //******************************************************
3749                     //** Check if labels fit
3750                     //******************************************************
3751 
3752                     // Check if grouping labels fit should be checked
3753                     bool checkLabelsFirstRowOnly = true;
3754                     if ((this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
3755                     {
3756                         // Only check grouping labels if we can reduce fonts size
3757                         checkLabelsFirstRowOnly = false;
3758                     }
3759 
3760                     // Check labels fit
3761                     fitDone = CheckLabelsFit(
3762                         chartGraph,
3763                         this.markSize + this.scrollBarSize + this.titleSize + spacer,
3764                         autoPlotPosition,
3765                         checkLabelsFirstRowOnly,
3766                         false);
3767 
3768                     //******************************************************
3769                     //** Adjust labels text properties to fit
3770                     //******************************************************
3771                     if (!fitDone)
3772                     {
3773                         // If font is bigger than average try to make it smaller
3774                         if (autoLabelFont.SizeInPoints >= _aveLabelFontSize &&
3775                             (this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
3776                         {
3777                             //Clean up the old font
3778                             autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
3779                                 autoLabelFont.FontFamily,
3780                                 autoLabelFont.SizeInPoints - 0.5f,
3781                                 autoLabelFont.Style,
3782                                 GraphicsUnit.Point);
3783                         }
3784 
3785                             // Try to use offset labels (2D charts and non-circular arae only!!!)
3786                         else if (!ChartArea.Area3DStyle.Enable3D &&
3787                             !ChartArea.chartAreaIsCurcular &&
3788                             originalLabels == null &&
3789                             autoLabelAngle == 0 &&
3790                             autoLabelOffset == 0 &&
3791                             (this.LabelAutoFitStyle & LabelAutoFitStyles.StaggeredLabels) == LabelAutoFitStyles.StaggeredLabels)
3792                         {
3793                             autoLabelOffset = 1;
3794                         }
3795 
3796                             // Try to insert new line characters in labels text
3797                         else if (!noWordWrap &&
3798                             (this.LabelAutoFitStyle & LabelAutoFitStyles.WordWrap) == LabelAutoFitStyles.WordWrap)
3799                         {
3800                             bool changed = false;
3801                             autoLabelOffset = 0;
3802 
3803                             // Check if backup copy of the original lables was made
3804                             if (originalLabels == null)
3805                             {
3806                                 // Copy current labels collection
3807                                 originalLabels = new CustomLabelsCollection(this);
3808                                 foreach (CustomLabel label in this.CustomLabels)
3809                                 {
3810                                     originalLabels.Add(label.Clone());
3811                                 }
3812                             }
3813 
3814                             // Try to insert new line character into the longest label
3815                             changed = WordWrapLongestLabel(this.CustomLabels);
3816 
3817                             // Word wrapping do not solve the labels overlapping issue
3818                             if (!changed)
3819                             {
3820                                 noWordWrap = true;
3821 
3822                                 // Restore original labels
3823                                 if (originalLabels != null)
3824                                 {
3825                                     this.CustomLabels.Clear();
3826                                     foreach (CustomLabel label in originalLabels)
3827                                     {
3828                                         this.CustomLabels.Add(label.Clone());
3829                                     }
3830 
3831                                     originalLabels = null;
3832                                 }
3833 
3834                                 if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3835                                 {
3836                                     if ((spacer == 0 ||
3837                                         spacer == 30f ||
3838                                         spacer == 20f) &&
3839                                         ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30 ||
3840                                         (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45 ||
3841                                         (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90))
3842                                     {
3843                                         // Try to use 90 degrees angle
3844                                         autoLabelAngle = 90;
3845                                         noWordWrap = false;
3846 
3847                                         // Usually 55% of Common.Chart area size is allowed for labels
3848                                         // Reduce that space.
3849                                         if (spacer == 0f)
3850                                         {
3851                                             // 30
3852                                             spacer = 30f;
3853                                         }
3854                                         else if (spacer == 30f)
3855                                         {
3856                                             // 20
3857                                             spacer = 20f;
3858                                         }
3859                                         else if (spacer == 20f)
3860                                         {
3861                                             // 5
3862                                             spacer = 5f;
3863                                         }
3864                                         else
3865                                         {
3866                                             autoLabelAngle = 0;
3867                                             noWordWrap = true;
3868                                         }
3869 
3870                                     }
3871                                     else
3872                                     {
3873                                         spacer = 0f;
3874                                     }
3875                                 }
3876                             }
3877                         }
3878 
3879                             // Try to change font angle
3880                         else if (autoLabelAngle != 90 &&
3881                             ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30 ||
3882                             (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45 ||
3883                             (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90))
3884                         {
3885                             spacer = 0f;
3886                             autoLabelOffset = 0;
3887 
3888                             if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30)
3889                             {
3890                                 // Increase angle by 45 degrees in 2D and 45 in 3D
3891                                 autoLabelAngle += (ChartArea.Area3DStyle.Enable3D) ? 45 : 30;
3892                             }
3893                             else if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45)
3894                             {
3895                                 // Increase angle by 45 degrees
3896                                 autoLabelAngle += 45;
3897                             }
3898                             else if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90)
3899                             {
3900                                 // Increase angle by 90 degrees
3901                                 autoLabelAngle += 90;
3902                             }
3903                         }
3904 
3905                             // Try to reduce font again
3906                         else if (autoLabelFont.SizeInPoints > _minLabelFontSize &&
3907                             (this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
3908                         {
3909                             //Clean up the old font
3910                             autoLabelAngle = 0;
3911                             autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
3912                                 autoLabelFont.FontFamily,
3913                                 autoLabelFont.SizeInPoints - 0.5f,
3914                                 autoLabelFont.Style,
3915                                 GraphicsUnit.Point);
3916                         }
3917 
3918                             // Failed to fit
3919                         else
3920                         {
3921                             // Use last font
3922                             if ((this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep30) == LabelAutoFitStyles.LabelsAngleStep30 ||
3923                                 (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep45) == LabelAutoFitStyles.LabelsAngleStep45 ||
3924                                 (this.LabelAutoFitStyle & LabelAutoFitStyles.LabelsAngleStep90) == LabelAutoFitStyles.LabelsAngleStep90)
3925                             {
3926                                 // Reset angle
3927                                 if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
3928                                 {
3929                                     autoLabelAngle = 90;
3930                                 }
3931                                 else
3932                                 {
3933                                     autoLabelAngle = 0;
3934                                 }
3935                             }
3936                             if ((this.LabelAutoFitStyle & LabelAutoFitStyles.StaggeredLabels) == LabelAutoFitStyles.StaggeredLabels)
3937                             {
3938                                 // Reset offset labels
3939                                 autoLabelOffset = 0;
3940                             }
3941                             fitDone = true;
3942                         }
3943                     }
3944                     else if (ChartArea.Area3DStyle.Enable3D &&
3945                         !ChartArea.chartAreaIsCurcular &&
3946                         autoLabelFont.SizeInPoints > _minLabelFontSize)
3947                     {
3948                         // Reduce auto-fit font by 1 for the 3D charts
3949                         autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
3950                             autoLabelFont.FontFamily,
3951                             autoLabelFont.SizeInPoints - 0.5f,
3952                             autoLabelFont.Style,
3953                             GraphicsUnit.Point);
3954                     }
3955                 }
3956 
3957 				// Change the auto-fit angle for top and bottom axes from 90 to -90
3958 				if(this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3959 				{
3960 					if(autoLabelAngle == 90)
3961 					{
3962 						autoLabelAngle = -90;
3963 					}
3964 				}
3965             }
3966 
3967             //*********************************************************
3968             //** Calculate overall labels size
3969             //*********************************************************
3970             this.labelSize = 0;
3971 
3972             // if labels are not enabled their size needs to remain zero
3973             if (this.LabelStyle.Enabled)
3974             {
3975                 //******************************************************
3976                 //** Calculate axis second labels row size
3977                 //******************************************************
3978                 this.labelSize = (maxAxisElementsSize) - this.markSize - this.scrollBarSize - this.titleSize;
3979                 if (this.labelSize > 0)
3980                 {
3981                     this.groupingLabelSizes = GetRequiredGroupLabelSize(chartGraph, (maxLabelSize / 100F) * maxAxisLabelRow2Size);
3982                     this.totlaGroupingLabelsSize = GetGroupLablesToatalSize();
3983                 }
3984 
3985                 //******************************************************
3986                 //** Calculate axis labels size
3987                 //******************************************************
3988                 this.labelSize -= this.totlaGroupingLabelsSize;
3989                 if (this.labelSize > 0)
3990                 {
3991                     // If axis is horizontal
3992                     if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
3993                     {
3994                         this.labelSize = elementSpacing + GetRequiredLabelSize(chartGraph,
3995                             (maxLabelSize / 100F) * (maxAxisElementsSize - this.markSize - this.scrollBarSize - this.titleSize), out this.unRotatedLabelSize);
3996                     }
3997                     // If axis is horizontal
3998                     else
3999                     {
4000                         this.labelSize = elementSpacing + GetRequiredLabelSize(chartGraph,
4001                             (maxLabelSize / 100F) * (maxAxisElementsSize - this.markSize - this.scrollBarSize - this.titleSize), out this.unRotatedLabelSize);
4002                     }
4003 
4004                     if (!this.LabelStyle.Enabled)
4005                     {
4006                         this.labelSize -= elementSpacing;
4007                     }
4008                 }
4009                 else
4010                 {
4011                     this.labelSize = 0;
4012                 }
4013 
4014                 this.labelSize += this.totlaGroupingLabelsSize;
4015             }
4016 
4017 #if SUBAXES
4018 			// Calculate offsets for all sub axes
4019 			if(!ChartArea.Area3DStyle.Enable3D &&
4020 				!ChartArea.chartAreaIsCurcular)
4021 			{
4022 				float currentOffset = this.markSize + this.labelSize + this.titleSize + this.scrollBarSize;
4023 				foreach(SubAxis subAxis in this.SubAxes)
4024 				{
4025 					if(subAxis.Enabled != AxisEnabled.False)
4026 					{
4027 						currentOffset += (float)subAxis.LocationOffset;
4028 						subAxis.offsetFromParent = currentOffset;
4029 						currentOffset += subAxis.markSize + subAxis.labelSize + subAxis.titleSize;
4030 					}
4031 				}
4032 			}
4033 #endif // SUBAXES
4034 
4035 
4036 #if Microsoft_CONTROL
4037             // Restore previous invalidation flag
4038 			Common.Chart.disableInvalidates = oldDisableInvalidates;
4039 #endif //Microsoft_CONTROL
4040         }
4041 
4042 		/// <summary>
4043 		/// Calculates axis interval so that labels will fit most efficiently.
4044 		/// </summary>
4045 		/// <param name="chartGraph">Chart graphics.</param>
4046 		/// <param name="autoPlotPosition">True if plot position is auto calculated.</param>
4047 		/// <param name="onlyIncreaseInterval">True if interval should only be increased.</param>
AdjustIntervalToFitLabels(ChartGraphics chartGraph, bool autoPlotPosition, bool onlyIncreaseInterval)4048 		private void AdjustIntervalToFitLabels(ChartGraphics chartGraph, bool autoPlotPosition, bool onlyIncreaseInterval)
4049 		{
4050 			// Calculates axis interval so that labels will fit most efficiently.
4051 			if(this.ScaleSegments.Count == 0)
4052 			{
4053 				this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, null, onlyIncreaseInterval);
4054 			}
4055 			else
4056 			{
4057 				// Allow values to go outside the segment boundary
4058 				this.ScaleSegments.AllowOutOfScaleValues = true;
4059 
4060 				// Adjust interval of each segment first
4061 				foreach(AxisScaleSegment axisScaleSegment in this.ScaleSegments)
4062 				{
4063 					this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, axisScaleSegment, onlyIncreaseInterval);
4064 				}
4065 
4066 				// Fill labels using new segment intervals
4067 				bool removeLabels = true;
4068 				int segmentIndex = 0;
4069 				ArrayList removedLabels = new ArrayList();
4070 				ArrayList removedLabelsIndexes = new ArrayList();
4071 				foreach(AxisScaleSegment scaleSegment in this.ScaleSegments)
4072 				{
4073 					scaleSegment.SetTempAxisScaleAndInterval();
4074 					this.FillLabels(removeLabels);
4075 					removeLabels = false;
4076 					scaleSegment.RestoreAxisScaleAndInterval();
4077 
4078 					// Remove last label of all segmenst except of the last
4079 					if(segmentIndex < this.ScaleSegments.Count - 1 &&
4080 						this.CustomLabels.Count > 0)
4081 					{
4082 						// Remove label and save it in the list
4083 						removedLabels.Add(this.CustomLabels[this.CustomLabels.Count - 1]);
4084 						removedLabelsIndexes.Add(this.CustomLabels.Count - 1);
4085 						this.CustomLabels.RemoveAt(this.CustomLabels.Count - 1);
4086 					}
4087 
4088 					++segmentIndex;
4089 				}
4090 
4091 				// Check all previously removed last labels of each segment if there
4092 				// is enough space to fit them
4093 				int reInsertedLabelsCount = 0;
4094 				int labelIndex = 0;
4095 				foreach(CustomLabel label in removedLabels)
4096 				{
4097 					// Re-insert the label
4098 					int labelInsertIndex = (int)removedLabelsIndexes[labelIndex] + reInsertedLabelsCount;
4099 					if(labelIndex < this.CustomLabels.Count)
4100 					{
4101 						this.CustomLabels.Insert(labelInsertIndex, label);
4102 					}
4103 					else
4104 					{
4105 						this.CustomLabels.Add(label);
4106 					}
4107 
4108 					// Check labels fit. Only horizontal or vertical fit is checked depending
4109 					// on the axis orientation.
4110 					ArrayList labelPositions = new ArrayList();
4111 					bool fitDone = CheckLabelsFit(
4112 						chartGraph,
4113 						this.markSize + this.scrollBarSize + this.titleSize,
4114 						autoPlotPosition,
4115 						true,
4116 						false,
4117 						(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? false : true,
4118 						(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? true : false,
4119 						labelPositions);
4120 
4121 					// If labels fit check if any of the label positions overlap
4122 					if(fitDone)
4123 					{
4124 						for(int index = 0; fitDone && index < labelPositions.Count; index++)
4125 						{
4126 							RectangleF rect1 = (RectangleF)labelPositions[index];
4127 							for(int index2 = index + 1; fitDone && index2 < labelPositions.Count; index2++)
4128 							{
4129 								RectangleF rect2 = (RectangleF)labelPositions[index2];
4130 								if(rect1.IntersectsWith(rect2))
4131 								{
4132 									fitDone = false;
4133 								}
4134 							}
4135 						}
4136 					}
4137 
4138 					// If labels do not fit or overlapp - remove completly
4139 					if(!fitDone)
4140 					{
4141 						this.CustomLabels.RemoveAt(labelInsertIndex);
4142 					}
4143 					else
4144 					{
4145 						++reInsertedLabelsCount;
4146 					}
4147 
4148 					++labelIndex;
4149 				}
4150 
4151 				// Make sure now values are rounded on segment boundary
4152 				this.ScaleSegments.AllowOutOfScaleValues = false;
4153 			}
4154 		}
4155 
4156 		/// <summary>
4157 		/// Checks if variable count labels mode is enabled.
4158 		/// </summary>
4159 		/// <returns>True if variable count labels mode is enabled.</returns>
IsVariableLabelCountModeEnabled()4160 		private bool IsVariableLabelCountModeEnabled()
4161 		{
4162 			// Make sure the variable interval mode is enabled and
4163 			// no custom label interval used.
4164 			if( (this.IntervalAutoMode == IntervalAutoMode.VariableCount || this.ScaleSegments.Count > 0) &&
4165 				!this.IsLogarithmic &&
4166 				(this.tempLabelInterval <= 0.0 || (double.IsNaN(this.tempLabelInterval) && this.Interval <= 0.0)) )
4167 			{
4168 				// This feature is not supported for charts that do not
4169 				// require X and Y axes (Pie, Radar, ...)
4170 				if(!ChartArea.requireAxes)
4171 				{
4172 					return false;
4173 				}
4174                 // This feature is not supported if the axis doesn't have data range
4175                 if (Double.IsNaN(this.minimum) || Double.IsNaN(this.maximum))
4176                 {
4177                     return false;
4178                 }
4179 				// Check if custom labels are used in the first row
4180 				bool customLabels = false;
4181 				foreach(CustomLabel label in this.CustomLabels)
4182 				{
4183 					if(label.customLabel && label.RowIndex == 0)
4184 					{
4185 						customLabels = true;
4186 						break;
4187 					}
4188 				}
4189 
4190 				// Proceed only if no custom labels are used in the first row
4191 				if(!customLabels)
4192 				{
4193 					return true;
4194 				}
4195 			}
4196 
4197 			return false;
4198 		}
4199 
4200 		/// <summary>
4201 		/// Calculates axis interval so that labels will fit most efficiently.
4202 		/// </summary>
4203 		/// <param name="chartGraph">Chart graphics.</param>
4204 		/// <param name="autoPlotPosition">True if plot position is auto calculated.</param>
4205 		/// <param name="axisScaleSegment">Axis scale segment to process.</param>
4206 		/// <param name="onlyIncreaseInterval">True if interval should only be increased.</param>
AdjustIntervalToFitLabels( ChartGraphics chartGraph, bool autoPlotPosition, AxisScaleSegment axisScaleSegment, bool onlyIncreaseInterval)4207 		private void AdjustIntervalToFitLabels(
4208 			ChartGraphics chartGraph,
4209 			bool autoPlotPosition,
4210 			AxisScaleSegment axisScaleSegment,
4211 			bool onlyIncreaseInterval)
4212 		{
4213 			// Re-fill the labels just for the scale segment provided
4214 			if(axisScaleSegment != null)
4215 			{
4216 				// Re-fill new axis labels
4217 				if(this.tempLabels != null)
4218 				{
4219 					this.CustomLabels.Clear();
4220 					foreach( CustomLabel label in this.tempLabels )
4221 					{
4222 						this.CustomLabels.Add(label.Clone());
4223 					}
4224 				}
4225 
4226 				// Fill labels just for the segment
4227 				axisScaleSegment.SetTempAxisScaleAndInterval();
4228 				this.FillLabels( true );
4229 				axisScaleSegment.RestoreAxisScaleAndInterval();
4230 			}
4231 
4232 			// Calculate minimum interval size
4233 			double minIntervalSzie = double.NaN;
4234 			ArrayList axisSeries = AxisScaleBreakStyle.GetAxisSeries(this);
4235 			foreach(Series series in axisSeries)
4236 			{
4237 				if(this.axisType == AxisName.X || this.axisType == AxisName.X2)
4238 				{
4239 					if(ChartHelper.IndexedSeries(series))
4240 					{
4241 						minIntervalSzie = 1.0;
4242 					}
4243 					else if(series.XValueType == ChartValueType.String ||
4244 						series.XValueType == ChartValueType.Int32 ||
4245 						series.XValueType == ChartValueType.UInt32 ||
4246 						series.XValueType == ChartValueType.UInt64 ||
4247 						series.XValueType == ChartValueType.Int64 )
4248 					{
4249 						minIntervalSzie = 1.0;
4250 					}
4251 				}
4252 				else
4253 				{
4254 					if(series.YValueType == ChartValueType.String ||
4255 						series.YValueType == ChartValueType.Int32 ||
4256 						series.YValueType == ChartValueType.UInt32 ||
4257 						series.YValueType == ChartValueType.UInt64 ||
4258 						series.YValueType == ChartValueType.Int64 )
4259 					{
4260 						minIntervalSzie = 1.0;
4261 					}
4262 				}
4263 			}
4264 
4265 
4266 			// Iterate while interval is not found
4267 			bool firstIteration = true;
4268 			bool increaseNumberOfLabels = true;
4269 			double currentInterval = (axisScaleSegment == null) ? this.labelStyle.GetInterval() : axisScaleSegment.Interval;
4270 			DateTimeIntervalType currentIntervalType = (axisScaleSegment == null) ? this.labelStyle.GetIntervalType() : axisScaleSegment.IntervalType;
4271 			DateTimeIntervalType lastFitIntervalType = currentIntervalType;
4272 			double lastFitInterval = currentInterval;
4273 			ArrayList lastFitLabels = new ArrayList();
4274 			bool intervalFound = false;
4275 			int iterationNumber = 0;
4276 			while(!intervalFound && iterationNumber <= 1000)
4277 			{
4278 				bool fillNewLabels = true;
4279 #if DEBUG
4280 				if(iterationNumber >= 999)
4281 				{
4282                     throw (new InvalidOperationException(SR.ExceptionAxisDynamicIntervalCalculationFailed));
4283 				}
4284 #endif // DEBUG
4285 
4286 				// Check labels fit. Only horizontal or vertical fit is checked depending
4287 				// on the axis orientation.
4288 				bool fitDone = CheckLabelsFit(
4289 					chartGraph,
4290 					this.markSize + this.scrollBarSize + this.titleSize,
4291 					autoPlotPosition,
4292 					true,
4293 					false,
4294 					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? false : true,
4295 					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? true : false,
4296 					null);
4297 
4298 				// Check if we need to increase or reduce number of labels
4299 				if(firstIteration)
4300 				{
4301 					firstIteration = false;
4302 					increaseNumberOfLabels = (fitDone) ? true : false;
4303 
4304 					// Check if we can decrease the interva;
4305 					if(onlyIncreaseInterval && increaseNumberOfLabels)
4306 					{
4307 						intervalFound = true;
4308 						continue;
4309 					}
4310 				}
4311 
4312 				// Find new interval. Value 0.0 means that interval cannot be
4313 				// reduced/increased any more and current interval should be used
4314 				double newInterval = 0.0;
4315 				DateTimeIntervalType newIntervalType = DateTimeIntervalType.Number;
4316 				if(increaseNumberOfLabels)
4317 				{
4318 					if(fitDone)
4319 					{
4320 						// Make a copy of last interval and labels collection that previously fit
4321 						lastFitInterval = currentInterval;
4322 						lastFitIntervalType = currentIntervalType;
4323 						lastFitLabels.Clear();
4324 						foreach(CustomLabel label in this.CustomLabels)
4325 						{
4326 							lastFitLabels.Add(label);
4327 						}
4328 
4329 						newIntervalType = currentIntervalType;
4330 						newInterval = this.ReduceLabelInterval(
4331 							currentInterval,
4332 							minIntervalSzie,
4333 							ref newIntervalType);
4334 					}
4335 					else
4336 					{
4337 						newInterval = lastFitInterval;
4338 						newIntervalType = lastFitIntervalType;
4339 						intervalFound = true;
4340 
4341 						// Reuse previously saved labels
4342 						fillNewLabels = false;
4343 						this.CustomLabels.Clear();
4344 						foreach(CustomLabel label in lastFitLabels)
4345 						{
4346 							this.CustomLabels.Add(label);
4347 						}
4348 
4349 					}
4350 				}
4351 				else
4352 				{
4353 					if(!fitDone && this.CustomLabels.Count > 1)
4354 					{
4355 						newIntervalType = currentIntervalType;
4356 						newInterval = this.IncreaseLabelInterval(
4357 							currentInterval,
4358 							ref newIntervalType);
4359 					}
4360 					else
4361 					{
4362 						intervalFound = true;
4363 					}
4364 				}
4365 
4366 				// Set new interval
4367 				if(newInterval != 0.0)
4368 				{
4369 					currentInterval = newInterval;
4370 					currentIntervalType = newIntervalType;
4371 
4372 					if(axisScaleSegment == null)
4373 					{
4374 						this.SetIntervalAndType(newInterval, newIntervalType);
4375 					}
4376 					else
4377 					{
4378 						axisScaleSegment.Interval = newInterval;
4379 						axisScaleSegment.IntervalType = newIntervalType;
4380 					}
4381 
4382 					// Re-fill new axis labels
4383 					if(fillNewLabels)
4384 					{
4385 						if(this.tempLabels != null)
4386 						{
4387 							this.CustomLabels.Clear();
4388 							foreach( CustomLabel label in this.tempLabels )
4389 							{
4390 								CustomLabels.Add(label.Clone());
4391 							}
4392 						}
4393 
4394 						if(axisScaleSegment == null)
4395 						{
4396 							this.FillLabels(true);
4397 						}
4398 						else
4399 						{
4400 							axisScaleSegment.SetTempAxisScaleAndInterval();
4401 							this.FillLabels( true );
4402 							axisScaleSegment.RestoreAxisScaleAndInterval();
4403 						}
4404 					}
4405 				}
4406 				else
4407 				{
4408 					intervalFound = true;
4409 				}
4410 
4411 				++iterationNumber;
4412 			}
4413 		}
4414 
4415 		/// <summary>
4416 		/// Reduces current label interval, so that more labels can fit.
4417 		/// </summary>
4418 		/// <param name="oldInterval">An interval to reduce.</param>
4419 		/// <param name="minInterval">Minimum interval size.</param>
4420         /// <param name="axisIntervalType">Interval type.</param>
4421 		/// <returns>New interval or 0.0 if interval cannot be reduced.</returns>
ReduceLabelInterval( double oldInterval, double minInterval, ref DateTimeIntervalType axisIntervalType)4422 		private double ReduceLabelInterval(
4423 			double oldInterval,
4424 			double minInterval,
4425 			ref DateTimeIntervalType axisIntervalType)
4426 		{
4427 			double newInterval = oldInterval;
4428 
4429 			// Calculate rounded interval value
4430 			double range = this.maximum - this.minimum;
4431 			int iterationIndex = 0;
4432 			if( axisIntervalType == DateTimeIntervalType.Auto ||
4433 				axisIntervalType == DateTimeIntervalType.NotSet ||
4434 				axisIntervalType == DateTimeIntervalType.Number)
4435 			{
4436 				// Process numeric scale
4437 				double devider = 2.0;
4438 				do
4439 				{
4440 #if DEBUG
4441 					if(iterationIndex >= 99)
4442 					{
4443                         throw (new InvalidOperationException(SR.ExceptionAxisIntervalDecreasingFailed));
4444 					}
4445 #endif // DEBUG
4446 
4447 					newInterval = CalcInterval( range / (range / (newInterval / devider)) );
4448 					if(newInterval == oldInterval)
4449 					{
4450 						devider *= 2.0;
4451 					}
4452 
4453 					++iterationIndex;
4454 				} while(newInterval == oldInterval && iterationIndex <= 100);
4455 			}
4456 			else
4457 			{
4458 				// Process date scale
4459 				if(oldInterval > 1.0 || oldInterval < 1.0)
4460 				{
4461 					if( axisIntervalType == DateTimeIntervalType.Minutes ||
4462 						axisIntervalType == DateTimeIntervalType.Seconds)
4463 					{
4464 						if(oldInterval >= 60)
4465 						{
4466 							newInterval = Math.Round(oldInterval / 2.0);
4467 						}
4468 						else if(oldInterval >= 30.0)
4469 						{
4470 							newInterval = 15.0;
4471 						}
4472 						else if(oldInterval >= 15.0)
4473 						{
4474 							newInterval = 5.0;
4475 						}
4476 						else if(oldInterval >= 5.0)
4477 						{
4478 							newInterval = 1.0;
4479 						}
4480 					}
4481 					else
4482 					{
4483 						newInterval = Math.Round(oldInterval / 2.0);
4484 					}
4485 					if(newInterval < 1.0)
4486 					{
4487 						newInterval = 1.0;
4488 					}
4489 				}
4490 				if(oldInterval == 1.0)
4491 				{
4492 					if(axisIntervalType == DateTimeIntervalType.Years)
4493 					{
4494 						newInterval = 6.0;
4495 						axisIntervalType = DateTimeIntervalType.Months;
4496 					}
4497 					else if(axisIntervalType == DateTimeIntervalType.Months)
4498 					{
4499 						newInterval = 2.0;
4500 						axisIntervalType = DateTimeIntervalType.Weeks;
4501 					}
4502 					else if(axisIntervalType == DateTimeIntervalType.Weeks)
4503 					{
4504 						newInterval = 2.0;
4505 						axisIntervalType = DateTimeIntervalType.Days;
4506 					}
4507 					else if(axisIntervalType == DateTimeIntervalType.Days)
4508 					{
4509 						newInterval = 12.0;
4510 						axisIntervalType = DateTimeIntervalType.Hours;
4511 					}
4512 					else if(axisIntervalType == DateTimeIntervalType.Hours)
4513 					{
4514 						newInterval = 30.0;
4515 						axisIntervalType = DateTimeIntervalType.Minutes;
4516 					}
4517 					else if(axisIntervalType == DateTimeIntervalType.Minutes)
4518 					{
4519 						newInterval = 30.0;
4520 						axisIntervalType = DateTimeIntervalType.Seconds;
4521 					}
4522 					else if(axisIntervalType == DateTimeIntervalType.Seconds)
4523 					{
4524 						newInterval = 100.0;
4525 						axisIntervalType = DateTimeIntervalType.Milliseconds;
4526 					}
4527 				}
4528 			}
4529 
4530 
4531 			// Make sure interal is not less than min interval specified
4532 			if(!double.IsNaN(minInterval) && newInterval < minInterval)
4533 			{
4534 				newInterval = 0.0;
4535 			}
4536 
4537 			return newInterval;
4538 		}
4539 
4540 		/// <summary>
4541 		/// Increases current label interval, so that less labels fit.
4542 		/// </summary>
4543 		/// <param name="oldInterval">An interval to increase.</param>
4544         /// <param name="axisIntervalType">Interval type.</param>
4545 		/// <returns>New interval or 0.0 if interval cannot be increased.</returns>
IncreaseLabelInterval( double oldInterval, ref DateTimeIntervalType axisIntervalType)4546 		private double IncreaseLabelInterval(
4547 			double oldInterval,
4548 			ref DateTimeIntervalType axisIntervalType)
4549 		{
4550 			double newInterval = oldInterval;
4551 
4552 			// Calculate rounded interval value
4553 			double range = this.maximum - this.minimum;
4554 			int iterationIndex = 0;
4555 			if( axisIntervalType == DateTimeIntervalType.Auto ||
4556 				axisIntervalType == DateTimeIntervalType.NotSet ||
4557 				axisIntervalType == DateTimeIntervalType.Number)
4558 			{
4559 				// Process numeric scale
4560 				double devider = 2.0;
4561 				do
4562 				{
4563 #if DEBUG
4564 					if(iterationIndex >= 99)
4565 					{
4566                         throw (new InvalidOperationException(SR.ExceptionAxisIntervalIncreasingFailed));
4567 					}
4568 #endif // DEBUG
4569 
4570 					newInterval = CalcInterval( range / (range / (newInterval * devider)) );
4571 					if(newInterval == oldInterval)
4572 					{
4573 						devider *= 2.0;
4574 					}
4575 					++iterationIndex;
4576 				} while(newInterval == oldInterval && iterationIndex <= 100);
4577 			}
4578 			else
4579 			{
4580 				// Process date scale
4581 				newInterval = oldInterval * 2.0;
4582 				if(axisIntervalType == DateTimeIntervalType.Years)
4583 				{
4584 					// Do nothing for years
4585 				}
4586 				else if(axisIntervalType == DateTimeIntervalType.Months)
4587 				{
4588 					if(newInterval >= 12.0)
4589 					{
4590 						newInterval = 1.0;
4591 						axisIntervalType = DateTimeIntervalType.Years;
4592 					}
4593 				}
4594 				else if(axisIntervalType == DateTimeIntervalType.Weeks)
4595 				{
4596 					if(newInterval >= 4.0)
4597 					{
4598 						newInterval = 1.0;
4599 						axisIntervalType = DateTimeIntervalType.Months;
4600 					}
4601 				}
4602 				else if(axisIntervalType == DateTimeIntervalType.Days)
4603 				{
4604 					if(newInterval >= 7.0)
4605 					{
4606 						newInterval = 1.0;
4607 						axisIntervalType = DateTimeIntervalType.Weeks;
4608 					}
4609 				}
4610 				else if(axisIntervalType == DateTimeIntervalType.Hours)
4611 				{
4612 					if(newInterval >= 60.0)
4613 					{
4614 						newInterval = 1.0;
4615 						axisIntervalType = DateTimeIntervalType.Days;
4616 					}
4617 				}
4618 				else if(axisIntervalType == DateTimeIntervalType.Minutes)
4619 				{
4620 					if(newInterval >= 60.0)
4621 					{
4622 						newInterval = 1.0;
4623 						axisIntervalType = DateTimeIntervalType.Hours;
4624 					}
4625 				}
4626 				else if(axisIntervalType == DateTimeIntervalType.Seconds)
4627 				{
4628 					if(newInterval >= 60.0)
4629 					{
4630 						newInterval = 1.0;
4631 						axisIntervalType = DateTimeIntervalType.Minutes;
4632 					}
4633 				}
4634 				else if(axisIntervalType == DateTimeIntervalType.Milliseconds)
4635 				{
4636 					if(newInterval >= 1000.0)
4637 					{
4638 						newInterval = 1.0;
4639 						axisIntervalType = DateTimeIntervalType.Seconds;
4640 					}
4641 				}
4642 			}
4643 
4644 			return newInterval;
4645 		}
4646 
4647         /// <summary>
4648         /// Finds the longest labels with the space and inserts the new line character.
4649         /// </summary>
4650         /// <param name="labels">Labels collection.</param>
4651         /// <returns>True if collection was modified.</returns>
WordWrapLongestLabel(CustomLabelsCollection labels)4652         private bool WordWrapLongestLabel(CustomLabelsCollection labels)
4653         {
4654             bool changed = false;
4655 
4656             // Each label may contain several lines of text.
4657             // Create a list that contains an array of text for each label.
4658             ArrayList labelTextRows = new ArrayList(labels.Count);
4659             foreach (CustomLabel label in labels)
4660             {
4661                 labelTextRows.Add(label.Text.Split('\n'));
4662             }
4663 
4664             // Find the longest label with a space
4665             int longestLabelSize = 5;
4666             int longestLabelIndex = -1;
4667             int longestLabelRowIndex = -1;
4668             int index = 0;
4669             foreach (string[] textRows in labelTextRows)
4670             {
4671                 for (int rowIndex = 0; rowIndex < textRows.Length; rowIndex++)
4672                 {
4673                     if (textRows[rowIndex].Length > longestLabelSize && textRows[rowIndex].Trim().IndexOf(' ') > 0)
4674                     {
4675                         longestLabelSize = textRows[rowIndex].Length;
4676                         longestLabelIndex = index;
4677                         longestLabelRowIndex = rowIndex;
4678                     }
4679                 }
4680                 ++index;
4681             }
4682 
4683             // Longest label with a space was found
4684             if (longestLabelIndex >= 0 && longestLabelRowIndex >= 0)
4685             {
4686                 // Try to find a space and replace it with a new line
4687                 string newText = ((string[])labelTextRows[longestLabelIndex])[longestLabelRowIndex];
4688                 for (index = 0; index < (newText.Length) / 2 - 1; index++)
4689                 {
4690                     if (newText[(newText.Length) / 2 - index] == ' ')
4691                     {
4692                         newText =
4693                             newText.Substring(0, (newText.Length) / 2 - index) +
4694                             "\n" +
4695                             newText.Substring((newText.Length) / 2 - index + 1);
4696                         changed = true;
4697                     }
4698                     else if (newText[(newText.Length) / 2 + index] == ' ')
4699                     {
4700                         newText =
4701                             newText.Substring(0, (newText.Length) / 2 + index) +
4702                             "\n" +
4703                             newText.Substring((newText.Length) / 2 + index + 1);
4704                         changed = true;
4705                     }
4706 
4707                     if (changed)
4708                     {
4709                         ((string[])labelTextRows[longestLabelIndex])[longestLabelRowIndex] = newText;
4710                         break;
4711                     }
4712                 }
4713 
4714                 // Update label text
4715                 if (changed)
4716                 {
4717                     // Construct label text from multiple rows separated by "\n"
4718                     CustomLabel label = labels[longestLabelIndex];
4719                     label.Text = string.Empty;
4720                     for (int rowIndex = 0; rowIndex < ((string[])labelTextRows[longestLabelIndex]).Length; rowIndex++)
4721                     {
4722                         if (rowIndex > 0)
4723                         {
4724                             label.Text += "\n";
4725                         }
4726                         label.Text += ((string[])labelTextRows[longestLabelIndex])[rowIndex];
4727                     }
4728                 }
4729             }
4730 
4731             return changed;
4732         }
4733 
4734         /// <summary>
4735         /// Calculates the auto-fit font for the circular Common.Chart area axis labels.
4736         /// </summary>
4737         /// <param name="graph">Chart graphics object.</param>
4738         /// <param name="axisList">List of sector labels.</param>
4739         /// <param name="labelsStyle">Circular labels style.</param>
4740         /// <param name="plotAreaRectAbs">Plotting area position.</param>
4741         /// <param name="areaRectAbs">Chart area position.</param>
4742         /// <param name="labelsSizeEstimate">Estimated size of labels.</param>
GetCircularAxisLabelsAutoFitFont( ChartGraphics graph, ArrayList axisList, CircularAxisLabelsStyle labelsStyle, RectangleF plotAreaRectAbs, RectangleF areaRectAbs, float labelsSizeEstimate)4743         internal void GetCircularAxisLabelsAutoFitFont(
4744             ChartGraphics graph,
4745             ArrayList axisList,
4746             CircularAxisLabelsStyle labelsStyle,
4747             RectangleF plotAreaRectAbs,
4748             RectangleF areaRectAbs,
4749             float labelsSizeEstimate)
4750         {
4751             // X axis settings defines if auto-fit font should be calculated
4752             if (!this.IsLabelAutoFit ||
4753                 this.LabelAutoFitStyle == LabelAutoFitStyles.None ||
4754                 !this.LabelStyle.Enabled)
4755             {
4756                 return;
4757             }
4758 
4759 			// Set minimum font size
4760 			_minLabelFontSize = Math.Min(this.LabelAutoFitMinFontSize, this.LabelAutoFitMaxFontSize);
4761 
4762             // Create new auto-fit font
4763             this.autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
4764                 this.LabelStyle.Font.FontFamily,
4765 				Math.Max(this.LabelAutoFitMaxFontSize, this.LabelAutoFitMinFontSize),
4766                 this.LabelStyle.Font.Style,
4767 				GraphicsUnit.Point);
4768 
4769             // Check if we allowed to increase font size while auto-fitting
4770             if ((this.LabelAutoFitStyle & LabelAutoFitStyles.IncreaseFont) != LabelAutoFitStyles.IncreaseFont)
4771             {
4772                 // Use axis labels font as starting point
4773                 this.autoLabelFont = this.LabelStyle.Font;
4774             }
4775 
4776             // Loop while labels do not fit
4777             bool fitDone = false;
4778             while (!fitDone)
4779             {
4780                 //******************************************************
4781                 //** Check if labels fit
4782                 //******************************************************
4783                 fitDone = CheckCircularLabelsFit(
4784                     graph,
4785                     axisList,
4786                     labelsStyle,
4787                     plotAreaRectAbs,
4788                     areaRectAbs,
4789                     labelsSizeEstimate);
4790 
4791                 //******************************************************
4792                 //** Adjust labels text properties to fit
4793                 //******************************************************
4794                 if (!fitDone)
4795                 {
4796                     // Try to reduce font size
4797                     if (autoLabelFont.SizeInPoints > _minLabelFontSize &&
4798                         (this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
4799                     {
4800                         autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
4801                             autoLabelFont.FontFamily,
4802                             autoLabelFont.SizeInPoints - 1,
4803                             autoLabelFont.Style,
4804                             GraphicsUnit.Point);
4805 
4806                     }
4807 
4808                     // Failed to fit
4809                     else
4810                     {
4811                         // Use last font with no angles
4812                         autoLabelAngle = 0;
4813                         autoLabelOffset = 0;
4814                         fitDone = true;
4815                     }
4816                 }
4817             }
4818         }
4819 
4820         /// <summary>
4821         /// Checks id circular axis labels fits using current auto-fit font.
4822         /// </summary>
4823         /// <param name="graph">Chart graphics object.</param>
4824         /// <param name="axisList">List of sector labels.</param>
4825         /// <param name="labelsStyle">Circular labels style.</param>
4826         /// <param name="plotAreaRectAbs">Plotting area position.</param>
4827         /// <param name="areaRectAbs">Chart area position.</param>
4828         /// <param name="labelsSizeEstimate">Estimated size of labels.</param>
4829         /// <returns>True if labels fit.</returns>
CheckCircularLabelsFit( ChartGraphics graph, ArrayList axisList, CircularAxisLabelsStyle labelsStyle, RectangleF plotAreaRectAbs, RectangleF areaRectAbs, float labelsSizeEstimate)4830         internal bool CheckCircularLabelsFit(
4831             ChartGraphics graph,
4832             ArrayList axisList,
4833             CircularAxisLabelsStyle labelsStyle,
4834             RectangleF plotAreaRectAbs,
4835             RectangleF areaRectAbs,
4836             float labelsSizeEstimate)
4837         {
4838             bool labelsFit = true;
4839 
4840             // Get absolute center of the area
4841             PointF areaCenterAbs = graph.GetAbsolutePoint(ChartArea.circularCenter);
4842 
4843             // Get absolute markers size and spacing
4844             float spacing = graph.GetAbsolutePoint(new PointF(0, this.markSize + Axis.elementSpacing)).Y;
4845 
4846             //*****************************************************************
4847             //** Loop through all axis labels
4848             //*****************************************************************
4849             RectangleF prevLabelPosition = RectangleF.Empty;
4850             float prevLabelSideAngle = float.NaN;
4851             foreach (CircularChartAreaAxis axis in axisList)
4852             {
4853                 //*****************************************************************
4854                 //** Measure label text
4855                 //*****************************************************************
4856                 SizeF textSize = graph.MeasureString(
4857                     axis.Title.Replace("\\n", "\n"),
4858                     this.autoLabelFont);
4859 
4860                 //*****************************************************************
4861                 //** Get circular style label position.
4862                 //*****************************************************************
4863                 if (labelsStyle == CircularAxisLabelsStyle.Circular ||
4864                     labelsStyle == CircularAxisLabelsStyle.Radial)
4865                 {
4866                     // Swith text size for the radial style
4867                     if (labelsStyle == CircularAxisLabelsStyle.Radial)
4868                     {
4869                         float tempValue = textSize.Width;
4870                         textSize.Width = textSize.Height;
4871                         textSize.Height = tempValue;
4872                     }
4873 
4874                     //*****************************************************************
4875                     //** Check overlapping with previous label
4876                     //*****************************************************************
4877 
4878                     // Get radius of plot area
4879                     float plotAreaRadius = areaCenterAbs.Y - plotAreaRectAbs.Y;
4880                     plotAreaRadius -= labelsSizeEstimate;
4881                     plotAreaRadius += spacing;
4882 
4883                     // Calculate angle on the side of the label
4884                     float leftSideAngle = (float)(Math.Atan((textSize.Width / 2f) / plotAreaRadius) * 180f / Math.PI);
4885                     float rightSideAngle = axis.AxisPosition + leftSideAngle;
4886                     leftSideAngle = axis.AxisPosition - leftSideAngle;
4887 
4888                     // Check if label overlap the previous label
4889                     if (!float.IsNaN(prevLabelSideAngle))
4890                     {
4891                         if (prevLabelSideAngle > leftSideAngle)
4892                         {
4893                             // Labels overlap
4894                             labelsFit = false;
4895                             break;
4896                         }
4897                     }
4898 
4899                     // Remember label side angle
4900                     prevLabelSideAngle = rightSideAngle - 1;
4901 
4902 
4903                     //*****************************************************************
4904                     //** Check if label is inside the Common.Chart area
4905                     //*****************************************************************
4906 
4907                     // Find the most outside point of the label
4908                     PointF outsidePoint = new PointF(areaCenterAbs.X, plotAreaRectAbs.Y);
4909                     outsidePoint.Y += labelsSizeEstimate;
4910                     outsidePoint.Y -= textSize.Height;
4911                     outsidePoint.Y -= spacing;
4912 
4913                     PointF[] rotatedPoint = new PointF[] { outsidePoint };
4914                     Matrix newMatrix = new Matrix();
4915                     newMatrix.RotateAt(axis.AxisPosition, areaCenterAbs);
4916                     newMatrix.TransformPoints(rotatedPoint);
4917 
4918                     // Check if rotated point is inside Common.Chart area
4919                     if (!areaRectAbs.Contains(rotatedPoint[0]))
4920                     {
4921                         // Label is not inside Common.Chart area
4922                         labelsFit = false;
4923                         break;
4924                     }
4925 
4926                 }
4927 
4928                 //*****************************************************************
4929                 //** Get horizontal style label position.
4930                 //*****************************************************************
4931                 else if (labelsStyle == CircularAxisLabelsStyle.Horizontal)
4932                 {
4933                     // Get text angle
4934                     float textAngle = axis.AxisPosition;
4935                     if (textAngle > 180f)
4936                     {
4937                         textAngle -= 180f;
4938                     }
4939 
4940                     // Get label rotated position
4941                     PointF[] labelPosition = new PointF[] { new PointF(areaCenterAbs.X, plotAreaRectAbs.Y) };
4942                     labelPosition[0].Y += labelsSizeEstimate;
4943                     labelPosition[0].Y -= spacing;
4944                     Matrix newMatrix = new Matrix();
4945                     newMatrix.RotateAt(textAngle, areaCenterAbs);
4946                     newMatrix.TransformPoints(labelPosition);
4947 
4948                     // Calculate label position
4949                     RectangleF curLabelPosition = new RectangleF(
4950                         labelPosition[0].X,
4951                         labelPosition[0].Y - textSize.Height / 2f,
4952                         textSize.Width,
4953                         textSize.Height);
4954                     if (textAngle < 5f)
4955                     {
4956                         curLabelPosition.X = labelPosition[0].X - textSize.Width / 2f;
4957                         curLabelPosition.Y = labelPosition[0].Y - textSize.Height;
4958                     }
4959                     if (textAngle > 175f)
4960                     {
4961                         curLabelPosition.X = labelPosition[0].X - textSize.Width / 2f;
4962                         curLabelPosition.Y = labelPosition[0].Y;
4963                     }
4964 
4965                     // Decrease label rectangle
4966                     curLabelPosition.Inflate(0f, -curLabelPosition.Height * 0.15f);
4967 
4968                     // Check if label position goes outside of the Common.Chart area.
4969                     if (!areaRectAbs.Contains(curLabelPosition))
4970                     {
4971                         // Label is not inside Common.Chart area
4972                         labelsFit = false;
4973                         break;
4974                     }
4975 
4976                     // Check if label position overlap previous label position.
4977                     if (!prevLabelPosition.IsEmpty && curLabelPosition.IntersectsWith(prevLabelPosition))
4978                     {
4979                         // Label intersects with previous label
4980                         labelsFit = false;
4981                         break;
4982                     }
4983 
4984                     // Set previous point position
4985                     prevLabelPosition = curLabelPosition;
4986                 }
4987             }
4988 
4989             return labelsFit;
4990         }
4991 
4992         #endregion
4993 
4994         #region Axis labels auto-fitting methods
4995 
4996         /// <summary>
4997         /// Adjust labels font size at second pass of auto fitting.
4998         /// </summary>
4999         /// <param name="chartGraph">Chart graphics object.</param>
5000         /// <param name="autoPlotPosition">Indicates that inner plot position is automatic.</param>
AdjustLabelFontAtSecondPass(ChartGraphics chartGraph, bool autoPlotPosition)5001         internal void AdjustLabelFontAtSecondPass(ChartGraphics chartGraph, bool autoPlotPosition)
5002         {
5003 #if SUBAXES
5004 			// Process all sub-axis
5005 			if(!ChartArea.Area3DStyle.Enable3D &&
5006 				!ChartArea.chartAreaIsCurcular)
5007 			{
5008 				foreach(SubAxis subAxis in this.SubAxes)
5009 				{
5010 					subAxis.AdjustLabelFontAtSecondPass(chartGraph, autoPlotPosition);
5011 				}
5012 			}
5013 #endif //SUBAXES
5014 
5015 
5016             //******************************************************
5017             //** First try to select the interval that will
5018             //** generate best fit labels.
5019             //******************************************************
5020 
5021 
5022 
5023 			// Make sure the variable interval mode is enabled
5024 			if( this.Enabled != AxisEnabled.False &&
5025 				this.LabelStyle.Enabled &&
5026 				this.IsVariableLabelCountModeEnabled() )
5027 			{
5028 				// Set font for labels fitting
5029 				if(this.autoLabelFont == null)
5030 				{
5031 					this.autoLabelFont = this.LabelStyle.Font;
5032 				}
5033 
5034 				// Reset angle and stagged flag used in the auto-fitting algorithm
5035 				if(this.autoLabelAngle < 0)
5036 				{
5037 					this.autoLabelAngle = this.LabelStyle.Angle;
5038 				}
5039 				if(this.autoLabelOffset < 0)
5040 				{
5041 					this.autoLabelOffset = (this.LabelStyle.IsStaggered) ? 1 : 0;
5042 				}
5043 
5044 				// Check labels fit
5045 				bool fitDone = CheckLabelsFit(
5046 					chartGraph,
5047 					this.markSize + this.scrollBarSize + this.titleSize,
5048 					autoPlotPosition,
5049 					true,
5050 					true,
5051 					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? false : true,
5052 					(this.AxisPosition == AxisPosition.Left || this.AxisPosition == AxisPosition.Right) ? true : false,
5053 					null);
5054 
5055 				// If there is a problem fitting labels try to reduce number of labels by
5056 				// increasing of the interval.
5057 				if(!fitDone)
5058 				{
5059 					// Adjust interval
5060 					this.AdjustIntervalToFitLabels(chartGraph, autoPlotPosition, true);
5061 				}
5062 			}
5063 
5064 
5065 
5066 
5067             //******************************************************
5068             //** If labels auto-fit is on try reducing font size.
5069             //******************************************************
5070 
5071             totlaGroupingLabelsSizeAdjustment = 0f;
5072             if (this.IsLabelAutoFit &&
5073                 this.LabelAutoFitStyle != LabelAutoFitStyles.None &&
5074                 this.Enabled != AxisEnabled.False)
5075             {
5076                 bool fitDone = false;
5077 
5078                 if (autoLabelFont == null)
5079                 {
5080                     autoLabelFont = this.LabelStyle.Font;
5081                 }
5082 
5083                 // Loop while labels do not fit
5084                 float oldLabelSecondRowSize = totlaGroupingLabelsSize;
5085                 while (!fitDone)
5086                 {
5087                     //******************************************************
5088                     //** Check if labels fit
5089                     //******************************************************
5090                     fitDone = CheckLabelsFit(
5091                         chartGraph,
5092                         this.markSize + this.scrollBarSize + this.titleSize,
5093                         autoPlotPosition,
5094                         true,
5095                         true);
5096 
5097                     //******************************************************
5098                     //** Adjust labels text properties to fit
5099                     //******************************************************
5100                     if (!fitDone)
5101                     {
5102                         // Try to reduce font
5103                         if (autoLabelFont.SizeInPoints > _minLabelFontSize)
5104                         {
5105                             // Reduce auto fit font
5106                             if (ChartArea != null && ChartArea.IsSameFontSizeForAllAxes)
5107                             {
5108                                 // Same font for all axes
5109                                 foreach (Axis currentAxis in ChartArea.Axes)
5110                                 {
5111                                     if (currentAxis.enabled && currentAxis.IsLabelAutoFit && currentAxis.autoLabelFont != null)
5112                                     {
5113                                         currentAxis.autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
5114                                             currentAxis.autoLabelFont.FontFamily,
5115                                             autoLabelFont.SizeInPoints - 1,
5116                                             currentAxis.autoLabelFont.Style,
5117                                             GraphicsUnit.Point);
5118                                     }
5119                                 }
5120                             }
5121                             else if ((this.LabelAutoFitStyle & LabelAutoFitStyles.DecreaseFont) == LabelAutoFitStyles.DecreaseFont)
5122                             {
5123                                 autoLabelFont = Common.Chart.chartPicture.FontCache.GetFont(
5124                                     autoLabelFont.FontFamily,
5125                                     autoLabelFont.SizeInPoints - 1,
5126                                     autoLabelFont.Style,
5127                                     GraphicsUnit.Point);
5128                             }
5129                             else
5130                             {
5131                                 // Failed to fit
5132                                 fitDone = true;
5133                             }
5134                         }
5135                         else
5136                         {
5137                             // Failed to fit
5138                             fitDone = true;
5139                         }
5140                     }
5141                 }
5142 
5143                 this.totlaGroupingLabelsSizeAdjustment = oldLabelSecondRowSize - totlaGroupingLabelsSize;
5144             }
5145         }
5146 
5147         /// <summary>
5148         /// Check if axis is logarithmic
5149         /// </summary>
5150         /// <param name="yValue">Y value from data</param>
5151         /// <returns>Corected Y value if axis is logarithmic</returns>
GetLogValue(double yValue)5152         internal double GetLogValue(double yValue)
5153         {
5154             // Check if axis is logarithmic
5155             if (this.IsLogarithmic)
5156             {
5157                 yValue = Math.Log(yValue, this.logarithmBase);
5158             }
5159 
5160             return yValue;
5161         }
5162 
5163         /// <summary>
5164         /// Checks if labels fit using current auto fit properties
5165         /// </summary>
5166         /// <param name="chartGraph">Chart graphics object.</param>
5167         /// <param name="otherElementsSize">Axis title and marks size.</param>
5168         /// <param name="autoPlotPosition">Indicates auto calculation of plotting area.</param>
5169         /// <param name="checkLabelsFirstRowOnly">Labels fit is checked during the second pass.</param>
5170         /// <param name="secondPass">Indicates second pass of labels fitting.</param>
5171         /// <returns>True if labels fit.</returns>
CheckLabelsFit( ChartGraphics chartGraph, float otherElementsSize, bool autoPlotPosition, bool checkLabelsFirstRowOnly, bool secondPass)5172         private bool CheckLabelsFit(
5173             ChartGraphics chartGraph,
5174             float otherElementsSize,
5175             bool autoPlotPosition,
5176             bool checkLabelsFirstRowOnly,
5177             bool secondPass)
5178         {
5179             return this.CheckLabelsFit(
5180                 chartGraph,
5181                 otherElementsSize,
5182                 autoPlotPosition,
5183                 checkLabelsFirstRowOnly,
5184                 secondPass,
5185                 true,
5186                 true,
5187                 null);
5188         }
5189 
5190         /// <summary>
5191         /// Checks if labels fit using current auto fit properties
5192         /// </summary>
5193         /// <param name="chartGraph">Chart graphics object.</param>
5194         /// <param name="otherElementsSize">Axis title and marks size.</param>
5195         /// <param name="autoPlotPosition">Indicates auto calculation of plotting area.</param>
5196         /// <param name="checkLabelsFirstRowOnly">Labels fit is checked during the second pass.</param>
5197         /// <param name="secondPass">Indicates second pass of labels fitting.</param>
5198         /// <param name="checkWidth">True if width should be checked.</param>
5199         /// <param name="checkHeight">True if height should be checked.</param>
5200         /// <param name="labelPositions">Returns an array of label positions.</param>
5201         /// <returns>True if labels fit.</returns>
CheckLabelsFit( ChartGraphics chartGraph, float otherElementsSize, bool autoPlotPosition, bool checkLabelsFirstRowOnly, bool secondPass, bool checkWidth, bool checkHeight, ArrayList labelPositions)5202         private bool CheckLabelsFit(
5203             ChartGraphics chartGraph,
5204             float otherElementsSize,
5205             bool autoPlotPosition,
5206             bool checkLabelsFirstRowOnly,
5207             bool secondPass,
5208             bool checkWidth,
5209             bool checkHeight,
5210             ArrayList labelPositions)
5211         {
5212             // Reset list of label positions
5213             if (labelPositions != null)
5214             {
5215                 labelPositions.Clear();
5216             }
5217 
5218             // Label string drawing format
5219             using (StringFormat format = new StringFormat())
5220             {
5221                 format.FormatFlags |= StringFormatFlags.LineLimit;
5222                 format.Trimming = StringTrimming.EllipsisCharacter;
5223 
5224                 // Initialize all labels position rectangle
5225                 RectangleF rect = RectangleF.Empty;
5226 
5227                 // Calculate max label size
5228                 float maxLabelSize = 0;
5229                 if (!autoPlotPosition)
5230                 {
5231                     if (this.GetIsMarksNextToAxis())
5232                     {
5233                         if (this.AxisPosition == AxisPosition.Top)
5234                             maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.Y;
5235                         else if (this.AxisPosition == AxisPosition.Bottom)
5236                             maxLabelSize = ChartArea.Position.Bottom - (float)GetAxisPosition();
5237                         if (this.AxisPosition == AxisPosition.Left)
5238                             maxLabelSize = (float)GetAxisPosition() - ChartArea.Position.X;
5239                         else if (this.AxisPosition == AxisPosition.Right)
5240                             maxLabelSize = ChartArea.Position.Right - (float)GetAxisPosition();
5241                     }
5242                     else
5243                     {
5244                         if (this.AxisPosition == AxisPosition.Top)
5245                             maxLabelSize = this.PlotAreaPosition.Y - ChartArea.Position.Y;
5246                         else if (this.AxisPosition == AxisPosition.Bottom)
5247                             maxLabelSize = ChartArea.Position.Bottom - this.PlotAreaPosition.Bottom;
5248                         if (this.AxisPosition == AxisPosition.Left)
5249                             maxLabelSize = this.PlotAreaPosition.X - ChartArea.Position.X;
5250                         else if (this.AxisPosition == AxisPosition.Right)
5251                             maxLabelSize = ChartArea.Position.Right - this.PlotAreaPosition.Right;
5252                     }
5253                     maxLabelSize *= 2F;
5254                 }
5255                 else
5256                 {
5257                     if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5258                         maxLabelSize = ChartArea.Position.Height;
5259                     else
5260                         maxLabelSize = ChartArea.Position.Width;
5261                 }
5262 
5263                 // Loop through all grouping labels (all except first row)
5264                 this.totlaGroupingLabelsSize = 0;
5265 
5266 
5267                 // Get number of groups
5268                 int groupLabelLevelCount = GetGroupLabelLevelCount();
5269 
5270                 // Check ig grouping labels exist
5271                 if (groupLabelLevelCount > 0)
5272                 {
5273                     groupingLabelSizes = new float[groupLabelLevelCount];
5274 
5275                     // Loop through each level of grouping labels
5276                     bool fitResult = true;
5277                     for (int groupLevelIndex = 1; groupLevelIndex <= groupLabelLevelCount; groupLevelIndex++)
5278                     {
5279                         groupingLabelSizes[groupLevelIndex - 1] = 0f;
5280 
5281                         // Loop through all labels in the level
5282                         foreach (CustomLabel label in this.CustomLabels)
5283                         {
5284                             // Skip if label middle point is outside current scaleView
5285                             if (label.RowIndex == 0)
5286                             {
5287                                 double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
5288                                 if (middlePoint < this.ViewMinimum || middlePoint > this.ViewMaximum)
5289                                 {
5290                                     continue;
5291                                 }
5292                             }
5293 
5294                             if (label.RowIndex == groupLevelIndex)
5295                             {
5296                                 // Calculate label rect
5297                                 double fromPosition = this.GetLinearPosition(label.FromPosition);
5298                                 double toPosition = this.GetLinearPosition(label.ToPosition);
5299                                 if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5300                                 {
5301                                     rect.Height = (maxLabelSize / 100F) * maxAxisLabelRow2Size / groupLabelLevelCount;
5302                                     rect.X = (float)Math.Min(fromPosition, toPosition);
5303                                     rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
5304                                 }
5305                                 else
5306                                 {
5307                                     rect.Width = (maxLabelSize / 100F) * maxAxisLabelRow2Size / groupLabelLevelCount;
5308                                     rect.Y = (float)Math.Min(fromPosition, toPosition);
5309                                     rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
5310                                 }
5311 
5312                                 // Measure string
5313                                 SizeF axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"), autoLabelFont);
5314 
5315                                 // Add image size
5316                                 if (label.Image.Length > 0)
5317                                 {
5318                                     SizeF imageAbsSize = new SizeF();
5319 
5320                                     if (this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
5321                                     {
5322                                         SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
5323                                         axisLabelSize.Width += imageRelSize.Width;
5324                                         axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
5325                                     }
5326                                 }
5327 
5328                                 // Add extra spacing for the box marking of the label
5329                                 if (label.LabelMark == LabelMarkStyle.Box)
5330                                 {
5331                                     // Get relative size from pixels and add it to the label size
5332                                     SizeF spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
5333                                     axisLabelSize.Width += spacerSize.Width;
5334                                     axisLabelSize.Height += spacerSize.Height;
5335                                 }
5336 
5337                                 // Calculate max height of the second row of labels
5338                                 if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5339                                 {
5340                                     groupingLabelSizes[groupLevelIndex - 1] = (float)Math.Max(groupingLabelSizes[groupLevelIndex - 1], axisLabelSize.Height);
5341                                 }
5342                                 else
5343                                 {
5344                                     axisLabelSize.Width = chartGraph.GetAbsoluteSize(new SizeF(axisLabelSize.Height, axisLabelSize.Height)).Height;
5345                                     axisLabelSize.Width = chartGraph.GetRelativeSize(new SizeF(axisLabelSize.Width, axisLabelSize.Width)).Width;
5346                                     groupingLabelSizes[groupLevelIndex - 1] = (float)Math.Max(groupingLabelSizes[groupLevelIndex - 1], axisLabelSize.Width);
5347                                 }
5348 
5349                                 // Check if string fits
5350                                 if (Math.Round(axisLabelSize.Width) >= Math.Round(rect.Width) &&
5351                                     checkWidth)
5352                                 {
5353                                     fitResult = false;
5354                                 }
5355                                 if (Math.Round(axisLabelSize.Height) >= Math.Round(rect.Height) &&
5356                                     checkHeight)
5357                                 {
5358                                     fitResult = false;
5359                                 }
5360                             }
5361                         }
5362                     }
5363 
5364                     this.totlaGroupingLabelsSize = this.GetGroupLablesToatalSize();
5365                     if (!fitResult && !checkLabelsFirstRowOnly)
5366                     {
5367                         return false;
5368                     }
5369 
5370                 }
5371 
5372                 // Loop through all labels in the first row
5373                 float angle = autoLabelAngle;
5374                 int labelIndex = 0;
5375                 foreach (CustomLabel label in this.CustomLabels)
5376                 {
5377                     // Skip if label middle point is outside current scaleView
5378                     if (label.RowIndex == 0)
5379                     {
5380                         double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
5381                         if (middlePoint < this.ViewMinimum || middlePoint > this.ViewMaximum)
5382                         {
5383                             continue;
5384                         }
5385                     }
5386 
5387                     if (label.RowIndex == 0)
5388                     {
5389 
5390                         // Force which scale segment to use when calculating label position
5391                         if (labelPositions != null)
5392                         {
5393                             this.ScaleSegments.EnforceSegment(this.ScaleSegments.FindScaleSegmentForAxisValue((label.FromPosition + label.ToPosition) / 2.0));
5394                         }
5395 
5396 
5397                         // Set label From and To coordinates
5398                         double fromPosition = this.GetLinearPosition(label.FromPosition);
5399                         double toPosition = this.GetLinearPosition(label.ToPosition);
5400 
5401 
5402                         // Reset scale segment to use when calculating label position
5403                         if (labelPositions != null)
5404                         {
5405                             this.ScaleSegments.EnforceSegment(null);
5406                         }
5407 
5408 
5409                         // Calculate single label position
5410                         rect.X = this.PlotAreaPosition.X;
5411                         rect.Y = (float)Math.Min(fromPosition, toPosition);
5412                         rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
5413 
5414                         float maxElementSize = maxAxisElementsSize;
5415                         if (maxAxisElementsSize - this.totlaGroupingLabelsSize > 55)
5416                         {
5417                             maxElementSize = 55 + this.totlaGroupingLabelsSize;
5418                         }
5419                         if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5420                         {
5421                             rect.Width = (maxLabelSize / 100F) *
5422                                 (maxElementSize - this.totlaGroupingLabelsSize - otherElementsSize - elementSpacing);
5423                         }
5424                         else
5425                         {
5426                             rect.Width = (maxLabelSize / 100F) *
5427                                 (maxElementSize - this.totlaGroupingLabelsSize - otherElementsSize - elementSpacing);
5428                         }
5429 
5430                         // Adjust label From/To position if labels are displayed with offset
5431                         if (autoLabelOffset == 1)
5432                         {
5433                             rect.Y -= rect.Height / 2F;
5434                             rect.Height *= 2F;
5435                             rect.Width /= 2F;
5436                         }
5437 
5438                         // If horizontal axis
5439                         if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5440                         {
5441                             // Switch rectangle sizes
5442                             float val = rect.Height;
5443                             rect.Height = rect.Width;
5444                             rect.Width = val;
5445 
5446                             // Set vertical font for measuring
5447                             if (angle != 0)
5448                             {
5449                                 format.FormatFlags |= StringFormatFlags.DirectionVertical;
5450                             }
5451                         }
5452                         else
5453                         {
5454                             // Set vertical font for measuring
5455                             if (angle == 90 || angle == -90)
5456                             {
5457                                 angle = 0;
5458                                 format.FormatFlags |= StringFormatFlags.DirectionVertical;
5459                             }
5460                         }
5461 
5462                         // Measure label text size. Add the 'I' character to allow a little bit of spacing between labels.
5463                         SizeF axisLabelSize = chartGraph.MeasureStringRel(
5464                             label.Text.Replace("\\n", "\n") + "W",
5465                             autoLabelFont,
5466                             (secondPass) ? rect.Size : ChartArea.Position.ToRectangleF().Size,
5467                             format);
5468 
5469                         // Width and height maybe zeros if rect is too small to fit the text and
5470                         // the LineLimit format flag is set.
5471                         if (label.Text.Length > 0 &&
5472                             (axisLabelSize.Width == 0f ||
5473                             axisLabelSize.Height == 0f))
5474                         {
5475                             // Measure string without the LineLimit flag
5476                             format.FormatFlags ^= StringFormatFlags.LineLimit;
5477                             axisLabelSize = chartGraph.MeasureStringRel(
5478                                 label.Text.Replace("\\n", "\n"),
5479                                 autoLabelFont,
5480                                 (secondPass) ? rect.Size : ChartArea.Position.ToRectangleF().Size,
5481                                 format);
5482                             format.FormatFlags |= StringFormatFlags.LineLimit;
5483                         }
5484 
5485 
5486                         // Add image size
5487                         if (label.Image.Length > 0)
5488                         {
5489                             SizeF imageAbsSize = new SizeF();
5490 
5491                             if(this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
5492                             {
5493                                 SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
5494                                 if ((format.FormatFlags & StringFormatFlags.DirectionVertical) == StringFormatFlags.DirectionVertical)
5495                                 {
5496                                     axisLabelSize.Height += imageRelSize.Height;
5497                                     axisLabelSize.Width = Math.Max(axisLabelSize.Width, imageRelSize.Width);
5498                                 }
5499                                 else
5500                                 {
5501                                     axisLabelSize.Width += imageRelSize.Width;
5502                                     axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
5503                                 }
5504                             }
5505                         }
5506 
5507                         // Add extra spacing for the box marking of the label
5508                         if (label.LabelMark == LabelMarkStyle.Box)
5509                         {
5510                             // Get relative size from pixels and add it to the label size
5511                             SizeF spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
5512                             axisLabelSize.Width += spacerSize.Width;
5513                             axisLabelSize.Height += spacerSize.Height;
5514                         }
5515 
5516 
5517                         // Calculate size using label angle
5518                         float width = axisLabelSize.Width;
5519                         float height = axisLabelSize.Height;
5520                         if (angle != 0)
5521                         {
5522                             // Decrease label rectangle width by 3%
5523                             rect.Width *= 0.97f;
5524 
5525                             if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5526                             {
5527                                 width = (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
5528                                 width += (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
5529 
5530                                 height = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
5531                                 height += (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
5532                             }
5533                             else
5534                             {
5535                                 width = (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
5536                                 width += (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
5537 
5538                                 height = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
5539                                 height += (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
5540                             }
5541                         }
5542 
5543                         // Save label position
5544                         if (labelPositions != null)
5545                         {
5546                             RectangleF labelPosition = rect;
5547                             if (angle == 0F || angle == 90F || angle == -90F)
5548                             {
5549                                 if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5550                                 {
5551                                     labelPosition.X = labelPosition.X + labelPosition.Width / 2f - width / 2f;
5552                                     labelPosition.Width = width;
5553                                 }
5554                                 else
5555                                 {
5556                                     labelPosition.Y = labelPosition.Y + labelPosition.Height / 2f - height / 2f;
5557                                     labelPosition.Height = height;
5558                                 }
5559                             }
5560                             labelPositions.Add(labelPosition);
5561                         }
5562 
5563                         // Check if string fits
5564                         if (angle == 0F)
5565                         {
5566                             if (width >= rect.Width && checkWidth)
5567                             {
5568                                 return false;
5569                             }
5570                             if (height >= rect.Height && checkHeight)
5571                             {
5572                                 return false;
5573                             }
5574                         }
5575                         if (angle == 90F || angle == -90F)
5576                         {
5577                             if (width >= rect.Width && checkWidth)
5578                             {
5579                                 return false;
5580                             }
5581                             if (height >= rect.Height && checkHeight)
5582                             {
5583                                 return false;
5584                             }
5585                         }
5586                         else
5587                         {
5588                             if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5589                             {
5590                                 if (width >= rect.Width * 2F && checkWidth)
5591                                 {
5592                                     return false;
5593                                 }
5594                                 if (height >= rect.Height * 2F && checkHeight)
5595                                 {
5596                                     return false;
5597                                 }
5598                             }
5599                             else
5600                             {
5601                                 if (width >= rect.Width * 2F && checkWidth)
5602                                 {
5603                                     return false;
5604                                 }
5605                                 if (height >= rect.Height * 2F && checkHeight)
5606                                 {
5607                                     return false;
5608                                 }
5609                             }
5610                         }
5611 
5612                         ++labelIndex;
5613                     }
5614                 }
5615             }
5616 
5617             return true;
5618         }
5619 
5620         /// <summary>
5621         /// Calculates the best size for labels area.
5622         /// </summary>
5623         /// <param name="chartGraph">Chart graphics object.</param>
5624         /// <param name="maxLabelSize">Maximum labels area size.</param>
5625         /// <param name="resultSize">Label size without angle = 0.</param>
GetRequiredLabelSize(ChartGraphics chartGraph, float maxLabelSize, out float resultSize)5626         private float GetRequiredLabelSize(ChartGraphics chartGraph, float maxLabelSize, out float resultSize)
5627         {
5628             float resultRotatedSize = 0F;
5629             resultSize = 0F;
5630             float angle = (autoLabelAngle < -90) ? this.LabelStyle.Angle : autoLabelAngle;
5631             labelNearOffset = float.MaxValue;
5632             labelFarOffset = float.MinValue;
5633 
5634             // Label string drawing format
5635             using (StringFormat format = new StringFormat())
5636             {
5637                 format.FormatFlags |= StringFormatFlags.LineLimit;
5638                 format.Trimming = StringTrimming.EllipsisCharacter;
5639 
5640                 // Initialize all labels position rectangle
5641                 RectangleF rectLabels = ChartArea.Position.ToRectangleF();
5642 
5643                 // Loop through all labels in the first row
5644                 foreach (CustomLabel label in this.CustomLabels)
5645                 {
5646                     // Skip if label middle point is outside current scaleView
5647                     if (label.RowIndex == 0)
5648                     {
5649                         decimal middlePoint = (decimal)(label.FromPosition + label.ToPosition) / (decimal)2.0;
5650                         if (middlePoint < (decimal)this.ViewMinimum || middlePoint > (decimal)this.ViewMaximum)
5651                         {
5652                             continue;
5653                         }
5654                     }
5655                     if (label.RowIndex == 0)
5656                     {
5657                         // Calculate single label position
5658                         RectangleF rect = rectLabels;
5659                         rect.Width = maxLabelSize;
5660 
5661                         // Set label From and To coordinates
5662                         double fromPosition = this.GetLinearPosition(label.FromPosition);
5663                         double toPosition = this.GetLinearPosition(label.ToPosition);
5664                         rect.Y = (float)Math.Min(fromPosition, toPosition);
5665                         rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
5666 
5667                         // Adjust label From/To position if labels are displayed with offset
5668                         if ((autoLabelOffset == -1) ? this.LabelStyle.IsStaggered : (autoLabelOffset == 1))
5669                         {
5670                             rect.Y -= rect.Height / 2F;
5671                             rect.Height *= 2F;
5672                         }
5673 
5674                         // If horizontal axis
5675                         if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5676                         {
5677                             // Switch rectangle sizes
5678                             float val = rect.Height;
5679                             rect.Height = rect.Width;
5680                             rect.Width = val;
5681 
5682                             // Set vertical font for measuring
5683                             if (angle != 0)
5684                             {
5685                                 format.FormatFlags |= StringFormatFlags.DirectionVertical;
5686                             }
5687                         }
5688                         else
5689                         {
5690                             // Set vertical font for measuring
5691                             if (angle == 90 || angle == -90)
5692                             {
5693                                 angle = 0;
5694                                 format.FormatFlags |= StringFormatFlags.DirectionVertical;
5695                             }
5696                         }
5697 
5698                         // Measure label text size
5699                         rect.Width = (float)Math.Ceiling(rect.Width);
5700                         rect.Height = (float)Math.Ceiling(rect.Height);
5701                         SizeF axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"),
5702                             (autoLabelFont != null) ? autoLabelFont : this.LabelStyle.Font,
5703                             rect.Size,
5704                             format);
5705 
5706                         // Width and height maybe zeros if rect is too small to fit the text and
5707                         // the LineLimit format flag is set.
5708                         if (axisLabelSize.Width == 0f || axisLabelSize.Height == 0f)
5709                         {
5710                             // Measure string without the LineLimit flag
5711                             format.FormatFlags ^= StringFormatFlags.LineLimit;
5712                             axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"),
5713                                 (autoLabelFont != null) ? autoLabelFont : this.LabelStyle.Font,
5714                                 rect.Size,
5715                                 format);
5716                             format.FormatFlags |= StringFormatFlags.LineLimit;
5717                         }
5718 
5719 
5720                         // Add image size
5721                         if (label.Image.Length > 0)
5722                         {
5723                             SizeF imageAbsSize = new SizeF();
5724 
5725                             if (this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
5726                             {
5727                                 SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
5728 
5729                                 if ((format.FormatFlags & StringFormatFlags.DirectionVertical) == StringFormatFlags.DirectionVertical)
5730                                 {
5731                                     axisLabelSize.Height += imageRelSize.Height;
5732                                     axisLabelSize.Width = Math.Max(axisLabelSize.Width, imageRelSize.Width);
5733                                 }
5734                                 else
5735                                 {
5736                                     axisLabelSize.Width += imageRelSize.Width;
5737                                     axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
5738                                 }
5739                             }
5740                         }
5741 
5742                         // Add extra spacing for the box marking of the label
5743                         if (label.LabelMark == LabelMarkStyle.Box)
5744                         {
5745                             // Get relative size from pixels and add it to the label size
5746                             SizeF spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
5747                             axisLabelSize.Width += spacerSize.Width;
5748                             axisLabelSize.Height += spacerSize.Height;
5749                         }
5750 
5751 
5752                         // Calculate size using label angle
5753                         float width = axisLabelSize.Width;
5754                         float height = axisLabelSize.Height;
5755                         if (angle != 0)
5756                         {
5757                             width = (float)Math.Cos((90 - Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
5758                             width += (float)Math.Cos((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
5759 
5760                             height = (float)Math.Sin((Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Height;
5761                             height += (float)Math.Sin((90 - Math.Abs(angle)) / 180F * Math.PI) * axisLabelSize.Width;
5762                         }
5763 
5764                         width = (float)Math.Ceiling(width) * 1.05f;
5765                         height = (float)Math.Ceiling(height) * 1.05f;
5766                         axisLabelSize.Width = (float)Math.Ceiling(axisLabelSize.Width) * 1.05f;
5767                         axisLabelSize.Height = (float)Math.Ceiling(axisLabelSize.Height) * 1.05f;
5768 
5769 
5770                         // If axis is horizontal
5771                         if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5772                         {
5773                             if (angle == 90 || angle == -90 || angle == 0)
5774                             {
5775                                 resultSize = Math.Max(resultSize, axisLabelSize.Height);
5776                                 resultRotatedSize = Math.Max(resultRotatedSize, axisLabelSize.Height);
5777 
5778                                 // Calculate the over hang of labels on the side
5779                                 labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - axisLabelSize.Width / 2f);
5780                                 labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + axisLabelSize.Width / 2f);
5781 
5782                             }
5783                             else
5784                             {
5785                                 resultSize = Math.Max(resultSize, axisLabelSize.Height);
5786                                 resultRotatedSize = Math.Max(resultRotatedSize, height);
5787 
5788                                 // Calculate the over hang of labels on the side
5789                                 if (angle > 0)
5790                                 {
5791                                     labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + width * 1.1f);
5792                                 }
5793                                 else
5794                                 {
5795                                     labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - width * 1.1f);
5796                                 }
5797                             }
5798                         }
5799                         // If axis is vertical
5800                         else
5801                         {
5802                             if (angle == 90 || angle == -90 || angle == 0)
5803                             {
5804                                 resultSize = Math.Max(resultSize, axisLabelSize.Width);
5805                                 resultRotatedSize = Math.Max(resultRotatedSize, axisLabelSize.Width);
5806 
5807                                 // Calculate the over hang of labels on the side
5808                                 labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - axisLabelSize.Height / 2f);
5809                                 labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + axisLabelSize.Height / 2f);
5810                             }
5811                             else
5812                             {
5813                                 resultSize = Math.Max(resultSize, axisLabelSize.Width);
5814                                 resultRotatedSize = Math.Max(resultRotatedSize, width);
5815 
5816                                 // Calculate the over hang of labels on the side
5817                                 if (angle > 0)
5818                                 {
5819                                     labelFarOffset = (float)Math.Max(labelFarOffset, (fromPosition + toPosition) / 2f + height * 1.1f);
5820                                 }
5821                                 else
5822                                 {
5823                                     labelNearOffset = (float)Math.Min(labelNearOffset, (fromPosition + toPosition) / 2f - height * 1.1f);
5824                                 }
5825                             }
5826                         }
5827 
5828                         // Check if we exceed the maximum value
5829                         if (resultSize > maxLabelSize)
5830                         {
5831                             resultSize = maxLabelSize;
5832                         }
5833                     }
5834                 }
5835             }
5836 
5837             // Adjust results if labels are displayed with offset
5838             if ((autoLabelOffset == -1) ? this.LabelStyle.IsStaggered : (autoLabelOffset == 1))
5839             {
5840                 resultSize *= 2F;
5841                 resultRotatedSize *= 2F;
5842 
5843                 // Check if we exceed the maximum value
5844                 if (resultSize > maxLabelSize)
5845                 {
5846                     resultSize = maxLabelSize;
5847                     resultRotatedSize = maxLabelSize;
5848                 }
5849             }
5850 
5851             // Adjust labels size for the 3D Common.Chart
5852             if (ChartArea.Area3DStyle.Enable3D && !ChartArea.chartAreaIsCurcular)
5853             {
5854                 // Increase labels size
5855                 resultSize *= 1.1f;
5856                 resultRotatedSize *= 1.1f;
5857             }
5858 
5859             return resultRotatedSize;
5860         }
5861 
5862         /// <summary>
5863         /// Gets total size of all grouping labels.
5864         /// </summary>
5865         /// <returns>Total size of all grouping labels.</returns>
GetGroupLablesToatalSize()5866         internal float GetGroupLablesToatalSize()
5867         {
5868             float size = 0f;
5869             if (this.groupingLabelSizes != null && this.groupingLabelSizes.Length > 0)
5870             {
5871                 foreach (float val in this.groupingLabelSizes)
5872                 {
5873                     size += val;
5874                 }
5875             }
5876 
5877             return size;
5878         }
5879 
5880         /// <summary>
5881         /// Gets number of levels of the grouping labels.
5882         /// </summary>
5883         /// <returns>Number of levels of the grouping labels.</returns>
GetGroupLabelLevelCount()5884         internal int GetGroupLabelLevelCount()
5885         {
5886             int groupLabelLevel = 0;
5887             foreach (CustomLabel label in this.CustomLabels)
5888             {
5889                 if (label.RowIndex > 0)
5890                 {
5891                     groupLabelLevel = Math.Max(groupLabelLevel, label.RowIndex);
5892                 }
5893             }
5894 
5895             return groupLabelLevel;
5896         }
5897 
5898         /// <summary>
5899         /// Calculates the best size for axis labels for all rows except first one (grouping labels).
5900         /// </summary>
5901         /// <param name="chartGraph">Chart graphics object.</param>
5902         /// <param name="maxLabelSize">Maximum labels area size.</param>
5903         /// <returns>Array of grouping label sizes for each level.</returns>
GetRequiredGroupLabelSize(ChartGraphics chartGraph, float maxLabelSize)5904         private float[] GetRequiredGroupLabelSize(ChartGraphics chartGraph, float maxLabelSize)
5905         {
5906             float[] resultSize = null;
5907 
5908             // Get number of groups
5909             int groupLabelLevelCount = GetGroupLabelLevelCount();
5910 
5911             // Check ig grouping labels exist
5912             if (groupLabelLevelCount > 0)
5913             {
5914                 // Create result array
5915                 resultSize = new float[groupLabelLevelCount];
5916 
5917                 // Loop through each level of grouping labels
5918                 for (int groupLevelIndex = 1; groupLevelIndex <= groupLabelLevelCount; groupLevelIndex++)
5919                 {
5920                     resultSize[groupLevelIndex - 1] = 0f;
5921 
5922                     // Loop through all labels in the level
5923                     foreach (CustomLabel label in this.CustomLabels)
5924                     {
5925                         // Skip if label middle point is outside current scaleView
5926                         if (label.RowIndex == 0)
5927                         {
5928                             double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
5929                             if (middlePoint < this.ViewMinimum || middlePoint > this.ViewMaximum)
5930                             {
5931                                 continue;
5932                             }
5933                         }
5934 
5935                         if (label.RowIndex == groupLevelIndex)
5936                         {
5937                             // Measure label text size
5938                             SizeF axisLabelSize = chartGraph.MeasureStringRel(label.Text.Replace("\\n", "\n"), (autoLabelFont != null) ? autoLabelFont : this.LabelStyle.Font);
5939                             axisLabelSize.Width = (float)Math.Ceiling(axisLabelSize.Width);
5940                             axisLabelSize.Height = (float)Math.Ceiling(axisLabelSize.Height);
5941 
5942 
5943 							// Add image size
5944 							if(label.Image.Length > 0)
5945 							{
5946                                 SizeF imageAbsSize = new SizeF();
5947 
5948                                 if(this.Common.ImageLoader.GetAdjustedImageSize(label.Image, chartGraph.Graphics, ref imageAbsSize))
5949 								{
5950 									SizeF imageRelSize = chartGraph.GetRelativeSize(imageAbsSize);
5951 									axisLabelSize.Width += imageRelSize.Width;
5952 									axisLabelSize.Height = Math.Max(axisLabelSize.Height, imageRelSize.Height);
5953 								}
5954 							}
5955 
5956 							// Add extra spacing for the box marking of the label
5957 							if(label.LabelMark == LabelMarkStyle.Box)
5958 							{
5959 								// Get relative size from pixels and add it to the label size
5960 								SizeF	spacerSize = chartGraph.GetRelativeSize(new SizeF(4, 4));
5961 								axisLabelSize.Width += spacerSize.Width;
5962 								axisLabelSize.Height += spacerSize.Height;
5963 							}
5964 
5965 
5966 
5967                             // If axis is horizontal
5968                             if (this.AxisPosition == AxisPosition.Bottom || this.AxisPosition == AxisPosition.Top)
5969                             {
5970                                 resultSize[groupLevelIndex - 1] = Math.Max(resultSize[groupLevelIndex - 1], axisLabelSize.Height);
5971                             }
5972                             // If axis is vertical
5973                             else
5974                             {
5975                                 axisLabelSize.Width = chartGraph.GetAbsoluteSize(new SizeF(axisLabelSize.Height, axisLabelSize.Height)).Height;
5976                                 axisLabelSize.Width = chartGraph.GetRelativeSize(new SizeF(axisLabelSize.Width, axisLabelSize.Width)).Width;
5977                                 resultSize[groupLevelIndex - 1] = Math.Max(resultSize[groupLevelIndex - 1], axisLabelSize.Width);
5978                             }
5979 
5980                             // Check if we exceed the maximum value
5981                             if (resultSize[groupLevelIndex - 1] > maxLabelSize / groupLabelLevelCount)
5982                             {
5983                                 // NOTE: Group Labels size limitations are removed !!!
5984                                 //	resultSize[groupLevelIndex - 1] = maxLabelSize / groupLabelLevelCount;
5985                                 //	break;
5986                             }
5987                         }
5988                     }
5989                 }
5990             }
5991 
5992             return resultSize;
5993         }
5994 
5995         #endregion
5996 
5997         #region Axis helper methods
5998 
5999 
6000         /// <summary>
6001         /// Gets main or sub axis associated with this axis.
6002         /// </summary>
6003         /// <param name="subAxisName">Sub axis name or empty string to get the main axis.</param>
6004         /// <returns>Main or sub axis of the main axis.</returns>
6005         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "subAxisName")]
GetSubAxis(string subAxisName)6006         internal Axis GetSubAxis(string subAxisName)
6007         {
6008 #if SUBAXES
6009 			if(!this.IsSubAxis && subAxisName.Length > 0)
6010 			{
6011 				SubAxis subAxis = this.SubAxes.FindByName(subAxisName);
6012 				if(subAxis == null)
6013 				{
6014 					throw(new InvalidOperationException( SR.ExceptionSubAxisNameNotFoundShort( subAxisName )));
6015 				}
6016 				return subAxis;
6017 			}
6018 #endif // SUBAXES
6019             return this;
6020         }
6021 
6022         /// <summary>
6023         /// Checks if axis marks should be next to the axis
6024         /// </summary>
6025         /// <returns>true if marks are next to axis.</returns>
GetIsMarksNextToAxis()6026         internal bool GetIsMarksNextToAxis()
6027         {
6028             if (ChartArea != null && ChartArea.chartAreaIsCurcular)
6029             {
6030                 return true;
6031             }
6032             return this.IsMarksNextToAxis;
6033         }
6034 
6035 		/// <summary>
6036 		/// Gets axis auto interval type.
6037 		/// </summary>
6038 		/// <returns>Axis interval type.</returns>
GetAxisIntervalType()6039 		internal DateTimeIntervalType GetAxisIntervalType()
6040 		{
6041 			if(InternalIntervalType == DateTimeIntervalType.Auto)
6042 			{
6043 				if(GetAxisValuesType() == ChartValueType.DateTime ||
6044 					GetAxisValuesType() == ChartValueType.Date ||
6045 					GetAxisValuesType() == ChartValueType.Time ||
6046                     GetAxisValuesType() == ChartValueType.DateTimeOffset)
6047 				{
6048 					return DateTimeIntervalType.Years;
6049 				}
6050 
6051                 return DateTimeIntervalType.Number;
6052             }
6053 
6054             return InternalIntervalType;
6055         }
6056 
6057         /// <summary>
6058         /// Gets axis values type depending on the series attached
6059         /// </summary>
6060         /// <returns>Axis values type.</returns>
GetAxisValuesType()6061         internal ChartValueType GetAxisValuesType()
6062         {
6063             ChartValueType type = ChartValueType.Double;
6064 
6065             // Check all series in this Common.Chart area attached to this axis
6066             if (this.Common != null && this.Common.DataManager.Series != null && ChartArea != null)
6067             {
6068                 foreach (Series series in this.Common.DataManager.Series)
6069                 {
6070                     bool seriesAttached = false;
6071 
6072                     // Check series name
6073                     if (series.ChartArea == ChartArea.Name && series.IsVisible())
6074                     {
6075                         // Check if axis type of series match
6076                         if (this.axisType == AxisName.X && series.XAxisType == AxisType.Primary)
6077                         {
6078 #if SUBAXES
6079 							if(((Axis)this).SubAxisName == series.XSubAxisName)
6080 #endif // SUBAXES
6081                             {
6082                                 seriesAttached = true;
6083                             }
6084                         }
6085                         else if (this.axisType == AxisName.X2 && series.XAxisType == AxisType.Secondary)
6086                         {
6087 #if SUBAXES
6088 							if(((Axis)this).SubAxisName == series.XSubAxisName)
6089 #endif // SUBAXES
6090                             {
6091                                 seriesAttached = true;
6092                             }
6093                         }
6094                         else if (this.axisType == AxisName.Y && series.YAxisType == AxisType.Primary)
6095                         {
6096 #if SUBAXES
6097 							if(((Axis)this).SubAxisName == series.YSubAxisName)
6098 #endif // SUBAXES
6099                             {
6100                                 seriesAttached = true;
6101                             }
6102                         }
6103                         else if (this.axisType == AxisName.Y2 && series.YAxisType == AxisType.Secondary)
6104                         {
6105 #if SUBAXES
6106 							if(((Axis)this).SubAxisName == series.YSubAxisName)
6107 #endif // SUBAXES
6108                             {
6109                                 seriesAttached = true;
6110                             }
6111                         }
6112                     }
6113 
6114                     // If series attached to this axes
6115                     if (seriesAttached)
6116                     {
6117                         if (this.axisType == AxisName.X || this.axisType == AxisName.X2)
6118                         {
6119                             type = series.XValueType;
6120                         }
6121                         else if (this.axisType == AxisName.Y || this.axisType == AxisName.Y2)
6122                         {
6123                             type = series.YValueType;
6124                         }
6125                         break;
6126                     }
6127                 }
6128             }
6129             return type;
6130         }
6131 
6132         /// <summary>
6133         /// Returns Arrow size
6134         /// </summary>
6135         /// <param name="arrowOrientation">Return arrow orientation.</param>
6136         /// <returns>Size of arrow</returns>
GetArrowSize(out ArrowOrientation arrowOrientation)6137         internal SizeF GetArrowSize(out ArrowOrientation arrowOrientation)
6138         {
6139             Axis opositeAxis;
6140             double size;
6141             double sizeOpposite;
6142             arrowOrientation = ArrowOrientation.Top;
6143 
6144             // Set the position of axis
6145             switch (AxisPosition)
6146             {
6147                 case AxisPosition.Left:
6148 
6149                     if (isReversed)
6150                         arrowOrientation = ArrowOrientation.Bottom;
6151                     else
6152                         arrowOrientation = ArrowOrientation.Top;
6153 
6154                     break;
6155                 case AxisPosition.Right:
6156 
6157                     if (isReversed)
6158                         arrowOrientation = ArrowOrientation.Bottom;
6159                     else
6160                         arrowOrientation = ArrowOrientation.Top;
6161 
6162                     break;
6163                 case AxisPosition.Bottom:
6164 
6165                     if (isReversed)
6166                         arrowOrientation = ArrowOrientation.Left;
6167                     else
6168                         arrowOrientation = ArrowOrientation.Right;
6169 
6170                     break;
6171                 case AxisPosition.Top:
6172 
6173                     if (isReversed)
6174                         arrowOrientation = ArrowOrientation.Left;
6175                     else
6176                         arrowOrientation = ArrowOrientation.Right;
6177 
6178                     break;
6179             }
6180 
6181             // Opposite axis. Arrow uses this axis to find
6182             // a shift from Common.Chart area border. This shift
6183             // depend on Tick mark size.
6184             switch (arrowOrientation)
6185             {
6186                 case ArrowOrientation.Left:
6187                     opositeAxis = ChartArea.AxisX;
6188                     break;
6189                 case ArrowOrientation.Right:
6190                     opositeAxis = ChartArea.AxisX2;
6191                     break;
6192                 case ArrowOrientation.Top:
6193                     opositeAxis = ChartArea.AxisY2;
6194                     break;
6195                 case ArrowOrientation.Bottom:
6196                     opositeAxis = ChartArea.AxisY;
6197                     break;
6198                 default:
6199                     opositeAxis = ChartArea.AxisX;
6200                     break;
6201             }
6202 
6203             // Arrow size has to have the same shape when width and height
6204             // are changed. When the picture is resized, width of the Common.Chart
6205             // picture is used only for arrow size.
6206             if (arrowOrientation == ArrowOrientation.Top || arrowOrientation == ArrowOrientation.Bottom)
6207             {
6208                 size = _lineWidth;
6209                 sizeOpposite = (double)(_lineWidth) * Common.Width / Common.Height;
6210             }
6211             else
6212             {
6213                 size = (double)(_lineWidth) * Common.Width / Common.Height;
6214                 sizeOpposite = _lineWidth;
6215             }
6216 
6217             // Arrow is sharp triangle
6218             if (_arrowStyle == AxisArrowStyle.SharpTriangle)
6219             {
6220                 // Arrow direction is vertical
6221                 if (arrowOrientation == ArrowOrientation.Top || arrowOrientation == ArrowOrientation.Bottom)
6222                     return new SizeF((float)(size * 2), (float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 4));
6223                 else
6224                     // Arrow direction is horizontal
6225                     return new SizeF((float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 4), (float)(size * 2));
6226             }
6227             // There is no arrow
6228             else if (_arrowStyle == AxisArrowStyle.None)
6229                 return new SizeF(0, 0);
6230             else// Arrow is triangle or line type
6231             {
6232                 // Arrow direction is vertical
6233                 if (arrowOrientation == ArrowOrientation.Top || arrowOrientation == ArrowOrientation.Bottom)
6234                     return new SizeF((float)(size * 2), (float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 2));
6235                 else
6236                     // Arrow direction is horizontal
6237                     return new SizeF((float)(opositeAxis.MajorTickMark.Size + sizeOpposite * 2), (float)(size * 2));
6238             }
6239         }
6240 
6241 
6242         /// <summary>
6243         /// Checks if arrow with specified orientation will require space
6244         /// in axis with specified position
6245         /// </summary>
6246         /// <param name="arrowOrientation">Arrow orientation.</param>
6247         /// <param name="axisPosition">Axis position.</param>
6248         /// <returns>True if arrow will be drawn in axis space</returns>
IsArrowInAxis(ArrowOrientation arrowOrientation, AxisPosition axisPosition)6249         private bool IsArrowInAxis(ArrowOrientation arrowOrientation, AxisPosition axisPosition)
6250         {
6251             if (axisPosition == AxisPosition.Top && arrowOrientation == ArrowOrientation.Top)
6252                 return true;
6253             else if (axisPosition == AxisPosition.Bottom && arrowOrientation == ArrowOrientation.Bottom)
6254                 return true;
6255             if (axisPosition == AxisPosition.Left && arrowOrientation == ArrowOrientation.Left)
6256                 return true;
6257             else if (axisPosition == AxisPosition.Right && arrowOrientation == ArrowOrientation.Right)
6258                 return true;
6259 
6260             return false;
6261         }
6262 
6263 
6264         /// <summary>
6265         /// This function converts real Interval to
6266         /// absolute Interval
6267         /// </summary>
6268         /// <param name="realInterval">A interval represented as double value</param>
6269         /// <returns>A interval represented in pixels</returns>
GetPixelInterval(double realInterval)6270         internal float GetPixelInterval(double realInterval)
6271         {
6272             double chartAreaSize;
6273 
6274             // The Chart area pixel size as double
6275             if (AxisPosition == AxisPosition.Top || AxisPosition == AxisPosition.Bottom)
6276             {
6277                 chartAreaSize = PlotAreaPosition.Right - PlotAreaPosition.X;
6278             }
6279             else
6280             {
6281                 chartAreaSize = PlotAreaPosition.Bottom - PlotAreaPosition.Y;
6282             }
6283 
6284             // Avoid division by zero.
6285             if (ViewMaximum - ViewMinimum == 0)
6286             {
6287                 return (float)(chartAreaSize / realInterval);
6288             }
6289 
6290             // The interval integer
6291             return (float)(chartAreaSize / (ViewMaximum - ViewMinimum) * realInterval);
6292         }
6293 
6294         /// <summary>
6295         /// Find if axis is on the edge of the Common.Chart plot area
6296         /// </summary>
6297         internal bool IsAxisOnAreaEdge
6298         {
6299             get
6300             {
6301                 double edgePosition = 0;
6302                 if (this.AxisPosition == AxisPosition.Bottom)
6303                 {
6304                     edgePosition = PlotAreaPosition.Bottom;
6305                 }
6306                 else if (this.AxisPosition == AxisPosition.Left)
6307                 {
6308                     edgePosition = PlotAreaPosition.X;
6309                 }
6310                 else if (this.AxisPosition == AxisPosition.Right)
6311                 {
6312                     edgePosition = PlotAreaPosition.Right;
6313                 }
6314                 else if (this.AxisPosition == AxisPosition.Top)
6315                 {
6316                     edgePosition = PlotAreaPosition.Y;
6317                 }
6318 
6319                 // DT Fix : problems with values on edge ~0.0005
6320                 if (Math.Abs(GetAxisPosition() - edgePosition) < 0.0015)
6321                 {
6322                     return true;
6323                 }
6324 
6325                 return false;
6326             }
6327         }
6328 
6329         /// <summary>
6330         /// Find axis position using crossing value.
6331         /// </summary>
6332         /// <returns>Relative position</returns>
GetAxisPosition()6333         internal double GetAxisPosition()
6334         {
6335             return GetAxisPosition(false);
6336         }
6337 
6338         /// <summary>
6339         /// Find axis position using crossing value.
6340         /// </summary>
6341         /// <param name="ignoreCrossing">Axis crossing should be ignored.</param>
6342         /// <returns>Relative position</returns>
GetAxisPosition(bool ignoreCrossing)6343         virtual internal double GetAxisPosition(bool ignoreCrossing)
6344         {
6345             Axis axisOpposite = GetOppositeAxis();
6346 
6347             // Get axis position for circular Common.Chart area
6348             if (ChartArea != null && ChartArea.chartAreaIsCurcular)
6349             {
6350                 return PlotAreaPosition.X + PlotAreaPosition.Width / 2f;
6351             }
6352 
6353             // Axis is not connected with any series. There is no maximum and minimum
6354             if (axisOpposite.maximum == axisOpposite.minimum ||
6355                 double.IsNaN(axisOpposite.maximum) ||
6356                 double.IsNaN(axisOpposite.minimum) ||
6357                 maximum == minimum ||
6358                 double.IsNaN(maximum) ||
6359                 double.IsNaN(minimum))
6360             {
6361                 switch (AxisPosition)
6362                 {
6363                     case AxisPosition.Top:
6364                         return PlotAreaPosition.Y;
6365                     case AxisPosition.Bottom:
6366                         return PlotAreaPosition.Bottom;
6367                     case AxisPosition.Right:
6368                         return PlotAreaPosition.Right;
6369                     case AxisPosition.Left:
6370                         return PlotAreaPosition.X;
6371                 }
6372             }
6373 
6374             // Auto crossing enabled
6375             if (Double.IsNaN(axisOpposite.crossing) || ignoreCrossing)
6376             {
6377                 // Primary
6378                 if (axisType == AxisName.X || axisType == AxisName.Y)
6379                     return axisOpposite.GetLinearPosition(axisOpposite.ViewMinimum);
6380                 else // Secondary
6381                     return axisOpposite.GetLinearPosition(axisOpposite.ViewMaximum);
6382             }
6383             else // Auto crossing disabled
6384             {
6385                 axisOpposite.crossing = axisOpposite.tempCrossing;
6386 
6387                 if (axisOpposite.crossing < axisOpposite.ViewMinimum)
6388                 {
6389                     axisOpposite.crossing = axisOpposite.ViewMinimum;
6390                 }
6391                 else if (axisOpposite.crossing > axisOpposite.ViewMaximum)
6392                 {
6393                     axisOpposite.crossing = axisOpposite.ViewMaximum;
6394                 }
6395             }
6396 
6397             return axisOpposite.GetLinearPosition(axisOpposite.crossing);
6398         }
6399 
6400         #endregion
6401 
6402         #region Axis 3D helper methods
6403 
6404         /// <summary>
6405         /// Returns angle between 2D axis line and it's 3D transformed projection.
6406         /// </summary>
6407         /// <returns>Axis projection angle.</returns>
GetAxisProjectionAngle()6408         internal double GetAxisProjectionAngle()
6409         {
6410             // Get Z position
6411             bool axisOnEdge;
6412             float zPosition = GetMarksZPosition(out axisOnEdge);
6413 
6414             // Get axis position
6415             float axisPosition = (float)GetAxisPosition();
6416 
6417             // Create two points on the sides of the axis
6418             Point3D[] axisPoints = new Point3D[2];
6419             if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
6420             {
6421                 axisPoints[0] = new Point3D(0f, axisPosition, zPosition);
6422                 axisPoints[1] = new Point3D(100f, axisPosition, zPosition);
6423             }
6424             else
6425             {
6426                 axisPoints[0] = new Point3D(axisPosition, 0f, zPosition);
6427                 axisPoints[1] = new Point3D(axisPosition, 100f, zPosition);
6428             }
6429 
6430             // Transform coordinates
6431             ChartArea.matrix3D.TransformPoints(axisPoints);
6432 
6433             // Round result
6434             axisPoints[0].X = (float)Math.Round(axisPoints[0].X, 4);
6435             axisPoints[0].Y = (float)Math.Round(axisPoints[0].Y, 4);
6436             axisPoints[1].X = (float)Math.Round(axisPoints[1].X, 4);
6437             axisPoints[1].Y = (float)Math.Round(axisPoints[1].Y, 4);
6438 
6439             // Calculate angle
6440             double angle = 0.0;
6441             if (this.AxisPosition == AxisPosition.Top || this.AxisPosition == AxisPosition.Bottom)
6442             {
6443                 angle = Math.Atan((axisPoints[1].Y - axisPoints[0].Y) / (axisPoints[1].X - axisPoints[0].X));
6444             }
6445             else
6446             {
6447                 angle = Math.Atan((axisPoints[1].X - axisPoints[0].X) / (axisPoints[1].Y - axisPoints[0].Y));
6448             }
6449 
6450             // Conver to degrees
6451             return (angle * 180.0) / Math.PI;
6452         }
6453 
6454         #endregion
6455 
6456         #region IDisposable Members
6457 
6458         /// <summary>
6459         /// Releases unmanaged and - optionally - managed resources
6460         /// </summary>
6461         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
Dispose(bool disposing)6462         protected override void Dispose(bool disposing)
6463         {
6464             if (disposing)
6465             {
6466                 if (_fontCache != null)
6467                 {
6468                     _fontCache.Dispose();
6469                     _fontCache = null;
6470                 }
6471 
6472                 if (labelStyle != null)
6473                 {
6474                     labelStyle.Dispose();
6475                     labelStyle = null;
6476                 }
6477 
6478                 if (_stripLines != null)
6479                 {
6480                     _stripLines.Dispose();
6481                     _stripLines = null;
6482                 }
6483                 if (_customLabels != null)
6484                 {
6485                     _customLabels.Dispose();
6486                     _customLabels = null;
6487                 }
6488                 if (tempLabels != null)
6489                 {
6490                     tempLabels.Dispose();
6491                     tempLabels = null;
6492                 }
6493 #if Microsoft_CONTROL
6494                 if (this.scrollBar != null)
6495                 {
6496                     this.scrollBar.Dispose();
6497                     this.scrollBar = null;
6498                 }
6499 #endif // Microsoft_CONTROL
6500             }
6501             base.Dispose(disposing);
6502         }
6503 
6504 
6505         #endregion
6506 
6507     }
6508 }
6509