Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web.DataVisualization / Common / General / Label.cs
1 //-------------------------------------------------------------
2 // <copyright company=\92Microsoft Corporation\92>
3 //   Copyright © Microsoft Corporation. All Rights Reserved.
4 // </copyright>
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 //  File:               LabelStyle.cs
9 //
10 //  Namespace:  DataVisualization.Charting
11 //
12 //      Classes:        CustomLabelsCollection, CustomLabel, LabelStyle
13 //
14 //  Purpose:    LabelStyle and CustomLabel classes are used to determine 
15 //              chart axis labels. Labels can be automatically 
16 //              generated based on the series data or be \93manually\94 
17 //              set by the user.
18 //
19 //      Reviewed:       AG - Jul 31, 2002
20 //              AG - Microsoft 14, 2007
21 //
22 //===================================================================
23
24 #region Used namespaces
25
26 using System;
27 using System.Collections;
28 using System.Collections.Specialized;
29 using System.Collections.Generic;
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Data;
33 using System.Drawing;
34 using System.Drawing.Design;
35 using System.Drawing.Drawing2D;
36 using System.Drawing.Text;
37
38 #if Microsoft_CONTROL
39         using System.Windows.Forms.DataVisualization.Charting.Data;
40         using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
41         using System.Windows.Forms.DataVisualization.Charting.Utilities;
42         using System.Windows.Forms.DataVisualization.Charting.Borders3D;
43         using System.Windows.Forms.DataVisualization.Charting;
44     using System.Globalization;
45         using System.ComponentModel.Design.Serialization;
46         using System.Reflection;
47 #else
48         using System.Web;
49         using System.Web.UI;
50         using System.Web.UI.DataVisualization.Charting;
51         using System.Web.UI.DataVisualization.Charting.Data;
52         using System.Web.UI.DataVisualization.Charting.Utilities;
53         using System.Web.UI.DataVisualization.Charting.ChartTypes;
54 #endif
55
56 #endregion
57
58 #if Microsoft_CONTROL
59         namespace System.Windows.Forms.DataVisualization.Charting
60 #else
61     namespace System.Web.UI.DataVisualization.Charting
62 #endif
63 {
64         #region Labels enumerations
65
66         /// <summary>
67     /// An enumeration that specifies a mark for custom labels.
68         /// </summary>
69         public enum LabelMarkStyle
70         {
71                 /// <summary>
72         /// No label marks are used.
73                 /// </summary>
74                 None, 
75
76                 /// <summary>
77                 /// Labels use side marks.
78                 /// </summary>
79                 SideMark, 
80
81                 /// <summary>
82                 /// Labels use line and side marks.
83                 /// </summary>
84                 LineSideMark,
85
86
87                 /// <summary>
88                 /// Draws a box around the label. The box always starts at the axis position.
89                 /// </summary>
90                 Box
91         };
92
93
94         /// <summary>
95         /// An enumeration of custom grid lines and tick marks flags used in the custom labels.
96         /// </summary>
97         [Flags]
98         public enum GridTickTypes
99         {
100                 /// <summary>
101                 /// No tick mark or grid line are shown.
102                 /// </summary>
103                 None = 0,
104
105                 /// <summary>
106                 /// Tick mark is shown.
107                 /// </summary>
108                 TickMark = 1,
109
110                 /// <summary>
111                 /// Grid line is shown.
112                 /// </summary>
113                 Gridline = 2,
114
115                 /// <summary>
116                 /// Tick mark and grid line are shown.
117                 /// </summary>
118                 All = TickMark | Gridline
119         }
120
121
122         /// <summary>
123         /// An enumeration of label styles for circular chart area axis.
124         /// </summary>
125         internal enum CircularAxisLabelsStyle
126         {
127                 /// <summary>
128                 /// Style depends on number of labels.
129                 /// </summary>
130                 Auto,
131
132                 /// <summary>
133                 /// Label text positions around the circular area.
134                 /// </summary>
135                 Circular,
136
137                 /// <summary>
138                 /// Label text is always horizontal.
139                 /// </summary>
140                 Horizontal,
141
142                 /// <summary>
143                 /// Label text has the same angle as circular axis.
144                 /// </summary>
145                 Radial
146         }
147         #endregion
148
149         /// <summary>
150     /// The CustomLabelsCollection class is a strongly typed collection of 
151     /// custom axis labels.
152         /// </summary>
153         [
154                 SRDescription("DescriptionAttributeCustomLabelsCollection_CustomLabelsCollection"),
155         ]
156 #if ASPPERM_35
157         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
158     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
159 #endif
160     public class CustomLabelsCollection : ChartElementCollection<CustomLabel>
161         {
162                 #region Constructors
163
164                 /// <summary>
165                 /// Custom labels collection object constructor
166                 /// </summary>
167                 /// <param name="axis">Reference to the axis object.</param>
168         internal CustomLabelsCollection(Axis axis) : base(axis)
169                 {
170                 }
171
172                 #endregion
173
174         #region Properties
175         internal Axis Axis
176         {
177             get { return Parent as Axis; }
178         }
179         #endregion
180
181         #region Labels adding methods
182
183         /// <summary>
184                 /// Adds a custom label into the collection.
185                 /// </summary>
186                 /// <param name="fromPosition">Label left position.</param>
187                 /// <param name="toPosition">Label right position.</param>
188                 /// <param name="text">Label text.</param>
189         /// <returns>Newly added item.</returns>
190         public CustomLabel Add(double fromPosition, double toPosition, string text)
191                 {
192                         CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
193             Add(label);
194             return label;
195                 }
196
197                 /// <summary>
198                 /// Adds one custom label into the collection. Custom label flag may be specified.
199                 /// </summary>
200                 /// <param name="fromPosition">Label left position.</param>
201                 /// <param name="toPosition">Label right position.</param>
202                 /// <param name="text">Label text.</param>
203                 /// <param name="customLabel">Indicates if label is custom (created by user).</param>
204                 /// <returns>Newly added item.</returns>
205                 internal CustomLabel Add(double fromPosition, double toPosition, string text, bool customLabel)
206                 {
207                         CustomLabel label = new CustomLabel(fromPosition, toPosition, text, 0, LabelMarkStyle.None);
208                         label.customLabel = customLabel;
209             Add(label);
210             return label;
211         }
212
213                 /// <summary>
214                 /// Adds a custom label into the collection.
215                 /// </summary>
216                 /// <param name="fromPosition">Label left position.</param>
217                 /// <param name="toPosition">Label right position.</param>
218                 /// <param name="text">Label text.</param>
219                 /// <param name="rowIndex">Label row index.</param>
220                 /// <param name="markStyle">Label marking style.</param>
221         /// <returns>Newly added item.</returns>
222                 public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle)
223                 {
224                         CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle);
225             Add(label);
226             return label;
227         }
228
229                 /// <summary>
230                 /// Adds a custom label into the collection.
231                 /// </summary>
232                 /// <param name="fromPosition">Label left position.</param>
233                 /// <param name="toPosition">Label right position.</param>
234                 /// <param name="text">Label text.</param>
235                 /// <param name="rowIndex">Label row index.</param>
236                 /// <param name="markStyle">Label marking style.</param>
237                 /// <returns>Index of newly added item.</returns>
238                 /// <param name="gridTick">Custom grid line and tick mark flag.</param>
239                 public CustomLabel Add(double fromPosition, double toPosition, string text, int rowIndex, LabelMarkStyle markStyle, GridTickTypes gridTick)
240                 {
241                         CustomLabel label = new CustomLabel(fromPosition, toPosition, text, rowIndex, markStyle, gridTick);
242             Add(label);
243             return label;
244         }
245
246
247                 /// <summary>
248         /// Adds multiple custom labels to the collection.
249         /// The labels will be DateTime labels with the specified interval type, 
250         /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
251                 /// </summary>
252         /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
253                 /// <param name="intervalType">Unit of measurement of the label step.</param>
254                 /// <param name="min">Minimum value..</param>
255                 /// <param name="max">Maximum value..</param>
256                 /// <param name="format">Label text format.</param>
257                 /// <param name="rowIndex">Label row index.</param>
258                 /// <param name="markStyle">Label marking style.</param>
259                 public void Add(double labelsStep, DateTimeIntervalType intervalType, double min, double max, string format, int rowIndex, LabelMarkStyle markStyle)
260                 {
261             // Find labels range min/max values
262                         if(min == 0.0 && 
263                                 max == 0.0 &&
264                                 this.Axis != null &&
265                                 !double.IsNaN(this.Axis.Minimum) &&
266                                 !double.IsNaN(this.Axis.Maximum))
267                         {
268                                 min = this.Axis.Minimum;
269                                 max = this.Axis.Maximum;
270                         }
271                         double  fromX = Math.Min(min, max);
272                         double  toX = Math.Max(min, max);
273
274             this.SuspendUpdates();
275             try
276             {
277
278                 // Loop through all label points
279                 double labelStart = fromX;
280                 double labelEnd = 0;
281                 while (labelStart < toX)
282                 {
283                     // Determine label end location
284                     if (intervalType == DateTimeIntervalType.Number)
285                     {
286                         labelEnd = labelStart + labelsStep;
287                     }
288                     else if (intervalType == DateTimeIntervalType.Milliseconds)
289                     {
290                         labelEnd = DateTime.FromOADate(labelStart).AddMilliseconds(labelsStep).ToOADate();
291                     }
292                     else if (intervalType == DateTimeIntervalType.Seconds)
293                     {
294                         labelEnd = DateTime.FromOADate(labelStart).AddSeconds(labelsStep).ToOADate();
295                     }
296                     else if (intervalType == DateTimeIntervalType.Minutes)
297                     {
298                         labelEnd = DateTime.FromOADate(labelStart).AddMinutes(labelsStep).ToOADate();
299                     }
300                     else if (intervalType == DateTimeIntervalType.Hours)
301                     {
302                         labelEnd = DateTime.FromOADate(labelStart).AddHours(labelsStep).ToOADate();
303                     }
304                     else if (intervalType == DateTimeIntervalType.Days)
305                     {
306                         labelEnd = DateTime.FromOADate(labelStart).AddDays(labelsStep).ToOADate();
307                     }
308                     else if (intervalType == DateTimeIntervalType.Weeks)
309                     {
310                         labelEnd = DateTime.FromOADate(labelStart).AddDays(7 * labelsStep).ToOADate();
311                     }
312                     else if (intervalType == DateTimeIntervalType.Months)
313                     {
314                         labelEnd = DateTime.FromOADate(labelStart).AddMonths((int)labelsStep).ToOADate();
315                     }
316                     else if (intervalType == DateTimeIntervalType.Years)
317                     {
318                         labelEnd = DateTime.FromOADate(labelStart).AddYears((int)labelsStep).ToOADate();
319                     }
320                     else
321                     {
322                         // Unsupported step type
323                         throw (new ArgumentException(SR.ExceptionAxisLabelsIntervalTypeUnsupported(intervalType.ToString())));
324                     }
325                     if (labelEnd > toX)
326                     {
327                         labelEnd = toX;
328                     }
329
330                     // Generate label text
331                     ChartValueType valueType = ChartValueType.Double;
332                     if (intervalType != DateTimeIntervalType.Number)
333                     {
334                         if (this.Axis.GetAxisValuesType() == ChartValueType.DateTimeOffset)
335                             valueType = ChartValueType.DateTimeOffset;
336                         else
337                             valueType = ChartValueType.DateTime;
338                     }
339                     string text = ValueConverter.FormatValue(
340                         this.Common.Chart,
341                         this.Axis,
342                         null,
343                         labelStart + (labelEnd - labelStart) / 2,
344                         format,
345                         valueType,
346                         ChartElementType.AxisLabels);
347
348                     // Add label
349                     CustomLabel label = new CustomLabel(labelStart, labelEnd, text, rowIndex, markStyle);
350                     this.Add(label);
351
352                     labelStart = labelEnd;
353                 }
354             }
355             finally
356             {
357                 this.ResumeUpdates();
358             }
359                 }
360
361                 /// <summary>
362         /// Adds multiple custom labels to the collection.
363         /// The labels will be DateTime labels with the specified interval type, 
364         /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
365                 /// </summary>
366         /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
367         /// <param name="intervalType">Unit of measurement of the label step.</param>
368                 public void Add(double labelsStep, DateTimeIntervalType intervalType)
369                 {
370                         Add(labelsStep, intervalType, 0, 0, "", 0, LabelMarkStyle.None);
371                 }
372
373                 /// <summary>
374         /// Adds multiple custom labels to the collection.
375         /// The labels will be DateTime labels with the specified interval type, 
376         /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
377         /// </summary>
378         /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
379         /// <param name="intervalType">Unit of measurement of the label step.</param>
380                 /// <param name="format">Label text format.</param>
381                 public void Add(double labelsStep, DateTimeIntervalType intervalType, string format)
382                 {
383                         Add(labelsStep, intervalType, 0, 0, format, 0, LabelMarkStyle.None);
384                 }
385
386                 /// <summary>
387         /// Adds multiple custom labels to the collection.
388         /// The labels will be DateTime labels with the specified interval type, 
389         /// and will be generated for the axis range that is determined by the minimum and maximum arguments.
390         /// </summary>
391         /// <param name="labelsStep">The label step determines how often the custom labels will be drawn.</param>
392         /// <param name="intervalType">Unit of measurement of the label step.</param>
393                 /// <param name="format">Label text format.</param>
394                 /// <param name="rowIndex">Label row index.</param>
395                 /// <param name="markStyle">Label marking style.</param>
396                 public void Add(double labelsStep, DateTimeIntervalType intervalType, string format, int rowIndex, LabelMarkStyle markStyle)
397                 {
398                         Add(labelsStep, intervalType, 0, 0, format, rowIndex, markStyle);
399                 }
400
401                 #endregion
402
403         }
404
405
406         /// <summary>
407     /// The CustomLabel class represents a single custom axis label. Text and 
408     /// position along the axis is provided by the caller.
409         /// </summary>
410         [
411         SRDescription("DescriptionAttributeCustomLabel_CustomLabel"),
412         DefaultProperty("Text"),
413         ]
414 #if Microsoft_CONTROL
415         public class CustomLabel : ChartNamedElement
416 #else
417 #if ASPPERM_35
418         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
419     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
420 #endif
421     public class CustomLabel : ChartNamedElement, IChartMapArea
422 #endif
423     {
424                 #region Fields and Constructors
425
426                 // Private data members, which store properties values
427                 private double                  _fromPosition = 0;
428                 private double                  _toPosition = 0;
429                 private string                  _text = "";
430                 private LabelMarkStyle  _labelMark = LabelMarkStyle.None;
431                 private Color                   _foreColor = Color.Empty;
432                 private Color                   _markColor = Color.Empty;
433                 private int                             _labelRowIndex = 0;
434
435                 // Custom grid lines and tick marks flags
436                 private GridTickTypes   _gridTick = GridTickTypes.None;
437
438                 // Indicates if label was automatically created or cpecified by user (custom)
439                 internal bool                   customLabel = true;
440
441                 // Image associated with the label
442                 private string                  _image = string.Empty;
443
444                 // Image transparent color
445                 private Color                   _imageTransparentColor = Color.Empty;
446
447                 // Label tooltip
448                 private string                  _tooltip = string.Empty;
449
450         private Axis            _axis = null;
451 #if !Microsoft_CONTROL
452
453                 // URL target of the label image.
454                 private string                  _imageUrl = string.Empty;
455
456                 // Other attributes of the label image map area.
457                 private string                  _imageMapAreaAttributes = string.Empty;
458
459         private string          _imagePostbackValue = String.Empty;
460
461                 // Label tooltip
462                 private string                  _url = string.Empty;
463
464                 // Other attributes of the label image map area.
465                 private string                  _mapAreaAttributes = string.Empty;
466         
467         private string          _postbackValue = String.Empty;
468
469
470 #endif // !Microsoft_CONTROL
471
472
473
474                 #endregion
475
476                 #region Constructors
477
478                 /// <summary>
479                 /// Default constructor
480                 /// </summary>
481                 public CustomLabel()
482                 {
483                 }
484
485                 /// <summary>
486                 /// CustomLabel constructor
487                 /// </summary>
488                 /// <param name="fromPosition">From position.</param>
489                 /// <param name="toPosition">To position.</param>
490                 /// <param name="text">Label text.</param>
491                 /// <param name="labelRow">Label row index.</param>
492                 /// <param name="markStyle">Label mark style.</param>
493                 public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle)
494                 {
495                         this._fromPosition = fromPosition;
496                         this._toPosition = toPosition;
497                         this._text = text;
498                         this._labelRowIndex = labelRow;
499                         this._labelMark = markStyle;
500                         this._gridTick = GridTickTypes.None;
501                 }
502
503                 /// <summary>
504                 /// CustomLabel constructor
505                 /// </summary>
506                 /// <param name="fromPosition">From position.</param>
507                 /// <param name="toPosition">To position.</param>
508                 /// <param name="text">Label text.</param>
509                 /// <param name="labelRow">Label row index.</param>
510                 /// <param name="markStyle">Label mark style.</param>
511                 /// <param name="gridTick">Custom grid line and tick marks flag.</param>
512                 public CustomLabel(double fromPosition, double toPosition, string text, int labelRow, LabelMarkStyle markStyle, GridTickTypes gridTick)
513                 {
514                         this._fromPosition = fromPosition;
515                         this._toPosition = toPosition;
516                         this._text = text;
517                         this._labelRowIndex = labelRow;
518                         this._labelMark = markStyle;
519                         this._gridTick = gridTick;
520                 }
521
522                 #endregion
523
524                 #region Helper methods
525
526                 /// <summary>
527                 /// Returns a cloned label object.
528                 /// </summary>
529                 /// <returns>Copy of current custom label.</returns>
530                 public CustomLabel Clone()
531                 {
532                         CustomLabel newLabel = new CustomLabel();
533
534                         newLabel.FromPosition = this.FromPosition;
535                         newLabel.ToPosition = this.ToPosition;
536                         newLabel.Text = this.Text;
537                         newLabel.ForeColor = this.ForeColor;
538                         newLabel.MarkColor = this.MarkColor;
539                         newLabel.RowIndex = this.RowIndex;
540                         newLabel.LabelMark = this.LabelMark;
541                         newLabel.GridTicks = this.GridTicks;
542
543
544
545                         newLabel.ToolTip = this.ToolTip;
546                         newLabel.Tag = this.Tag;
547                         newLabel.Image = this.Image;
548                         newLabel.ImageTransparentColor = this.ImageTransparentColor;
549
550 #if !Microsoft_CONTROL
551                         newLabel.Url = this.Url;
552                         newLabel.MapAreaAttributes = this.MapAreaAttributes;
553                         newLabel.ImageUrl = this.ImageUrl;
554                         newLabel.ImageMapAreaAttributes = this.ImageMapAreaAttributes;
555 #endif // !Microsoft_CONTROL
556
557
558
559                         return newLabel;
560                 }
561
562         internal override IChartElement Parent
563         {
564             get
565             {
566                 return base.Parent;
567             }
568             set
569             {
570                 base.Parent = value;
571                 if (value != null)
572                 {
573                     _axis = Parent.Parent as Axis;
574                 }
575             }
576         }
577
578                 /// <summary>
579                 /// Gets the axis to which this object is attached to.
580                 /// </summary>
581                 /// <returns>Axis.</returns>
582         [
583         Browsable(false),
584         DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
585         SerializationVisibilityAttribute(SerializationVisibility.Hidden),
586         ]
587                 public Axis Axis
588                 {
589             get 
590             {
591                 return _axis;
592             }
593                 }
594
595                 #endregion
596
597                 #region CustomLabel properties
598
599                 /// <summary>
600                 /// Gets or sets the tooltip of the custom label.
601                 /// </summary>
602                 [
603 #if !Microsoft_CONTROL
604                 PersistenceMode(PersistenceMode.Attribute),
605 #endif //!Microsoft_CONTROL
606                 SRCategory("CategoryAttributeMapArea"),
607                 Bindable(true),
608         SRDescription("DescriptionAttributeToolTip"),
609                 DefaultValue("")
610                 ]
611                 public string ToolTip
612                 {
613                         set
614                         {
615                                 this._tooltip = value;
616                         }
617                         get
618                         {
619                                 return this._tooltip;
620                         }
621                 }
622
623
624 #if !Microsoft_CONTROL
625
626                 /// <summary>
627                 /// URL target of the custom label.
628                 /// </summary>
629                 [
630                 SRCategory("CategoryAttributeMapArea"),
631                 Bindable(true),
632                 SRDescription("DescriptionAttributeUrl"),
633                 DefaultValue(""),
634                 PersistenceMode(PersistenceMode.Attribute),
635         Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base)
636                 ]
637                 public string Url
638                 {
639                         set
640                         {
641                                 this._url = value;
642                         }
643                         get
644                         {
645                                 return this._url;
646                         }
647                 }
648
649                 /// <summary>
650                 /// Gets or sets the other attributes of the custom label map area.
651                 /// </summary>
652                 [
653                 SRCategory("CategoryAttributeMapArea"),
654                 Bindable(true),
655                 SRDescription("DescriptionAttributeMapAreaAttributes"),
656                 DefaultValue(""),
657                 PersistenceMode(PersistenceMode.Attribute)
658                 ]
659                 public string MapAreaAttributes
660                 {
661                         set
662                         {
663                 this._mapAreaAttributes = value;
664                         }
665                         get
666                         {
667                 return this._mapAreaAttributes;
668                         }
669                 }
670
671         /// <summary>
672         /// Gets or sets the postback value which can be processed on a click event.
673         /// </summary>
674         /// <value>The value which is passed to a click event as an argument.</value>
675         [DefaultValue("")]
676         [SRCategory(SR.Keys.CategoryAttributeMapArea)]
677         [SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
678         public string PostBackValue
679         {
680             get
681             {
682                 return this._postbackValue;
683             }
684             set
685             {
686                 this._postbackValue = value;
687             }
688         }
689
690                 /// <summary>
691                 /// Gets or sets the URL target of the custom label image.
692                 /// </summary>
693                 [
694                 SRCategory("CategoryAttributeMapArea"),
695                 Bindable(true),
696                 SRDescription("DescriptionAttributeCustomLabel_ImageUrl"),
697                 DefaultValue(""),
698                 PersistenceMode(PersistenceMode.Attribute),
699         Editor(Editors.UrlValueEditor.Editor, Editors.UrlValueEditor.Base),
700         System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")
701                 ]
702                 public string ImageUrl
703                 {
704                         set
705                         {
706                 this._imageUrl = value;
707                         }
708                         get
709                         {
710                 return this._imageUrl;
711                         }
712                 }
713
714                 /// <summary>
715         /// Gets or sets the other attributes of the map area of the custom label image.
716                 /// </summary>
717                 [
718                 SRCategory("CategoryAttributeMapArea"),
719                 Bindable(true),
720                 SRDescription("DescriptionAttributeMapAreaAttributes"),
721                 DefaultValue(""),
722                 PersistenceMode(PersistenceMode.Attribute)
723                 ]
724                 public string ImageMapAreaAttributes
725                 {
726                         set
727                         {
728                 this._imageMapAreaAttributes = value;
729                         }
730                         get
731                         {
732                 return this._imageMapAreaAttributes;
733                         }
734                 }
735
736         /// <summary>
737         /// Gets or sets the postback value which can be processed on a click event.
738         /// </summary>
739         /// <value>The value which is passed to a click event as an argument.</value>
740         [DefaultValue("")]
741         [SRCategory(SR.Keys.CategoryAttributeMapArea)]
742         [SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
743         public string ImagePostBackValue
744         {
745             get
746             {
747                 return this._imagePostbackValue;
748             }
749             set
750             {
751                 this._imagePostbackValue = value;
752             }
753         }
754
755
756 #endif // !Microsoft_CONTROL
757
758         /// <summary>
759                 /// Gets or sets the label image.
760                 /// </summary>
761                 [
762                 SRCategory("CategoryAttributeAppearance"),
763                 Bindable(true),
764                 DefaultValue(""),
765                 SRDescription("DescriptionAttributeCustomLabel_Image"),
766         Editor(Editors.ImageValueEditor.Editor, Editors.ImageValueEditor.Base),
767                 #if !Microsoft_CONTROL
768                 PersistenceMode(PersistenceMode.Attribute),
769                 #endif
770                 NotifyParentPropertyAttribute(true)
771                 ]
772                 public string Image
773                 {
774                         get
775                         {
776                                 return _image;
777                         }
778                         set
779                         {
780                                 _image = value;
781                                 Invalidate();
782                         }
783                 }
784
785                 /// <summary>
786         /// Gets or sets a color which will be replaced with a transparent color while drawing the image.
787                 /// </summary>
788                 [
789                 SRCategory("CategoryAttributeAppearance"),
790                 Bindable(true),
791                 DefaultValue(typeof(Color), ""),
792                 NotifyParentPropertyAttribute(true),
793         SRDescription("DescriptionAttributeImageTransparentColor"),
794         TypeConverter(typeof(ColorConverter)),
795         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
796                 #if !Microsoft_CONTROL
797                 PersistenceMode(PersistenceMode.Attribute)
798                 #endif
799                 ]
800                 public Color ImageTransparentColor
801                 {
802                         get
803                         {
804                                 return _imageTransparentColor;
805                         }
806                         set
807                         {
808                                 _imageTransparentColor = value;
809                                 this.Invalidate();
810                         }
811                 }
812
813
814
815                 /// <summary>
816                 /// Custom label name. This property is for internal use only.
817                 /// </summary>
818                 [
819                 SRCategory("CategoryAttributeAppearance"),
820                 SRDescription("DescriptionAttributeCustomLabel_Name"),
821                 DefaultValue("Custom LabelStyle"),
822                 DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
823                 DesignOnlyAttribute(true),
824                 SerializationVisibilityAttribute(SerializationVisibility.Hidden)
825                 ]
826                 public override string Name
827                 {
828                         get
829                         {
830                                 return base.Name;
831                         }
832                         set
833                         {
834                                 base.Name = value;
835                         }
836                 }
837
838                 /// <summary>
839                 /// Gets or sets a property which specifies whether
840         /// custom tick marks and grid lines will be drawn in the center of the label.
841                 /// </summary>
842                 [
843                 SRCategory("CategoryAttributeAppearance"),
844                 Bindable(true),
845                 DefaultValue(GridTickTypes.None),
846                 SRDescription("DescriptionAttributeCustomLabel_GridTicks"),
847         Editor(Editors.FlagsEnumUITypeEditor.Editor, Editors.FlagsEnumUITypeEditor.Base)
848                 ]
849                 public GridTickTypes GridTicks
850                 {
851                         get
852                         {
853                                 return _gridTick;
854                         }
855                         set
856                         {
857                                 _gridTick = value;
858                                 this.Invalidate();
859                         }
860                 }
861
862                 /// <summary>
863                 /// Gets or sets the end position of the custom label in axis coordinates.
864                 /// </summary>
865                 [
866                 SRCategory("CategoryAttributeAppearance"),
867                 Bindable(true),
868                 DefaultValue(0.0),
869                 SRDescription("DescriptionAttributeCustomLabel_From"),
870                 #if !Microsoft_CONTROL
871                 PersistenceMode(PersistenceMode.Attribute),
872                 #endif
873         TypeConverter(typeof(AxisLabelDateValueConverter))
874                 ]
875                 public double FromPosition
876                 {
877                         get
878                         {
879                                 return _fromPosition;
880                         }
881                         set
882                         {
883                                 _fromPosition = value;
884                                 this.Invalidate();
885                         }
886                 }
887
888                 /// <summary>
889         /// Gets or sets the starting position of the custom label in axis coordinates.
890                 /// </summary>
891                 [
892                 SRCategory("CategoryAttributeAppearance"),
893                 Bindable(true),
894                 DefaultValue(0.0),
895                 SRDescription("DescriptionAttributeCustomLabel_To"),
896                 #if !Microsoft_CONTROL
897                 PersistenceMode(PersistenceMode.Attribute),
898                 #endif
899         TypeConverter(typeof(AxisLabelDateValueConverter))
900                 ]
901                 public double ToPosition
902                 {
903                         get
904                         {
905                                 return _toPosition;
906                         }
907                         set
908                         {
909                                 _toPosition = value;
910                                 this.Invalidate();
911                         }
912                 }
913
914                 /// <summary>
915         /// Gets or sets the text of the custom label.
916                 /// </summary>
917                 [
918                 SRCategory("CategoryAttributeAppearance"),
919                 Bindable(true),
920                 DefaultValue(""),
921                 SRDescription("DescriptionAttributeCustomLabel_Text"),
922                 #if !Microsoft_CONTROL
923                 PersistenceMode(PersistenceMode.Attribute)
924                 #endif
925                 ]
926                 public string Text
927                 {
928                         get
929                         {
930                                 return _text;
931                         }
932                         set
933                         {
934                                 _text = value;
935                                 this.Invalidate();
936                         }
937                 }
938
939                 /// <summary>
940         /// Gets or sets the text color of the custom label.
941                 /// </summary>
942                 [
943                 SRCategory("CategoryAttributeAppearance"),
944                 Bindable(true),
945                 DefaultValue(typeof(Color), ""),
946         SRDescription("DescriptionAttributeForeColor"),
947                 NotifyParentPropertyAttribute(true),
948         TypeConverter(typeof(ColorConverter)),
949         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
950                 #if !Microsoft_CONTROL
951                 PersistenceMode(PersistenceMode.Attribute)
952                 #endif
953                 ]
954                 public Color ForeColor
955                 {
956                         get
957                         {
958                                 return _foreColor;
959                         }
960                         set
961                         {
962                                 _foreColor = value;
963                                 this.Invalidate();
964                         }
965                 }
966
967                 /// <summary>
968         /// Gets or sets the color of the label mark line of the custom label.
969                 /// </summary>
970                 [
971                 SRCategory("CategoryAttributeAppearance"),
972                 Bindable(true),
973                 DefaultValue(typeof(Color), ""),
974                 SRDescription("DescriptionAttributeCustomLabel_MarkColor"),
975                 NotifyParentPropertyAttribute(true),
976         TypeConverter(typeof(ColorConverter)),
977         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
978                 #if !Microsoft_CONTROL
979                 PersistenceMode(PersistenceMode.Attribute)
980                 #endif
981                 ]
982                 public Color MarkColor
983                 {
984                         get
985                         {
986                                 return _markColor;
987                         }
988                         set
989                         {
990                                 _markColor = value;
991                                 this.Invalidate();
992                         }
993                 }
994
995                 /// <summary>
996         /// Gets or sets the row index of the custom label.
997                 /// </summary>
998                 [
999                 SRCategory("CategoryAttributeAppearance"),
1000                 Bindable(true),
1001                 DefaultValue(0),
1002                 SRDescription("DescriptionAttributeCustomLabel_RowIndex"),
1003                 #if !Microsoft_CONTROL
1004                 PersistenceMode(PersistenceMode.Attribute)
1005                 #endif
1006                 ]
1007                 public int RowIndex
1008                 {
1009                         get
1010                         {
1011                                 return this._labelRowIndex;
1012                         }
1013                         set
1014                         {
1015                                 if(value < 0)
1016                                 {
1017                     throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexIsNegative));
1018                                 }
1019
1020                                 this._labelRowIndex = value;
1021                                 this.Invalidate();
1022                         }
1023                 }
1024
1025                 /// <summary>
1026                 /// Gets or sets a property which define the marks for the labels in the second row. 
1027                 /// </summary>
1028                 [
1029                 SRCategory("CategoryAttributeAppearance"),
1030                 Bindable(true),
1031                 DefaultValue(LabelMarkStyle.None),
1032                 SRDescription("DescriptionAttributeCustomLabel_LabelMark"),
1033                 #if !Microsoft_CONTROL
1034                 PersistenceMode(PersistenceMode.Attribute)
1035                 #endif
1036                 ]
1037                 public LabelMarkStyle LabelMark
1038                 {
1039                         get
1040                         {
1041                                 return _labelMark;
1042                         }
1043                         set
1044                         {
1045                                 _labelMark = value;
1046                                 this.Invalidate();
1047                         }
1048                 }
1049
1050                 #endregion
1051
1052         }
1053
1054         /// <summary>
1055     /// The LabelStyle class contains properties which define the visual appearance of 
1056     /// the axis labels, their interval and position. This class is also 
1057     /// responsible for calculating the position of all the labels and 
1058     /// drawing them. 
1059         /// </summary>
1060         [
1061                 SRDescription("DescriptionAttributeLabel_Label"),
1062                 DefaultProperty("Enabled"),
1063         ]
1064 #if ASPPERM_35
1065         [AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
1066     [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
1067 #endif
1068     public class LabelStyle : ChartElement
1069         {
1070                 #region Fields
1071
1072                 // Reference to the Axis 
1073                 private Axis                                    _axis = null;
1074
1075                 // Private data members, which store properties values
1076                 private bool                                    _enabled = true;
1077
1078                 internal double                                 intervalOffset = double.NaN;
1079                 internal double                                 interval = double.NaN;
1080                 internal DateTimeIntervalType   intervalType = DateTimeIntervalType.NotSet;
1081                 internal DateTimeIntervalType   intervalOffsetType = DateTimeIntervalType.NotSet;
1082
1083         private FontCache               _fontCache = new FontCache();
1084                 private Font                                    _font;
1085                 private Color                                   _foreColor = Color.Black;
1086                 internal int                                    angle = 0;
1087                 internal bool                                   isStaggered = false;
1088                 private bool                                    _isEndLabelVisible = true;
1089                 private bool                                    _truncatedLabels = false;
1090                 private string                                  _format = "";
1091
1092                 #endregion
1093
1094                 #region Constructors
1095
1096                 /// <summary>
1097                 /// Public default constructor.
1098                 /// </summary>
1099                 public LabelStyle()
1100                 {
1101             _font = _fontCache.DefaultFont;
1102                 }
1103
1104         /// <summary>
1105         /// Public constructor.
1106         /// </summary>
1107         /// <param name="axis">Axis which owns the grid.</param>
1108                 internal LabelStyle(Axis axis) 
1109             : this()
1110                 {
1111                         _axis = axis;
1112                 }
1113
1114                 #endregion
1115
1116                 #region Axis labels drawing methods
1117
1118                 /// <summary>
1119                 /// Draws axis labels on the circular chart area.
1120                 /// </summary>
1121                 /// <param name="graph">Reference to the Chart Graphics object.</param>
1122                 internal void PaintCircular( ChartGraphics graph )
1123                 {
1124                         // Label string drawing format                  
1125             using (StringFormat format = new StringFormat())
1126             {
1127                 format.FormatFlags |= StringFormatFlags.LineLimit;
1128                 format.Trimming = StringTrimming.EllipsisCharacter;
1129
1130                 // Labels are disabled for this axis
1131                 if (!_axis.LabelStyle.Enabled)
1132                     return;
1133
1134                 // Draw text with anti-aliasing
1135                 /*
1136                 if( (graph.AntiAliasing & AntiAliasing.Text) == AntiAliasing.Text )
1137                 {
1138                     graph.TextRenderingHint = TextRenderingHint.AntiAlias;
1139                 }
1140                 else
1141                 {
1142                     graph.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
1143                 }
1144                 */
1145
1146                 // Gets axis labels style
1147                 CircularAxisLabelsStyle labelsStyle = this._axis.ChartArea.GetCircularAxisLabelsStyle();
1148
1149                 // Get list of circular axes with labels
1150                 ArrayList circularAxes = this._axis.ChartArea.GetCircularAxisList();
1151
1152                 // Draw each axis label
1153                 int index = 0;
1154                 foreach (CircularChartAreaAxis circAxis in circularAxes)
1155                 {
1156                     if (circAxis.Title.Length > 0)
1157                     {
1158                         //******************************************************************
1159                         //** Calculate label position corner position
1160                         //******************************************************************
1161                         PointF labelRelativePosition = new PointF(
1162                             this._axis.ChartArea.circularCenter.X,
1163                             this._axis.ChartArea.PlotAreaPosition.Y);
1164
1165                         // Adjust labels Y position
1166                         labelRelativePosition.Y -= _axis.markSize + Axis.elementSpacing;
1167
1168                         // Convert to absolute
1169                         PointF[] labelPosition = new PointF[] { graph.GetAbsolutePoint(labelRelativePosition) };
1170
1171                         // Get label rotation angle
1172                         float labelAngle = circAxis.AxisPosition;
1173                         ICircularChartType chartType = this._axis.ChartArea.GetCircularChartType();
1174                         if (chartType != null && chartType.XAxisCrossingSupported())
1175                         {
1176                             if (!double.IsNaN(this._axis.ChartArea.AxisX.Crossing))
1177                             {
1178                                 labelAngle += (float)this._axis.ChartArea.AxisX.Crossing;
1179                             }
1180                         }
1181
1182                         // Make sure angle is presented as a positive number
1183                         while (labelAngle < 0)
1184                         {
1185                             labelAngle = 360f + labelAngle;
1186                         }
1187
1188                         // Set graphics rotation matrix
1189                         Matrix newMatrix = new Matrix();
1190                         newMatrix.RotateAt(labelAngle, graph.GetAbsolutePoint(this._axis.ChartArea.circularCenter));
1191                         newMatrix.TransformPoints(labelPosition);
1192
1193                         // Set text alignment
1194                         format.LineAlignment = StringAlignment.Center;
1195                         format.Alignment = StringAlignment.Near;
1196                         if (labelsStyle != CircularAxisLabelsStyle.Radial)
1197                         {
1198                             if (labelAngle < 5f || labelAngle > 355f)
1199                             {
1200                                 format.Alignment = StringAlignment.Center;
1201                                 format.LineAlignment = StringAlignment.Far;
1202                             }
1203                             if (labelAngle < 185f && labelAngle > 175f)
1204                             {
1205                                 format.Alignment = StringAlignment.Center;
1206                                 format.LineAlignment = StringAlignment.Near;
1207                             }
1208                             if (labelAngle > 185f && labelAngle < 355f)
1209                             {
1210                                 format.Alignment = StringAlignment.Far;
1211                             }
1212                         }
1213                         else
1214                         {
1215                             if (labelAngle > 180f)
1216                             {
1217                                 format.Alignment = StringAlignment.Far;
1218                             }
1219                         }
1220
1221
1222                         // Set text rotation angle
1223                         float textAngle = labelAngle;
1224                         if (labelsStyle == CircularAxisLabelsStyle.Radial)
1225                         {
1226                             if (labelAngle > 180)
1227                             {
1228                                 textAngle += 90f;
1229                             }
1230                             else
1231                             {
1232                                 textAngle -= 90f;
1233                             }
1234                         }
1235                         else if (labelsStyle == CircularAxisLabelsStyle.Circular)
1236                         {
1237                             format.Alignment = StringAlignment.Center;
1238                             format.LineAlignment = StringAlignment.Far;
1239                         }
1240
1241                         // Set text rotation matrix
1242                         Matrix oldMatrix = graph.Transform;
1243                         if (labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
1244                         {
1245                             Matrix textRotationMatrix = oldMatrix.Clone();
1246                             textRotationMatrix.RotateAt(textAngle, labelPosition[0]);
1247                             graph.Transform = textRotationMatrix;
1248                         }
1249
1250                         // Get axis titl (label) color
1251                         Color labelColor = _foreColor;
1252                         if (!circAxis.TitleForeColor.IsEmpty)
1253                         {
1254                             labelColor = circAxis.TitleForeColor;
1255                         }
1256
1257                         // Draw label
1258                         using (Brush brush = new SolidBrush(labelColor))
1259                         {
1260                             graph.DrawString(
1261                                 circAxis.Title.Replace("\\n", "\n"),
1262                                 (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
1263                                 brush,
1264                                 labelPosition[0],
1265                                 format);
1266                         }
1267
1268                         // Process selection region 
1269                         if (this._axis.Common.ProcessModeRegions)
1270                         {
1271                             SizeF size = graph.MeasureString(circAxis.Title.Replace("\\n", "\n"), (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont);
1272                             RectangleF labelRect = GetLabelPosition(
1273                                 labelPosition[0],
1274                                 size,
1275                                 format);
1276                             PointF[] points = new PointF[]
1277                                                         {
1278                                                                 labelRect.Location, 
1279                                                                 new PointF(labelRect.Right, labelRect.Y),
1280                                                                 new PointF(labelRect.Right, labelRect.Bottom),
1281                                                                 new PointF(labelRect.X, labelRect.Bottom)
1282                                                         };
1283
1284                             using (GraphicsPath path = new GraphicsPath())
1285                             {
1286                                 path.AddPolygon(points);
1287                                 path.CloseAllFigures();
1288                                 path.Transform(graph.Transform);
1289                                 this._axis.Common.HotRegionsList.AddHotRegion(
1290                                     path,
1291                                     false,
1292                                     ChartElementType.AxisLabels,
1293                                     circAxis.Title);
1294                             }
1295                     }
1296
1297                                         // Restore graphics
1298                                         if(labelsStyle == CircularAxisLabelsStyle.Radial || labelsStyle == CircularAxisLabelsStyle.Circular)
1299                                         {
1300                                                 graph.Transform = oldMatrix;
1301                                         }
1302                                 }
1303
1304                     ++index;
1305                 }
1306             }
1307
1308                 }
1309
1310                 /// <summary>
1311                 /// Gets rectangle position of the label.
1312                 /// </summary>
1313                 /// <param name="position">Original label position.</param>
1314                 /// <param name="size">Label text size.</param>
1315                 /// <param name="format">Label string format.</param>
1316                 /// <returns>Label rectangle position.</returns>
1317                 internal static RectangleF GetLabelPosition(
1318                         PointF position, 
1319                         SizeF size,
1320                         StringFormat format)
1321                 {
1322                         // Calculate label position rectangle
1323                         RectangleF      labelPosition = RectangleF.Empty;
1324                         labelPosition.Width = size.Width;
1325                         labelPosition.Height = size.Height;
1326
1327                         if(format.Alignment == StringAlignment.Far)
1328                         {
1329                                 labelPosition.X = position.X - size.Width;
1330                         }
1331                         else if(format.Alignment == StringAlignment.Near)
1332                         {
1333                                 labelPosition.X = position.X;
1334                         }
1335                         else if(format.Alignment == StringAlignment.Center)
1336                         {
1337                                 labelPosition.X = position.X - size.Width/2F;
1338                         }
1339
1340                         if(format.LineAlignment == StringAlignment.Far)
1341                         {
1342                                 labelPosition.Y = position.Y - size.Height;
1343                         }
1344                         else if(format.LineAlignment == StringAlignment.Near)
1345                         {
1346                                 labelPosition.Y = position.Y;
1347                         }
1348                         else if(format.LineAlignment == StringAlignment.Center)
1349                         {
1350                                 labelPosition.Y = position.Y - size.Height/2F;
1351                         }
1352
1353                         return labelPosition;
1354                 }
1355
1356                 /// <summary>
1357                 /// Draws axis labels.
1358                 /// </summary>
1359                 /// <param name="graph">Reference to the Chart Graphics object.</param>
1360                 /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
1361                 internal void Paint( ChartGraphics graph, bool backElements )
1362                 {
1363                         // Label string drawing format                  
1364             using (StringFormat format = new StringFormat())
1365             {
1366                 format.FormatFlags |= StringFormatFlags.LineLimit;
1367                 format.Trimming = StringTrimming.EllipsisCharacter;
1368
1369                 // Labels are disabled for this axis
1370                 if (!_axis.LabelStyle.Enabled)
1371                     return;
1372                 // deliant fix-> VSTS #157848, #143286 - drawing custom label in empty axis
1373                 if (Double.IsNaN(_axis.ViewMinimum) || Double.IsNaN(_axis.ViewMaximum))
1374                     return;
1375
1376
1377                 // Draw labels in 3D space
1378                 if (this._axis.ChartArea.Area3DStyle.Enable3D && !this._axis.ChartArea.chartAreaIsCurcular)
1379                 {
1380                     this.Paint3D(graph, backElements);
1381                     return;
1382                 }
1383
1384                 // Initialize all labels position rectangle
1385                 RectangleF rectLabels = _axis.ChartArea.Position.ToRectangleF();
1386                 float labelSize = _axis.labelSize;
1387
1388                 if (_axis.AxisPosition == AxisPosition.Left)
1389                 {
1390                     rectLabels.Width = labelSize;
1391                     if (_axis.GetIsMarksNextToAxis())
1392                         rectLabels.X = (float)_axis.GetAxisPosition();
1393                     else
1394                         rectLabels.X = _axis.PlotAreaPosition.X;
1395
1396                     rectLabels.X -= labelSize + _axis.markSize;
1397
1398                     // Set label text alignment
1399                     format.Alignment = StringAlignment.Far;
1400                     format.LineAlignment = StringAlignment.Center;
1401                 }
1402                 else if (_axis.AxisPosition == AxisPosition.Right)
1403                 {
1404                     rectLabels.Width = labelSize;
1405                     if (_axis.GetIsMarksNextToAxis())
1406                         rectLabels.X = (float)_axis.GetAxisPosition();
1407                     else
1408                         rectLabels.X = _axis.PlotAreaPosition.Right;
1409                     rectLabels.X += _axis.markSize;
1410
1411                     // Set label text alignment
1412                     format.Alignment = StringAlignment.Near;
1413                     format.LineAlignment = StringAlignment.Center;
1414                 }
1415                 else if (_axis.AxisPosition == AxisPosition.Top)
1416                 {
1417                     rectLabels.Height = labelSize;
1418                     if (_axis.GetIsMarksNextToAxis())
1419                         rectLabels.Y = (float)_axis.GetAxisPosition();
1420                     else
1421                         rectLabels.Y = _axis.PlotAreaPosition.Y;
1422                     rectLabels.Y -= labelSize + _axis.markSize;
1423
1424                     // Set label text alignment
1425                     format.Alignment = StringAlignment.Center;
1426                     format.LineAlignment = StringAlignment.Far;
1427                 }
1428                 else if (_axis.AxisPosition == AxisPosition.Bottom)
1429                 {
1430                     rectLabels.Height = labelSize;
1431                     if (_axis.GetIsMarksNextToAxis())
1432                         rectLabels.Y = (float)_axis.GetAxisPosition();
1433                     else
1434                         rectLabels.Y = _axis.PlotAreaPosition.Bottom;
1435                     rectLabels.Y += _axis.markSize;
1436
1437                     // Set label text alignment
1438                     format.Alignment = StringAlignment.Center;
1439                     format.LineAlignment = StringAlignment.Near;
1440                 }
1441
1442                 // Calculate bounding rectangle
1443                 RectangleF boundaryRect = rectLabels;
1444                 if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
1445                 {
1446                     if (_axis.AxisPosition == AxisPosition.Left)
1447                     {
1448                         boundaryRect.X += _axis.totlaGroupingLabelsSize;
1449                         boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
1450                     }
1451                     else if (_axis.AxisPosition == AxisPosition.Right)
1452                     {
1453                         boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
1454                     }
1455                     else if (_axis.AxisPosition == AxisPosition.Top)
1456                     {
1457                         boundaryRect.Y += _axis.totlaGroupingLabelsSize;
1458                         boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
1459                     }
1460                     else if (_axis.AxisPosition == AxisPosition.Bottom)
1461                     {
1462                         boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
1463                     }
1464                 }
1465
1466                 // Check if the AJAX zooming and scrolling mode is enabled.
1467                 // Labels are drawn slightly different in this case.
1468                 bool ajaxScrollingEnabled = false;
1469                 bool firstFrame = true;
1470                 bool lastFrame = true;
1471
1472                 // Draw all labels from the collection
1473                 int labelIndex = 0;
1474                 foreach (CustomLabel label in this._axis.CustomLabels)
1475                 {
1476                     bool truncatedLeft = false;
1477                     bool truncatedRight = false;
1478                     double labelFrom = label.FromPosition;
1479                     double labelTo = label.ToPosition;
1480                     bool useRelativeCoordiantes = false;
1481                     double labelFromRelative = double.NaN;
1482                     double labelToRelative = double.NaN;
1483
1484                     // Skip if label middle point is outside current scaleView
1485                     if (label.RowIndex == 0)
1486                     {
1487                         double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
1488                         decimal viewMin = (decimal)_axis.ViewMinimum;
1489                         decimal viewMax = (decimal)_axis.ViewMaximum;
1490
1491                         if (ajaxScrollingEnabled)
1492                         {
1493                             // Skip very first and last labels if they are partialy outside the scaleView
1494                             if (firstFrame)
1495                             {
1496                                 if ((decimal)label.FromPosition < (decimal)_axis.Minimum)
1497                                 {
1498                                     continue;
1499                                 }
1500                             }
1501                             if (lastFrame)
1502                             {
1503                                 if ((decimal)label.ToPosition > (decimal)_axis.Maximum)
1504                                 {
1505                                     continue;
1506                                 }
1507                             }
1508
1509                             // Skip label only if it is compleltly out of the scaleView
1510                             if ((decimal)label.ToPosition < viewMin ||
1511                                 (decimal)label.FromPosition > viewMax)
1512                             {
1513                                 continue;
1514                             }
1515
1516                             // RecalculateAxesScale label index starting from the first frame.
1517                             // Index is used to determine position of the offset labels
1518                             if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
1519                             {
1520                                 // Reset index
1521                                 labelIndex = 0;
1522
1523                                 // Get first series attached to this axis
1524                                 Series axisSeries = null;
1525                                 if (_axis.axisType == AxisName.X || _axis.axisType == AxisName.X2)
1526                                 {
1527                                     List<string> seriesArray = _axis.ChartArea.GetXAxesSeries((_axis.axisType == AxisName.X) ? AxisType.Primary : AxisType.Secondary, _axis.SubAxisName);
1528                                     if (seriesArray.Count > 0)
1529                                     {
1530                                         axisSeries = _axis.Common.DataManager.Series[seriesArray[0]];
1531                                         if (axisSeries != null && !axisSeries.IsXValueIndexed)
1532                                         {
1533                                             axisSeries = null;
1534                                         }
1535                                     }
1536                                 }
1537
1538                                 // Set start position and iterate through label positions
1539                                 // NOTE: Labels offset should not be taken in the account
1540                                 double currentPosition = _axis.Minimum;
1541                                 while (currentPosition < _axis.Maximum)
1542                                 {
1543                                     if (currentPosition >= middlePoint)
1544                                     {
1545                                         break;
1546                                     }
1547
1548                                     currentPosition += ChartHelper.GetIntervalSize(currentPosition, _axis.LabelStyle.GetInterval(), _axis.LabelStyle.GetIntervalType(),
1549                                         axisSeries, 0.0, DateTimeIntervalType.Number, true);
1550                                     ++labelIndex;
1551                                 }
1552
1553                             }
1554                         }
1555                         else
1556                         {
1557                             // Skip label if label middle point is not in the scaleView
1558                             if ((decimal)middlePoint < viewMin ||
1559                                 (decimal)middlePoint > viewMax)
1560                             {
1561                                 continue;
1562                             }
1563                         }
1564
1565
1566
1567                         // Make sure label To and From coordinates are processed by one scale segment based 
1568                         // on the label middle point position.
1569                         if (_axis.ScaleSegments.Count > 0)
1570                         {
1571                             AxisScaleSegment scaleSegment = _axis.ScaleSegments.FindScaleSegmentForAxisValue(middlePoint);
1572                             _axis.ScaleSegments.AllowOutOfScaleValues = true;
1573                             _axis.ScaleSegments.EnforceSegment(scaleSegment);
1574                         }
1575
1576
1577
1578                         // Use center point instead of the To/From if label takes all scaleView
1579                         // This is done to avoid issues with labels drawing with high 
1580                         // zooming levels.
1581                         if ((decimal)label.FromPosition < viewMin &&
1582                             (decimal)label.ToPosition > viewMax)
1583                         {
1584                             // Indicates that chart relative coordinates should be used instead of axis values
1585                             useRelativeCoordiantes = true;
1586
1587                             // Calculate label From/To in relative coordinates using 
1588                             // label middle point and 100% width.
1589                             labelFromRelative = _axis.GetLinearPosition(middlePoint) - 50.0;
1590                             labelToRelative = labelFromRelative + 100.0;
1591                         }
1592                     }
1593                     else
1594                     {
1595                         // Skip labels completly outside the scaleView
1596                         if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
1597                         {
1598                             continue;
1599                         }
1600
1601                         // Check if label is partially visible.
1602                         if (!ajaxScrollingEnabled &&
1603                             _axis.ScaleView.IsZoomed)
1604                         {
1605                             if (label.FromPosition < _axis.ViewMinimum)
1606                             {
1607                                 truncatedLeft = true;
1608                                 labelFrom = _axis.ViewMinimum;
1609                             }
1610                             if (label.ToPosition > _axis.ViewMaximum)
1611                             {
1612                                 truncatedRight = true;
1613                                 labelTo = _axis.ViewMaximum;
1614                             }
1615                         }
1616                     }
1617
1618                     // Calculate single label position
1619                     RectangleF rect = rectLabels;
1620
1621                     // Label is in the first row
1622                     if (label.RowIndex == 0)
1623                     {
1624                         if (_axis.AxisPosition == AxisPosition.Left)
1625                         {
1626                             rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
1627                             rect.Width = _axis.unRotatedLabelSize;
1628
1629                             // Adjust label rectangle if offset labels are used
1630                             if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
1631                             {
1632                                 rect.Width /= 2F;
1633                                 if (labelIndex % 2 != 0F)
1634                                 {
1635                                     rect.X += rect.Width;
1636                                 }
1637                             }
1638                         }
1639                         else if (_axis.AxisPosition == AxisPosition.Right)
1640                         {
1641                             rect.Width = _axis.unRotatedLabelSize;
1642
1643                             // Adjust label rectangle if offset labels are used
1644                             if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
1645                             {
1646                                 rect.Width /= 2F;
1647                                 if (labelIndex % 2 != 0F)
1648                                 {
1649                                     rect.X += rect.Width;
1650                                 }
1651                             }
1652                         }
1653                         else if (_axis.AxisPosition == AxisPosition.Top)
1654                         {
1655                             rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
1656                             rect.Height = _axis.unRotatedLabelSize;
1657
1658                             // Adjust label rectangle if offset labels are used
1659                             if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
1660                             {
1661                                 rect.Height /= 2F;
1662                                 if (labelIndex % 2 != 0F)
1663                                 {
1664                                     rect.Y += rect.Height;
1665                                 }
1666                             }
1667                         }
1668                         else if (_axis.AxisPosition == AxisPosition.Bottom)
1669                         {
1670                             rect.Height = _axis.unRotatedLabelSize;
1671
1672                             // Adjust label rectangle if offset labels are used
1673                             if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
1674                             {
1675                                 rect.Height /= 2F;
1676                                 if (labelIndex % 2 != 0F)
1677                                 {
1678                                     rect.Y += rect.Height;
1679                                 }
1680                             }
1681                         }
1682
1683                         // Increase label index
1684                         ++labelIndex;
1685                     }
1686
1687                     // Label is in the second row
1688                     else if (label.RowIndex > 0)
1689                     {
1690                         if (_axis.AxisPosition == AxisPosition.Left)
1691                         {
1692                             rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
1693                             for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
1694                             {
1695                                 rect.X += _axis.groupingLabelSizes[index - 1];
1696                             }
1697                             rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
1698                         }
1699                         else if (_axis.AxisPosition == AxisPosition.Right)
1700                         {
1701                             rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
1702                             for (int index = 1; index < label.RowIndex; index++)
1703                             {
1704                                 rect.X += _axis.groupingLabelSizes[index - 1];
1705                             }
1706                             rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
1707                         }
1708                         else if (_axis.AxisPosition == AxisPosition.Top)
1709                         {
1710                             rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
1711                             for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
1712                             {
1713                                 rect.Y += _axis.groupingLabelSizes[index - 1];
1714                             }
1715                             rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
1716                         }
1717                         if (_axis.AxisPosition == AxisPosition.Bottom)
1718                         {
1719                             rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
1720                             for (int index = 1; index < label.RowIndex; index++)
1721                             {
1722                                 rect.Y += _axis.groupingLabelSizes[index - 1];
1723                             }
1724                             rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
1725                         }
1726                     }
1727
1728                     // Unknown label row value
1729                     else
1730                     {
1731                         throw (new InvalidOperationException(SR.ExceptionAxisLabelIndexIsNegative));
1732                     }
1733
1734                     // Set label From and To coordinates
1735                     double fromPosition = _axis.GetLinearPosition(labelFrom);
1736                     double toPosition = _axis.GetLinearPosition(labelTo);
1737                     if (useRelativeCoordiantes)
1738                     {
1739                         useRelativeCoordiantes = false;
1740                         fromPosition = labelFromRelative;
1741                         toPosition = labelToRelative;
1742                     }
1743
1744                     if (_axis.AxisPosition == AxisPosition.Top || _axis.AxisPosition == AxisPosition.Bottom)
1745                     {
1746                         rect.X = (float)Math.Min(fromPosition, toPosition);
1747                         rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
1748
1749                         // Adjust label To/From position if offset labels are used
1750                         if (label.RowIndex == 0 &&
1751                             ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
1752                         {
1753                             rect.X -= rect.Width / 2F;
1754                             rect.Width *= 2F;
1755                         }
1756                     }
1757                     else
1758                     {
1759                         rect.Y = (float)Math.Min(fromPosition, toPosition);
1760                         rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
1761
1762                         // Adjust label To/From position if offset labels are used
1763                         if (label.RowIndex == 0 &&
1764                             ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
1765                         {
1766                             rect.Y -= rect.Height / 2F;
1767                             rect.Height *= 2F;
1768                         }
1769                     }
1770
1771                     // Draw label
1772                     using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
1773                     {
1774                         graph.DrawLabelStringRel(_axis,
1775                             label.RowIndex,
1776                             label.LabelMark,
1777                             label.MarkColor,
1778                             label.Text,
1779                             label.Image,
1780                             label.ImageTransparentColor,
1781                             (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
1782                             brush,
1783                             rect,
1784                             format,
1785                             (_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle,
1786                             (!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
1787                             label,
1788                             truncatedLeft,
1789                             truncatedRight);
1790                     }
1791
1792                     // Clear scale segment enforcement
1793                     _axis.ScaleSegments.EnforceSegment(null);
1794                     _axis.ScaleSegments.AllowOutOfScaleValues = false;
1795                 }
1796             }
1797                 }
1798
1799                 #endregion
1800
1801                 #region 3D Axis labels drawing methods
1802
1803                 /// <summary>
1804                 /// Get a rectangle between chart area position and plotting area on specified side.
1805                 /// Also sets axis labels string formatting for the specified labels position.
1806                 /// </summary>
1807                 /// <param name="area">Chart area object.</param>
1808                 /// <param name="position">Position in chart area.</param>
1809                 /// <param name="stringFormat">Axis labels string format.</param>
1810                 /// <returns>Axis labels rectangle.</returns>
1811                 private RectangleF GetAllLabelsRect(ChartArea area, AxisPosition position, StringFormat stringFormat)
1812                 {
1813                         // Find axis with same position
1814                         Axis labelsAxis = null;
1815                         foreach(Axis curAxis in area.Axes)
1816                         {
1817                                 if(curAxis.AxisPosition == position)
1818                                 {
1819                                         labelsAxis = curAxis;
1820                                         break;
1821                                 }
1822                         }
1823
1824                         if(labelsAxis == null)
1825                         {
1826                                 return RectangleF.Empty;
1827                         }
1828
1829                         // Calculate rect for different positions
1830                         RectangleF rectLabels = area.Position.ToRectangleF();
1831                         if( position == AxisPosition.Left )
1832                         {
1833                                 rectLabels.Width = labelsAxis.labelSize;
1834                                 if( labelsAxis.GetIsMarksNextToAxis() )
1835                                 {
1836                                         rectLabels.X = (float)labelsAxis.GetAxisPosition();
1837                                         rectLabels.Width = (float)Math.Max(rectLabels.Width, rectLabels.X - labelsAxis.PlotAreaPosition.X);
1838                                 }
1839                                 else
1840                                 {
1841                                         rectLabels.X = labelsAxis.PlotAreaPosition.X;
1842                                 }
1843
1844                                 rectLabels.X -= rectLabels.Width;
1845
1846                                 if(area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
1847                                 {
1848                                         rectLabels.X -= labelsAxis.markSize;
1849                                 }
1850
1851                                 // Set label text alignment
1852                                 stringFormat.Alignment = StringAlignment.Far;
1853                                 stringFormat.LineAlignment = StringAlignment.Center;
1854                         }
1855                         else if( position == AxisPosition.Right )
1856                         {
1857                                 rectLabels.Width = labelsAxis.labelSize;
1858                                 if( labelsAxis.GetIsMarksNextToAxis() )
1859                                 {
1860                                         rectLabels.X = (float)labelsAxis.GetAxisPosition();
1861                                         rectLabels.Width = (float)Math.Max(rectLabels.Width, labelsAxis.PlotAreaPosition.Right - rectLabels.X);
1862                                 }
1863                                 else
1864                                 {
1865                                         rectLabels.X = labelsAxis.PlotAreaPosition.Right;
1866                                 }
1867                                 
1868                                 if(!area.IsSideSceneWallOnLeft() || area.Area3DStyle.WallWidth == 0)
1869                                 {
1870                                         rectLabels.X += labelsAxis.markSize;
1871                                 }
1872
1873                                 // Set label text alignment
1874                                 stringFormat.Alignment = StringAlignment.Near;
1875                                 stringFormat.LineAlignment = StringAlignment.Center;
1876                         }
1877                         else if( position == AxisPosition.Top )
1878                         {
1879                                 rectLabels.Height = labelsAxis.labelSize;
1880                                 if( labelsAxis.GetIsMarksNextToAxis() )
1881                                 {
1882                                         rectLabels.Y = (float)labelsAxis.GetAxisPosition();
1883                                         rectLabels.Height = (float)Math.Max(rectLabels.Height, rectLabels.Y - labelsAxis.PlotAreaPosition.Y);
1884                                 }
1885                                 else
1886                                 {
1887                                         rectLabels.Y = labelsAxis.PlotAreaPosition.Y;
1888                                 }
1889
1890                                 rectLabels.Y -= rectLabels.Height;
1891
1892                                 if(area.Area3DStyle.WallWidth == 0)
1893                                 {
1894                                         rectLabels.Y -= labelsAxis.markSize;
1895                                 }
1896
1897                                 // Set label text alignment
1898                                 stringFormat.Alignment = StringAlignment.Center;
1899                                 stringFormat.LineAlignment = StringAlignment.Far;
1900                         }
1901                         else if( position == AxisPosition.Bottom )
1902                         {
1903                                 rectLabels.Height = labelsAxis.labelSize;
1904                                 if( labelsAxis.GetIsMarksNextToAxis() )
1905                                 {
1906                                         rectLabels.Y = (float)labelsAxis.GetAxisPosition();
1907                                         rectLabels.Height = (float)Math.Max(rectLabels.Height, labelsAxis.PlotAreaPosition.Bottom - rectLabels.Y);
1908                                 }
1909                                 else
1910                                 {
1911                                         rectLabels.Y = labelsAxis.PlotAreaPosition.Bottom;
1912                                 }
1913                                 rectLabels.Y += labelsAxis.markSize;
1914
1915                                 // Set label text alignment
1916                                 stringFormat.Alignment = StringAlignment.Center;
1917                                 stringFormat.LineAlignment = StringAlignment.Near;
1918                         }
1919
1920                         return rectLabels;
1921                 }
1922
1923         /// <summary>
1924         /// Gets position of axis labels.
1925         /// Top and Bottom axis labels can be drawn on the sides (left or right)
1926         /// of the plotting area. If angle between axis and it's projection is
1927         /// between -25 and 25 degrees the axis are drawn at the bottom/top, 
1928         /// otherwise labels are moved on the left or right side.
1929         /// </summary>
1930         /// <param name="axis">Axis object.</param>
1931         /// <returns>Position where axis labels should be drawn.</returns>
1932                 private AxisPosition GetLabelsPosition(Axis axis)
1933                 {
1934                         // Get angle between 2D axis and it's 3D projection.
1935                         double axisAngle = axis.GetAxisProjectionAngle();
1936
1937                         // Pick the side to draw the labels on
1938                         if(axis.AxisPosition == AxisPosition.Bottom)
1939                         {
1940                                 if(axisAngle <= -25 )
1941                                         return AxisPosition.Right;
1942                                 else if(axisAngle >= 25 )
1943                                         return AxisPosition.Left;
1944                         }
1945                         else if(axis.AxisPosition == AxisPosition.Top)
1946                         {
1947                                 if(axisAngle <= -25 )
1948                                         return AxisPosition.Left;
1949                                 else if(axisAngle >= 25 )
1950                                         return AxisPosition.Right;
1951                         }
1952
1953                         // Labels are on the same side as the axis
1954                         return axis.AxisPosition;
1955                 }
1956
1957                 /// <summary>
1958                 /// Draws axis labels in 3D space.
1959                 /// </summary>
1960                 /// <param name="graph">Reference to the Chart Graphics object.</param>
1961                 /// <param name="backElements">Back elements of the axis should be drawn in 3D scene.</param>
1962                 internal void Paint3D( ChartGraphics graph, bool backElements )
1963                 {
1964                         // Label string drawing format                  
1965             using (StringFormat format = new StringFormat())
1966             {
1967                 format.Trimming = StringTrimming.EllipsisCharacter;
1968
1969                 // Calculate single pixel size in relative coordinates
1970                 SizeF pixelSize = graph.GetRelativeSize(new SizeF(1f, 1f));
1971
1972                 //********************************************************************
1973                 //** Determine the side of the plotting area to draw the labels on.
1974                 //********************************************************************
1975                 AxisPosition labelsPosition = GetLabelsPosition(_axis);
1976
1977                 //*****************************************************************
1978                 //** Set the labels Z position
1979                 //*****************************************************************
1980                 bool axisOnEdge;
1981                 float labelsZPosition = _axis.GetMarksZPosition(out axisOnEdge);
1982
1983                 // Adjust Z position for the "bent" tick marks
1984                 bool adjustForWallWidth = false;
1985                 if (this._axis.AxisPosition == AxisPosition.Top &&
1986                     !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Top, backElements, false))
1987                 {
1988                     adjustForWallWidth = true;
1989                 }
1990                 if (this._axis.AxisPosition == AxisPosition.Left &&
1991                     !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Left, backElements, false))
1992                 {
1993                     adjustForWallWidth = true;
1994                 }
1995                 if (this._axis.AxisPosition == AxisPosition.Right &&
1996                     !this._axis.ChartArea.ShouldDrawOnSurface(SurfaceNames.Right, backElements, false))
1997                 {
1998                     adjustForWallWidth = true;
1999                 }
2000
2001                 if (adjustForWallWidth && this._axis.ChartArea.Area3DStyle.WallWidth > 0)
2002                 {
2003                     if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.InsideArea)
2004                     {
2005                         labelsZPosition -= this._axis.ChartArea.areaSceneWallWidth.Width;
2006                     }
2007                     else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.OutsideArea)
2008                     {
2009                         labelsZPosition -= this._axis.MajorTickMark.Size + this._axis.ChartArea.areaSceneWallWidth.Width;
2010                     }
2011                     else if (this._axis.MajorTickMark.TickMarkStyle == TickMarkStyle.AcrossAxis)
2012                     {
2013                         labelsZPosition -= this._axis.MajorTickMark.Size / 2f + this._axis.ChartArea.areaSceneWallWidth.Width;
2014                     }
2015                 }
2016
2017                 //*****************************************************************
2018                 //** Check if labels should be drawn as back or front element.
2019                 //*****************************************************************
2020                 bool labelsInsidePlotArea = (this._axis.GetIsMarksNextToAxis() && !axisOnEdge);
2021                 if (backElements == labelsInsidePlotArea)
2022                 {
2023                     // Skip drawing
2024                     return;
2025                 }
2026
2027                 //********************************************************************
2028                 //** Initialize all labels position rectangle
2029                 //********************************************************************
2030                 RectangleF rectLabels = this.GetAllLabelsRect(this._axis.ChartArea, this._axis.AxisPosition, format);
2031
2032                 //********************************************************************
2033                 //** Calculate bounding rectangle used to truncate labels on the
2034                 //** chart area boundary if TruncatedLabels property is set to true.
2035                 //********************************************************************
2036                 RectangleF boundaryRect = rectLabels;
2037                 if (boundaryRect != RectangleF.Empty && _axis.totlaGroupingLabelsSize > 0)
2038                 {
2039                     if (this._axis.AxisPosition == AxisPosition.Left)
2040                     {
2041                         boundaryRect.X += _axis.totlaGroupingLabelsSize;
2042                         boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
2043                     }
2044                     else if (this._axis.AxisPosition == AxisPosition.Right)
2045                     {
2046                         boundaryRect.Width -= _axis.totlaGroupingLabelsSize;
2047                     }
2048                     else if (this._axis.AxisPosition == AxisPosition.Top)
2049                     {
2050                         boundaryRect.Y += _axis.totlaGroupingLabelsSize;
2051                         boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
2052                     }
2053                     else if (this._axis.AxisPosition == AxisPosition.Bottom)
2054                     {
2055                         boundaryRect.Height -= _axis.totlaGroupingLabelsSize;
2056                     }
2057                 }
2058
2059                 // Pre-calculated height of the first labels row
2060                 float firstLabelsRowHeight = -1f;
2061
2062                 // For 3D axis labels the first row of labels 
2063                 // has to be drawn after all other rows because 
2064                 // of hot regions.
2065                 for (int selectionRow = 0; selectionRow <= this._axis.GetGroupLabelLevelCount(); selectionRow++)
2066                 {
2067                     //********************************************************************
2068                     //** Draw all labels from the collection
2069                     //********************************************************************
2070                     int labelIndex = 0;
2071                     foreach (CustomLabel label in this._axis.CustomLabels)
2072                     {
2073                         bool truncatedLeft = false;
2074                         bool truncatedRight = false;
2075                         double labelFrom = label.FromPosition;
2076                         double labelTo = label.ToPosition;
2077
2078                         if (label.RowIndex != selectionRow)
2079                         {
2080                             continue;
2081                         }
2082
2083                         // Skip if label middle point is outside current scaleView
2084                         if (label.RowIndex == 0)
2085                         {
2086                             double middlePoint = (label.FromPosition + label.ToPosition) / 2.0;
2087                             if ((decimal)middlePoint < (decimal)_axis.ViewMinimum ||
2088                                 (decimal)middlePoint > (decimal)_axis.ViewMaximum)
2089                             {
2090                                 continue;
2091                             }
2092                         }
2093                         else
2094                         {
2095                             // Skip labels completly outside the scaleView
2096                             if (label.ToPosition <= _axis.ViewMinimum || label.FromPosition >= _axis.ViewMaximum)
2097                             {
2098                                 continue;
2099                             }
2100
2101                             // Check if label is partially visible
2102                             if (_axis.ScaleView.IsZoomed)
2103                             {
2104                                 if (label.FromPosition < _axis.ViewMinimum)
2105                                 {
2106                                     truncatedLeft = true;
2107                                     labelFrom = _axis.ViewMinimum;
2108                                 }
2109                                 if (label.ToPosition > _axis.ViewMaximum)
2110                                 {
2111                                     truncatedRight = true;
2112                                     labelTo = _axis.ViewMaximum;
2113                                 }
2114                             }
2115                         }
2116
2117
2118                         // Calculate single label position
2119                         RectangleF rect = rectLabels;
2120
2121                         // Label is in the first row
2122                         if (label.RowIndex == 0)
2123                         {
2124                             if (this._axis.AxisPosition == AxisPosition.Left)
2125                             {
2126                                 if (!this._axis.GetIsMarksNextToAxis())
2127                                 {
2128                                     rect.X = rectLabels.Right - _axis.unRotatedLabelSize;
2129                                     rect.Width = _axis.unRotatedLabelSize;
2130                                 }
2131
2132                                 // Adjust label rectangle if offset labels are used
2133                                 if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
2134                                 {
2135                                     rect.Width /= 2F;
2136                                     if (labelIndex % 2 != 0F)
2137                                     {
2138                                         rect.X += rect.Width;
2139                                     }
2140                                 }
2141                             }
2142                             else if (this._axis.AxisPosition == AxisPosition.Right)
2143                             {
2144                                 if (!this._axis.GetIsMarksNextToAxis())
2145                                 {
2146                                     rect.Width = _axis.unRotatedLabelSize;
2147                                 }
2148
2149                                 // Adjust label rectangle if offset labels are used
2150                                 if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
2151                                 {
2152                                     rect.Width /= 2F;
2153                                     if (labelIndex % 2 != 0F)
2154                                     {
2155                                         rect.X += rect.Width;
2156                                     }
2157                                 }
2158                             }
2159                             else if (this._axis.AxisPosition == AxisPosition.Top)
2160                             {
2161                                 if (!this._axis.GetIsMarksNextToAxis())
2162                                 {
2163                                     rect.Y = rectLabels.Bottom - _axis.unRotatedLabelSize;
2164                                     rect.Height = _axis.unRotatedLabelSize;
2165                                 }
2166
2167                                 // Adjust label rectangle if offset labels are used
2168                                 if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
2169                                 {
2170                                     rect.Height /= 2F;
2171                                     if (labelIndex % 2 != 0F)
2172                                     {
2173                                         rect.Y += rect.Height;
2174                                     }
2175                                 }
2176                             }
2177                             else if (this._axis.AxisPosition == AxisPosition.Bottom)
2178                             {
2179                                 if (!this._axis.GetIsMarksNextToAxis())
2180                                 {
2181                                     rect.Height = _axis.unRotatedLabelSize;
2182                                 }
2183
2184                                 // Adjust label rectangle if offset labels are used
2185                                 if ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1))
2186                                 {
2187                                     rect.Height /= 2F;
2188                                     if (labelIndex % 2 != 0F)
2189                                     {
2190                                         rect.Y += rect.Height;
2191                                     }
2192                                 }
2193                             }
2194
2195                             // Increase label index
2196                             ++labelIndex;
2197                         }
2198
2199                             // Label is in the second row
2200                         else if (label.RowIndex > 0)
2201                         {
2202                             // Hide grouping labels (where index of row > 0) when they are displayed 
2203                             // not on the same side as their axis. Fixes MS issue #64.
2204                             if (labelsPosition != this._axis.AxisPosition)
2205                             {
2206                                 continue;
2207                             }
2208
2209                             if (_axis.AxisPosition == AxisPosition.Left)
2210                             {
2211                                 rect.X += _axis.totlaGroupingLabelsSizeAdjustment;
2212                                 for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
2213                                 {
2214                                     rect.X += _axis.groupingLabelSizes[index - 1];
2215                                 }
2216                                 rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
2217                             }
2218                             else if (_axis.AxisPosition == AxisPosition.Right)
2219                             {
2220                                 rect.X = rect.Right - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;// + Axis.elementSpacing * 0.25f;
2221                                 for (int index = 1; index < label.RowIndex; index++)
2222                                 {
2223                                     rect.X += _axis.groupingLabelSizes[index - 1];
2224                                 }
2225                                 rect.Width = _axis.groupingLabelSizes[label.RowIndex - 1];
2226                             }
2227                             else if (_axis.AxisPosition == AxisPosition.Top)
2228                             {
2229                                 rect.Y += _axis.totlaGroupingLabelsSizeAdjustment;
2230                                 for (int index = _axis.groupingLabelSizes.Length; index > label.RowIndex; index--)
2231                                 {
2232                                     rect.Y += _axis.groupingLabelSizes[index - 1];
2233                                 }
2234                                 rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
2235                             }
2236                             if (_axis.AxisPosition == AxisPosition.Bottom)
2237                             {
2238                                 rect.Y = rect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment;
2239                                 for (int index = 1; index < label.RowIndex; index++)
2240                                 {
2241                                     rect.Y += _axis.groupingLabelSizes[index - 1];
2242                                 }
2243                                 rect.Height = _axis.groupingLabelSizes[label.RowIndex - 1];
2244                             }
2245                         }
2246
2247                             // Unknown label row value
2248                         else
2249                         {
2250                             throw (new InvalidOperationException(SR.ExceptionAxisLabelRowIndexMustBe1Or2));
2251                         }
2252
2253                         //********************************************************************
2254                         //** Set label From and To coordinates.
2255                         //********************************************************************
2256                         double fromPosition = _axis.GetLinearPosition(labelFrom);
2257                         double toPosition = _axis.GetLinearPosition(labelTo);
2258                         if (this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom)
2259                         {
2260                             rect.X = (float)Math.Min(fromPosition, toPosition);
2261                             rect.Width = (float)Math.Max(fromPosition, toPosition) - rect.X;
2262                             if (rect.Width < pixelSize.Width)
2263                             {
2264                                 rect.Width = pixelSize.Width;
2265                             }
2266
2267                             // Adjust label To/From position if offset labels are used
2268                             if (label.RowIndex == 0 &&
2269                                 ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
2270                             {
2271                                 rect.X -= rect.Width / 2F;
2272                                 rect.Width *= 2F;
2273                             }
2274                         }
2275                         else
2276                         {
2277                             rect.Y = (float)Math.Min(fromPosition, toPosition);
2278                             rect.Height = (float)Math.Max(fromPosition, toPosition) - rect.Y;
2279                             if (rect.Height < pixelSize.Height)
2280                             {
2281                                 rect.Height = pixelSize.Height;
2282                             }
2283
2284                             // Adjust label To/From position if offset labels are used
2285                             if (label.RowIndex == 0 &&
2286                                 ((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
2287                             {
2288                                 rect.Y -= rect.Height / 2F;
2289                                 rect.Height *= 2F;
2290                             }
2291                         }
2292
2293                         // Save original rect
2294                         RectangleF initialRect = new RectangleF(rect.Location, rect.Size);
2295
2296                         //********************************************************************
2297                         //** Transform and adjust label rectangle coordinates in 3D space.
2298                         //********************************************************************
2299                         Point3D[] rectPoints = new Point3D[3];
2300                         if (this._axis.AxisPosition == AxisPosition.Left)
2301                         {
2302                             rectPoints[0] = new Point3D(rect.Right, rect.Y, labelsZPosition);
2303                             rectPoints[1] = new Point3D(rect.Right, rect.Y + rect.Height / 2f, labelsZPosition);
2304                             rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
2305                             this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
2306                             rect.Y = rectPoints[0].Y;
2307                             rect.Height = rectPoints[2].Y - rect.Y;
2308                             rect.Width = rectPoints[1].X - rect.X;
2309                         }
2310                         else if (this._axis.AxisPosition == AxisPosition.Right)
2311                         {
2312                             rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
2313                             rectPoints[1] = new Point3D(rect.X, rect.Y + rect.Height / 2f, labelsZPosition);
2314                             rectPoints[2] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
2315                             this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
2316                             rect.Y = rectPoints[0].Y;
2317                             rect.Height = rectPoints[2].Y - rect.Y;
2318                             rect.Width = rect.Right - rectPoints[1].X;
2319                             rect.X = rectPoints[1].X;
2320                         }
2321                         else if (this._axis.AxisPosition == AxisPosition.Top)
2322                         {
2323                             // Transform 3 points of the rectangle
2324                             rectPoints[0] = new Point3D(rect.X, rect.Bottom, labelsZPosition);
2325                             rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Bottom, labelsZPosition);
2326                             rectPoints[2] = new Point3D(rect.Right, rect.Bottom, labelsZPosition);
2327                             this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
2328
2329                             if (labelsPosition == AxisPosition.Top)
2330                             {
2331                                 rect.X = rectPoints[0].X;
2332                                 rect.Width = rectPoints[2].X - rect.X;
2333                                 rect.Height = rectPoints[1].Y - rect.Y;
2334                             }
2335                             else if (labelsPosition == AxisPosition.Right)
2336                             {
2337                                 RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
2338                                 rect.Y = rectPoints[0].Y;
2339                                 rect.Height = rectPoints[2].Y - rect.Y;
2340                                 rect.X = rectPoints[1].X;
2341                                 rect.Width = rightLabelsRect.Right - rect.X;
2342                             }
2343                             else if (labelsPosition == AxisPosition.Left)
2344                             {
2345                                 RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
2346                                 rect.Y = rectPoints[2].Y;
2347                                 rect.Height = rectPoints[0].Y - rect.Y;
2348                                 rect.X = rightLabelsRect.X;
2349                                 rect.Width = rectPoints[1].X - rightLabelsRect.X;
2350                             }
2351                         }
2352                         else if (this._axis.AxisPosition == AxisPosition.Bottom)
2353                         {
2354                             // Transform 3 points of the rectangle
2355                             rectPoints[0] = new Point3D(rect.X, rect.Y, labelsZPosition);
2356                             rectPoints[1] = new Point3D(rect.X + rect.Width / 2f, rect.Y, labelsZPosition);
2357                             rectPoints[2] = new Point3D(rect.Right, rect.Y, labelsZPosition);
2358                             this._axis.ChartArea.matrix3D.TransformPoints(rectPoints);
2359
2360                             if (labelsPosition == AxisPosition.Bottom)
2361                             {
2362                                 rect.X = rectPoints[0].X;
2363                                 rect.Width = rectPoints[2].X - rect.X;
2364                                 rect.Height = rect.Bottom - rectPoints[1].Y;
2365                                 rect.Y = rectPoints[1].Y;
2366                             }
2367                             else if (labelsPosition == AxisPosition.Right)
2368                             {
2369                                 RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
2370                                 rect.Y = rectPoints[2].Y;
2371                                 rect.Height = rectPoints[0].Y - rect.Y;
2372                                 rect.X = rectPoints[1].X;
2373                                 rect.Width = rightLabelsRect.Right - rect.X;
2374
2375                                 // Adjust label rect by shifting it down by quarter of the tick size
2376                                 if (this._axis.autoLabelAngle == 0)
2377                                 {
2378                                     rect.Y += this._axis.markSize / 4f;
2379                                 }
2380                             }
2381                             else if (labelsPosition == AxisPosition.Left)
2382                             {
2383                                 RectangleF rightLabelsRect = this.GetAllLabelsRect(this._axis.ChartArea, labelsPosition, format);
2384                                 rect.Y = rectPoints[0].Y;
2385                                 rect.Height = rectPoints[2].Y - rect.Y;
2386                                 rect.X = rightLabelsRect.X;
2387                                 rect.Width = rectPoints[1].X - rightLabelsRect.X;
2388
2389                                 // Adjust label rect by shifting it down by quarter of the tick size
2390                                 if (this._axis.autoLabelAngle == 0)
2391                                 {
2392                                     rect.Y += this._axis.markSize / 4f;
2393                                 }
2394                             }
2395                         }
2396
2397                         // Find axis with same position
2398                         Axis labelsAxis = null;
2399                         foreach (Axis curAxis in this._axis.ChartArea.Axes)
2400                         {
2401                             if (curAxis.AxisPosition == labelsPosition)
2402                             {
2403                                 labelsAxis = curAxis;
2404                                 break;
2405                             }
2406                         }
2407
2408                         //********************************************************************
2409                         //** Adjust font angles for Top and Bottom axis
2410                         //********************************************************************
2411                         int labelsFontAngle = (_axis.autoLabelAngle < -90) ? angle : _axis.autoLabelAngle;
2412                         if (labelsPosition != this._axis.AxisPosition)
2413                         {
2414                             if ((this._axis.AxisPosition == AxisPosition.Top || this._axis.AxisPosition == AxisPosition.Bottom) &&
2415                                 (labelsFontAngle == 90 || labelsFontAngle == -90))
2416                             {
2417                                 labelsFontAngle = 0;
2418                             }
2419                             else if (this._axis.AxisPosition == AxisPosition.Bottom)
2420                             {
2421                                 if (labelsPosition == AxisPosition.Left && labelsFontAngle > 0)
2422                                 {
2423                                     labelsFontAngle = -labelsFontAngle;
2424                                 }
2425                                 else if (labelsPosition == AxisPosition.Right && labelsFontAngle < 0)
2426                                 {
2427                                     labelsFontAngle = -labelsFontAngle;
2428                                 }
2429                             }
2430                             else if (this._axis.AxisPosition == AxisPosition.Top)
2431                             {
2432                                 if (labelsPosition == AxisPosition.Left && labelsFontAngle < 0)
2433                                 {
2434                                     labelsFontAngle = -labelsFontAngle;
2435                                 }
2436                                 else if (labelsPosition == AxisPosition.Right && labelsFontAngle > 0)
2437                                 {
2438                                     labelsFontAngle = -labelsFontAngle;
2439                                 }
2440                             }
2441                         }
2442
2443                         //********************************************************************
2444                         //** NOTE: Code below improves chart labels readability in scenarios 
2445                         //** described in MS issue #65.
2446                         //**
2447                         //** Prevent labels in the first row from overlapping the grouping
2448                         //** labels in the rows below. The solution only apply to the limited 
2449                         //** use cases defined by the condition below.
2450                         //********************************************************************
2451                         StringFormatFlags oldFormatFlags = format.FormatFlags; 
2452
2453                         if (label.RowIndex == 0 &&
2454                             labelsFontAngle == 0 &&
2455                             _axis.groupingLabelSizes != null &&
2456                             _axis.groupingLabelSizes.Length > 0 &&
2457                             this._axis.AxisPosition == AxisPosition.Bottom &&
2458                             labelsPosition == AxisPosition.Bottom &&
2459                             !((this._axis.autoLabelOffset == -1) ? this.IsStaggered : (this._axis.autoLabelOffset == 1)))
2460                         {
2461                             if (firstLabelsRowHeight == -1f)
2462                             {
2463                                 // Calculate first labels row max height
2464                                 Point3D[] labelPositionPoints = new Point3D[1];
2465                                 labelPositionPoints[0] = new Point3D(initialRect.X, initialRect.Bottom - _axis.totlaGroupingLabelsSize - _axis.totlaGroupingLabelsSizeAdjustment, labelsZPosition);
2466                                 this._axis.ChartArea.matrix3D.TransformPoints(labelPositionPoints);
2467
2468                                 float height = labelPositionPoints[0].Y - rect.Y;
2469
2470                                 firstLabelsRowHeight = (height > 0f) ? height : rect.Height;
2471                             }
2472
2473                             // Resuse pre-calculated first labels row height
2474                             rect.Height = firstLabelsRowHeight;
2475
2476                             // Change current string format to prevent strings to go out of the 
2477                             // specified bounding rectangle
2478                             if ((format.FormatFlags & StringFormatFlags.LineLimit) == 0)
2479                             {
2480                                 format.FormatFlags |= StringFormatFlags.LineLimit;
2481                             }
2482                         }
2483
2484
2485                         //********************************************************************
2486                         //** Draw label text.
2487                         //********************************************************************
2488
2489                         using (Brush brush = new SolidBrush((label.ForeColor.IsEmpty) ? _foreColor : label.ForeColor))
2490                         {
2491                             graph.DrawLabelStringRel(
2492                                 labelsAxis,
2493                                 label.RowIndex,
2494                                 label.LabelMark,
2495                                 label.MarkColor,
2496                                 label.Text,
2497                                 label.Image,
2498                                 label.ImageTransparentColor,
2499                                 (_axis.autoLabelFont == null) ? _font : _axis.autoLabelFont,
2500                                 brush,
2501                                 rect,
2502                                 format,
2503                                 labelsFontAngle,
2504                                 (!this.TruncatedLabels || label.RowIndex > 0) ? RectangleF.Empty : boundaryRect,
2505                                 label,
2506                                 truncatedLeft,
2507                                 truncatedRight);
2508                         }
2509
2510                         // Restore old string format that was temporary modified
2511                         if (format.FormatFlags != oldFormatFlags)
2512                         {
2513                             format.FormatFlags = oldFormatFlags;
2514                         }
2515                     }
2516                 }
2517             }
2518                 }
2519
2520                 #endregion
2521
2522                 #region Helper methods
2523
2524                 /// <summary>
2525                 /// Sets the axis to which this object attached to.
2526                 /// </summary>
2527                 /// <returns>Axis object.</returns>
2528                 internal Axis Axis
2529                 {
2530             set { _axis = value; }
2531                 }
2532
2533
2534                 /// <summary>
2535                 /// Invalidate chart picture
2536                 /// </summary>
2537                 internal override void Invalidate()
2538                 {
2539 #if Microsoft_CONTROL
2540
2541                         if(this._axis != null)
2542                         {
2543                                 this._axis.Invalidate();
2544                         }
2545 #endif
2546             base.Invalidate();
2547                 }
2548
2549                 #endregion
2550
2551                 #region Label properties
2552
2553                 /// <summary>
2554                 /// Gets or sets the interval offset of the label.
2555                 /// </summary>
2556         [
2557         SRCategory("CategoryAttributeData"),
2558         Bindable(true),
2559         SRDescription("DescriptionAttributeLabel_IntervalOffset"),
2560         DefaultValue(Double.NaN),
2561         #if !Microsoft_CONTROL
2562          PersistenceMode(PersistenceMode.Attribute),
2563         #endif
2564          RefreshPropertiesAttribute(RefreshProperties.All),
2565         TypeConverter(typeof(AxisElementIntervalValueConverter))
2566         ]
2567         public double IntervalOffset
2568         {
2569             get
2570             {
2571                 return intervalOffset;
2572             }
2573             set
2574             {
2575                 intervalOffset = value;
2576                 this.Invalidate();
2577             }
2578         }
2579
2580
2581
2582         /// <summary>
2583         /// Gets the interval offset.
2584         /// </summary>
2585         /// <returns></returns>
2586         internal double GetIntervalOffset()
2587                 {
2588                         if(double.IsNaN(intervalOffset) && this._axis != null)
2589                         {
2590                                 return this._axis.IntervalOffset;
2591                         }
2592                         return intervalOffset;
2593                 }
2594
2595                 /// <summary>
2596                 /// Gets or sets the unit of measurement of the label offset.
2597                 /// </summary>
2598                 [
2599                 SRCategory("CategoryAttributeData"),
2600                 Bindable(true),
2601                 DefaultValue(DateTimeIntervalType.NotSet),
2602                 SRDescription("DescriptionAttributeLabel_IntervalOffsetType"),
2603                 RefreshPropertiesAttribute(RefreshProperties.All),
2604                 #if !Microsoft_CONTROL
2605                 PersistenceMode(PersistenceMode.Attribute)
2606                 #endif
2607                 ]
2608         public DateTimeIntervalType IntervalOffsetType
2609         {
2610             get
2611             {
2612                 return intervalOffsetType;
2613             }
2614             set
2615             {
2616                 intervalOffsetType = value;
2617                 this.Invalidate();
2618             }
2619         }
2620
2621
2622         /// <summary>
2623         /// Gets the type of the interval offset.
2624         /// </summary>
2625         /// <returns></returns>
2626                 internal DateTimeIntervalType GetIntervalOffsetType()
2627                 {
2628                         if(intervalOffsetType == DateTimeIntervalType.NotSet && this._axis != null)
2629                         {
2630                                 return this._axis.IntervalOffsetType;
2631                         }
2632                         return intervalOffsetType;
2633                 }
2634
2635                 /// <summary>
2636                 /// Gets or sets the interval size of the label.
2637                 /// </summary>
2638                 [
2639                 SRCategory("CategoryAttributeData"),
2640                 Bindable(true),
2641                 DefaultValue(Double.NaN),
2642                 SRDescription("DescriptionAttributeLabel_Interval"),
2643         TypeConverter(typeof(AxisElementIntervalValueConverter)),
2644                 #if !Microsoft_CONTROL
2645                 PersistenceMode(PersistenceMode.Attribute),
2646                 #endif
2647                 ]
2648         public double Interval
2649         {
2650             get
2651             {
2652                 return interval;
2653             }
2654             set
2655             {
2656                 interval = value;
2657
2658                 // Reset original property value fields
2659                 if (this._axis != null)
2660                 {
2661                     this._axis.tempLabelInterval = interval;
2662                 }
2663
2664                 this.Invalidate();
2665             }
2666         }
2667
2668
2669         /// <summary>
2670         /// Gets the interval.
2671         /// </summary>
2672         /// <returns></returns>
2673                 internal double GetInterval()
2674                 {
2675                                 if(double.IsNaN(interval) && this._axis != null)
2676                                 {
2677                                         return this._axis.Interval;
2678                                 }
2679                                 return interval;
2680                 }
2681
2682                 /// <summary>
2683         /// Gets or sets the unit of measurement of the interval size of the label.
2684                 /// </summary>
2685                 [
2686                 SRCategory("CategoryAttributeData"),
2687                 Bindable(true),
2688                 DefaultValue(DateTimeIntervalType.NotSet),
2689                 SRDescription("DescriptionAttributeLabel_IntervalType"),
2690                 RefreshPropertiesAttribute(RefreshProperties.All),
2691                 #if !Microsoft_CONTROL
2692                 PersistenceMode(PersistenceMode.Attribute)
2693                 #endif
2694                 ]
2695         public DateTimeIntervalType IntervalType
2696         {
2697             get
2698             {
2699                 return intervalType;
2700             }
2701             set
2702             {
2703                 intervalType = value;
2704
2705                 // Reset original property value fields
2706                 if (this._axis != null)
2707                 {
2708                     this._axis.tempLabelIntervalType = intervalType;
2709                 }
2710
2711                 this.Invalidate();
2712             }
2713         }
2714
2715
2716         /// <summary>
2717         /// Gets the type of the interval.
2718         /// </summary>
2719         /// <returns></returns>
2720                 internal DateTimeIntervalType GetIntervalType()
2721                 {
2722                         if(intervalType == DateTimeIntervalType.NotSet && this._axis != null)
2723                         {
2724                                 return this._axis.IntervalType;
2725                         }
2726                         return intervalType;
2727                 }
2728
2729                 /// <summary>
2730         /// Gets or sets the font of the label.
2731                 /// </summary>
2732                 [
2733                 SRCategory("CategoryAttributeAppearance"),
2734                 Bindable(true),
2735                 DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
2736                 SRDescription("DescriptionAttributeLabel_Font"),
2737                 #if !Microsoft_CONTROL
2738                 PersistenceMode(PersistenceMode.Attribute)
2739                 #endif
2740                 ]
2741                 public Font Font
2742                 {
2743                         get
2744                         {
2745                                 return _font;
2746                         }
2747                         set
2748                         {
2749                                 // Turn off labels autofitting 
2750                 if (this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
2751                                 {
2752                                         if(!this._axis.Common.Chart.serializing)
2753                                         {
2754                                                 this._axis.IsLabelAutoFit = false;
2755                                         }
2756                                 }
2757
2758                                 _font = value;
2759                                 this.Invalidate();
2760                         }
2761                 }
2762
2763                 /// <summary>
2764         /// Gets or sets the fore color of the label.
2765                 /// </summary>
2766                 [
2767                 SRCategory("CategoryAttributeAppearance"),
2768                 Bindable(true),
2769                 DefaultValue(typeof(Color), "Black"),
2770         SRDescription("DescriptionAttributeFontColor"),
2771                 NotifyParentPropertyAttribute(true),
2772         TypeConverter(typeof(ColorConverter)),
2773         Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base),
2774                 #if !Microsoft_CONTROL
2775                 PersistenceMode(PersistenceMode.Attribute)
2776                 #endif
2777                 ]
2778                 public Color ForeColor
2779                 {
2780                         get
2781                         {
2782                                 return _foreColor;
2783                         }
2784                         set
2785                         {
2786                                 _foreColor = value;
2787                                 this.Invalidate();
2788                         }
2789                 }
2790
2791                 /// <summary>
2792         /// Gets or sets a value that represents the angle at which font is drawn.
2793                 /// </summary>
2794                 [
2795                 SRCategory("CategoryAttributeAppearance"),
2796                 Bindable(true),
2797                 DefaultValue(0),
2798                 SRDescription("DescriptionAttributeLabel_FontAngle"),
2799                 #if !Microsoft_CONTROL
2800                 PersistenceMode(PersistenceMode.Attribute),
2801                 #endif
2802                 RefreshPropertiesAttribute(RefreshProperties.All)
2803                 ]
2804                 public int Angle
2805                 {
2806                         get
2807                         {
2808                                 return angle;
2809                         }
2810                         set
2811                         {
2812                                 if(value < -90 || value > 90)
2813                                 {
2814                     throw (new ArgumentOutOfRangeException("value", SR.ExceptionAxisLabelFontAngleInvalid));
2815                                 }
2816                                 
2817                                 // Turn of label offset if angle is not 0, 90 or -90
2818                                 if(IsStaggered && value != 0 && value != -90 && value != 90)
2819                                 {
2820                                         IsStaggered = false;
2821                                 }
2822
2823                                 // Turn off labels autofitting 
2824                                 if(this._axis != null && this._axis.Common!=null && this._axis.Common.Chart != null)
2825                                 {
2826                     if (!this._axis.Common.Chart.serializing)
2827                                         {
2828                                                 this._axis.IsLabelAutoFit = false;
2829                                         }
2830                                 }
2831
2832                                 angle = value;
2833                                 this.Invalidate();
2834                         }
2835                 }
2836
2837                 /// <summary>
2838                 /// Gets or sets a property which specifies whether the labels are shown with offset.
2839                 /// </summary>
2840                 [
2841                 SRCategory("CategoryAttributeAppearance"),
2842                 Bindable(true),
2843                 DefaultValue(false),
2844                 SRDescription("DescriptionAttributeLabel_OffsetLabels"),
2845                 #if !Microsoft_CONTROL
2846                 PersistenceMode(PersistenceMode.Attribute),
2847                 #endif
2848                 RefreshPropertiesAttribute(RefreshProperties.All)
2849                 ]
2850                 public bool IsStaggered
2851                 {
2852                         get
2853                         {
2854                                 return isStaggered;
2855                         }
2856                         set
2857                         {
2858                                 // Make sure that angle is 0, 90 or -90
2859                                 if(value && (this.Angle != 0 || this.Angle != -90 || this.Angle != 90))
2860                                 {
2861                                         this.Angle = 0;
2862                                 }
2863
2864                                 // Turn off labels autofitting 
2865                 if (this._axis != null && this._axis.Common != null && this._axis.Common.Chart != null)
2866                 {
2867                     if (!this._axis.Common.Chart.serializing)
2868                     {
2869                         this._axis.IsLabelAutoFit = false;
2870                                         }
2871                                 }
2872
2873                                 isStaggered = value;
2874
2875                                 this.Invalidate();
2876                         }
2877                 }
2878
2879                 /// <summary>
2880                 /// Gets or sets a property which specifies whether the labels are shown at axis ends.
2881                 /// </summary>
2882                 [
2883         SRCategory("CategoryAttributeAppearance"),
2884                 Bindable(true),
2885                 DefaultValue(true),
2886                 SRDescription("DescriptionAttributeLabel_ShowEndLabels"),
2887                 #if !Microsoft_CONTROL
2888                 PersistenceMode(PersistenceMode.Attribute)
2889                 #endif
2890                 ]
2891                 public bool IsEndLabelVisible
2892                 {
2893                         get
2894                         {
2895                                 return _isEndLabelVisible;
2896                         }
2897                         set
2898                         {
2899                                 _isEndLabelVisible = value;
2900                                 this.Invalidate();
2901                         }
2902                 }
2903
2904                 /// <summary>
2905         /// Gets or sets a property which specifies whether the label can be truncated.
2906                 /// </summary>
2907                 [
2908                 SRCategory("CategoryAttributeAppearance"),
2909                 Bindable(true),
2910                 DefaultValue(false),
2911                 SRDescription("DescriptionAttributeLabel_TruncatedLabels"),
2912                 #if !Microsoft_CONTROL
2913                 PersistenceMode(PersistenceMode.Attribute)
2914                 #endif
2915                 ]
2916                 public bool TruncatedLabels
2917                 {
2918                         get
2919                         {
2920                                 return _truncatedLabels;
2921                         }
2922                         set
2923                         {
2924                                 _truncatedLabels = value;
2925                                 this.Invalidate();
2926                         }
2927                 }
2928
2929                 /// <summary>
2930                 /// Gets or sets the formatting string for the label text.
2931                 /// </summary>
2932                 [
2933         SRCategory("CategoryAttributeAppearance"),
2934                 Bindable(true),
2935                 DefaultValue(""),
2936                 SRDescription("DescriptionAttributeLabel_Format"),
2937                 #if !Microsoft_CONTROL
2938                 PersistenceMode(PersistenceMode.Attribute),
2939                 #endif
2940                 ]
2941                 public string Format
2942                 {
2943                         get
2944                         {
2945                                 return _format;
2946                         }
2947                         set
2948                         {
2949                                 _format = value;
2950                                 this.Invalidate();
2951                         }
2952                 }
2953
2954                 /// <summary>
2955                 /// Gets or sets a property which indicates whether the label is enabled.
2956                 /// </summary>
2957                 [
2958                 SRCategory("CategoryAttributeAppearance"),
2959                 Bindable(true),
2960                 DefaultValue(true),
2961                 SRDescription("DescriptionAttributeLabel_Enabled"),
2962                 #if !Microsoft_CONTROL
2963                 PersistenceMode(PersistenceMode.Attribute)
2964                 #endif
2965                 ]
2966                 public bool Enabled
2967                 {
2968                         get
2969                         {
2970                 return _enabled;
2971                         }
2972                         set
2973                         {
2974                 _enabled = value;
2975                                 this.Invalidate();
2976                         }
2977                 }
2978                 #endregion
2979
2980         #region IDisposable Members
2981
2982         /// <summary>
2983         /// Releases unmanaged and - optionally - managed resources
2984         /// </summary>
2985         /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
2986         protected override void Dispose(bool disposing)
2987         {
2988             if (disposing)
2989             {
2990                 //Free managed resources
2991                 if (_fontCache!=null)
2992                 {
2993                     _fontCache.Dispose();
2994                     _fontCache = null;
2995                 }
2996             }
2997         }
2998
2999         #endregion
3000
3001         }
3002 }