File: Common\General\AxisScrollZoom.cs
Project: ndp\fx\src\DataVisualization\System.Windows.Forms.DataVisualization.csproj (System.Windows.Forms.DataVisualization)
//-------------------------------------------------------------
// <copyright company=’Microsoft Corporation’>
//   Copyright © Microsoft Corporation. All Rights Reserved.
// </copyright>
//-------------------------------------------------------------
// @owner=alexgor, deliant
//=================================================================
//  File:		AxisScrollZoom.cs
//
//  Namespace:	System.Web.UI.WebControls[Windows.Forms].Charting
//
//	Classes:	AxisScaleView, ViewEventArgs, DoubleNanValueConverter
//
//  Purpose:	AxisScaleView class represents a data scaleView, and is 
//              exposed using the Axis.ScaleView property. A data scaleView is 
//              a "scaleView" of data that has a start position (represented 
//              by the Position property) and a size (represented by 
//              the Size property).
//
//              Axis data scaleView is used in zooming and scrolling when
//              only part of the data must be visible. Views always 
//              belong to an axis, and a scaleView can result from either 
//              user interaction or by calling the Zoom or Scroll 
//              methods. User interaction, accomplished using range 
//              selection along an axis using the mouse, is possible 
//              if the IsUserSelectionEnabled property of the chart area'
//              s cursor property is set to true. The end-user selects 
//              a range by left-clicking the mouse and dragging the 
//              mouse, and when the mouse button is released the 
//              selected range is then displayed as a scaleView. 
//
//	Reviewed:	AG - Microsoft 16, 2007
//
//===================================================================
 
#region Used namespace
 
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using System.Collections;
using System.Globalization;
 
#if Microsoft_CONTROL
	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;
using System.Diagnostics.CodeAnalysis;
 
 
#else
	using System.Web.UI.DataVisualization.Charting;
	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 Scrolling  enumerations
 
#if Microsoft_CONTROL

    /// <summary>
	/// Scrolling type enumeration.
	/// </summary>
    public enum ScrollType
	{
		/// <summary>
		/// Scrolls by substracting one small size.
		/// </summary>
		SmallDecrement,
		/// <summary>
		/// Scrolls by adding one small size.
		/// </summary>
		SmallIncrement,
		/// <summary>
		/// Scrolls by substracting one scaleView size.
		/// </summary>
		LargeDecrement,
		/// <summary>
		/// Scrolls by adding one scaleView size.
		/// </summary>
		LargeIncrement,
		/// <summary>
		/// Scrolls to the first scaleView.
		/// </summary>
		First,
		/// <summary>
		/// Scrolls to the last scaleView.
		/// </summary>
		Last
	}
 
#endif // Microsoft_CONTROL
 
	#endregion
 
    /// <summary>
    /// AxisScaleView class represents a scale view which allows to display 
    /// only part of the available data.
    /// </summary>
	[
		SRDescription("DescriptionAttributeAxisDataView_AxisDataView"),
		DefaultProperty("Position"),
	]
#if ASPPERM_35
	[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
#endif
    public class AxisScaleView
	{
		#region Fields
 
		// Reference to the axis object
		internal Axis					axis = null;
 
		// Axis data scaleView position
		private	double					_position = double.NaN;
 
		// Axis data scaleView size
		private	double					_size = double.NaN;
 
		// Axis data scaleView size units type
		private	DateTimeIntervalType	_sizeType = DateTimeIntervalType.Auto;
 
#if Microsoft_CONTROL
        
        // Axis data scaleView minimum scaleView/scrolling size
		private	double					_minSize = double.NaN;
 
		// Axis data scaleView minimum scaleView/scrolling size units type
		private	DateTimeIntervalType	_minSizeType = DateTimeIntervalType.Auto;
 
		// Axis data scaleView zooming UI interface enabled flag
		private	bool					_zoomable = true;
 
		// Axis data scaleView scroll line size
		private	double					_smallScrollSize = double.NaN;
 
		// Axis data scaleView scroll line size units type
		private	DateTimeIntervalType	_smallScrollSizeType = DateTimeIntervalType.Auto;
 
		// Axis data scaleView scroll line minimum size
		private	double					_smallScrollMinSize = 1.0;
 
		// Axis data scaleView scroll line minimum size units type
		private	DateTimeIntervalType	_smallScrollMinSizeType = DateTimeIntervalType.Auto;
 
        // Axis data scaleView scroll line minimum size
        private double _currentSmallScrollSize = double.NaN;
 
        // Axis data scaleView scroll line minimum size units type
        private DateTimeIntervalType    _currentSmallScrollSizeType = DateTimeIntervalType.Auto;
 
		// Storage for the saved data scaleView states (position/size/sizetype)
		internal ArrayList				dataViewStates = null;
        
#endif
 
		// Ignore validation flag
		private	bool					_ignoreValidation = false;
 
		#endregion
 
		#region Constructor
 
		/// <summary>
		/// Default constructor
		/// </summary>
		public AxisScaleView()
		{
			this.axis = null;
		}
 
		/// <summary>
		/// Internal constructor.
		/// </summary>
		/// <param name="axis">Data scaleView axis.</param>
        internal AxisScaleView(Axis axis)
		{
			this.axis = axis;
		}
 
		#endregion
 
		#region Axis data scaleView properties
 
		/// <summary>
		/// Gets or sets the position of the AxisScaleView.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(Double.NaN),
		SRDescription("DescriptionAttributeAxisDataView_Position"),
		TypeConverter(typeof(DoubleDateNanValueConverter)),
		ParenthesizePropertyNameAttribute(true)
		]
		public double Position
		{
			get
			{
				// Axis scaleView is not supported in circular chrt areas
				if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular)
				{
					return Double.NaN;
				}
				return _position;
			}
			set
			{
				// Axis scaleView is not supported in circular chrt areas
				if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular)
				{
					return;
				}
 
				if(_position != value)
				{
					// Set new position
					_position = value;
 
					// Align scaleView in connected areas
					if(this.axis != null && this.axis.ChartArea != null && this.axis.Common != null && this.axis.Common.ChartPicture != null)
					{
						if(!this.axis.ChartArea.alignmentInProcess)
						{
							AreaAlignmentOrientations orientation = (this.axis.axisType == AxisName.X || this.axis.axisType== AxisName.X2) ?
								AreaAlignmentOrientations.Vertical : AreaAlignmentOrientations.Horizontal;
							this.axis.Common.ChartPicture.AlignChartAreasAxesView(this.axis.ChartArea, orientation);
						}
					}
					
					// Validate chart
					if(!_ignoreValidation && axis != null)
					{
						axis.Invalidate();
					}
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the size of the AxisScaleView
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(Double.NaN),
		SRDescription("DescriptionAttributeAxisDataView_Size"),
		TypeConverter(typeof(DoubleNanValueConverter)),
		ParenthesizePropertyNameAttribute(true)
		]
		public double Size
		{
			get
			{
				// Axis scaleView is not supported in circular chrt areas
				if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular)
				{
					return Double.NaN;
				}
 
				return _size;
			}
			set
			{
				// Axis scaleView is not supported in circular chrt areas
				if(this.axis != null && this.axis.ChartArea != null && this.axis.ChartArea.chartAreaIsCurcular)
				{
					return;
				}
 
				if(_size != value)
				{
					// Set size value
					_size = value;
 
				
					// Align scaleView in connected areas
					if(this.axis != null && this.axis.ChartArea != null && this.axis.Common != null && this.axis.Common.ChartPicture != null)
					{
						if(!this.axis.ChartArea.alignmentInProcess)
						{
							AreaAlignmentOrientations orientation = (this.axis.axisType == AxisName.X || this.axis.axisType== AxisName.X2) ?
								AreaAlignmentOrientations.Vertical : AreaAlignmentOrientations.Horizontal;
							this.axis.Common.ChartPicture.AlignChartAreasAxesView(this.axis.ChartArea, orientation);
						}
					}
#if Microsoft_CONTROL 					
					// Reset current scrolling line size
					this._currentSmallScrollSize = double.NaN;
#endif //Microsoft_CONTROL 
					// Validate chart
					if(!_ignoreValidation && axis != null)
					{
						axis.Invalidate();
					}
				}
			}
		}
 
		/// <summary>
        /// Gets or sets the unit of measurement of the Size property.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(DateTimeIntervalType.Auto),
		SRDescription("DescriptionAttributeAxisDataView_SizeType"),
		ParenthesizePropertyNameAttribute(true)
		]
		public DateTimeIntervalType SizeType
		{
			get
			{
				return _sizeType;
			}
			set
			{
				if(_sizeType != value)
				{
					// Set size type
					_sizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto;
 
					// Align scaleView in connected areas
					if(this.axis != null && this.axis.ChartArea != null && this.axis.Common != null && this.axis.Common.ChartPicture != null)
					{
						if(!this.axis.ChartArea.alignmentInProcess)
						{
							AreaAlignmentOrientations orientation = (this.axis.axisType == AxisName.X || this.axis.axisType== AxisName.X2) ?
								AreaAlignmentOrientations.Vertical : AreaAlignmentOrientations.Horizontal;
							this.axis.Common.ChartPicture.AlignChartAreasAxesView(this.axis.ChartArea, orientation);
						}
					}
					
					// Validate chart
					if(!_ignoreValidation && axis != null)
					{
						axis.Invalidate();
					}
				}
			}
		}
 
        /// <summary>
        /// Indicates if axis is zoomed-in.
        /// </summary>
        [
        SRCategory("CategoryAttributeAxisView"),
        Bindable(false),
        Browsable(false),
        SRDescription("DescriptionAttributeAxisDataView_IsZoomed"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        SerializationVisibility(SerializationVisibility.Hidden),
        ]
        public bool IsZoomed
        {
            get
            {
                return (
                    !double.IsNaN(this.Size) &&
                    this.Size != 0.0 &&
                    !double.IsNaN(this.Position));
            }
        }
 
#if Microsoft_CONTROL

		/// <summary>
		/// Gets or sets the minimum size of the AxisScaleView.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(Double.NaN),
		SRDescription("DescriptionAttributeAxisDataView_MinSize"),
		TypeConverter(typeof(DoubleNanValueConverter))
		]
		public double MinSize
		{
			get
			{
				return _minSize;
			}
			set
			{
				_minSize = value;
			}
		}
 
		/// <summary>
		/// Gets or sets the unit of measurement of the MinSize property.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(DateTimeIntervalType.Auto),
		SRDescription("DescriptionAttributeAxisDataView_MinSizeType"),
		]
		public DateTimeIntervalType MinSizeType
		{
			get
			{
				return _minSizeType;
			}
			set
			{
				_minSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto;
			}
		}
 
		/// <summary>
		/// Gets or sets a flag which indicates whether the zooming user interface is enabled.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(true),
		SRDescription("DescriptionAttributeAxisDataView_Zoomable"),
        SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly",
            Justification="'Zoomable' is a commonly used term and generally well understood"),
		]
		public bool Zoomable
		{
			get
			{
				return _zoomable;
			}
			set
			{
				_zoomable = value;
			}
		}
 
		/// <summary>
		/// Gets or sets the small scrolling size.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(Double.NaN),
		SRDescription("DescriptionAttributeAxisDataView_SmallScrollSize"),
		TypeConverter(typeof(AxisMinMaxAutoValueConverter))
		]
		public double SmallScrollSize
		{
			get
			{
				return _smallScrollSize;
			}
			set
			{
				if(_smallScrollSize != value)
				{
					// Set size value
					_smallScrollSize = value;
 
					// Validate chart
					if(!_ignoreValidation && axis != null)
					{
						axis.Invalidate();
					}
				}
			}
		}
 
		/// <summary>
		/// Gets or sets the unit of measurement for the SmallScrollMinSize property
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(DateTimeIntervalType.Auto),
		SRDescription("DescriptionAttributeAxisDataView_SmallScrollSizeType"),
		]
		public DateTimeIntervalType SmallScrollSizeType
		{
			get
			{
				return _smallScrollSizeType;
			}
			set
			{
				if(_smallScrollSizeType != value)
				{
					// Set size type
					_smallScrollSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto;
 
					// Validate chart
					if(!_ignoreValidation && axis != null)
					{
						axis.Invalidate();
					}
				}
			}
		}
 
		/// <summary>
		/// Gets or sets the minimum small scrolling size. 
        /// Only used if the small scrolling size is not set.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(1.0),
		SRDescription("DescriptionAttributeAxisDataView_SmallScrollMinSize")
		]
		public double SmallScrollMinSize
		{
			get
			{
				return _smallScrollMinSize;
			}
			set
			{
				if(_smallScrollMinSize != value)
				{
                    // Set size value
                    _smallScrollMinSize = value;
 
					_currentSmallScrollSize = double.NaN;
 
                    // Validate chart
					if(!_ignoreValidation && axis != null)
					{
						axis.Invalidate();
					}
				}
			}
		}
 
		/// <summary>
		/// Gets or sets the unit of measurement for the SmallScrollMinSize property.
		/// </summary>
		[
		SRCategory("CategoryAttributeAxisView"),
		Bindable(true),
		DefaultValue(DateTimeIntervalType.Auto),
        SRDescription("DescriptionAttributeAxisDataView_SmallScrollMinSizeType"),
		]
		public DateTimeIntervalType SmallScrollMinSizeType
		{
			get
			{
				return _smallScrollMinSizeType;
			}
			set
			{
				if(_smallScrollMinSizeType != value)
				{
					// Set size type
					_smallScrollMinSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto;
 
					_currentSmallScrollSize = double.NaN;
 
                    // Validate chart
					if(!_ignoreValidation && axis != null)
					{
						axis.Invalidate();
					}
				}
			}
		}
 
#endif // Microsoft_CONTROL
 
        #endregion
 
        #region ScaleView position internal methods
 
        /// <summary>
        /// Call this method to get the minimum axis value of a data view.
		/// </summary>
		/// <returns>The minimum axis value for the data view.</returns>
        [Browsable(false)]
        [Utilities.SerializationVisibility(Utilities.SerializationVisibility.Hidden)]
        public double ViewMinimum
		{
            get
            {
                // If zooming is enabled
                if (!Double.IsNaN(this.Size))
                {
                    // If size set only use axis minimum for scaleView position
                    if (Double.IsNaN(this.Position))
                    {
                        this.Position = this.axis.Minimum;
                    }
                    // Check if scaleView position and size are set
                    else
                    {
                        // Calculate and add axis side margin
                        if (this.Position <= axis.minimum)
                        {
                            return this.Position;
                        }
                        else // Add a margin only if scaleView is inside data point scaleView 
                        {
                            return this.Position - axis.marginView;
                        }
                    }
                }
 
                // Return axis scale minimum value if scaleView position is not set
                return axis.minimum;
            }
		}
 
        /// <summary>
        /// Maximum axis value of a data view.
        /// </summary>
        /// <returns>The maximum axis value for the data view.</returns>
		[Browsable(false)]
        [Utilities.SerializationVisibility(Utilities.SerializationVisibility.Hidden)]
        public double ViewMaximum
		{
            get
            {
                // If zooming is enabled
                if (!Double.IsNaN(this.Size))
                {
                    // If size set only use axis minimum for scaleView position
                    if (Double.IsNaN(this.Position))
                    {
                        this.Position = this.axis.Minimum;
                    }
 
                    // Check if scaleView position and size are set
                    else
                    {
                        // Get axis interval
                        double viewSize = ChartHelper.GetIntervalSize(this.Position, this.Size, this.SizeType);
 
                        // Calculate and add axis side margin
                        if (this.Position + viewSize >= axis.maximum)
                        {
                            return this.Position + viewSize;
                        }
                        else // Add a margin only if scaleView is inside data point scaleView 
                        {
                            return this.Position + viewSize + axis.marginView;
                        }
                    }
                }
 
                // Return axis scale maximum value if scaleView position is not set
                return axis.maximum;
            }
		}
 
		#endregion
 
		#region Scrolling methods
 
#if Microsoft_CONTROL

		/// <summary>
		/// Call this method to scroll to a specified position along an axis.
		/// </summary>
		/// <param name="scrollType">Direction and size to scroll.</param>
		public void Scroll(ScrollType scrollType)
		{
			this.Scroll(scrollType, false);
		}
 
		/// <summary>
		/// Scrolls axis data scaleView from current position.
		/// </summary>
		/// <param name="scrollType">Direction and size to scroll.</param>
		/// <param name="fireChangeEvents">Fire scaleView position events from this method.</param>
		internal void Scroll(ScrollType scrollType, bool fireChangeEvents)
		{
			// Adjust current position depending on the scroll type
			double	newPosition = this._position;
			switch(scrollType)
			{
				case(ScrollType.SmallIncrement):
                    newPosition += ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.GetScrollingLineSize(), this.GetScrollingLineSizeType());
					break;
				case(ScrollType.SmallDecrement):
                    newPosition -= ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.GetScrollingLineSize(), this.GetScrollingLineSizeType());
					break;
				case(ScrollType.LargeIncrement):
                    newPosition += ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.Size, this.SizeType);
					break;
				case(ScrollType.LargeDecrement):
                    newPosition -= ((axis.IsReversed) ? -1 : 1) * ChartHelper.GetIntervalSize(this._position, this.Size, this.SizeType);
					break;
				case(ScrollType.First):
					if(!axis.IsReversed)
					{
						newPosition = (axis.minimum + axis.marginView);
					}
					else
					{
						newPosition = (axis.maximum - axis.marginView);
					}
					break;
				case(ScrollType.Last):
				{
                    double viewSize = ChartHelper.GetIntervalSize(newPosition, this.Size, this.SizeType);
					if(!axis.IsReversed)
					{
						newPosition = (axis.maximum - axis.marginView - viewSize);
					}
					else
					{
						newPosition = (axis.minimum + axis.marginView + viewSize);
					}
					break;
				}
			}
 
			// Scroll to the new position
			this.Scroll(newPosition, fireChangeEvents);
		}
 
        /// <summary>
		/// Call this method to scroll to a specified position along an axis.
		/// </summary>
		/// <param name="newPosition">New position.</param>
		public void Scroll(double newPosition)
		{
			this.Scroll(newPosition, false);
		}
 
        /// <summary>
        /// Call this method to scroll to a specified position along an axis.
        /// </summary>
        /// <param name="newPosition">New position.</param>
        public void Scroll(DateTime newPosition)
        {
            this.Scroll(newPosition.ToOADate(), false);
        }
 
		/// <summary>
		/// Internal helper method for scrolling into specified position.
		/// </summary>
		/// <param name="newPosition">New data scaleView position.</param>
		/// <param name="fireChangeEvents">Fire scaleView position events from this method.</param>
		internal void Scroll(double newPosition, bool fireChangeEvents)
		{
			// Get current scaleView size
            double viewSize = ChartHelper.GetIntervalSize(newPosition, this.Size, this.SizeType);
 
            // Validate new scaleView position
			if(newPosition < (axis.minimum + axis.marginView))
			{
				newPosition = (axis.minimum + axis.marginView);
			}
			else if(newPosition > (axis.maximum - axis.marginView - viewSize))
			{
				newPosition = (axis.maximum - axis.marginView - viewSize);
			}
 
            // Fire scaleView position changing events
			ViewEventArgs	arguments = new ViewEventArgs(this.axis, newPosition, this.Size, this.SizeType);
			if(fireChangeEvents && GetChartObject() != null)
			{
				GetChartObject().OnAxisViewChanging(arguments);
				newPosition = arguments.NewPosition;
			}
 
			// Check if data scaleView position and size is different from current
			if(newPosition == this.Position)
			{
				return;
			}
 
			// Change scaleView position
			this.Position = newPosition;
 
			// Fire scaleView position changed events
			if(fireChangeEvents && GetChartObject() != null)
			{
				GetChartObject().OnAxisViewChanged(arguments);
			}
		}
 
#endif
        #endregion
 
        #region Zooming and ZoomResetting methods
 
#if Microsoft_CONTROL

		/// <summary>
		/// Sets a new axis data view/position based on the start and end dates specified.
		/// </summary>
		/// <param name="viewPosition">New start position for the axis scale view.</param>
		/// <param name="viewSize">New size for the axis scale view.</param>
		/// <param name="viewSizeType">New unit of measurement of the size.</param>
		/// <param name="saveState">Indicates whether the current size/position needs to be saved.</param>
		public void Zoom(double viewPosition, double viewSize, DateTimeIntervalType viewSizeType, bool saveState)
		{
			this.Zoom(viewPosition, viewSize, viewSizeType, false, saveState);
		}
 
		/// <summary>
		/// Sets a new axis data view/position based on the specified start and end values.
		/// </summary>
		/// <param name="viewStart">New start position for the axis scale view.</param>
		/// <param name="viewEnd">New end position for the axis scale view.</param>
		public void Zoom(double viewStart, double viewEnd)
		{
			this.Zoom(viewStart, viewEnd - viewStart, DateTimeIntervalType.Number, false, false);
		}
 
		/// <summary>
		/// Sets a new axis data view/position based on the start and end dates specified. 
		/// </summary>
		/// <param name="viewPosition">New start position for the axis scale view.</param>
		/// <param name="viewSize">New size for the axis scale view.</param>
		/// <param name="viewSizeType">New unit of measurement of the size.</param>
		public void Zoom(double viewPosition, double viewSize, DateTimeIntervalType viewSizeType)
		{
			this.Zoom(viewPosition, viewSize, viewSizeType, false, false);
        }
 
        /// <summary>
		/// Reset the specified number of zooming operations by restoring axis data view. 
		/// </summary>
		/// <param name="numberOfViews">Number of zoom operations to reset. Zero for all.</param>
		public void ZoomReset(int numberOfViews)
		{
			this.LoadDataViewState(numberOfViews, false);
		}
 
		/// <summary>
		/// Reset one zooming operation by restoring axis data view.
		/// </summary>
		public void ZoomReset()
		{
			this.LoadDataViewState(1, false);
		}
 
		/// <summary>
		/// Reset several zooming operation by restoring data scaleView size/position.
		/// </summary>
		/// <param name="numberOfViews">How many scaleView zoom operations to reset. Zero for all.</param>
		/// <param name="fireChangeEvents">Fire scaleView position events from this method.</param>
		internal void ZoomReset(int numberOfViews, bool fireChangeEvents)
		{
			this.LoadDataViewState(numberOfViews, fireChangeEvents);
		}
 
        /// <summary>
		/// Internal helper zooming method.
		/// </summary>
		/// <param name="viewPosition">New data scaleView start posiion.</param>
		/// <param name="viewSize">New data scaleView size.</param>
		/// <param name="viewSizeType">New data scaleView size units type.</param>
		/// <param name="fireChangeEvents">Fire scaleView position events from this method.</param>
		/// <param name="saveState">Indicates that current scaleView size/position must be save, so it can be restored later.</param>
		/// <returns>True if zoom operation was made.</returns>
		internal bool Zoom(
			double viewPosition, 
			double viewSize, 
			DateTimeIntervalType viewSizeType, 
			bool fireChangeEvents,
			bool saveState)
		{
			// Validate new scaleView position and size
			ValidateViewPositionSize(ref viewPosition, ref viewSize, ref viewSizeType);
 
			// Fire scaleView position/size changing events
			ViewEventArgs	arguments = new ViewEventArgs(this.axis, viewPosition, viewSize, viewSizeType);
			if(fireChangeEvents && GetChartObject() != null)
			{
				GetChartObject().OnAxisViewChanging(arguments);
				viewPosition = arguments.NewPosition;
				viewSize = arguments.NewSize;
				viewSizeType = arguments.NewSizeType;
			}
 
			// Check if data scaleView position and size is different from current
			if(viewPosition == this.Position && 
				viewSize == this.Size && 
				viewSizeType == this.SizeType)
			{
				return false;
			}
 
			// Save current data scaleView state, so it can be restored
			if(saveState)
			{
				SaveDataViewState();
			}
 
            // Change scaleView position/size
			this._ignoreValidation = true;
			this.Position = viewPosition;
			this.Size = viewSize;
			this.SizeType = viewSizeType;
			this._ignoreValidation = false;
 
			// Reset current scrolling line size
			this._currentSmallScrollSize = double.NaN;
 
			// Invalidate chart
            axis.Invalidate();
 
			// Fire scaleView position/size changed events
			if(fireChangeEvents && GetChartObject() != null)
			{
				GetChartObject().OnAxisViewChanged(arguments);
			}
 
			return true;
		}
 
#endif
 
        #endregion
 
        #region Data scaleView state saving/restoring methods
 
#if Microsoft_CONTROL

		/// <summary>
		/// Saves current data scaleView position/size/sizetype, so
		/// it can be restored later.
		/// </summary>
		/// <param name="numberOfViews">Number of time to reset zoom. Zero for all.</param>
		/// <param name="fireChangeEvents">Fire scaleView position events from this method.</param>
		private void LoadDataViewState(int numberOfViews, bool fireChangeEvents)
		{
			// Check parameters
			if(numberOfViews < 0)
			{
                throw (new ArgumentOutOfRangeException("numberOfViews", SR.ExceptionScrollBarZoomResetsNumberInvalid));
			}
			// Check if storage was created
			if(dataViewStates != null && dataViewStates.Count >= 3)
			{
				// Find starting index of restoring state
				int	dataStartIndex = 0;
				if(numberOfViews > 0)
				{
					dataStartIndex = dataViewStates.Count - numberOfViews * 3;
					if(dataStartIndex < 0)
					{
						dataStartIndex = 0;
					}
				}
 
 
				// Fire scaleView position/size changing events
				ViewEventArgs	arguments = new ViewEventArgs(
					this.axis, 
					(double)dataViewStates[dataStartIndex], 
					(double)dataViewStates[dataStartIndex + 1], 
					(DateTimeIntervalType)dataViewStates[dataStartIndex + 2]);
				if(fireChangeEvents && GetChartObject() != null)
				{
					GetChartObject().OnAxisViewChanging(arguments);
				}
 
                // Restore data
				this.Position	= arguments.NewPosition;
				this.Size		= arguments.NewSize;
				this.SizeType	= arguments.NewSizeType;
 
				// Fire scaleView position/size changed events
				if(fireChangeEvents && GetChartObject() != null)
				{
					GetChartObject().OnAxisViewChanged(arguments);
				}
 
                // Clear data
                int itemsToRemove = numberOfViews * 3;
                if (itemsToRemove > (dataViewStates.Count - dataStartIndex))
                {
                    itemsToRemove = dataViewStates.Count - dataStartIndex;
                }
                dataViewStates.RemoveRange(dataStartIndex, itemsToRemove);
 
 
                // clean up the history state when the numberOfViews == 0 (reset all by docs)
                if ( numberOfViews == 0 )
                {
                    dataViewStates.Clear();
                }
                if (Double.IsNaN(this.Position) || Double.IsNaN(this.Size))
                {
                    this.Position = Double.NaN;
                    this.Size = Double.NaN;
                }
 
            }
 
			// Nothing to restore - just disable the data scaleView
			else
			{
				// Fire scaleView position/size changing events
				ViewEventArgs	arguments = new ViewEventArgs(
					this.axis, 
					double.NaN, 
					double.NaN, 
					DateTimeIntervalType.Auto);
 
				if(fireChangeEvents && GetChartObject() != null)
				{
					GetChartObject().OnAxisViewChanging(arguments);
				}
 
                // Restore data
				this.Position	= arguments.NewPosition;
				this.Size		= arguments.NewSize;
				this.SizeType	= arguments.NewSizeType;
 
				// Fire scaleView position/size changed events
				if(fireChangeEvents && GetChartObject() != null)
				{
					GetChartObject().OnAxisViewChanged(arguments);
				}
    		}
            // clear cached chart areas and bitmap buffers
            GetChartObject().Refresh();
		}
 
		/// <summary>
		/// Saves current data scaleView position/size/sizetype, so
		/// it can be restored later.
		/// </summary>
		private void SaveDataViewState()
		{
			// Create storage array
			if(dataViewStates == null)
			{
				dataViewStates = new ArrayList();
			}
 
			// Save data scaleView state
			dataViewStates.Add(this.Position);
			dataViewStates.Add(this.Size);
			dataViewStates.Add(this.SizeType);
		}
#endif
 
        #endregion
 
        #region Helper methods
 
#if Microsoft_CONTROL
		/// <summary>
		/// Initialize internal scrolling line size variables for later use.
		/// This size is used in to scroll chart one line up or down.
		/// </summary>
		private void GetCurrentViewSmallScrollSize()
		{
			//**************************************************************************
			//** Check if current scrolling line size was not already calculated
			//**************************************************************************
			if(double.IsNaN(_currentSmallScrollSize))
			{
				//**************************************************************************
				//** Calculate line size depending on the current scaleView size
				//**************************************************************************
				if(this.SizeType == DateTimeIntervalType.Auto || this.SizeType == DateTimeIntervalType.Number)
				{
					// Set line size type
					_currentSmallScrollSizeType = DateTimeIntervalType.Number;
 
					// Devide scaleView by 20 to find the scrolling line size
					double newSize = this.Size / 20.0;
 
					// Make sure that current line size is even with minimum value
					if(!double.IsNaN(this.SmallScrollMinSize) && this.SmallScrollMinSize != 0.0)
					{
						double rounder = (Math.Round(newSize / this.SmallScrollMinSize));
						if(rounder < 0)
						{
							rounder = 1;
						}
						newSize = rounder * this.SmallScrollMinSize;
					}
 
					// Set new current line size
					this._currentSmallScrollSize = newSize;
				}
				else
				{
					// Calculate line size for date/time
                    double viewEndPosition = this.Position + ChartHelper.GetIntervalSize(this.Position, this.Size, this.SizeType);
					_currentSmallScrollSize = axis.CalcInterval( 
						this.Position, 
						viewEndPosition, 
						true, 
						out _currentSmallScrollSizeType, 
						ChartValueType.Auto);
				}
 
                //**************************************************************************
				//** Make sure calculated scroll line size is not smaller than the minimum 
				//**************************************************************************
				if(!double.IsNaN(this.SmallScrollMinSize) && this.SmallScrollMinSize != 0.0)
				{
                    double newLineSize = ChartHelper.GetIntervalSize(this.Position, _currentSmallScrollSize, _currentSmallScrollSizeType);
                    double minLineSize = ChartHelper.GetIntervalSize(this.Position, this.SmallScrollMinSize, this.SmallScrollMinSizeType);
					if(newLineSize < minLineSize)
					{
						_currentSmallScrollSize = SmallScrollMinSize;
						_currentSmallScrollSizeType = SmallScrollMinSizeType;
					}
				}
			}
		}
 
		/// <summary>
		/// Returns the scroll line size.
		/// </summary>
		/// <returns>Scroll line size.</returns>
		internal double GetScrollingLineSize()
		{	
			// Scroll line size/type is specificly set by user
			if(!double.IsNaN(this.SmallScrollSize))
			{
				return this.SmallScrollSize;
			}
 
			// Calcualte scroll line size depending on the current scaleView size
			GetCurrentViewSmallScrollSize();
 
			// Return line size
			return _currentSmallScrollSize;
		}
 
		/// <summary>
		/// Returns the scroll line size units type.
		/// </summary>
		/// <returns>Scroll line size units type.</returns>
		internal DateTimeIntervalType GetScrollingLineSizeType()
		{
			// Scroll line size/type is specificly set by user
			if(!double.IsNaN(this.SmallScrollSize))
			{
				return this.SmallScrollSizeType;
			}
 
			// Calcualte scroll line size depending on the current scaleView size
			GetCurrentViewSmallScrollSize();
 
			// Return line size units type
			return _currentSmallScrollSizeType;
		}
 
		/// <summary>
		/// Helper method, which validates the axis data scaleView position and size.
		/// Returns adjusted scaleView position and size.
		/// </summary>
		/// <param name="viewPosition">ScaleView position.</param>
		/// <param name="viewSize">ScaleView size.</param>
		/// <param name="viewSizeType">ScaleView size units type.</param>
		private void ValidateViewPositionSize(ref double viewPosition, ref double viewSize, ref DateTimeIntervalType viewSizeType)
		{
			//****************************************************************
			//** Check if new scaleView position is inside axis scale 
			//** minimum/maximum without margin.
			//****************************************************************
			if(viewPosition < (axis.minimum + axis.marginView))
			{
				if(viewSizeType == DateTimeIntervalType.Auto || viewSizeType == DateTimeIntervalType.Number)
				{
					viewSize -= (axis.minimum + axis.marginView) - viewPosition;
				}
				viewPosition = (axis.minimum + axis.marginView);
			}
			else if(viewPosition > (axis.maximum - axis.marginView))
			{
                if(viewSizeType == DateTimeIntervalType.Auto || viewSizeType == DateTimeIntervalType.Number)
				{
					viewSize -= viewPosition - (axis.maximum - axis.marginView);
				}
				viewPosition = (axis.maximum - axis.marginView);
			}
 
            //****************************************************************
			//** Check if new scaleView size is not smaller than minimum size
			//** set by the user
			//****************************************************************
            double newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType);
            double minViewSize = ChartHelper.GetIntervalSize(viewPosition, 1, this.MinSizeType);
			if(!double.IsNaN(this.MinSize))
			{
                minViewSize = ChartHelper.GetIntervalSize(viewPosition, this.MinSize, this.MinSizeType);
				if(newViewSize < minViewSize)
				{
					viewSize = (double.IsNaN(this.MinSize)) ? 1 : this.MinSize;
					viewSizeType = this.MinSizeType;
                    newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType);
				}
			}
			
			//****************************************************************
			//** Check if new scaleView size is smaller than (0.000000001)
			//****************************************************************
			if(newViewSize < 0.000000001)
			{
				viewSize = 0.000000001;
				viewSizeType = DateTimeIntervalType.Number;
                newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType);
			}
 
			//****************************************************************
			//** Check if new scaleView end position (position + size) is inside 
			//** axis scale minimum/maximum without margin.
			//****************************************************************
			while( (viewPosition + newViewSize) > (axis.maximum - axis.marginView) )
			{
				double	currentSize = viewSize;
				DateTimeIntervalType currentSizeType = viewSizeType;
 
				// Try to reduce the scaleView size
				if(newViewSize > minViewSize)
				{
					// Try to adjust the scaleView size
					if(viewSize > 1)
					{
						--viewSize;
					}
					else if(viewSizeType == DateTimeIntervalType.Years)
					{
						viewSize = 11;
						viewSizeType = DateTimeIntervalType.Months;
					}
					else if(viewSizeType == DateTimeIntervalType.Months)
					{
						viewSize = 4;
						viewSizeType = DateTimeIntervalType.Weeks;
					}
					else if(viewSizeType == DateTimeIntervalType.Weeks)
					{
						viewSize = 6;
						viewSizeType = DateTimeIntervalType.Days;
					}
					else if(viewSizeType == DateTimeIntervalType.Days)
					{
						viewSize = 23;
						viewSizeType = DateTimeIntervalType.Hours;
					}
					else if(viewSizeType == DateTimeIntervalType.Hours)
					{
						viewSize = 59;
						viewSizeType = DateTimeIntervalType.Minutes;
					}
					else if(viewSizeType == DateTimeIntervalType.Minutes)
					{
						viewSize = 59;
						viewSizeType = DateTimeIntervalType.Seconds;
					}
					else if(viewSizeType == DateTimeIntervalType.Seconds)
					{
						viewSize = 999;
						viewSizeType = DateTimeIntervalType.Milliseconds;
					}
					else
					{
						viewPosition = (axis.maximum - axis.marginView) - minViewSize;
						break;
					}
 
					// Double check that scaleView size is not smaller than min size
                    newViewSize = ChartHelper.GetIntervalSize(viewPosition, viewSize, viewSizeType);
					if(newViewSize < minViewSize)
					{
						// Can't adjust size no more (restore prev. value)
						viewSize = currentSize;
						viewSizeType = currentSizeType;
 
						// Adjust the start position
						viewPosition = (axis.maximum - axis.marginView) - minViewSize;
						break;
					}
				}
				else
				{
					// Adjust the start position
					viewPosition = (axis.maximum - axis.marginView) - newViewSize;
					break;
				}
			}
        }
 
        /// <summary>
		/// Helper function which returns a reference to the chart object.
		/// </summary>
		/// <returns>Chart object reference.</returns>
		internal Chart GetChartObject()
		{
			if(this.axis != null && this.axis.Common!=null)
			{
    			return this.axis.Common.Chart;
			}
 
			return null;
        }
#endif //Microsoft_CONTROL
 
        #endregion
    }
 
#if Microsoft_CONTROL

	/// <summary>
	/// This class is used as a parameter object in the AxisViewChanged and AxisViewChanging events of the root Chart object.
	/// </summary>
	public class ViewEventArgs : EventArgs
	{
    #region Private fields

			// Private fields for properties values storage
			private		Axis					_axis = null;
			private		double					_newPosition = double.NaN;
			private		double					_newSize = double.NaN;
			private		DateTimeIntervalType	_newSizeType = DateTimeIntervalType.Auto;
 
        #endregion

    #region Constructors

			/// <summary>
			/// ViewEventArgs constructor.
			/// </summary>
			/// <param name="axis">Axis of the scale view.</param>
			/// <param name="newPosition">New scale view start position.</param>
			public ViewEventArgs(Axis axis, double newPosition)
			{
				this._axis = axis;
				this._newPosition = newPosition;
			}
 
			/// <summary>
			/// ViewEventArgs constructor.
			/// </summary>
			/// <param name="axis">Axis of the scale view.</param>
			/// <param name="newPosition">New scale view start position.</param>
			/// <param name="newSize">New scale view size.</param>
			/// <param name="newSizeType">New unit of measurement of the size.</param>
			public ViewEventArgs(Axis axis, double newPosition, double newSize, DateTimeIntervalType newSizeType)
			{
				this._axis = axis;
				this._newPosition = newPosition;
				this._newSize = newSize;
				this._newSizeType = newSizeType;
			}
 
    #endregion

    #region Properties

		/// <summary>
		/// Axis of the event.
		/// </summary>
		[
		SRDescription("DescriptionAttributeAxis"),
		]
		public Axis Axis
		{
			get
			{
				return _axis;
			}
		}
 
		/// <summary>
		/// ChartArea of the event.
		/// </summary>
		[
		SRDescription("DescriptionAttributeChartArea"),
		]
		public ChartArea ChartArea
		{
			get
			{
				return _axis.ChartArea;
			}
		}
 
		/// <summary>
		/// New scale view start position.
		/// </summary>
		[
		SRDescription("DescriptionAttributeViewEventArgs_NewPosition"),
		]
		public double NewPosition
		{
			get
			{
				return _newPosition;
			}
			set
			{
				_newPosition = value;
			}
		}
 
		/// <summary>
		/// New scale view size.
		/// </summary>
		[
		SRDescription("DescriptionAttributeViewEventArgs_NewSize"),
		]
		public double NewSize
		{
			get
			{
				return _newSize;
			}
			set
			{
				_newSize = value;
			}
		}
 
		/// <summary>
		/// New unit of measurement of the scale view.
		/// </summary>
		[
		SRDescription("DescriptionAttributeViewEventArgs_NewSizeType"),
		]
		public DateTimeIntervalType NewSizeType
		{
			get
			{
				return _newSizeType;
			}
			set
			{
				_newSizeType = (value != DateTimeIntervalType.NotSet) ? value : DateTimeIntervalType.Auto;
			}
		}
 
    #endregion
	}
 
#endif	// #if Microsoft_CONTROL
}
 
#if Microsoft_CONTROL
	namespace System.Windows.Forms.DataVisualization.Charting
#else
	namespace System.Web.UI.DataVisualization.Charting
#endif
{
	/// <summary>
	/// Designer converter class
	/// Converts Double.NaN values to/from "Not set".
	/// </summary>
	internal class DoubleNanValueConverter : DoubleConverter
	{
		#region Converter methods
 
		/// <summary>
		/// Standard values supported.  This method always return true.
		/// </summary>
		/// <param name="context">Descriptor context.</param>
		/// <returns>True.</returns>
		public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
		{
			return true;
		}
 
		/// <summary>
		/// Standard values are not exclusive.  This method always return false.
		/// </summary>
		/// <param name="context">Descriptor context.</param>
		/// <returns>False.</returns>
		public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
		{
			return false;
		}
 
		/// <summary>
		/// Get in the collection of standard values.
		/// </summary>
		/// <param name="context">Descriptor context.</param>
		public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
		{
			ArrayList values = new ArrayList();
			values.Add(Double.NaN);
				
			return new StandardValuesCollection(values);
		}
 
        /// <summary>
        /// Convert double.NaN to string "Not set"
        /// </summary>
        /// <param name="context">Descriptor context.</param>
        /// <param name="culture">Culture information.</param>
        /// <param name="value">Value to convert.</param>
        /// <param name="destinationType">Conversion destination type.</param>
        /// <returns>Converted object.</returns>
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
		{  
			double	doubleValue = (double)value;
			if (destinationType == typeof(string))
			{
				if(Double.IsNaN(doubleValue))
				{
                    return Constants.NotSetValue;
				}
			}
 
			// Call base class
			return base.ConvertTo(context, culture, value, destinationType);
		}
 
		/// <summary>
		/// Convert minimum or maximum values from string.
		/// </summary>
		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			// If converting from string value
            string crossingValue = value as string;
            if (crossingValue != null)
			{
                if (String.Compare(crossingValue, Constants.NotSetValue, StringComparison.OrdinalIgnoreCase) == 0)
				{
					return Double.NaN;
				}
			}
					
			// Call base converter
			return base.ConvertFrom(context, culture, value);
		}
 
			#endregion
	}
 
	/// <summary>
	/// Designer converter class
	/// Converts Double.NaN values to/from "Not set".
	/// Converts value to/from date strings.
	/// </summary>
    internal class DoubleDateNanValueConverter : DoubleConverter
	{
		#region Converter methods
 
		/// <summary>
		/// Standard values supported - return true
		/// </summary>
		/// <param name="context">Descriptor context.</param>
		/// <returns>Standard values supported.</returns>
		public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
		{
			return true;
		}
 
		/// <summary>
		/// Standard values are not exclusive - return false
		/// </summary>
		/// <param name="context">Descriptor context.</param>
		/// <returns>Non exclusive standard values.</returns>
		public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
		{
			return false;
		}
 
		/// <summary>
		/// Fill in the list of predefined values.
		/// </summary>
		/// <param name="context">Descriptor context.</param>
		public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
		{
			ArrayList values = new ArrayList();
			values.Add(Double.NaN);
				
			return new StandardValuesCollection(values);
		}
 
        /// <summary>
        /// Convert values to string if step type is set to one of the DateTime type
        /// </summary>
        /// <param name="context">Descriptor context.</param>
        /// <param name="culture">Culture information.</param>
        /// <param name="value">Value to convert.</param>
        /// <param name="destinationType">Conversion destination type.</param>
        /// <returns>Converted object.</returns>
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
		{  
			// Check for NaN
			if (destinationType == typeof(string))
			{
				if(Double.IsNaN((double)value))
				{
                    return Constants.NotSetValue;
				}
			}
 
			if (context != null && context.Instance != null)
			{
				// Get access to the Axis object
				Axis axis = null;
				if(context.Instance is AxisScaleView)
				{
					axis = ((AxisScaleView)context.Instance).axis;
				}
 
#if Microsoft_CONTROL

				else if(context.Instance is Cursor)
				{
					axis = ((Cursor)context.Instance).GetAxis();
				}
#endif // Microsoft_CONTROL
 
				if (axis != null && destinationType == typeof(string))
				{
                    string strValue = ConvertDateTimeToString(
                        (double)value,
                        axis.GetAxisValuesType(),
                        axis.InternalIntervalType);
 
                    if (strValue != null)
                        return strValue;
				}
				
			}
			return base.ConvertTo(context, culture, value, destinationType);
		}
 
        public static string ConvertDateTimeToString(
            double dtValue, 
            ChartValueType axisValuesType,
            DateTimeIntervalType dtIntervalType)
        {
            string strValue = null;
            // Use axis values types if interval is automatic
            if (dtIntervalType == DateTimeIntervalType.Auto)
            {
                if (axisValuesType == ChartValueType.DateTime ||
                    axisValuesType == ChartValueType.Time ||
                    axisValuesType == ChartValueType.Date ||
                    axisValuesType == ChartValueType.DateTimeOffset)
                {
                    strValue = DateTime.FromOADate(dtValue).ToString("g", System.Globalization.CultureInfo.CurrentCulture);
                }
            }
            else
            {
                if (dtIntervalType != DateTimeIntervalType.Number)
                {
                    // Covert value to date/time
                    if (dtIntervalType < DateTimeIntervalType.Hours)
                    {
                        strValue = DateTime.FromOADate(dtValue).ToShortDateString();
                    }
                    else
                    {
                        strValue = DateTime.FromOADate(dtValue).ToString("g", System.Globalization.CultureInfo.CurrentCulture);
                    }
                }
            }
            
            if (axisValuesType == ChartValueType.DateTimeOffset && strValue != null)
                strValue += " +0";
 
            return strValue;
        }
 
		/// <summary>
		/// Convert Min and Max values from string if step type is set to one of the DateTime type
		/// </summary>
		/// <param name="context">Descriptor context.</param>
		/// <param name="culture">Culture information.</param>
		/// <param name="value">Value to convert from.</param>
		/// <returns>Converted object.</returns>
		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			object	result = null;
			bool	convertFromDate = false;
 
			// If converting from string value
            string crossingValue = value as string;
			if (crossingValue != null)
			{
                if (String.Compare(crossingValue, Constants.NotSetValue, StringComparison.OrdinalIgnoreCase) == 0)
				{
					return Double.NaN;
				}
			}
 
			// If context interface provided check if we are dealing with DateTime values
			if (context != null && context.Instance != null && context.Instance is Axis)
			{
 
				// Get axis object
				Axis	axis = null;
				if(context.Instance is AxisScaleView)
				{
					axis = ((AxisScaleView)context.Instance).axis;
				}
 
#if Microsoft_CONTROL
				else if(context.Instance is Cursor)
				{
					axis = ((Cursor)context.Instance).GetAxis();
				}
#endif // Microsoft_CONTROL
 
                if (axis != null && crossingValue != null)
				{
					if(axis.InternalIntervalType == DateTimeIntervalType.Auto)
					{
						if(axis.GetAxisValuesType() == ChartValueType.DateTime ||
							axis.GetAxisValuesType() == ChartValueType.Date ||
							axis.GetAxisValuesType() == ChartValueType.Time ||
                            axis.GetAxisValuesType() == ChartValueType.DateTimeOffset) 
						{
							convertFromDate = true;
						}
					}
					else
					{
						if(axis.InternalIntervalType != DateTimeIntervalType.Number) 
						{
							convertFromDate = true;
						}
					}
				}
			}
 
			// Try to convert from double string
            try
            {
                result = base.ConvertFrom(context, culture, value);
            }
            catch (ArgumentException)
            {
                result = null;
            }
            catch (NotSupportedException)
            {
                result = null;
            }
 
			// Try to convert from date/time string
            if (crossingValue != null && (convertFromDate || result == null))
            {
                DateTime valueAsDate;
                bool parseSucceed = DateTime.TryParse(crossingValue, CultureInfo.InvariantCulture, DateTimeStyles.None, out valueAsDate);
 
                if (parseSucceed)
                {
                    return valueAsDate.ToOADate();
                }
            }
 
			// Call base converter
			return base.ConvertFrom(context, culture, value);
		}
 
	#endregion
	}
 
}