File: Common\Annotation\AnnotationBase.cs
Project: ndp\fx\src\DataVisualization\System.Web.DataVisualization.csproj (System.Web.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		Annotation.cs
//
//  Namespace:	System.Web.UI.WebControls[Windows.Forms].Charting
//
//	Classes:	Annotation, AnnotationPositionChangingEventArgs
//
//  Purpose:	Base class for all anotation objects. Provides 
//				basic set of properties and methods.
//
//	Reviewed:	
//
//===================================================================
 
#region Used namespace
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Globalization;
using System.Data;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
 
#if Microsoft_CONTROL
using System.ComponentModel.Design.Serialization;
using System.Reflection;
using System.Windows.Forms;
	using System.Windows.Forms.DataVisualization.Charting;
	using System.Windows.Forms.DataVisualization.Charting.Data;
	using System.Windows.Forms.DataVisualization.Charting.ChartTypes;
	using System.Windows.Forms.DataVisualization.Charting.Utilities;
	using System.Windows.Forms.DataVisualization.Charting.Borders3D;
#else
using System.Web;
using System.Web.UI;
using System.Web.UI.DataVisualization.Charting;
using System.Web.UI.DataVisualization.Charting.Data;
using System.Web.UI.DataVisualization.Charting.Utilities;
#endif
#endregion
 
#if Microsoft_CONTROL
	namespace System.Windows.Forms.DataVisualization.Charting
#else
namespace System.Web.UI.DataVisualization.Charting
 
#endif
{
	#region Enumerations
 
	/// <summary>
	/// Annotation object selection points style.
	/// </summary>
	/// <remarks>
	/// Enumeration is for internal use only and should not be part of the documentation.
	/// </remarks>
	internal enum SelectionPointsStyle
	{
		/// <summary>
		/// Selection points are displayed top left and bottom right corners
		/// </summary>
		TwoPoints,
 
		/// <summary>
		/// Selection points are displayed on all sides and corners of the rectangle.
		/// </summary>
		Rectangle,
	}
 
	/// <summary>
	/// Annotation object resizing\moving mode.
	/// </summary>
	/// <remarks>
	/// Enumeration is for internal use only and should not be part of the documentation.
	/// </remarks>
	internal enum ResizingMode
	{
		/// <summary>
		/// Top Left selection handle is used.
		/// </summary>
		TopLeftHandle = 0,
		/// <summary>
		/// Top selection handle is used.
		/// </summary>
		TopHandle = 1,
		/// <summary>
		/// Top Right selection handle is used.
		/// </summary>
		TopRightHandle = 2,
		/// <summary>
		/// Right selection handle is used.
		/// </summary>
		RightHandle = 3,
		/// <summary>
		/// Bottom Right selection handle is used.
		/// </summary>
		BottomRightHandle = 4,
		/// <summary>
		/// Bottom selection handle is used.
		/// </summary>
		BottomHandle = 5,
		/// <summary>
		/// Bottom Left selection handle is used.
		/// </summary>
		BottomLeftHandle = 6,
		/// <summary>
		/// Left selection handle is used.
		/// </summary>
		LeftHandle = 7,
		/// <summary>
		/// Anchor selection handle is used.
		/// </summary>
		AnchorHandle = 8,
		/// <summary>
		/// No selection handles used - moving mode.
		/// </summary>
		Moving = 16,
		/// <summary>
		/// Moving points of the annotation path.
		/// </summary>
		MovingPathPoints = 32,
		/// <summary>
		/// No moving or resizing.
		/// </summary>
		None = 64,
	}
 
#endregion
 
	/// <summary>
	/// <b>Annotation</b> is an abstract class that defines properties and methods 
	/// common to all annotations.
	/// </summary>
	/// <remarks>
	/// All annotations are derived from the <b>Annotation</b> class, which can be 
	/// used to set properties common to all annotation objects (e.g. color, position, 
	/// anchoring and others). 
	/// </remarks>
	[
	SRDescription("DescriptionAttributeAnnotation_Annotation"),
	DefaultProperty("Name"),
	]
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
#if !Microsoft_CONTROL
    public abstract class Annotation : ChartNamedElement, IChartMapArea
#else
    public abstract class Annotation : ChartNamedElement
#endif
	{
        #region Fields
 
 
		// Name of the chart area the annotation is clipped to
		private		string					_clipToChartArea = Constants.NotSetValue;
 
		// Indicates that annotation is selected
		private		bool					_isSelected = false;
 
		// Indicates that annotation size is defined in relative chart coordinates
		private		bool					_isSizeAlwaysRelative = true;
		
		// Position attribute fields
		private		double					_x = double.NaN;
		private		double					_y = double.NaN;
		private		double					_width = double.NaN;
		private		double					_height = double.NaN;
 
		// Annotation axes attaching fields
		private		string					_axisXName = String.Empty;
		private		string					_axisYName = String.Empty;
		private		Axis					_axisX = null;
		private		Axis					_axisY = null;
 
		// Visual attribute fields
		private		bool					_visible = true;
		private		ContentAlignment		_alignment = ContentAlignment.MiddleCenter;
		private		Color					_foreColor = Color.Black;
        private     FontCache               _fontCache = new FontCache();
        private     Font                    _textFont;
        private     TextStyle               _textStyle = TextStyle.Default;
		internal    Color					lineColor = Color.Black;
		private		int						_lineWidth = 1;
		private		ChartDashStyle			_lineDashStyle = ChartDashStyle.Solid;
		private		Color					_backColor = Color.Empty;
		private		ChartHatchStyle			_backHatchStyle = ChartHatchStyle.None;
		private		GradientStyle			_backGradientStyle = GradientStyle.None;
		private		Color					_backSecondaryColor = Color.Empty;
		private		Color					_shadowColor = Color.FromArgb(128, 0, 0, 0);
		private		int						_shadowOffset = 0;
 
		// Anchor position attribute fields
		private		string					_anchorDataPointName = String.Empty;
		private		DataPoint				_anchorDataPoint = null;
		private		DataPoint				_anchorDataPoint2 = null;
		private		double					_anchorX = double.NaN;
		private		double					_anchorY = double.NaN;
		internal	double					anchorOffsetX = 0.0;
        internal    double                  anchorOffsetY = 0.0;
        internal    ContentAlignment        anchorAlignment = ContentAlignment.BottomCenter;
 
		// Selection handles position (starting top-left and moving clockwise)
		internal	RectangleF[]			selectionRects = null;
 
		// Annotation tooltip
		private		string					_tooltip = String.Empty;
 
		// Selection handles size
		internal const int					selectionMarkerSize = 6;
 
		// Pre calculated relative position of annotation and anchor point
		internal	RectangleF				currentPositionRel = new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
		internal	PointF					currentAnchorLocationRel = new PointF(float.NaN, float.NaN);
 
		// Smart labels style		
		private		AnnotationSmartLabelStyle	_smartLabelStyle = null;
 
		// Index of last selected point in the annotation path
		internal	int						currentPathPointIndex = -1;
 
		// Group this annotation belongs too
		internal	AnnotationGroup			annotationGroup = null;
 
#if Microsoft_CONTROL

		// Selection and editing permissions
        private     bool                    _allowSelecting = false;
        private     bool                    _allowMoving = false;
        private     bool                    _allowAnchorMoving = false;
        private     bool                    _allowResizing = false;
        private     bool                    _allowTextEditing = false;
        private     bool                    _allowPathEditing = false;
 
#endif //Microsoft_CONTROL
 
#if Microsoft_CONTROL

		// Indicates that annotation position was changed. Flag used to fire events.
		internal	bool					positionChanged = false;
 
		// Relative location of last placement position
		internal	PointF					lastPlacementPosition = PointF.Empty;
 
		// Relative location of annotation anchor, when it's started to move
		internal	PointF					startMoveAnchorLocationRel = PointF.Empty;
 
#endif // Microsoft_CONTROL
 
        // Relative position of annotation, when it's started to move/resize
		internal	RectangleF				startMovePositionRel = RectangleF.Empty;
 
		// Relative position of annotation, when it's started to move/resize
		internal	GraphicsPath			startMovePathRel = null;
 
#if !Microsoft_CONTROL
 
		// Annotation map area attributes
		private		string					_url = String.Empty;
		private		string					_mapAreaAttributes = String.Empty;
        private     string                  _postbackValue = String.Empty;
 
#endif	// !Microsoft_CONTROL
 
        /// <summary>
        /// Limit of annotation width and height.
        /// </summary>
        internal static  double             WidthHightLimit = 290000000;
 
		#endregion
 
		#region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="Annotation"/> class.
        /// </summary>
        protected Annotation() 
        {
            _textFont = _fontCache.DefaultFont;
        } 
 
		#endregion
 
		#region Properties
 
		#region Miscellaneous
        
		/// <summary>
		/// Gets or sets an annotation's unique name.
		/// </summary>
		/// <value>
		/// A <b>string</b> that represents an annotation's unique name.
		/// </value>
		[
		SRCategory("CategoryAttributeMisc"),
		Bindable(true),
		SRDescription("DescriptionAttributeName4"),
		ParenthesizePropertyNameAttribute(true),
		]
		public override string Name
		{
			get
			{
				return base.Name;
			}
			set
			{
                base.Name = value;
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation's type name.
		/// </summary>
		/// <remarks>
		/// This property is used to get the name of each annotation Style
		/// (e.g. Line, Rectangle, Ellipse). 
		/// <para>
		/// This property is for internal use and is hidden at design and run time.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeMisc"),
		Bindable(true),
		Browsable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		SRDescription("DescriptionAttributeAnnotation_AnnotationType"),
		]
		public abstract string AnnotationType
		{
			get;
		}
 
 
		/// <summary>
		/// Gets or sets the name of the chart area which an annotation is clipped to.
		/// </summary>
		/// <value>
		/// A string which represents the name of an existing chart area.
		/// </value>
		/// <remarks>
		/// If the chart area name is specified, an annotation will only be drawn inside the 
		/// plotting area of the chart area specified.  All parts of the annotation 
		/// outside of the plotting area will be clipped.
		/// <para>
		/// To disable chart area clipping, set the property to "NotSet" or an empty string.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeMisc"),
        DefaultValue(Constants.NotSetValue),
		SRDescription("DescriptionAttributeAnnotationClipToChartArea"),
        TypeConverter(typeof(LegendAreaNameConverter))
		]
		virtual public string ClipToChartArea
		{
			get
			{
				return _clipToChartArea;
			}
			set
			{
                if (value != _clipToChartArea)
                {
                    if (String.IsNullOrEmpty(value))
                    {
                        _clipToChartArea = Constants.NotSetValue;
                    }
                    else
                    {
                        if (Chart != null && Chart.ChartAreas != null)
                        {
                            Chart.ChartAreas.VerifyNameReference(value);
                        }
                        _clipToChartArea = value;
                    }
                    this.Invalidate();
                }
			}
		}
 
 
		/// <summary>
		/// Gets or sets the smart labels style of an annotation.
		/// </summary>
		/// <value>
		/// An <see cref="AnnotationSmartLabelStyle"/> object that represents an annotation's 
		/// smart labels style properties.
		/// </value>
		/// <remarks>
		/// Smart labels are used to prevent an annotation from overlapping data point labels 
		/// and other annotations.
		/// <para>
		/// Note that data point labels must also have smart labels enabled.
		/// </para>
		/// </remarks>
		[
		Browsable(true),
		SRCategory("CategoryAttributeMisc"),
		Bindable(true),
		SRDescription("DescriptionAttributeSmartLabels"),
#if Microsoft_CONTROL
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 
#else
		PersistenceMode(PersistenceMode.InnerProperty),
#endif
		]
		public AnnotationSmartLabelStyle SmartLabelStyle
		{
			get
			{
                if (this._smartLabelStyle == null)
                {
                    this._smartLabelStyle = new AnnotationSmartLabelStyle(this);
                }
                return _smartLabelStyle;
			}
			set
			{
				value.chartElement = this;
				_smartLabelStyle = value;
				this.Invalidate();
			}
		}
 
        /// <summary>
        /// Gets the group, if any, the annotation belongs to.
        /// </summary>
        [
        Browsable(false),
        DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
        SerializationVisibilityAttribute(SerializationVisibility.Hidden),
        ]
        public AnnotationGroup AnnotationGroup
        {
            get { return this.annotationGroup; }
        }
 
		#endregion
 
		#region Position
 
		/// <summary>
		/// Gets or sets a flag that specifies whether the size of an annotation is always 
		/// defined in relative chart coordinates.
		/// <seealso cref="Width"/>
		/// <seealso cref="Height"/>
		/// </summary>
		/// <value>
		/// <b>True</b> if an annotation's <see cref="Width"/> and <see cref="Height"/> are always 
		/// in chart relative coordinates, <b>false</b> otherwise.
		/// </value>
		/// <remarks>
		/// An annotation's width and height may be set in relative chart or axes coordinates. 
		/// By default, relative chart coordinates are used.
		/// <para>
		/// To use axes coordinates for size set the <b>IsSizeAlwaysRelative</b> property to 
		/// <b>false</b> and either anchor the annotation to a data point or set the 
		/// <see cref="AxisX"/> or <see cref="AxisY"/> properties.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributePosition"),
		DefaultValue(true),
		SRDescription("DescriptionAttributeSizeAlwaysRelative"),
		]
		virtual public bool IsSizeAlwaysRelative
		{
			get
			{
				return _isSizeAlwaysRelative;
			}
			set
			{
				_isSizeAlwaysRelative = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the X coordinate of an annotation.
		/// <seealso cref="AnchorDataPoint"/>
		/// <seealso cref="AnchorX"/>
		/// </summary>
		/// <value>
        /// A Double value that represents the X coordinate of an annotation.
		/// </value>
		/// <remarks>
		/// The X coordinate of an annotation is in relative chart coordinates or axes coordinates. Chart 
		/// relative coordinates are used by default.
		/// <para>
		/// To use axes coordinates, anchor 
		/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or 
		/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties.
		/// </para>
		/// <para>
		/// Set the X position to Double.NaN ("NotSet") to achieve automatic position calculation 
		/// when the annotation is anchored using the <see cref="AnchorDataPoint"/> property or 
		/// the <see cref="AnchorX"/> and <see cref="AnchorY"/> properties.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributePosition"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeAnnotationBaseX"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "X")]
        virtual public double X
		{
			get
			{
				return _x;
			}
			set
			{
				_x = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the Y coordinate of an annotation.
		/// <seealso cref="AnchorDataPoint"/>
		/// <seealso cref="AnchorY"/>
		/// </summary>
		/// <value>
        /// A Double value that represents the Y coordinate of an annotation.
		/// </value>
		/// <remarks>
		/// The Y coordinate of an annotation is in relative chart coordinates or axes coordinates. Chart 
		/// relative coordinates are used by default.
		/// <para>
		/// To use axes coordinates, anchor 
		/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or 
		/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties.
		/// </para>
		/// <para>
		/// Set the Y position to Double.NaN ("NotSet") to achieve automatic position calculation 
		/// when the annotation is anchored using the <see cref="AnchorDataPoint"/> property or 
		/// the <see cref="AnchorX"/> and <see cref="AnchorY"/> properties.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributePosition"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeAnnotationBaseY"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
        [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Y")]
		virtual public double Y
		{
			get
			{
				return _y;
			}
			set
			{
				_y = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation's width.
		/// <seealso cref="IsSizeAlwaysRelative"/>
		/// <seealso cref="AxisX"/>
		/// </summary>
		/// <value>
        /// A Double value that represents an annotation's width.
		/// </value>
		/// <remarks>
		/// An annotation's width can be a negative value, in which case the annotation orientation 
		/// is switched.
		/// <para>
		/// Annotation width can be in relative chart or axes coordinates. Chart 
		/// relative coordinates are used by default.
		/// </para>
		/// <para>
		/// To use axes coordinates, anchor 
		/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or 
		/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties 
		/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
		/// </para>
		/// <para>
		/// Set the width to Double.NaN ("NotSet") to achieve automatic size calculation for 
		/// annotations with text. The size will automatically be calculated based on 
		/// the annotation text and font size.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributePosition"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeAnnotationWidth"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
		virtual public double Width
		{
			get
			{
				return _width;
			}
			set
			{
                if (value < -WidthHightLimit || value > WidthHightLimit)
                {
                    throw new ArgumentException(SR.ExceptionValueMustBeInRange("Width", (-WidthHightLimit).ToString(CultureInfo.CurrentCulture), WidthHightLimit.ToString(CultureInfo.CurrentCulture)));
                }
                _width = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation's height.
		/// <seealso cref="IsSizeAlwaysRelative"/>
		/// <seealso cref="AxisY"/>
		/// </summary>
		/// <value>
		/// A Double value that represents an annotation's height.
		/// </value>
		/// <remarks>
		/// An annotation's height can be a negative value, in which case the annotation orientation 
		/// is switched.
		/// <para>
		/// Annotation height can be in relative chart or axes coordinates. Chart 
		/// relative coordinates are used by default.
		/// </para>
		/// <para>
		/// To use axes coordinates, anchor 
		/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or 
		/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties 
		/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
		/// </para>
		/// <para>
		/// Set the height to Double.NaN ("NotSet") to achieve automatic size calculation for 
		/// annotations with text. The size will automatically be calculated based on 
		/// the annotation text and font size.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributePosition"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeAnnotationHeight"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
		virtual public double Height
		{
			get
			{
				return _height;
			}
			set
			{
                if (value < -WidthHightLimit || value > WidthHightLimit)
                {
                    throw new ArgumentException(SR.ExceptionValueMustBeInRange("Height", (-WidthHightLimit).ToString(CultureInfo.CurrentCulture), WidthHightLimit.ToString(CultureInfo.CurrentCulture)));
                }
                _height = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation position's right boundary.
		/// <seealso cref="IsSizeAlwaysRelative"/>
		/// <seealso cref="AxisX"/>
		/// </summary>
		/// <value>
		/// A Double value that represents the position of an annotation's right boundary.
		/// </value>
		/// <remarks>
		/// To use axes coordinates, anchor 
		/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or 
		/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties 
		/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
		/// </remarks>
		[
		SRCategory("CategoryAttributePosition"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeRight3"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		Browsable(false),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
		virtual public double Right
		{
			get
			{
				return _x + _width;
			}
			set
			{
				_width = value - _x;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation position's bottom boundary.
		/// <seealso cref="IsSizeAlwaysRelative"/>
		/// <seealso cref="AxisX"/>
		/// </summary>
		/// <value>
		/// A Double value that represents the position of an annotation's bottom boundary.
		/// </value>
		/// <remarks>
		/// To use axes coordinates, anchor 
		/// an annotation to a data point using the <see cref="AnchorDataPoint"/> property, or 
		/// set the annotation axes using the <see cref="AxisX"/> or <see cref="AxisY"/> properties 
		/// and set the <see cref="IsSizeAlwaysRelative"/> property to <b>false</b>.
		/// </remarks>
		[
		SRCategory("CategoryAttributePosition"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeBottom"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		Browsable(false),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
		virtual public double Bottom
		{
			get
			{
				return _y + _height;
			}
			set
			{
				_height = value - _y;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		#endregion
 
		#region Visual Attributes
 
#if Microsoft_CONTROL
        /// <summary>
		/// Gets or sets a flag that determines if an annotation is selected.
		/// <seealso cref="AllowSelecting"/>
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation is selected, <b>false</b> otherwise.
		/// </value>
#else
        /// <summary>
		/// Gets or sets a flag that determines if an annotation is selected.
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation is selected, <b>false</b> otherwise.
		/// </value>
#endif // Microsoft_CONTROL
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(false),
		Browsable(false),
		SRDescription("DescriptionAttributeSelected"),
		]
		virtual public bool IsSelected
		{
			get
			{
				return _isSelected;
			}
			set
			{
				_isSelected = value;
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation selection points style.
		/// </summary>
		/// <value>
		/// A <see cref="SelectionPointsStyle"/> value that represents annotation
		/// selection style.
		/// </value>
		/// <remarks>
        /// This property is for internal use and is hidden at design and run time.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(SelectionPointsStyle.Rectangle),
		ParenthesizePropertyNameAttribute(true),
		Browsable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		SRDescription("DescriptionAttributeSelectionPointsStyle"),
		]
		virtual internal SelectionPointsStyle SelectionPointsStyle
		{
			get
			{
				return SelectionPointsStyle.Rectangle;
			}
		}
 
		/// <summary>
		/// Gets or sets a flag that specifies whether an annotation is visible.
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation is visible, <b>false</b> otherwise.
		/// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(true),
		SRDescription("DescriptionAttributeVisible"),
		ParenthesizePropertyNameAttribute(true),
		]
		virtual public bool Visible
		{
			get
			{
				return _visible;
			}
			set
			{
				_visible = value;
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation's content alignment.
		/// </summary>
		/// <value>
		/// A <see cref="ContentAlignment"/> value that represents the content alignment.
		/// </value>
		/// <remarks>
		/// This property is used to align text for <see cref="TextAnnotation"/>, <see cref="RectangleAnnotation"/>,  
		/// <see cref="EllipseAnnotation"/> and <see cref="CalloutAnnotation"/> objects, and to align 
		/// a non-scaled image inside an <see cref="ImageAnnotation"/> object.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(ContentAlignment), "MiddleCenter"),
		SRDescription("DescriptionAttributeAlignment"),
		]
		virtual public ContentAlignment Alignment
		{
			get
			{
				return _alignment;
			}
			set
			{
				_alignment = value;
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the text color of an annotation.
		/// <seealso cref="Font"/>
		/// </summary>
		/// <value>
		/// A <see cref="Color"/> value used for the text color of an annotation.
		/// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Color), "Black"),
        SRDescription("DescriptionAttributeForeColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
		]
		virtual public Color ForeColor
		{
			get
			{
				return _foreColor;
			}
			set
			{
				_foreColor = value;
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the font of an annotation's text.
		/// <seealso cref="ForeColor"/>
		/// </summary>
		/// <value>
		/// A <see cref="Font"/> object used for an annotation's text.
		/// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Font), "Microsoft Sans Serif, 8pt"),
		SRDescription("DescriptionAttributeTextFont"),
		]
		virtual public Font Font
		{
			get
			{
				return _textFont;
			}
			set
			{
				_textFont = value;
				this.Invalidate(); 
			}
		}
 
        /// <summary>
        /// Gets or sets an annotation's text style.
        /// <seealso cref="Font"/>
        /// <seealso cref="ForeColor"/>
        /// </summary>
        /// <value>
        /// A <see cref="TextStyle"/> value used to draw an annotation's text.
        /// </value>
        [
        SRCategory("CategoryAttributeAppearance"),
        DefaultValue(typeof(TextStyle), "Default"),
        SRDescription("DescriptionAttributeTextStyle"),
        ]
        virtual public TextStyle TextStyle
        {
            get
            {
                return _textStyle;
            }
            set
            {
                _textStyle = value;
                Invalidate();
            }
        }
 
        /// <summary>
        /// Gets or sets the color of an annotation line.
        /// <seealso cref="LineWidth"/>
        /// <seealso cref="LineDashStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> value used to draw an annotation line.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Color), "Black"),
        SRDescription("DescriptionAttributeLineColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
		]
		virtual public Color LineColor
		{
			get
			{
				return lineColor;
			}
			set
			{
				lineColor = value;
				Invalidate();
			}
		}
 
        /// <summary>
        /// Gets or sets the width of an annotation line.
        /// <seealso cref="LineColor"/>
        /// <seealso cref="LineDashStyle"/>
        /// </summary>
        /// <value>
        /// An integer value defining the width of an annotation line in pixels.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(1),
        SRDescription("DescriptionAttributeLineWidth"),
		]
		virtual public int LineWidth
		{
			get
			{
				return _lineWidth;
			}
			set
			{
				if(value < 0)
				{
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationLineWidthIsNegative));
				}
				_lineWidth = value;
				Invalidate();
			}
		}
 
        /// <summary>
        /// Gets or sets the style of an annotation line.
        /// <seealso cref="LineWidth"/>
        /// <seealso cref="LineColor"/>
        /// </summary>
        /// <value>
        /// A <see cref="ChartDashStyle"/> value used to draw an annotation line.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(ChartDashStyle.Solid),
        SRDescription("DescriptionAttributeLineDashStyle"),
		]
		virtual public ChartDashStyle LineDashStyle
		{
			get
			{
				return _lineDashStyle;
			}
			set
			{
				_lineDashStyle = value;
				Invalidate();
			}
		}
 
        /// <summary>
        /// Gets or sets the background color of an annotation.
        /// <seealso cref="BackSecondaryColor"/>
        /// <seealso cref="BackHatchStyle"/>
        /// <seealso cref="BackGradientStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> value used for the background of an annotation.
        /// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Color), ""),
        SRDescription("DescriptionAttributeBackColor"),
		NotifyParentPropertyAttribute(true),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
		]
		virtual public Color BackColor
		{
			get
			{
				return _backColor;
			}
			set
			{
				_backColor = value;
				Invalidate();
			}
		}
 
        /// <summary>
        /// Gets or sets the background hatch style of an annotation.
        /// <seealso cref="BackSecondaryColor"/>
        /// <seealso cref="BackColor"/>
        /// <seealso cref="BackGradientStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="ChartHatchStyle"/> value used for the background of an annotation.
        /// </value>
        /// <remarks>
        /// Two colors are used to draw the hatching, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
        /// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(ChartHatchStyle.None),
		NotifyParentPropertyAttribute(true),
		SRDescription("DescriptionAttributeBackHatchStyle"),
		Editor(Editors.HatchStyleEditor.Editor, Editors.HatchStyleEditor.Base)
		]
		virtual public ChartHatchStyle BackHatchStyle
		{
			get
			{
				return _backHatchStyle;
			}
			set
			{
				_backHatchStyle = value;
				Invalidate();
			}
		}
        /// <summary>
        /// Gets or sets the background gradient style of an annotation.
        /// <seealso cref="BackSecondaryColor"/>
        /// <seealso cref="BackColor"/>
        /// <seealso cref="BackHatchStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="GradientStyle"/> value used for the background of an annotation.
        /// </value>
        /// <remarks>
        /// Two colors are used to draw the gradient, <see cref="BackColor"/> and <see cref="BackSecondaryColor"/>.
        /// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(GradientStyle.None),
		NotifyParentPropertyAttribute(true),
       	SRDescription("DescriptionAttributeBackGradientStyle"),
		Editor(Editors.GradientEditor.Editor, Editors.GradientEditor.Base)
		]		
		virtual public GradientStyle BackGradientStyle
		{
			get
			{
				return _backGradientStyle;
			}
			set
			{
				_backGradientStyle = value;
				Invalidate();
			}
		}
 
        /// <summary>
        /// Gets or sets the secondary background color of an annotation.
        /// <seealso cref="BackColor"/>
        /// <seealso cref="BackHatchStyle"/>
        /// <seealso cref="BackGradientStyle"/>
        /// </summary>
        /// <value>
        /// A <see cref="Color"/> value used for the secondary color of an annotation background with 
        /// hatching or gradient fill.
        /// </value>
        /// <remarks>
        /// This color is used with <see cref="BackColor"/> when <see cref="BackHatchStyle"/> or
        /// <see cref="BackGradientStyle"/> are used.
        /// </remarks>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Color), ""),
		NotifyParentPropertyAttribute(true),
        SRDescription("DescriptionAttributeBackSecondaryColor"),
        TypeConverter(typeof(ColorConverter)),
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
		] 
		virtual public Color BackSecondaryColor
		{
			get
			{
				return _backSecondaryColor;
			}
			set
			{
				_backSecondaryColor = value;
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the color of an annotation's shadow.
		/// <seealso cref="ShadowOffset"/>
		/// </summary>
		/// <value>
		/// A <see cref="Color"/> value used to draw an annotation's shadow.
		/// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(typeof(Color), "128,0,0,0"),
        SRDescription("DescriptionAttributeShadowColor"),
        TypeConverter(typeof(ColorConverter)), 
        Editor(Editors.ChartColorEditor.Editor, Editors.ChartColorEditor.Base)
		]
		virtual public Color ShadowColor
		{
			get
			{
				return _shadowColor;
			}
			set
			{
				_shadowColor = value;
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the offset between an annotation and its shadow.
		/// <seealso cref="ShadowColor"/>
		/// </summary>
		/// <value>
		/// An integer value that represents the offset between an annotation and its shadow.
		/// </value>
		[
		SRCategory("CategoryAttributeAppearance"),
		DefaultValue(0),
        SRDescription("DescriptionAttributeShadowOffset"),
		]
		virtual public int ShadowOffset
		{
			get
			{
				return _shadowOffset;
			}
			set
			{
				_shadowOffset = value;
				Invalidate();
			}
		}
 
		#endregion
 
		#region Axes Attaching
 
		/// <summary>
		/// Gets or sets the name of the X axis which an annotation is attached to.
		/// </summary>
		/// <value>
		/// A string value that represents the name of the X axis which an annotation
		/// is attached to.
		/// </value>
		/// <remarks>
        /// This property is for internal use and is hidden at design and run time.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchorAxes"),
		DefaultValue(""),
		Browsable(false),
		Bindable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		SRDescription("DescriptionAttributeAxisXName"),
		]
		virtual public string  AxisXName
		{
			get
			{
				if(_axisXName.Length == 0 && _axisX != null)
				{
					_axisXName = GetAxisName(_axisX);
				}
				return _axisXName;
			}
			set
			{
				_axisXName = value;
				_axisX = null;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}		
 
		/// <summary>
        /// Gets or sets the name of the Y axis which an annotation is attached to.
		/// </summary>
		/// <value>
		/// A string value that represents the name of the Y axis which an annotation
		/// is attached to.
		/// </value>
		/// <remarks>
        /// This property is for internal use and is hidden at design and run time.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchorAxes"),
		Browsable(false),
		Bindable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		DefaultValue(""),
		SRDescription("DescriptionAttributeAxisYName"),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		]
		virtual public string  AxisYName
		{
			get
			{
				//  Always return empty string to prevent property serialization
				// "YAxisName" property will be used instead.
				return string.Empty;
			}
			set
			{
				this.YAxisName = value;
			}
		}		
 
 
		/// <summary>
        /// Gets or sets the name of the Y axis which an annotation is attached to.
		/// NOTE: "AxisYName" property was used before but the name was changed to solve the
		/// duplicated hash value during the serialization with the "TitleSeparator" property. 
		/// </summary>
		/// <value>
		/// A string value that represents the name of the Y axis which an annotation
		/// is attached to.
		/// </value>
		/// <remarks>
        /// This property is for internal use and is hidden at design and run time.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchorAxes"),
		Browsable(false),
		Bindable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		DefaultValue(""),
		SRDescription("DescriptionAttributeAxisYName"),
		]
		virtual public string  YAxisName
		{
			get
			{
				if(_axisYName.Length == 0 && _axisY != null)
				{
					_axisYName = GetAxisName(_axisY);
				}
				return _axisYName;
			}
			set
			{
				_axisYName = value;
				_axisY = null;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}		
 
		/// <summary>
		/// Gets or sets the X axis which an annotation is attached to.
		/// <seealso cref="AxisY"/>
		/// <seealso cref="IsSizeAlwaysRelative"/>
		/// </summary>
		/// <value>
		/// <see cref="Axis"/> object which an annotation is attached to.
		/// </value>
		/// <remarks>
		/// When an annotation is attached to an axis, its X position is always in 
		/// axis coordinates. To define an annotation's size in axis coordinates as well, 
		/// make sure the <see cref="IsSizeAlwaysRelative"/> property is set to <b>false</b>.
		/// <para>
		/// Set this value to <b>null</b> or <b>nothing</b> to disable attachment to the axis.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchorAxes"),
		DefaultValue(null),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		SRDescription("DescriptionAttributeAxisX"),
		Editor(Editors.AnnotationAxisUITypeEditor.Editor, Editors.AnnotationAxisUITypeEditor.Base),
		TypeConverter(typeof(AnnotationAxisValueConverter)),
		]
		virtual public Axis AxisX
		{
			get
			{
				if(_axisX == null && _axisXName.Length > 0)
				{
					_axisX = GetAxisByName(_axisXName);
				}
				return _axisX;
			}
			set
			{
				_axisX = value;
				_axisXName = String.Empty;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}		
 
		/// <summary>
		/// Gets or sets the Y axis which an annotation is attached to.
		/// <seealso cref="AxisX"/>
		/// <seealso cref="IsSizeAlwaysRelative"/>
		/// </summary>
		/// <value>
		/// <see cref="Axis"/> object which an annotation is attached to.
		/// </value>
		/// <remarks>
		/// When an annotation is attached to an axis, its Y position is always in 
		/// axis coordinates. To define an annotation's size in axis coordinates as well, 
		/// make sure <see cref="IsSizeAlwaysRelative"/> property is set to <b>false</b>.
		/// <para>
		/// Set this value to <b>null</b> or <b>nothing</b> to disable annotation attachment to an axis.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchorAxes"),
		DefaultValue(null),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		SRDescription("DescriptionAttributeAxisY"),
		Editor(Editors.AnnotationAxisUITypeEditor.Editor, Editors.AnnotationAxisUITypeEditor.Base),
		TypeConverter(typeof(AnnotationAxisValueConverter)),
		]
		virtual public Axis AxisY
		{
			get
			{
				if(_axisY == null && _axisYName.Length > 0)
				{
					_axisY = GetAxisByName(_axisYName);
				}
				return _axisY;
			}
			set
			{
				_axisY = value;
				_axisYName = String.Empty;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}		
 
		#endregion
 
		#region Anchor
 
		/// <summary>
		/// Gets or sets the name of a data point which an annotation is anchored to.
		/// </summary>
		/// <value>
		/// A string value that represents the name of the data point which an 
		/// annotation is anchored to.
		/// </value>
		/// <remarks>
        /// This property is for internal use and is hidden at design and run time.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchor"),
		Browsable(false),
		Bindable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		DefaultValue(""),
		SRDescription("DescriptionAttributeAnchorDataPointName"),
		]
		virtual public string  AnchorDataPointName
		{
			get
			{
				if(_anchorDataPointName.Length == 0 && _anchorDataPoint != null)
				{
					_anchorDataPointName = GetDataPointName(_anchorDataPoint);
				}
				return _anchorDataPointName;
			}
			set
			{
				_anchorDataPointName = value;
				_anchorDataPoint = null;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}		
 
		/// <summary>
		/// Gets or sets the data point an annotation is anchored to.
		/// <seealso cref="AnchorAlignment"/>
		/// <seealso cref="AnchorOffsetX"/>
		/// <seealso cref="AnchorOffsetY"/>
		/// <seealso cref="AnchorX"/>
		/// <seealso cref="AnchorY"/>
        /// <seealso cref="SetAnchor(Charting.DataPoint)"/>
        /// <seealso cref="SetAnchor(Charting.DataPoint, Charting.DataPoint)"/>
		/// </summary>
		/// <value>
		/// A <see cref="DataPoint"/> object an annotation is anchored to.
		/// </value>
		/// <remarks>
		/// The annotation is anchored to the X and Y values of the specified data point, 
		/// and automatically uses the same axes coordinates as the data point.
		/// <para>
		/// To automatically position an annotation relative to an anchor point, make sure 
		/// its <see cref="X"/> and <see cref="Y"/> properties are set to <b>Double.NaN</b>.
		/// The <see cref="AnchorAlignment"/> property may be used to change an annotation's 
		/// automatic position alignment to an anchor point. The <see cref="AnchorOffsetX"/> and 
		/// <see cref="AnchorOffsetY"/> properties may be used to add extra spacing.
		/// </para>
		/// <para>
		/// When using this property, make sure the <see cref="AnchorX"/> and <see cref="AnchorY"/> 
		/// properties are set to <b>Double.NaN</b> (they have precedence).
		/// </para>
		/// <para>
		/// Set this value to <b>null</b> or <b>nothing</b> to disable annotation anchoring to a data point.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchor"),
		DefaultValue(null),
		DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden),
		SerializationVisibilityAttribute(SerializationVisibility.Hidden),
		SRDescription("DescriptionAttributeAnchorDataPoint"),
		Editor(Editors.AnchorPointUITypeEditor.Editor, Editors.AnchorPointUITypeEditor.Base),
		TypeConverter(typeof(AnchorPointValueConverter)),
		]
		virtual public DataPoint AnchorDataPoint
		{
			get
			{
				if(_anchorDataPoint == null && _anchorDataPointName.Length > 0)
				{
					_anchorDataPoint = GetDataPointByName(_anchorDataPointName);
				}
				return _anchorDataPoint;
			}
			set
			{
				_anchorDataPoint = value;
				_anchorDataPointName = String.Empty;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the X coordinate the annotation is anchored to.
		/// <seealso cref="AnchorY"/>
		/// <seealso cref="AnchorOffsetX"/>
		/// <seealso cref="AnchorOffsetY"/>
		/// <seealso cref="AnchorAlignment"/>
		/// <seealso cref="AnchorDataPoint"/>
		/// </summary>
		/// <value>
		/// A double value that represents the X coordinate which an annotation is anchored to.
		/// </value>
		/// <remarks>
		/// The annotation is anchored to the X coordinate specified in relative or axis coordinates, 
		/// depending on the <see cref="AxisX"/> property value.
		/// <para>
		/// To automatically position an annotation relative to an anchor point, make sure 
		/// its <see cref="X"/> property is set to <b>Double.NaN</b>.
		/// The <see cref="AnchorAlignment"/> property may be used to change the annotation's 
		/// automatic position alignment to the anchor point. The <see cref="AnchorOffsetX"/> and 
		/// <see cref="AnchorOffsetY"/> properties may be used to add extra spacing.
		/// </para>
		/// <para>
		/// This property has a higher priority than the <see cref="AnchorDataPoint"/> property.
		/// </para>
		/// <para>
		/// Set this value to <b>Double.NaN</b> to disable annotation anchoring to the value.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchor"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeAnchorX"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
		virtual public double AnchorX
		{
			get
			{
				return _anchorX;
			}
			set
			{
				_anchorX = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the Y coordinate which an annotation is anchored to.
		/// <seealso cref="AnchorY"/>
		/// <seealso cref="AnchorOffsetX"/>
		/// <seealso cref="AnchorOffsetY"/>
		/// <seealso cref="AnchorAlignment"/>
		/// <seealso cref="AnchorDataPoint"/>
		/// </summary>
		/// <value>
		/// A double value that represents the Y coordinate which an annotation is anchored to.
		/// </value>
		/// <remarks>
		/// The annotation is anchored to the Y coordinate specified in relative or axis coordinates, 
		/// depending on the <see cref="AxisX"/> property value.
		/// <para>
		/// To automatically position an annotation relative to an anchor point, make sure 
		/// its <see cref="Y"/> property is set to <b>Double.NaN</b>.
		/// The <see cref="AnchorAlignment"/> property may be used to change the annotation's 
		/// automatic position alignment to the anchor point. The <see cref="AnchorOffsetX"/> and 
		/// <see cref="AnchorOffsetY"/> properties may be used to add extra spacing.
		/// </para>
		/// <para>
		/// This property has a higher priority than the <see cref="AnchorDataPoint"/> property.
		/// </para>
		/// <para>
		/// Set this value to <b>Double.NaN</b> to disable annotation anchoring to the value.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchor"),
		DefaultValue(double.NaN),
		SRDescription("DescriptionAttributeAnchorY"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		TypeConverter(typeof(DoubleNanValueConverter)),
		]
		virtual public double AnchorY
		{
			get
			{
				return _anchorY;
			}
			set
			{
				_anchorY = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets the x-coordinate offset between the positions of an annotation and its anchor point.
		/// <seealso cref="AnchorOffsetY"/>
		/// <seealso cref="AnchorDataPoint"/>
		/// <seealso cref="AnchorX"/>
		/// <seealso cref="AnchorAlignment"/>
		/// </summary>
		/// <value>
        /// A double value that represents the x-coordinate offset between the positions of an annotation and its anchor point.
		/// </value>
		/// <remarks>
		/// The annotation must be anchored using the <see cref="AnchorDataPoint"/> or 
		/// <see cref="AnchorX"/> properties, and its <see cref="X"/> property must be set 
		/// to <b>Double.NaN</b>.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchor"),
		DefaultValue(0.0),
		SRDescription("DescriptionAttributeAnchorOffsetX3"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		]
		virtual public double AnchorOffsetX
		{
			get
			{
				return anchorOffsetX;
			}
			set
			{
				if(value > 100.0 || value < -100.0)
				{
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationAnchorOffsetInvalid));
				}
				anchorOffsetX = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
        /// <summary>
        /// Gets or sets the y-coordinate offset between the positions of an annotation and its anchor point.
        /// <seealso cref="Annotation.AnchorOffsetX"/>
        /// <seealso cref="Annotation.AnchorDataPoint"/>
        /// <seealso cref="Annotation.AnchorY"/>
        /// <seealso cref="Annotation.AnchorAlignment"/>
        /// </summary>
        /// <value>
        /// A double value that represents the y-coordinate offset between the positions of an annotation and its anchor point.
        /// </value>
        /// <remarks>
        /// Annotation must be anchored using <see cref="Annotation.AnchorDataPoint"/> or 
        /// <see cref="Annotation.AnchorY"/> properties and it's <see cref="Annotation.Y"/> property must be set
        /// to <b>Double.NaN</b>.
        /// </remarks>
		[
		SRCategory("CategoryAttributeAnchor"),
		DefaultValue(0.0),
		SRDescription("DescriptionAttributeAnchorOffsetY3"),
		RefreshPropertiesAttribute(RefreshProperties.All),
		]
		virtual public double AnchorOffsetY
		{
			get
			{
				return anchorOffsetY;
			}
			set
			{
				if(value > 100.0 || value < -100.0)
				{
                    throw (new ArgumentOutOfRangeException("value", SR.ExceptionAnnotationAnchorOffsetInvalid));
				}
				anchorOffsetY = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		/// <summary>
		/// Gets or sets an annotation position's alignment to the anchor point.
		/// <seealso cref="AnchorX"/>
		/// <seealso cref="AnchorY"/>
		/// <seealso cref="AnchorDataPoint"/>
		/// <seealso cref="AnchorOffsetX"/>
		/// <seealso cref="AnchorOffsetY"/>
		/// </summary>
		/// <value>
		/// A <see cref="ContentAlignment"/> value that represents the annotation's alignment to 
		/// the anchor point.
		/// </value>
		/// <remarks>
		/// The annotation must be anchored using either <see cref="AnchorDataPoint"/>, or the <see cref="AnchorX"/> 
		/// and <see cref="AnchorY"/> properties. Its <see cref="X"/> and <see cref="Y"/> 
		/// properties must be set to <b>Double.NaN</b>.
		/// </remarks>
		[
		SRCategory("CategoryAttributeAnchor"),
		DefaultValue(typeof(ContentAlignment), "BottomCenter"),
        SRDescription("DescriptionAttributeAnchorAlignment"),
		]
		virtual public ContentAlignment AnchorAlignment
		{
			get
			{
				return anchorAlignment;
			}
			set
			{
				anchorAlignment = value;
				this.ResetCurrentRelativePosition();
				Invalidate();
			}
		}
 
		#endregion	// Anchoring
 
		#region Editing Permissions
 
#if Microsoft_CONTROL

		/// <summary>
		/// Gets or sets a flag that specifies whether an annotation may be selected 
		/// with a mouse by the end user.
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation may be selected, <b>false</b> otherwise.
		/// </value>
		[
        SRCategory("CategoryAttributeEditing"),
        DefaultValue(false),
		SRDescription("DescriptionAttributeAllowSelecting"),
		]
		virtual public bool AllowSelecting
		{
			get
			{
				return _allowSelecting;
			}
			set
			{
				_allowSelecting = value;
			}
		}
 
		/// <summary>
		/// Gets or sets a flag that specifies whether an annotation may be moved 
		/// with a mouse by the end user.
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation may be moved, <b>false</b> otherwise.
		/// </value>
		[
        SRCategory("CategoryAttributeEditing"),
        DefaultValue(false),
		SRDescription("DescriptionAttributeAllowMoving"),
		]
		virtual public bool AllowMoving
		{
			get
			{
				return _allowMoving;
			}
			set
			{
				_allowMoving = value;
			}
		}
 
		/// <summary>
		/// Gets or sets a flag that specifies whether an annotation anchor may be moved 
		/// with a mouse by the end user.
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation anchor may be moved, <b>false</b> otherwise.
		/// </value>
		[
		SRCategory("CategoryAttributeEditing"),
		DefaultValue(false),
		SRDescription("DescriptionAttributeAllowAnchorMoving3"),
		]
		virtual public bool AllowAnchorMoving
		{
			get
			{
				return _allowAnchorMoving;
			}
			set
			{
				_allowAnchorMoving = value;
			}
		}		
 
		/// <summary>
		/// Gets or sets a flag that specifies whether an annotation may be resized 
		/// with a mouse by the end user.
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation may be resized, <b>false</b> otherwise.
		/// </value>
		[
        SRCategory("CategoryAttributeEditing"),
        DefaultValue(false),
		SRDescription("DescriptionAttributeAllowResizing"),
		]
		virtual public bool AllowResizing
		{
			get
			{
				return _allowResizing;
			}
			set
			{
				_allowResizing = value;
			}
		}
 
		/// <summary>
		/// Gets or sets a flag that specifies whether an annotation's text may be edited 
		/// when the end user double clicks on the text.
		/// </summary>
		/// <value>
		/// <b>True</b> if the annotation text may be edited, <b>false</b> otherwise.
		/// </value>
		[
        SRCategory("CategoryAttributeEditing"),
        DefaultValue(false),
		SRDescription("DescriptionAttributeAllowTextEditing"),
		]
		virtual public bool AllowTextEditing
		{
			get
			{
				return _allowTextEditing;
			}
			set
			{
				_allowTextEditing = value;
			}
		}
 
		/// <summary>
		/// Gets or sets a flag that specifies whether a polygon annotation's points 
		/// may be moved with a mouse by the end user.
		/// </summary>
		/// <value>
		/// <b>True</b> if the polygon annotation's points may be moved, <b>false</b> otherwise.
		/// </value>
		[
        SRCategory("CategoryAttributeEditing"),
        DefaultValue(false),
		SRDescription("DescriptionAttributeAllowPathEditing3"),
		]
		virtual public bool AllowPathEditing
		{
			get
			{
				return _allowPathEditing;
			}
			set
			{
				_allowPathEditing = value;
			}
		}
		
#endif // Microsoft_CONTROL
 
		#endregion
 
		#region Interactivity
 
		/// <summary>
		/// Gets or sets an annotation's tooltip text.
		/// </summary>
		/// <value>
		/// A string value.
		/// </value>
		/// <remarks>
		/// Special keywords can be used in the text when an annotation is anchored to 
		/// a data point using the <see cref="AnchorDataPoint"/> property.  For a listing of 
		/// these keywords, refer to the "Annotations" help topic.
		/// </remarks>
		[
 
        SRCategory("CategoryAttributeMisc"),
		DefaultValue(""),
        SRDescription("DescriptionAttributeToolTip"),
		]
		virtual public string  ToolTip
		{
			get
			{
				return _tooltip;
			}
			set
			{
				_tooltip = value;
 
			}
		}
 
#if !Microsoft_CONTROL
 
        /// <summary>
		/// Gets or sets an annotation's Url.
		/// </summary>
		/// <value>
		/// A string value.
		/// </value>
		/// <remarks>
		/// Special keywords can be used when an annotation is anchored to 
		/// a data point using the <see cref="AnchorDataPoint"/> property.  For a listing of 
		/// these keywords, refer to the "Annotations" help topic.
		/// </remarks>
		[
		SRCategory("CategoryAttributeMisc"),
		DefaultValue(""),
		SRDescription("DescriptionAttributeUrl"),
		]
		virtual public string  Url
		{
			get
			{
				return _url;
			}
			set
			{
				_url = value;
 
			}
		}	
 
		/// <summary>
		/// Gets or sets an annotation's map area attributes.
		/// </summary>
		/// <value>
		/// A string value.
		/// </value>
		/// <remarks>
		/// This string will be added to the attributes of the image map generated
		/// for the annotation.
		/// <para>
		/// Special keywords can be used when an annotation is anchored to 
		/// a data point using the <see cref="AnchorDataPoint"/> property.  For a listing of 
		/// these keywords, refer to the "Annotations" help topic.
		/// </para>
		/// </remarks>
		[
		SRCategory("CategoryAttributeMisc"),
		DefaultValue(""),
		SRDescription("DescriptionAttributeMapAreaAttributes"),
		]
		virtual public string  MapAreaAttributes
		{
			get
			{
				return _mapAreaAttributes;
			}
			set
			{
				_mapAreaAttributes = value;
 
			}
		}
 
        /// <summary>
        /// Gets or sets the postback value which can be processed on click event.
        /// </summary>
        /// <value>The value which is passed to click event as argument.</value>
        [DefaultValue("")]
        [SRCategory(SR.Keys.CategoryAttributeMapArea)]
        [SRDescription(SR.Keys.DescriptionAttributePostBackValue)]
        public string PostBackValue 
        { 
            get 
            { 
                return this._postbackValue; 
            } 
            set 
            { 
                this._postbackValue = value;
            } 
        }
 
 
#endif // !Microsoft_CONTROL
 
        #endregion // Interactivity
 
        #endregion
 
        #region Methods
 
        #region Painting
 
        /// <summary>
		/// Paints the annotation object using the specified graphics.
		/// </summary>
		/// <param name="graphics">
		/// A <see cref="ChartGraphics"/> object used to paint the annotation object.
		/// </param>
		/// <param name="chart">
		/// Reference to the annotation's <see cref="Chart"/> control owner.
		/// </param>
        abstract internal void Paint(Chart chart, ChartGraphics graphics);
 
		/// <summary>
		/// Paints annotation selection markers.
		/// </summary>
		/// <param name="chartGraphics">Chart graphics used for painting.</param>
		/// <param name="rect">Selection rectangle.</param>
		/// <param name="path">Selection path.</param>
		virtual internal void PaintSelectionHandles(ChartGraphics chartGraphics, RectangleF rect, GraphicsPath path)
		{
			// Define markers appearance style
			Color	markerBorderColor = Color.Black;
			Color	markerColor = Color.FromArgb(200, 255, 255, 255);
            MarkerStyle markerStyle = MarkerStyle.Square;
            int markerSize = selectionMarkerSize;
            Boolean selected = this.IsSelected;
 
            SizeF markerSizeRel = chartGraphics.GetRelativeSize(new SizeF(markerSize, markerSize));
            if (this.Common.ProcessModePaint &&
				!this.Common.ChartPicture.isPrinting)
			{
				// Clear selection rectangles
				this.selectionRects = null;
 
				// Check if annotation is selected
                if (selected)
				{
					// Create selection rectangles
					this.selectionRects = new RectangleF[9];
 
					// Draw selection handles for single dimension annotations like line.
					if(this.SelectionPointsStyle == SelectionPointsStyle.TwoPoints)
					{
						// Save selection handles position in array elements 0 and 4
						this.selectionRects[(int)ResizingMode.TopLeftHandle] = new RectangleF(
							rect.X - markerSizeRel.Width/2f,
							rect.Y - markerSizeRel.Height/2f,
							markerSizeRel.Width,
							markerSizeRel.Height);
						this.selectionRects[(int)ResizingMode.BottomRightHandle] = new RectangleF(
							rect.Right - markerSizeRel.Width/2f,
							rect.Bottom - markerSizeRel.Height/2f,
							markerSizeRel.Width,
							markerSizeRel.Height);
 
 
						// Draw selection handle
						chartGraphics.DrawMarkerRel(
							rect.Location,
                            markerStyle,
							markerSize,
							markerColor,
							markerBorderColor,
							1,
							"",
							Color.Empty,
							0,
							Color.FromArgb(128, 0, 0, 0),
							RectangleF.Empty);
 
						chartGraphics.DrawMarkerRel(
							new PointF(rect.Right, rect.Bottom),
                            markerStyle,
							markerSize,
							markerColor,
							markerBorderColor,
							1,
							"",
							Color.Empty,
							0,
							Color.FromArgb(128, 0, 0, 0),
							RectangleF.Empty);
					}
					else if(this.SelectionPointsStyle == SelectionPointsStyle.Rectangle)
					{
						for(int index = 0; index < 8; index++)
						{
							// Get handle position
							PointF	handlePosition = PointF.Empty;
							switch((ResizingMode)index)
							{
								case ResizingMode.TopLeftHandle:
									handlePosition = rect.Location;
									break;
								case ResizingMode.TopHandle:
									handlePosition = new PointF(rect.X + rect.Width / 2f, rect.Y);
									break;
								case ResizingMode.TopRightHandle:
									handlePosition = new PointF(rect.Right, rect.Y);
									break;
								case ResizingMode.RightHandle:
									handlePosition = new PointF(rect.Right, rect.Y + rect.Height / 2f);
									break;
								case ResizingMode.BottomRightHandle:
									handlePosition = new PointF(rect.Right, rect.Bottom);
									break;
								case ResizingMode.BottomHandle:
									handlePosition = new PointF(rect.X + rect.Width / 2f, rect.Bottom);
									break;
								case ResizingMode.BottomLeftHandle:
									handlePosition = new PointF(rect.X, rect.Bottom);
									break;
								case ResizingMode.LeftHandle:
									handlePosition = new PointF(rect.X, rect.Y + rect.Height / 2f);
									break;
							}
 
							// Save selection handles position in array elements 0 and 4
							this.selectionRects[index] = new RectangleF(
								handlePosition.X - markerSizeRel.Width/2f,
								handlePosition.Y - markerSizeRel.Height/2f,
								markerSizeRel.Width,
								markerSizeRel.Height);
 
							// Draw selection handle
							chartGraphics.DrawMarkerRel(
								handlePosition,
                                markerStyle,
								markerSize,
								markerColor,
								markerBorderColor,
								1,
								"",
								Color.Empty,
								0,
								Color.FromArgb(128, 0, 0, 0),
								RectangleF.Empty);
						}
					}
 
 
					//********************************************************************
					//** Draw anchor selection handle
					//********************************************************************
 
					// Get vertical and horizontal axis
					Axis	vertAxis = null;
					Axis	horizAxis = null;
					GetAxes(ref vertAxis, ref horizAxis);
 
					// Get anchor position
					double	anchorX = double.NaN;
					double	anchorY = double.NaN;
					bool	relativeX = false;
					bool	relativeY = false;
					this.GetAnchorLocation(ref anchorX, ref anchorY, ref relativeX, ref relativeY);
 
					// Convert anchor location to relative coordinates
					if(!double.IsNaN(anchorX) && !double.IsNaN(anchorY))
					{
						if( !relativeX && horizAxis != null )
						{
							anchorX = horizAxis.ValueToPosition(anchorX);
						}
						if( !relativeY && vertAxis != null )
						{
							anchorY = vertAxis.ValueToPosition(anchorY);
						}
 
						// Apply 3D transforamtion if required
						ChartArea	chartArea = null;
						if(horizAxis != null && horizAxis.ChartArea != null)
						{
							chartArea = horizAxis.ChartArea;
						}
						if(vertAxis != null && vertAxis.ChartArea != null)
						{
							chartArea = vertAxis.ChartArea;
						}
						if(chartArea != null && 
							chartArea.Area3DStyle.Enable3D == true &&
							!chartArea.chartAreaIsCurcular &&
                            chartArea.requireAxes &&
							chartArea.matrix3D.IsInitialized())
						{
                            // Get anotation Z coordinate (use scene depth or anchored point Z position)
                            float positionZ = chartArea.areaSceneDepth;
                            if (this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
                            {
                                float depth = 0f;
                                chartArea.GetSeriesZPositionAndDepth(
                                    this.AnchorDataPoint.series,
                                    out depth,
                                    out positionZ);
                                positionZ += depth / 2f;
                            }
 
                            // Define 3D points of annotation object
                            Point3D[] annot3DPoints = new Point3D[1];
                            annot3DPoints[0] = new Point3D((float)anchorX, (float)anchorY, positionZ);
 
                            // Tranform cube coordinates
                            chartArea.matrix3D.TransformPoints(annot3DPoints);
 
                            // Get transformed coordinates
                            anchorX = annot3DPoints[0].X;
                            anchorY = annot3DPoints[0].Y;
						}
 
						// Save selection handles position in array elements 0 and 4
						this.selectionRects[(int)ResizingMode.AnchorHandle] = new RectangleF(
							(float)anchorX - markerSizeRel.Width/2f,
							(float)anchorY - markerSizeRel.Height/2f,
							markerSizeRel.Width,
							markerSizeRel.Height);
 
						// Draw circular selection handle
						chartGraphics.DrawMarkerRel(
							new PointF((float)anchorX, (float)anchorY),
							MarkerStyle.Cross,
							selectionMarkerSize + 3,
							markerColor,
							markerBorderColor,
							1,
							"",
							Color.Empty,
							0,
							Color.FromArgb(128, 0, 0, 0),
							RectangleF.Empty);
					}
 
#if Microsoft_CONTROL

					//********************************************************************
					//** Draw path selection handles
					//********************************************************************
					if(path != null && AllowPathEditing)
					{
						// Create selection rectangles for each point
						PointF[]	pathPoints = path.PathPoints;
						RectangleF[] newSelectionRects = new RectangleF[pathPoints.Length + 9];
 
						// Copy previous rectangles (first nine elements)
						for(int index = 0; index < this.selectionRects.Length; index++)
						{
							newSelectionRects[index] = this.selectionRects[index];
						}
						this.selectionRects = newSelectionRects;
 
						// Loop through all points
						for(int index = 0; index < pathPoints.Length; index++)
						{
							// Get handle position
							PointF	handlePosition = chartGraphics.GetRelativePoint(pathPoints[index]);
 
							// Save selection handles position in array elements 0 and 4
							this.selectionRects[9 + index] = new RectangleF(
								handlePosition.X - markerSizeRel.Width/2f,
								handlePosition.Y - markerSizeRel.Height/2f,
								markerSizeRel.Width,
								markerSizeRel.Height);
 
							// Draw selection handle
							chartGraphics.DrawMarkerRel(
								handlePosition,
								MarkerStyle.Circle,
								selectionMarkerSize + 1,
								markerColor,
								markerBorderColor,
								1,
								"",
								Color.Empty,
								0,
								Color.FromArgb(128, 0, 0, 0),
								RectangleF.Empty);
						}
					}
 
#endif // Microsoft_CONTROL
 
				}
			}
		}
 
		#endregion
 
		#region Position and Size
 
		/// <summary>
		/// Resizes an annotation according to its content size.
		/// </summary>
		/// <remarks>
		/// Sets the annotation width and height to fit the specified text. This method applies to 
		/// <see cref="TextAnnotation"/>, <see cref="RectangleAnnotation"/>, <see cref="EllipseAnnotation"/>
		/// and <see cref="CalloutAnnotation"/> objects only.
		/// </remarks>
		virtual public void ResizeToContent()
		{
			RectangleF position = GetContentPosition();
			if(!double.IsNaN(position.Width))
			{
				this.Width = position.Width;
			}
			if(!double.IsNaN(position.Height))
			{
				this.Height = position.Height;
			}
		}
 
		/// <summary>
		/// Gets an annotation's content position.
		/// </summary>
		/// <returns>Annotation's content size.</returns>
		virtual internal RectangleF GetContentPosition()
		{
			return new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
		}
 
		/// <summary>
		/// Gets an annotation's anchor point location.
		/// </summary>
		/// <param name="anchorX">Returns the anchor X coordinate.</param>
		/// <param name="anchorY">Returns the anchor Y coordinate.</param>
		/// <param name="inRelativeAnchorX">Indicates if X coordinate is in relative chart coordinates.</param>
		/// <param name="inRelativeAnchorY">Indicates if Y coordinate is in relative chart coordinates.</param>
		private void GetAnchorLocation(ref double anchorX, ref double anchorY, ref bool inRelativeAnchorX, ref bool inRelativeAnchorY)
		{
			anchorX = this.AnchorX;
			anchorY = this.AnchorY;
 
			if(this.AnchorDataPoint != null &&
				this.AnchorDataPoint.series != null &&
				this.Chart != null &&
				this.Chart.chartPicture != null)
			{
				// Anchor data point is not allowed for gropped annotations
				if(this.AnnotationGroup != null)
				{
                    throw (new InvalidOperationException(SR.ExceptionAnnotationGroupedAnchorDataPointMustBeEmpty));
				}
 
				// Get data point relative coordinate
				if( double.IsNaN(anchorX) || double.IsNaN(anchorY))
				{
					// Get X value from data point
					if( double.IsNaN(anchorX) )
					{
						anchorX = this.AnchorDataPoint.positionRel.X;
						inRelativeAnchorX = true;
					}
 
					// Get Y value from data point
					if( double.IsNaN(anchorY) )
					{
						anchorY = this.AnchorDataPoint.positionRel.Y;
						inRelativeAnchorY = true;
					}
				}
			}
		}
	
		/// <summary>
		/// Gets annotation object position in relative coordinates.
		/// </summary>
		/// <param name="location">Returns annotation location.</param>
		/// <param name="size">Returns annotation size.</param>
		/// <param name="anchorLocation">Returns annotation anchor point location.</param>
		virtual internal void GetRelativePosition(out PointF location, out SizeF size, out PointF anchorLocation)
		{
			bool	saveCurrentPosition = true;
 
			//***********************************************************************
			//** Check if position was precalculated
			//***********************************************************************
			if(!double.IsNaN(currentPositionRel.X) && !double.IsNaN(currentPositionRel.X))
			{
				location = currentPositionRel.Location;
				size = currentPositionRel.Size;
				anchorLocation = currentAnchorLocationRel;
				return;
			}
 
			//***********************************************************************
			//** Get vertical and horizontal axis
			//***********************************************************************
			Axis	vertAxis = null;
			Axis	horizAxis = null;
			GetAxes(ref vertAxis, ref horizAxis);
 
			//***********************************************************************
			//** Check if annotation was anchored to 2 points.
			//***********************************************************************
			if(this._anchorDataPoint != null &&
				this._anchorDataPoint2 != null)
			{
				// Annotation size is in axis coordinates
				this.IsSizeAlwaysRelative = false;
 
				// Set annotation size
				this.Height = 
					vertAxis.PositionToValue(this._anchorDataPoint2.positionRel.Y, false) - 
					vertAxis.PositionToValue(this._anchorDataPoint.positionRel.Y, false);
				this.Width = 
					horizAxis.PositionToValue(this._anchorDataPoint2.positionRel.X, false) - 
					horizAxis.PositionToValue(this._anchorDataPoint.positionRel.X, false);
 
				// Reset second anchor point after setting width and height
				this._anchorDataPoint2 = null;
			}
 
			//***********************************************************************
			//** Flags which indicate that coordinate was already transformed 
			//** into chart relative coordinate system.
			//***********************************************************************
			bool	inRelativeX = false;
			bool	inRelativeY = false;
			bool	inRelativeWidth = (_isSizeAlwaysRelative) ? true : false;
			bool	inRelativeHeight = (_isSizeAlwaysRelative) ? true : false;
			bool	inRelativeAnchorX = false;
			bool	inRelativeAnchorY = false;
			
			//***********************************************************************
			//** Get anchoring coordinates from anchored Data Point.
			//***********************************************************************
			double	anchorX = this.AnchorX;
			double	anchorY = this.AnchorY;
			GetAnchorLocation(ref anchorX, ref anchorY, ref inRelativeAnchorX, ref inRelativeAnchorY);
 
			//***********************************************************************
			//** Calculate scaling and translation for the annotations in the group.
			//***********************************************************************
			AnnotationGroup group = this.AnnotationGroup;
			PointF groupLocation = PointF.Empty;
			double groupScaleX = 1.0;
			double groupScaleY = 1.0;
			if(group != null)
			{
				// Do not save relative position of annotations inside the group
				saveCurrentPosition = false;
 
				// Take relative position of the group
				SizeF groupSize = SizeF.Empty;
				PointF groupAnchorLocation = PointF.Empty;
				group.GetRelativePosition(out groupLocation, out groupSize, out groupAnchorLocation);
 
				// Calculate Scale
				groupScaleX = groupSize.Width / 100.0;
				groupScaleY = groupSize.Height / 100.0;
			}
 
 
			//***********************************************************************
			//** Get annotation automatic size.
			//***********************************************************************
			double	relativeWidth = this._width;
			double	relativeHeight = this._height;
 
			// Get annotation content position
			RectangleF	contentPosition = GetContentPosition();
 
			// Set annotation size if not set to custom value
			if( double.IsNaN(relativeWidth) )
			{
				relativeWidth = contentPosition.Width;
				inRelativeWidth = true;
			}
			else
			{
				relativeWidth *= groupScaleX;
			}
			if( double.IsNaN(relativeHeight) )
			{
				relativeHeight = contentPosition.Height;
				inRelativeHeight = true;
			}
			else
			{
				relativeHeight *= groupScaleY;   
			}
 
			//***********************************************************************
			//** Provide "dummy" size at design time
			//***********************************************************************
			if(this.Chart != null && this.Chart.IsDesignMode())
			{
				if(this.IsSizeAlwaysRelative ||
					(vertAxis == null && horizAxis == null) )
				{
					if(double.IsNaN(relativeWidth))
					{
						relativeWidth = 20.0;
						saveCurrentPosition = false;
					}
					if(double.IsNaN(relativeHeight))
					{
						relativeHeight = 20.0;
						saveCurrentPosition = false;
					}
				}
			}
 
			//***********************************************************************
			//** Get annotation location.
			//***********************************************************************
			double	relativeX = this.X;
			double	relativeY = this.Y;
			
			// Check if annotation location Y coordinate is defined
			if( double.IsNaN(relativeY) && !double.IsNaN(anchorY) )
			{
				inRelativeY = true;
				double	relativeAnchorY = anchorY;
				if(!inRelativeAnchorY && vertAxis != null)
				{
					relativeAnchorY = vertAxis.ValueToPosition(anchorY);
				}
				if(this.AnchorAlignment == ContentAlignment.TopCenter ||
					this.AnchorAlignment == ContentAlignment.TopLeft ||
					this.AnchorAlignment == ContentAlignment.TopRight)
				{
					relativeY = relativeAnchorY + this.AnchorOffsetY;
					relativeY *= groupScaleY;
				}
				else if(this.AnchorAlignment == ContentAlignment.BottomCenter ||
					this.AnchorAlignment == ContentAlignment.BottomLeft ||
					this.AnchorAlignment == ContentAlignment.BottomRight)
				{
					relativeY = relativeAnchorY - this.AnchorOffsetY;
					relativeY *= groupScaleY;
					if(relativeHeight != 0f && !double.IsNaN(relativeHeight))
					{
						if(inRelativeHeight)
						{
							relativeY -= relativeHeight;
						}
						else if(vertAxis != null)
						{
							float yValue = (float)vertAxis.PositionToValue(relativeY);
							float bottomRel = (float)vertAxis.ValueToPosition(yValue + relativeHeight);
							relativeY -= bottomRel - relativeY;
						}
					}
				}
				else 
				{
					relativeY = relativeAnchorY + this.AnchorOffsetY;
					relativeY *= groupScaleY;
					if(relativeHeight != 0f && !double.IsNaN(relativeHeight))
					{
						if(inRelativeHeight)
						{
							relativeY -= relativeHeight/2f;
						}
						else if(vertAxis != null)
						{
							float yValue = (float)vertAxis.PositionToValue(relativeY);
							float bottomRel = (float)vertAxis.ValueToPosition(yValue + relativeHeight);
							relativeY -= (bottomRel - relativeY) / 2f;
						}
					}
				}
			}
			else
			{
				relativeY *= groupScaleY;
			}
 
			// Check if annotation location X coordinate is defined
			if( double.IsNaN(relativeX) && !double.IsNaN(anchorX) )
			{
				inRelativeX = true;
				double	relativeAnchorX = anchorX;
				if(!inRelativeAnchorX && horizAxis != null)
				{
					relativeAnchorX = horizAxis.ValueToPosition(anchorX);
				}
				if(this.AnchorAlignment == ContentAlignment.BottomLeft ||
					this.AnchorAlignment == ContentAlignment.MiddleLeft ||
					this.AnchorAlignment == ContentAlignment.TopLeft)
				{
					relativeX = relativeAnchorX + this.AnchorOffsetX;
					relativeX *= groupScaleX;
				}
				else if(this.AnchorAlignment == ContentAlignment.BottomRight ||
					this.AnchorAlignment == ContentAlignment.MiddleRight ||
					this.AnchorAlignment == ContentAlignment.TopRight)
				{
					relativeX = relativeAnchorX - this.AnchorOffsetX;
					relativeX *= groupScaleX;
					if(relativeWidth != 0f && !double.IsNaN(relativeWidth))
					{
						if(inRelativeWidth)
						{
							relativeX -= relativeWidth;
						}
						else if(horizAxis != null)
						{
							float xValue = (float)horizAxis.PositionToValue(relativeX);
							relativeX -= horizAxis.ValueToPosition(xValue + relativeWidth) - relativeX;
						}
					}
				}
				else 
				{
					relativeX = relativeAnchorX + this.AnchorOffsetX;
					relativeX *= groupScaleX;
					if(relativeWidth != 0f && !double.IsNaN(relativeWidth))
					{
						if(inRelativeWidth)
						{
							relativeX -= relativeWidth/2f;
						}
						else if(horizAxis != null)
						{
							float xValue = (float)horizAxis.PositionToValue(relativeX);
							relativeX -= (horizAxis.ValueToPosition(xValue + relativeWidth) - relativeX) / 2f;
						}
					}
				}
			}
			else
			{
				relativeX *= groupScaleX;
			}
 
			// Translate
			relativeX += groupLocation.X;
			relativeY += groupLocation.Y;
 
			//***********************************************************************
			//** Get annotation automatic location.
			//***********************************************************************
 
			// Set annotation size if not set to custom value
			if( double.IsNaN(relativeX) )
			{
				relativeX = contentPosition.X * groupScaleX;
				inRelativeX = true;
			}
			if( double.IsNaN(relativeY) )
			{
				relativeY = contentPosition.Y * groupScaleY;
				inRelativeY = true;
			}
 
			//***********************************************************************
			//** Convert coordinates from axes values to relative coordinates.
			//***********************************************************************
 
			// Check if values are set in axis values
			if(horizAxis != null)
			{
				if(!inRelativeX)
				{
					relativeX = horizAxis.ValueToPosition(relativeX);
				}
				if(!inRelativeAnchorX)
				{
					anchorX = horizAxis.ValueToPosition(anchorX);
				}
				if(!inRelativeWidth)
				{
					relativeWidth = horizAxis.ValueToPosition(
						horizAxis.PositionToValue(relativeX, false) + relativeWidth) - relativeX;
				}
			}
			if(vertAxis != null)
			{
				if(!inRelativeY)
				{
					relativeY = vertAxis.ValueToPosition(relativeY);
				}
				if(!inRelativeAnchorY)
				{
					anchorY = vertAxis.ValueToPosition(anchorY);
				}
				if(!inRelativeHeight)
				{
					relativeHeight = vertAxis.ValueToPosition(
						vertAxis.PositionToValue(relativeY, false) + relativeHeight) - relativeY;
				}
			}
            bool isTextAnnotation = this is TextAnnotation;
			//***********************************************************************
			//** Apply 3D transforamtion if required
			//***********************************************************************
			ChartArea	chartArea = null;
			if(horizAxis != null && horizAxis.ChartArea != null)
			{
				chartArea = horizAxis.ChartArea;
			}
			if(vertAxis != null && vertAxis.ChartArea != null)
			{
				chartArea = vertAxis.ChartArea;
			}
			if(chartArea != null && 
				chartArea.Area3DStyle.Enable3D == true &&
				!chartArea.chartAreaIsCurcular &&
                chartArea.requireAxes &&
				chartArea.matrix3D.IsInitialized())
			{
				// Get anotation Z coordinate (use scene depth or anchored point Z position)
				float			positionZ = chartArea.areaSceneDepth;	
				if(this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
				{
					float depth = 0f;
					chartArea.GetSeriesZPositionAndDepth(
						this.AnchorDataPoint.series,
						out depth,
						out positionZ);
					positionZ += depth / 2f;
				}
 
				// Define 3D points of annotation object
				Point3D[]		annot3DPoints = new Point3D[3];
				annot3DPoints[0] = new Point3D((float)relativeX, (float)relativeY, positionZ);
				annot3DPoints[1] = new Point3D((float)(relativeX + relativeWidth), (float)(relativeY + relativeHeight), positionZ);
				annot3DPoints[2] = new Point3D((float)anchorX, (float)anchorY, positionZ);
 
				// Tranform cube coordinates
				chartArea.matrix3D.TransformPoints( annot3DPoints );
 
				// Get transformed coordinates
				relativeX = annot3DPoints[0].X;
				relativeY = annot3DPoints[0].Y;
				anchorX = annot3DPoints[2].X;
				anchorY = annot3DPoints[2].Y;
				
				// Don't adjust size for text annotation
                if (!(isTextAnnotation && this.IsSizeAlwaysRelative))
				{
					relativeWidth = annot3DPoints[1].X - relativeX;
					relativeHeight = annot3DPoints[1].Y - relativeY;
				}
			}
 
			//***********************************************************************
			//** Provide "dummy" position at design time
			//***********************************************************************
			if(this.Chart != null && this.Chart.IsDesignMode())
			{
				if(double.IsNaN(relativeX))
				{
					relativeX = groupLocation.X;
					saveCurrentPosition = false;
				}
				if(double.IsNaN(relativeY))
				{
					relativeY = groupLocation.Y;
					saveCurrentPosition = false;
				}
				if(double.IsNaN(relativeWidth))
				{
					relativeWidth = 20.0 * groupScaleX;
					saveCurrentPosition = false;
				}
				if(double.IsNaN(relativeHeight))
				{
					relativeHeight = 20.0 * groupScaleY;
					saveCurrentPosition = false;
				}
			}
 
			//***********************************************************************
			//** Initialize returned values
			//***********************************************************************
			location = new PointF( (float)relativeX, (float)relativeY );
			size = new SizeF( (float)relativeWidth, (float)relativeHeight );
			anchorLocation = new PointF( (float)anchorX, (float)anchorY );
 
			//***********************************************************************
			//** Adjust text based annotaion position using SmartLabelStyle.
			//***********************************************************************
			// Check if smart labels are enabled
            if (this.SmartLabelStyle.Enabled && isTextAnnotation &&
				group == null)
			{
				// Anchor point must be set
				if(!double.IsNaN(anchorX) && !double.IsNaN(anchorY) &&
					double.IsNaN(this.X) && double.IsNaN(this.Y))
				{
					if(this.Chart != null && 
						this.Chart.chartPicture != null)
					{
						// Remember old movement distance restriction
						double oldMinMovingDistance = this.SmartLabelStyle.MinMovingDistance;
						double oldMaxMovingDistance = this.SmartLabelStyle.MaxMovingDistance;
 
						// Increase annotation moving restrictions according to the anchor offset
						PointF anchorOffsetAbs = this.GetGraphics().GetAbsolutePoint(
							new PointF((float)this.AnchorOffsetX, (float)this.AnchorOffsetY));
						float maxAnchorOffsetAbs = Math.Max(anchorOffsetAbs.X, anchorOffsetAbs.Y);
						if(maxAnchorOffsetAbs > 0.0)
						{
							this.SmartLabelStyle.MinMovingDistance += maxAnchorOffsetAbs;
							this.SmartLabelStyle.MaxMovingDistance += maxAnchorOffsetAbs;
						}
 
						// Adjust label position using SmartLabelStyle algorithm
						LabelAlignmentStyles	labelAlignment = LabelAlignmentStyles.Bottom;
                        using (StringFormat format = new StringFormat())
                        {
                            SizeF markerSizeRel = new SizeF((float)this.AnchorOffsetX, (float)this.AnchorOffsetY);
                            PointF newlocation = this.Chart.chartPicture.annotationSmartLabel.AdjustSmartLabelPosition(
                                this.Common,
                                this.Chart.chartPicture.ChartGraph,
                                chartArea,
                                this.SmartLabelStyle,
                                location,
                                size,
                                format,
                                anchorLocation,
                                markerSizeRel,
                                labelAlignment,
                                (this is CalloutAnnotation));
 
                            // Restore old movement distance restriction
                            this.SmartLabelStyle.MinMovingDistance = oldMinMovingDistance;
                            this.SmartLabelStyle.MaxMovingDistance = oldMaxMovingDistance;
 
                            // Check if annotation should be hidden
                            if (newlocation.IsEmpty)
                            {
                                location = new PointF(float.NaN, float.NaN);
                            }
                            else
                            {
                                // Get new position using alignment in format
                                RectangleF newPosition = this.Chart.chartPicture.annotationSmartLabel.GetLabelPosition(
                                    this.Chart.chartPicture.ChartGraph,
                                    newlocation,
                                    size,
                                    format,
                                    false);
 
                                // Set new location
                                location = newPosition.Location;
                            }
                        }
					}
				}
				else
				{
					// Add annotation position into the list (to prevent overlapping)
                    using (StringFormat format = new StringFormat())
                    {
                        this.Chart.chartPicture.annotationSmartLabel.AddSmartLabelPosition(
                            this.Chart.chartPicture.ChartGraph,
                            location,
                            size,
                            format);
                    }
				}
			}
 
			//***********************************************************************
			//** Save calculated position
			//***********************************************************************
			if(saveCurrentPosition)
			{
				currentPositionRel = new RectangleF(location, size);
				currentAnchorLocationRel = new PointF(anchorLocation.X, anchorLocation.Y);
			}
		}
 
#if Microsoft_CONTROL
		/// <summary>
		/// Set annotation object position using rectangle in relative coordinates.
		/// Automatically converts relative coordinates to axes values if required.
		/// </summary>
		/// <param name="position">Position in relative coordinates.</param>
		/// <param name="anchorPoint">Anchor location in relative coordinates.</param>
		internal void SetPositionRelative(RectangleF position, PointF anchorPoint)
		{
			SetPositionRelative(position, anchorPoint, false);
		}
#endif // Microsoft_CONTROL
 
		/// <summary>
		/// Set annotation object position using rectangle in relative coordinates.
		/// Automatically converts relative coordinates to axes values if required.
		/// </summary>
		/// <param name="position">Position in relative coordinates.</param>
		/// <param name="anchorPoint">Anchor location in relative coordinates.</param>
		/// <param name="userInput">Indicates if position changing was a result of the user input.</param>
		internal void SetPositionRelative(RectangleF position, PointF anchorPoint, bool userInput)
		{
			double	newX = position.X;
			double	newY = position.Y;
			double	newRight = position.Right;
			double	newBottom = position.Bottom;
			double	newWidth = position.Width;
			double	newHeight = position.Height;
			double	newAnchorX = anchorPoint.X;
			double	newAnchorY = anchorPoint.Y;
 
			//***********************************************************************
			//** Set pre calculated position and anchor location
			//***********************************************************************
			this.currentPositionRel = new RectangleF(position.Location, position.Size);
			this.currentAnchorLocationRel = new PointF(anchorPoint.X, anchorPoint.Y);
 
			//***********************************************************************
			//** Get vertical and horizontal axis
			//***********************************************************************
			Axis	vertAxis = null;
			Axis	horizAxis = null;
			GetAxes(ref vertAxis, ref horizAxis);
 
			//***********************************************************************
			//** Disable anchoring to point and axes in 3D
			//** This is done due to the issues of moving elements in 3D space.
			//***********************************************************************
			ChartArea	chartArea = null;
			if(horizAxis != null && horizAxis.ChartArea != null)
			{
				chartArea = horizAxis.ChartArea;
			}
			if(vertAxis != null && vertAxis.ChartArea != null)
			{
				chartArea = vertAxis.ChartArea;
			}
			if(chartArea != null && chartArea.Area3DStyle.Enable3D == true)
			{
				// If anchor point was set - get its relative position and use it as an anchor point
				if(this.AnchorDataPoint != null)
				{
					bool	inRelativeCoordX = true;
					bool	inRelativeCoordY = true;
					this.GetAnchorLocation(ref newAnchorX, ref newAnchorY, ref inRelativeCoordX, ref inRelativeCoordY);
					this.currentAnchorLocationRel = new PointF((float)newAnchorX, (float)newAnchorY);
				}
 
				// In 3D always use relative annotation coordinates
				// Disconnect annotation from axes and anchor point
				this.AnchorDataPoint = null;
				this.AxisX = null;
				this.AxisY = null;
				horizAxis = null;
				vertAxis = null;
			}
 
 
			//***********************************************************************
			//** Convert relative coordinates to axis values
			//***********************************************************************
			if(horizAxis != null)
			{
				newX = horizAxis.PositionToValue(newX, false);
				if(!double.IsNaN(newAnchorX))
				{
					newAnchorX = horizAxis.PositionToValue(newAnchorX, false);
				}
 
				// Adjust for the IsLogarithmic axis
				if( horizAxis.IsLogarithmic ) 
				{
					newX = Math.Pow( horizAxis.logarithmBase, newX );
					if(!double.IsNaN(newAnchorX))
					{
						newAnchorX = Math.Pow( horizAxis.logarithmBase, newAnchorX );
					}
				}
 
				if(!this.IsSizeAlwaysRelative)
				{
					if(float.IsNaN(position.Right) && 
						!float.IsNaN(position.Width) && 
						!float.IsNaN(anchorPoint.X) )
					{
						newRight = horizAxis.PositionToValue(anchorPoint.X + position.Width, false);
						if( horizAxis.IsLogarithmic ) 
						{
							newRight = Math.Pow( horizAxis.logarithmBase, newRight );
						}
						newWidth = newRight - newAnchorX;
					}
					else
					{
						newRight = horizAxis.PositionToValue(position.Right, false);
						if( horizAxis.IsLogarithmic ) 
						{
							newRight = Math.Pow( horizAxis.logarithmBase, newRight );
						}
						newWidth = newRight - newX;
					}
				}
			}
			if(vertAxis != null)
			{
				newY = vertAxis.PositionToValue(newY, false);
				if(!double.IsNaN(newAnchorY))
				{
					newAnchorY = vertAxis.PositionToValue(newAnchorY, false);
				}
 
				// NOTE: Fixes issue #4113
				// Adjust for the IsLogarithmic axis
				if( vertAxis.IsLogarithmic ) 
				{
					newY = Math.Pow( vertAxis.logarithmBase, newY );
					if(!double.IsNaN(newAnchorY))
					{
						newAnchorY = Math.Pow( vertAxis.logarithmBase, newAnchorY );
					}
				}
 
				if(!this.IsSizeAlwaysRelative)
				{
					if(float.IsNaN(position.Bottom) && 
						!float.IsNaN(position.Height) && 
						!float.IsNaN(anchorPoint.Y) )
					{
						newBottom = vertAxis.PositionToValue(anchorPoint.Y + position.Height, false);
						if( vertAxis.IsLogarithmic ) 
						{
							newBottom = Math.Pow( vertAxis.logarithmBase, newBottom );
						}
						newHeight = newBottom - newAnchorY;
					}
					else
					{
						newBottom = vertAxis.PositionToValue(position.Bottom, false);
						if( vertAxis.IsLogarithmic ) 
						{
							newBottom = Math.Pow( vertAxis.logarithmBase, newBottom );
						}
						newHeight = newBottom - newY;
					}
				}
			}
 
			// Fire position changing event when position changed by user.
			if(userInput)
			{
#if Microsoft_CONTROL
				// Set flag that annotation position was changed
				this.positionChanged = true;
 
				// Fire position changing event
				if(this.Chart != null)
				{
					AnnotationPositionChangingEventArgs args = new AnnotationPositionChangingEventArgs();
					args.NewLocationX = newX;
					args.NewLocationY = newY;
					args.NewSizeWidth = newWidth;
					args.NewSizeHeight = newHeight;
					args.NewAnchorLocationX = newAnchorX;
					args.NewAnchorLocationY = newAnchorY;
					args.Annotation = this;
 
					if(this.Chart.OnAnnotationPositionChanging(ref args))
					{
						// Get user changed position/anchor
						newX = args.NewLocationX;
						newY = args.NewLocationY;
						newWidth = args.NewSizeWidth;
						newHeight = args.NewSizeHeight;
						newAnchorX = args.NewAnchorLocationX;
						newAnchorY = args.NewAnchorLocationY;
					}
				}
#endif // Microsoft_CONTROL
			}
 
			// Adjust location & size
			this.X = newX;
			this.Y = newY;
			this.Width = newWidth;
			this.Height = newHeight;
			this.AnchorX = newAnchorX;
			this.AnchorY = newAnchorY;
 
			// Invalidate annotation
			this.Invalidate();
 
			return;
		}
        /// <summary>
        /// Adjust annotation location and\or size as a result of user action.
        /// </summary>
        /// <param name="movingDistance">Distance to resize/move the annotation.</param>
        /// <param name="resizeMode">Resizing mode.</param>
		virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode)
		{
			AdjustLocationSize(movingDistance, resizeMode, true);
		}
 
        /// <summary>
        /// Adjust annotation location and\or size as a result of user action.
        /// </summary>
        /// <param name="movingDistance">Distance to resize/move the annotation.</param>
        /// <param name="resizeMode">Resizing mode.</param>
        /// <param name="pixelCoord">Distance is in pixels, otherwise relative.</param>
		virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode, bool pixelCoord)
		{
			AdjustLocationSize(movingDistance, resizeMode, pixelCoord, false);
		}
 
        /// <summary>
        /// Adjust annotation location and\or size as a result of user action.
        /// </summary>
        /// <param name="movingDistance">Distance to resize/move the annotation.</param>
        /// <param name="resizeMode">Resizing mode.</param>
        /// <param name="pixelCoord">Distance is in pixels, otherwise relative.</param>
        /// <param name="userInput">Indicates if position changing was a result of the user input.</param>
		virtual internal void AdjustLocationSize(SizeF movingDistance, ResizingMode resizeMode, bool pixelCoord, bool userInput)
		{
			if(!movingDistance.IsEmpty)
			{
				// Convert pixel coordinates into relative 
				if(pixelCoord)
				{
					movingDistance = Chart.chartPicture.ChartGraph.GetRelativeSize(movingDistance);
				}
 
				// Get annotation position in relative coordinates
				PointF firstPoint = PointF.Empty;
				PointF anchorPoint = PointF.Empty;
				SizeF size = SizeF.Empty;
				if(userInput)
				{
#if Microsoft_CONTROL
					if(this.startMovePositionRel.X == 0f &&
						this.startMovePositionRel.Y == 0f &&
						this.startMovePositionRel.Width == 0f &&
						this.startMovePositionRel.Height == 0f)
					{
						GetRelativePosition(out firstPoint, out size, out anchorPoint);
						this.startMovePositionRel = new RectangleF(firstPoint, size);
						this.startMoveAnchorLocationRel = new PointF(anchorPoint.X, anchorPoint.Y);
					}
					firstPoint = this.startMovePositionRel.Location;
					size = this.startMovePositionRel.Size;
					anchorPoint = this.startMoveAnchorLocationRel;
#else // Microsoft_CONTROL
					GetRelativePosition(out firstPoint, out size, out anchorPoint);
#endif // Microsoft_CONTROL
					
				}
				else
				{
					GetRelativePosition(out firstPoint, out size, out anchorPoint);
				}
 
				if(resizeMode == ResizingMode.TopLeftHandle)
				{
					firstPoint.X -= movingDistance.Width;
					firstPoint.Y -= movingDistance.Height;
					size.Width += movingDistance.Width;
					size.Height += movingDistance.Height;
				}
				else if(resizeMode == ResizingMode.TopHandle)
				{
					firstPoint.Y -= movingDistance.Height;
					size.Height += movingDistance.Height;
				}
				else if(resizeMode == ResizingMode.TopRightHandle)
				{
					firstPoint.Y -= movingDistance.Height;
					size.Width -= movingDistance.Width;
					size.Height += movingDistance.Height;
				}
				else if(resizeMode == ResizingMode.RightHandle)
				{
					size.Width -= movingDistance.Width;
				}
				else if(resizeMode == ResizingMode.BottomRightHandle)
				{
					size.Width -= movingDistance.Width;
					size.Height -= movingDistance.Height;
				}
				else if(resizeMode == ResizingMode.BottomHandle)
				{
					size.Height -= movingDistance.Height;
				}
				else if(resizeMode == ResizingMode.BottomLeftHandle)
				{
					firstPoint.X -= movingDistance.Width;
					size.Width += movingDistance.Width;
					size.Height -= movingDistance.Height;
				}
				else if(resizeMode == ResizingMode.LeftHandle)
				{
					firstPoint.X -= movingDistance.Width;
					size.Width += movingDistance.Width;
				}
				else if(resizeMode == ResizingMode.AnchorHandle)
				{
					anchorPoint.X -= movingDistance.Width;
					anchorPoint.Y -= movingDistance.Height;
				}
				else if(resizeMode == ResizingMode.Moving)
				{
					firstPoint.X -= movingDistance.Width;
					firstPoint.Y -= movingDistance.Height;
				}
 
				// Make sure we do not override automatic Width and Heigth
				if(resizeMode == ResizingMode.Moving)
				{
					if( double.IsNaN(this.Width) )
					{
						size.Width = float.NaN;
					}
					if( double.IsNaN(this.Height) )
					{
						size.Height = float.NaN;
					}
				}
 
				// Make sure we do not override automatic X and Y
				if(resizeMode == ResizingMode.AnchorHandle)
				{
					if( double.IsNaN(this.X) )
					{
						firstPoint.X = float.NaN;
					}
					if( double.IsNaN(this.Y) )
					{
						firstPoint.Y = float.NaN;
					}
				}
				else if(double.IsNaN(this.AnchorX) || double.IsNaN(this.AnchorY) )
				{
					anchorPoint = new PointF(float.NaN, float.NaN);
				}
 
				// Set annotation position from rectangle in relative coordinates
				SetPositionRelative(new RectangleF(firstPoint, size), anchorPoint, userInput);
			}
			return;
		}
 
		#endregion
 
		#region Anchor Point and Axes Converters
 
		/// <summary>
		/// Checks if annotation draw anything in the anchor position (except selection handle)
		/// </summary>
		/// <returns>True if annotation "connects" itself and anchor point visually.</returns>
		virtual internal bool IsAnchorDrawn()
		{
			return false;
		}
 
		/// <summary>
		/// Gets data point by name.
		/// </summary>
		/// <param name="dataPointName">Data point name to find.</param>
		/// <returns>Data point.</returns>
		internal DataPoint GetDataPointByName(string dataPointName)
		{
			DataPoint dataPoint = null;
 
            if (Chart != null && dataPointName.Length > 0)
            {
                // Split series name and point index
                int separatorIndex = dataPointName.IndexOf("\\r", StringComparison.Ordinal);
                if (separatorIndex > 0)
                {
                    string seriesName = dataPointName.Substring(0, separatorIndex);
                    string pointIndex = dataPointName.Substring(separatorIndex + 2);
 
                    int index;
                    if (int.TryParse(pointIndex, NumberStyles.Any, CultureInfo.InvariantCulture, out index))
                    {
                        dataPoint = Chart.Series[seriesName].Points[index];
                    }
                }
            }
        	
			return dataPoint;
		}
 
		/// <summary>
		/// Gets axis by name.
		/// </summary>
		/// <param name="axisName">Axis name to find.</param>
		/// <returns>Data point.</returns>
		private Axis GetAxisByName(string axisName)
		{
            Debug.Assert(axisName != null, "GetAxisByName: handed a null axis name");
 
			Axis axis = null;
 
            try
            {
                if (Chart != null && axisName.Length > 0)
                {
                    // Split series name and point index
                    int separatorIndex = axisName.IndexOf("\\r", StringComparison.Ordinal);
                    if (separatorIndex > 0)
                    {
                        string areaName = axisName.Substring(0, separatorIndex);
                        string axisType = axisName.Substring(separatorIndex + 2);
                        switch ((AxisName)Enum.Parse(typeof(AxisName), axisType))
                        {
                            case (AxisName.X):
                                axis = Chart.ChartAreas[areaName].AxisX;
                                break;
                            case (AxisName.Y):
                                axis = Chart.ChartAreas[areaName].AxisY;
                                break;
                            case (AxisName.X2):
                                axis = Chart.ChartAreas[areaName].AxisX2;
                                break;
                            case (AxisName.Y2):
                                axis = Chart.ChartAreas[areaName].AxisY2;
                                break;
                        }
                    }
                }
            }
            catch (ArgumentNullException)
            {
                axis = null;
            }
            catch (ArgumentException)
            {
                axis = null;
            }
				
			return axis;
		}
 
		/// <summary>
		/// Gets data point unique name.
		/// </summary>
		/// <param name="dataPoint">Data point to get the name for.</param>
		/// <returns>Data point name.</returns>
		internal string GetDataPointName(DataPoint dataPoint)
		{
			string name = String.Empty;
			if(dataPoint.series != null)
			{
				int pointIndex = dataPoint.series.Points.IndexOf(dataPoint);
				if(pointIndex >= 0)
				{
					name = dataPoint.series.Name + 
						"\\r" + 
						pointIndex.ToString(CultureInfo.InvariantCulture);
				}
			}
			return name;
		}
 
		/// <summary>
		/// Gets axis unique name.
		/// </summary>
		/// <param name="axis">Axis to get the name for.</param>
		/// <returns>Axis name.</returns>
		private string GetAxisName(Axis axis)
		{
			string name = String.Empty;
			if(axis.ChartArea != null)
			{
				name = axis.ChartArea.Name + 
					"\\r" + 
					axis.AxisName.ToString();
			}
			return name;
		}
 
		#endregion
 
		#region Z Order Methods
 
		/// <summary>
		/// Sends an annotation to the back of all annotations.
		/// <seealso cref="BringToFront"/>
		/// </summary>
		virtual public void SendToBack()
		{
			// Find collection of annotation objects this annotation belongs too
			AnnotationCollection collection = null;
			if(Chart != null)
			{
				collection = Chart.Annotations;
			}
 
			// Check if annotation belongs to the group
			AnnotationGroup group = AnnotationGroup;
			if(group != null)
			{
				collection = group.Annotations;
			}
 
			// Check if annotation is found
			if(collection != null)
			{
				Annotation annot = collection.FindByName(this.Name);
				if(annot != null)
				{
					// Reinsert annotation at the beginning of the collection
					collection.Remove(annot);
					collection.Insert(0, annot);
				}
			}
		}
 
		/// <summary>
		/// Brings an annotation to the front of all annotations.
		/// <seealso cref="SendToBack"/>
		/// </summary>
		virtual public void BringToFront()
		{
			// Find collection of annotation objects this annotation belongs too
			AnnotationCollection collection = null;
			if(Chart != null)
			{
				collection = Chart.Annotations;
			}
 
			// Check if annotation belongs to the group
			AnnotationGroup group = AnnotationGroup;
			if(group != null)
			{
				collection = group.Annotations;
			}
 
			// Check if annotation is found
			if(collection != null)
			{
				Annotation annot = collection.FindByName(this.Name);
				if(annot != null)
				{
					// Reinsert annotation at the end of the collection
					collection.Remove(annot);
					collection.Add(this);
				}
			}
		}
 
		#endregion // Z Order Methods
 
		#region Group Related Methods
 
		#endregion // Group Related Methods
 
		#region SmartLabelStyle methods
 
		/// <summary>
		/// Adds anchor position to the list. Used to check SmartLabelStyle overlapping.
		/// </summary>
		/// <param name="list">List to add to.</param>
		internal void AddSmartLabelMarkerPositions(ArrayList list)		
		{
			// Anchor position is added to the list of non-overlapped markers
			if(this.Visible && this.IsAnchorDrawn())
			{
				// Get vertical and horizontal axis
				Axis	vertAxis = null;
				Axis	horizAxis = null;
				GetAxes(ref vertAxis, ref horizAxis);
 
				// Get anchor position
				double	anchorX = double.NaN;
				double	anchorY = double.NaN;
				bool	relativeX = false;
				bool	relativeY = false;
				this.GetAnchorLocation(ref anchorX, ref anchorY, ref relativeX, ref relativeY);
 
				// Convert anchor location to relative coordinates
				if(!double.IsNaN(anchorX) && !double.IsNaN(anchorY))
				{
					if( !relativeX && horizAxis != null )
					{
						anchorX = horizAxis.ValueToPosition(anchorX);
					}
					if( !relativeY && vertAxis != null )
					{
						anchorY = vertAxis.ValueToPosition(anchorY);
					}
 
					// Apply 3D transforamtion if required
					ChartArea	chartArea = null;
					if(horizAxis != null && horizAxis.ChartArea != null)
					{
						chartArea = horizAxis.ChartArea;
					}
					if(vertAxis != null && vertAxis.ChartArea != null)
					{
						chartArea = vertAxis.ChartArea;
					}
					if(chartArea != null && 
						chartArea.Area3DStyle.Enable3D == true &&
						!chartArea.chartAreaIsCurcular &&
                        chartArea.requireAxes &&
						chartArea.matrix3D.IsInitialized())
					{
						// Get anotation Z coordinate (use scene depth or anchored point Z position)
						float			positionZ = chartArea.areaSceneDepth;	
						if(this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
						{
							float depth = 0f;
							chartArea.GetSeriesZPositionAndDepth(
								this.AnchorDataPoint.series,
								out depth,
								out positionZ);
							positionZ += depth / 2f;
						}
 
						// Define 3D points of annotation object
						Point3D[]		annot3DPoints = new Point3D[1];
						annot3DPoints[0] = new Point3D((float)anchorX, (float)anchorY, positionZ);
 
						// Tranform cube coordinates
						chartArea.matrix3D.TransformPoints( annot3DPoints );
 
						// Get transformed coordinates
						anchorX = annot3DPoints[0].X;
						anchorY = annot3DPoints[0].Y;
					}
 
					// Save selection handles position in array elements 0 and 4
					if(this.GetGraphics() != null)
					{
						SizeF	markerSizeRel = this.GetGraphics().GetRelativeSize(
							new SizeF(1f, 1f));
						RectangleF anchorRect = new RectangleF(
							(float)anchorX - markerSizeRel.Width/2f,
							(float)anchorY - markerSizeRel.Height/2f,
							markerSizeRel.Width,
							markerSizeRel.Height);
 
						list.Add(anchorRect);
					}
				}
			}
		}
 
		#endregion
 
		#region Public Anchoring Methods
 
		/// <summary>
		/// Anchors an annotation to a data point.
		/// <seealso cref="AnchorDataPoint"/>
		/// <seealso cref="AnchorX"/>
		/// <seealso cref="AnchorY"/>
		/// </summary>
		/// <param name="dataPoint">
		/// <see cref="DataPoint"/> to be anchored to.
		/// </param>
		/// <remarks>
		/// Anchors an annotation to the specified data point.
		/// </remarks>
		public void SetAnchor(DataPoint dataPoint)
		{
			SetAnchor(dataPoint, null);
		}
 
		/// <summary>
		/// Anchors an annotation to two data points.
		/// <seealso cref="AnchorDataPoint"/>
		/// <seealso cref="AnchorX"/>
		/// <seealso cref="AnchorY"/>
		/// </summary>
		/// <param name="dataPoint1">
		/// First anchor <see cref="DataPoint"/>.
		/// </param>
		/// <param name="dataPoint2">
		/// Second anchor <see cref="DataPoint"/>.
		/// </param>
		/// <remarks>
		/// Anchors an annotation's top/left and bottom/right corners to the 
		/// specified data points.
		/// </remarks>
		public void SetAnchor(DataPoint dataPoint1, DataPoint dataPoint2)
		{
			// Set annotation position to automatic
			this.X = double.NaN;
			this.Y = double.NaN;
 
			// Reset anchor point if any
			this.AnchorX = double.NaN;
			this.AnchorY = double.NaN;
 
			// Set anchor point
			this.AnchorDataPoint = dataPoint1;
 
			// Get vertical and horizontal axis
			Axis	vertAxis = null;
			Axis	horizAxis = null;
			GetAxes(ref vertAxis, ref horizAxis);
 
			// Set Width and Height in axis coordinates
			if(dataPoint2 != null && dataPoint1 != null)
			{
                this._anchorDataPoint2 = dataPoint2;
			}
 
			// Invalidate annotation
			this.Invalidate();
		}
 
		#endregion // Public Anchoring Methods
 
		#region Placement Methods
 
#if Microsoft_CONTROL

		/// <summary>
		/// Begins end user placement of an annotation using the mouse.
		/// </summary>
		/// <remarks>
		/// When this method is called, the end user is allowed to place an annotation using the 
		/// mouse.
		/// <para>
		/// Placement will finish when the end user specifies all required points, or 
		/// the <see cref="EndPlacement"/> method is called.</para>
		/// </remarks>
		virtual public void BeginPlacement()
		{
			// Can't place annotations inside the group
			if(this.AnnotationGroup != null)
			{
                throw (new InvalidOperationException(SR.ExceptionAnnotationGroupedUnableToStartPlacement));
			}
 
			if(this.Chart != null)
			{
				// Set the annotation object which is currently placed 
				this.Chart.Annotations.placingAnnotation = this;
			}
			else
			{
                throw (new InvalidOperationException(SR.ExceptionAnnotationNotInCollection));
			}
 
		}
 
		/// <summary>
		/// Ends user placement of an annotation.
		/// </summary>
		/// <remarks>
		/// Ends an annotation placement operation previously started by a 
		/// <see cref="BeginPlacement"/> method call.
		/// <para>
		/// Calling this method is not required, since placement will automatically
		/// end when an end user enters all required points. However, it is useful when an annotation 
		/// placement operation needs to be aborted for some reason.
		/// </para>
		/// </remarks>
		virtual public void EndPlacement()
		{
			if(this.Chart != null)
			{
				// Reset currently placed annotation object
				this.Chart.Annotations.placingAnnotation = null;
 
				// Restore default cursor
				this.Chart.Cursor = this.Chart.defaultCursor;
 
				// Clear last placement mouse position
				this.lastPlacementPosition = PointF.Empty;
 
				// Fire annotation placed event
				this.Chart.OnAnnotationPlaced(this);
			}
		}
 
		/// <summary>
		/// Handles mouse down event during annotation placement.
		/// </summary>
		/// <param name="point">Mouse cursor position in pixels.</param>
		/// <param name="buttons">Mouse button down.</param>
		internal virtual void PlacementMouseDown(PointF point, MouseButtons buttons)
		{
			if(buttons == MouseButtons.Right)
			{
				// Stop any pacement
				this.EndPlacement();
			}
			if(buttons == MouseButtons.Left &&
				IsValidPlacementPosition(point.X, point.Y))
			{
				if(this.lastPlacementPosition.IsEmpty)
				{
					// Remeber position where mouse was clicked
					this.lastPlacementPosition = this.GetGraphics().GetRelativePoint(point);
 
					// Get annotation position in relative coordinates
					PointF firstPoint = PointF.Empty;
					PointF anchorPoint = PointF.Empty;
					SizeF size = SizeF.Empty;
					this.GetRelativePosition(out firstPoint, out size, out anchorPoint);
 
					// Set annotation X, Y coordinate
					if(this.AllowMoving)
					{
						firstPoint = this.GetGraphics().GetRelativePoint(point);
 
						// Do not change default position
						if(double.IsNaN(this.AnchorX))
						{
							anchorPoint.X = float.NaN;
						}
						if(double.IsNaN(this.AnchorY))
						{
							anchorPoint.Y = float.NaN;
						}
 
					}
					else if(this.AllowAnchorMoving)
					{
						anchorPoint = this.GetGraphics().GetRelativePoint(point);
 
						// Do not change default position
						if(double.IsNaN(this.X))
						{
							firstPoint.X = float.NaN;
						}
						if(double.IsNaN(this.Y))
						{
							firstPoint.Y = float.NaN;
						}
					}
 
					// Do not change default size
					if(double.IsNaN(this.Width))
					{
						size.Width = float.NaN;
					}
					if(double.IsNaN(this.Height))
					{
						size.Height = float.NaN;
					}
 
					// Set annotation position
					this.positionChanged = true;
					this.SetPositionRelative(
						new RectangleF(firstPoint, size), 
						anchorPoint, 
						true);
 
					// Invalidate and update the chart
					if(Chart != null)
					{
						Invalidate();
						Chart.UpdateAnnotations();
					}
				}
			}
		}
 
		/// <summary>
		/// Handles mouse up event during annotation placement.
		/// </summary>
		/// <param name="point">Mouse cursor position in pixels.</param>
		/// <param name="buttons">Mouse button Up.</param>
		/// <returns>Return true when placing finished.</returns>
		internal virtual bool PlacementMouseUp(PointF point, MouseButtons buttons)
		{
			bool result = false;
			if(buttons == MouseButtons.Left)
			{
				// Get annotation position in relative coordinates
				PointF firstPoint = PointF.Empty;
				PointF anchorPoint = PointF.Empty;
				SizeF size = SizeF.Empty;
				this.GetRelativePosition(out firstPoint, out size, out anchorPoint);
 
				if(this.AllowResizing)
				{
					PointF pointRel = this.GetGraphics().GetRelativePoint(point);
					size = new SizeF(
						pointRel.X - this.lastPlacementPosition.X, 
						pointRel.Y - this.lastPlacementPosition.Y);
				}
				else
				{
					// Do not change default size
					if(double.IsNaN(this.Width))
					{
						size.Width = float.NaN;
					}
					if(double.IsNaN(this.Height))
					{
						size.Height = float.NaN;
					}
				}
 
				// Do not change default position
				if(double.IsNaN(this.X))
				{
					firstPoint.X = float.NaN;
				}
				if(double.IsNaN(this.Y))
				{
					firstPoint.Y = float.NaN;
				}
				if(double.IsNaN(this.AnchorX))
				{
					anchorPoint.X = float.NaN;
				}
				if(double.IsNaN(this.AnchorY))
				{
					anchorPoint.Y = float.NaN;
				}
 
				// Set annotation position
				this.positionChanged = true;
				this.SetPositionRelative(
					new RectangleF(firstPoint, size), 
					anchorPoint, 
					true);
 
				// End placement
				if(!size.IsEmpty || !this.AllowResizing)
				{
					result = true;
					this.EndPlacement();
				}
 
				// Invalidate and update the chart
				if(Chart != null)
				{
					Invalidate();
					Chart.UpdateAnnotations();
				}
			}
 
			return result;
		}
 
		/// <summary>
		/// Handles mouse move event during annotation placement.
		/// </summary>
		/// <param name="point">Mouse cursor position in pixels.</param>
		internal virtual void PlacementMouseMove(PointF point)
		{
			// Check if annotation was moved
			if( this.GetGraphics() != null &&
				!this.lastPlacementPosition.IsEmpty)
			{
				// Get annotation position in relative coordinates
				PointF firstPoint = PointF.Empty;
				PointF anchorPoint = PointF.Empty;
				SizeF size = SizeF.Empty;
				this.GetRelativePosition(out firstPoint, out size, out anchorPoint);
 
				if(this.AllowResizing)
				{
					PointF pointRel = this.GetGraphics().GetRelativePoint(point);
					size = new SizeF(
						pointRel.X - this.lastPlacementPosition.X, 
						pointRel.Y - this.lastPlacementPosition.Y);
				}
 
				// Do not change default position
				if(double.IsNaN(this.X))
				{
					firstPoint.X = float.NaN;
				}
				if(double.IsNaN(this.Y))
				{
					firstPoint.Y = float.NaN;
				}
				if(double.IsNaN(this.AnchorX))
				{
					anchorPoint.X = float.NaN;
				}
				if(double.IsNaN(this.AnchorY))
				{
					anchorPoint.Y = float.NaN;
				}
 
				// Set annotation position
				this.positionChanged = true;
				this.SetPositionRelative(
					new RectangleF(firstPoint, size), 
					anchorPoint, 
					true);
 
				// Invalidate and update the chart
				if(this.Chart != null)
				{
					Invalidate();
					this.Chart.UpdateAnnotations();
				}
			}
		}
 
		/// <summary>
		/// Checks if specified position is valid for placement.
		/// </summary>
		/// <param name="x">X coordinate.</param>
		/// <param name="y">Y coordinate.</param>
		/// <returns>True if annotation can be placed at specified coordinates.</returns>
		virtual internal bool IsValidPlacementPosition(float x, float y)
		{
			if(this.Chart != null &&
				this.GetGraphics() != null)
			{
				// Check if cursor is over the area where placement allowed
				// If so - change cursor to cross
				RectangleF	placementRect = new RectangleF(0f, 0f, 100f, 100f);
				if(this.ClipToChartArea.Length > 0 &&
					this.ClipToChartArea != Constants.NotSetValue)
				{
					ChartArea area = Chart.ChartAreas[this.ClipToChartArea];
					placementRect = area.PlotAreaPosition.ToRectangleF();
				}
				placementRect = this.GetGraphics().GetAbsoluteRectangle(placementRect);
				if(placementRect.Contains(x, y))
				{
					return true;
				}
			}
			return false;
		}
 
#endif // Microsoft_CONTROL
 
        #endregion // Placement Methods
 
        #region Helper Methods
 
        /// <summary>
		/// Helper method that checks if annotation is visible.
		/// </summary>
		/// <returns>True if annotation is visible.</returns>
		internal bool IsVisible()
		{
			if(this.Visible)
			{
				if(this.Chart != null)
				{
					// Check if annotation is anchored to the data point
					ChartArea area = null;
					if(this.AnchorDataPoint != null && 
						this.AnchorDataPoint.series != null)
					{
						if(this.Chart.ChartAreas.IndexOf(this.AnchorDataPoint.series.ChartArea) >= 0)
						{
							area = this.Chart.ChartAreas[this.AnchorDataPoint.series.ChartArea];
						}
					}
					if(area == null &&
						this._anchorDataPoint2 != null && 
						this._anchorDataPoint2.series != null)
					{
						if(this.Chart.ChartAreas.IndexOf(this._anchorDataPoint2.series.ChartArea) >= 0)
						{
							area = this.Chart.ChartAreas[this._anchorDataPoint2.series.ChartArea];
						}
					}
 
					// Check if annotation uses chart area axis values
					if(area == null && this.AxisX != null)
					{
						area = this.AxisX.ChartArea;
					}
					if(area == null && this.AxisY != null)
					{
						area = this.AxisY.ChartArea;
					}
 
					// Check if associated area is visible
					if(area != null &&
						!area.Visible)
					{
						return false;
					}
				}
			
					
				return true;
			}
			return false;
		}
 
		/// <summary>
		/// Resets pre-calculated annotation position.
		/// </summary>
		internal void ResetCurrentRelativePosition()
		{
			this.currentPositionRel = new RectangleF(float.NaN, float.NaN, float.NaN, float.NaN);
			this.currentAnchorLocationRel = new PointF(float.NaN, float.NaN);
		}
 
		/// <summary>
		/// Replaces predefined keyword inside the string with their values if
		/// annotation is anchored to the data point.
		/// </summary>
		/// <param name="strOriginal">Original string with keywords.</param>
		/// <returns>Modified string.</returns>
		internal string ReplaceKeywords(string strOriginal)
		{
			if(this.AnchorDataPoint != null)
			{
				return this.AnchorDataPoint.ReplaceKeywords(strOriginal);
			}
			return strOriginal;
		}
 
		/// <summary>
		/// Checks if anchor point of the annotation is visible.
		/// </summary>
		/// <returns>True if anchor point is visible.</returns>
		internal bool IsAnchorVisible()
		{
			// Get axes objects
			Axis	vertAxis = null;
			Axis	horizAxis = null;
			GetAxes(ref vertAxis, ref horizAxis);
 
			// Get anchor position
			bool	inRelativeAnchorX = false;
			bool	inRelativeAnchorY = false;
			double	anchorX = this.AnchorX;
			double	anchorY = this.AnchorY;
			GetAnchorLocation(ref anchorX, ref anchorY, ref inRelativeAnchorX, ref inRelativeAnchorY);
 
			// Check if anchor is set
			if( !double.IsNaN(anchorX) && !double.IsNaN(anchorY) )
			{
				// Check if anchor is in axes coordinates
				if(this.AnchorDataPoint != null || 
					this.AxisX != null ||
					this.AxisY != null)
				{
					// Convert anchor point to relative coordinates
					if(!inRelativeAnchorX && horizAxis != null)
					{
						anchorX = horizAxis.ValueToPosition(anchorX);
					}
					if(!inRelativeAnchorY && vertAxis != null)
					{
						anchorY = vertAxis.ValueToPosition(anchorY);
					}
 
					// Get chart area
					ChartArea chartArea = null;
					if(horizAxis != null)
					{
						chartArea = horizAxis.ChartArea;
					}
					if(chartArea == null && vertAxis != null)
					{
						chartArea = vertAxis.ChartArea;
					}
 
					// Apply 3D transforamtion if required
					if(chartArea != null && chartArea.Area3DStyle.Enable3D == true)
					{
						if(!chartArea.chartAreaIsCurcular &&
                            chartArea.requireAxes &&
							chartArea.matrix3D.IsInitialized())
						{
                            // Get anotation Z coordinate (use scene depth or anchored point Z position)
                            float positionZ = chartArea.areaSceneDepth;
                            if (this.AnchorDataPoint != null && this.AnchorDataPoint.series != null)
                            {
                                float depth = 0f;
                                chartArea.GetSeriesZPositionAndDepth(
                                    this.AnchorDataPoint.series,
                                    out depth,
                                    out positionZ);
                                positionZ += depth / 2f;
                            }
 
                            // Define 3D points of annotation object
                            Point3D[] annot3DPoints = new Point3D[1];
                            annot3DPoints[0] = new Point3D((float)anchorX, (float)anchorY, positionZ);
 
                            // Tranform cube coordinates
                            chartArea.matrix3D.TransformPoints(annot3DPoints);
 
                            // Get transformed coordinates
                            anchorX = annot3DPoints[0].X;
                            anchorY = annot3DPoints[0].Y;
						}
					}
 
					// Get plot rectangle position and inflate it slightly 
					// to solve any float rounding issues.
					RectangleF rect = chartArea.PlotAreaPosition.ToRectangleF();
					rect.Inflate(0.00001f, 0.00001f);
 
					// Check if anchor point is in the plotting area
					if(!rect.Contains((float)anchorX, (float)anchorY))
					{
						return false;
					}
				}
			}
 
			return true;
		}
 
		/// <summary>
		/// Returns chart graphics objects.
		/// </summary>
		/// <returns>Chart graphics object.</returns>
		internal ChartGraphics GetGraphics()
		{
            if (this.Common != null)
			{
				return this.Common.graph;
			}
			return null;
		}
#if Microsoft_CONTROL
		/// <summary>
		/// Checks if provided pixel coordinate is contained in one of the 
		/// selection handles rectangle.
		/// </summary>
		/// <param name="point">Coordinate in pixels.</param>
		/// <returns>Resizing mode.</returns>
		internal ResizingMode GetSelectionHandle(PointF point)
		{
			ResizingMode resizingMode = ResizingMode.None;
 
			if( this.Common != null &&
				this.Common.graph != null)
			{
				// Convert point to relative coordinates
				point = this.Common.graph.GetRelativePoint(point);
 
				// Check if point is in one of the selection handles
				if(this.selectionRects != null)
				{
					for(int index = 0; index < this.selectionRects.Length; index++)
					{
						if(!this.selectionRects[index].IsEmpty && 
							this.selectionRects[index].Contains(point))
						{
							if(index > (int)ResizingMode.AnchorHandle)
							{
								resizingMode = ResizingMode.MovingPathPoints;
								this.currentPathPointIndex = index - 9;
							}
							else
							{
								resizingMode = (ResizingMode)index;
							}
						}
					}
				}
			}
 
			return resizingMode;
		}
#endif //Microsoft_CONTROL
		/// <summary>
		/// Gets data point X or Y axis.
		/// </summary>
		/// <param name="dataPoint">Data point to get the axis for.</param>
		/// <param name="axisName">X or Y axis to get.</param>
		/// <returns>Data point axis.</returns>
		private Axis GetDataPointAxis(DataPoint dataPoint, AxisName axisName)
		{
            if (dataPoint != null && dataPoint.series != null && Chart != null)
            {
                // Get data point chart area
                ChartArea chartArea = Chart.ChartAreas[dataPoint.series.ChartArea];
 
                // Get point X axis
                if ((axisName == AxisName.X || axisName == AxisName.X2) &&
                    !chartArea.switchValueAxes)
                {
                    return chartArea.GetAxis(axisName, dataPoint.series.XAxisType, dataPoint.series.XSubAxisName);
                }
                else
                {
                    return chartArea.GetAxis(axisName, dataPoint.series.YAxisType, dataPoint.series.YSubAxisName);
                }
            }
			return null;
		}
 
		/// <summary>
		/// Gets annotation vertical and horizontal axes.
		/// </summary>
		/// <param name="vertAxis">Returns annotation vertical axis or null.</param>
		/// <param name="horizAxis">Returns annotation horizontal axis or null.</param>
		internal void GetAxes(ref Axis vertAxis, ref Axis horizAxis)
		{
			vertAxis = null;
			horizAxis = null;
 
			if(this.AxisX != null && this.AxisX.ChartArea != null)
			{
				if(this.AxisX.ChartArea.switchValueAxes)
				{
					vertAxis = this.AxisX;
				}
				else
				{
					horizAxis = this.AxisX;
				}
			}
			if(this.AxisY != null && this.AxisY.ChartArea != null)
			{
				if(this.AxisY.ChartArea.switchValueAxes)
				{
					horizAxis = this.AxisY;
				}
				else
				{
					vertAxis = this.AxisY;
				}
			}
 
			// Get axes from attached data point
			if(this.AnchorDataPoint != null)
			{
				if(horizAxis == null)
				{
					horizAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.X);
 
                    // For chart types like Bar, RangeBar and others, position of X and Y axes are flipped
                    if (horizAxis != null && horizAxis.ChartArea != null && horizAxis.ChartArea.switchValueAxes)
                    {
                        horizAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.Y);
                    }
				}
				if(vertAxis == null)
				{
					vertAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.Y);
 
                    // For chart types like Bar, RangeBar and others, position of X and Y axes are flipped
                    if (vertAxis != null && vertAxis.ChartArea != null && vertAxis.ChartArea.switchValueAxes)
                    {
                        vertAxis = GetDataPointAxis(this.AnchorDataPoint, AxisName.X);
                    }
                }
			}
 
			// No axes coordinate system for grouped annotations
			if(vertAxis != null || horizAxis != null)
			{
				if(this.AnnotationGroup != null)
				{
                    throw (new InvalidOperationException(SR.ExceptionAnnotationGroupedAxisMustBeEmpty));
				}
			}
		}
 
		#endregion
 
		#endregion
    
        #region IDisposable Members
 
        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing) 
        {
            if (disposing) 
            {   
                //Free managed resources
                if (_fontCache != null)
                {
                    _fontCache.Dispose();
                    _fontCache = null;
                }
            }
            base.Dispose(disposing);
        }
 
 
        #endregion
    }
 
#if Microsoft_CONTROL

	/// <summary>
	/// This class is used to stores position changing event data for an annotation.
	/// </summary>
	/// <remarks>
	/// Provides additional data like the new annotation and anchor position when an end user 
	/// is moving the annotation with the mouse.
	/// <para>
	/// Can be used to restrict annotation movement, or snap the annotation position to 
	/// specific points.
	/// </para>
	/// </remarks>
	[
	SRDescription("DescriptionAttributeAnnotationPositionChangingEventArgs_AnnotationPositionChangingEventArgs"),
	]
	public class AnnotationPositionChangingEventArgs : EventArgs
	{
		#region Fields

        private Annotation _Annotation = null;
		/// <summary>
		/// Gets or sets the annotation the event is fired for.
		/// </summary>
        public Annotation Annotation
        {
            get { return _Annotation; }
            set { _Annotation = value; }
        }
 
        private double _NewLocationX = 0.0;
        /// <summary>
        /// Gets or sets the new X location of the annotation.
        /// </summary>
        public double NewLocationX
        {
            get { return _NewLocationX; }
            set { _NewLocationX = value; }
        }
 
        private double _NewLocationY = 0.0;
        /// <summary>
        /// Gets or sets the new Y location of the annotation.
        /// </summary>
        public double NewLocationY
        {
            get { return _NewLocationY; }
            set { _NewLocationY = value; }
        }
 
        private double _NewSizeWidth = 0.0;
        /// <summary>
        /// Gets or sets the new width of the annotation.
        /// </summary>
        public double NewSizeWidth
        {
            get { return _NewSizeWidth; }
            set { _NewSizeWidth = value; }
        }
 
        private double _NewSizeHeight = 0.0;
        /// <summary>
        /// Gets or sets the new height of the annotation.
        /// </summary>
        public double NewSizeHeight
        {
            get { return _NewSizeHeight; }
            set { _NewSizeHeight = value; }
        }
 
        private double _NewAnchorLocationX = 0.0;
        /// <summary>
        /// Gets or sets the new annotation anchor point X location.
        /// </summary>
        public double NewAnchorLocationX
        {
            get { return _NewAnchorLocationX; }
            set { _NewAnchorLocationX = value; }
        }
 
        private double _NewAnchorLocationY = 0.0;
        /// <summary>
        /// Gets or sets the new annotation anchor point Y location.
        /// </summary>
        public double NewAnchorLocationY
        {
            get { return _NewAnchorLocationY; }
            set { _NewAnchorLocationY = value; }
        }
 
		#endregion // Fields

		#region Properties

 
		/// <summary>
		/// Gets or sets the new location and size of the annotation.
		/// </summary>
		[
		Browsable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		]
		public RectangleF NewPosition 
		{
			get
			{
				return new RectangleF(
					(float)this.NewLocationX,
					(float)this.NewLocationY,
					(float)this.NewSizeWidth,
					(float)this.NewSizeHeight);
			}
			set
			{
				this.NewLocationX = value.X;
				this.NewLocationY = value.Y;
				this.NewSizeWidth = value.Width;
				this.NewSizeHeight = value.Height;
			}
		}
 
		/// <summary>
		/// Gets or sets the new anchor location of the annotation.
		/// </summary>
		[
		Browsable(false),
		EditorBrowsableAttribute(EditorBrowsableState.Never),
		]
		public PointF NewAnchorLocation
		{
			get
			{
				return new PointF(
					(float)this.NewAnchorLocationX,
					(float)this.NewAnchorLocationY);
			}
			set
			{
				this.NewAnchorLocationX = value.X;
				this.NewAnchorLocationY = value.Y;
			}
		}
 
		#endregion // Properties
	}
 
#endif //Microsoft_CONTROL
}