717 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			717 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //============================================================================
 | |
| //ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C#
 | |
| //Copyright ?2004  John Champion
 | |
| //
 | |
| //This library is free software; you can redistribute it and/or
 | |
| //modify it under the terms of the GNU Lesser General Public
 | |
| //License as published by the Free Software Foundation; either
 | |
| //version 2.1 of the License, or (at your option) any later version.
 | |
| //
 | |
| //This library is distributed in the hope that it will be useful,
 | |
| //but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| //Lesser General Public License for more details.
 | |
| //
 | |
| //You should have received a copy of the GNU Lesser General Public
 | |
| //License along with this library; if not, write to the Free Software
 | |
| //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | |
| //=============================================================================
 | |
| 
 | |
| using System;
 | |
| using System.Drawing;
 | |
| using System.Collections.Generic;
 | |
| 
 | |
| namespace DrawGraph
 | |
| {
 | |
| 	/// <summary>
 | |
| 	/// A collection class containing a list of <see cref="CurveItem"/> objects
 | |
| 	/// that define the set of curves to be displayed on the graph.
 | |
| 	/// </summary>
 | |
| 	/// 
 | |
| 	/// <author> John Champion
 | |
| 	/// modified by Jerry Vos</author>
 | |
| 	/// <version> $Revision: 3.41 $ $Date: 2007/04/16 00:03:01 $ </version>
 | |
| 	[Serializable]
 | |
| 	public class CurveList : List<CurveItem>, ICloneable
 | |
| 	{
 | |
| 
 | |
| 	#region Properties
 | |
| 		// internal temporary value that keeps
 | |
| 		// the max number of points for any curve
 | |
| 		// associated with this curveList
 | |
| 		private int	maxPts;
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Read only value for the maximum number of points in any of the curves
 | |
| 		/// in the list.
 | |
| 		/// </summary>
 | |
| 		public int MaxPts
 | |
| 		{
 | |
| 			get { return maxPts; }
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Read only property that returns the number of curves in the list that are of
 | |
| 		/// type <see cref="Bar"/>.
 | |
| 		/// </summary>
 | |
| 		public int NumBars
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				int count = 0;
 | |
| 				foreach ( CurveItem curve in this )
 | |
| 				{
 | |
| 					if ( curve.IsBar )
 | |
| 						count++;
 | |
| 				}
 | |
| 
 | |
| 				return count;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Read only property that returns the number of pie slices in the list (class type is
 | |
| 		/// <see cref="PieItem"/> ).
 | |
| 		/// </summary>
 | |
| 		public int NumPies
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				int count = 0;
 | |
| 				foreach ( CurveItem curve in this )
 | |
| 				{
 | |
| 					if ( curve.IsPie )
 | |
| 						count++;
 | |
| 				}
 | |
| 
 | |
| 				return count;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Read only property that determines if all items in the <see cref="CurveList"/> are
 | |
| 		/// Pies.
 | |
| 		/// </summary>
 | |
| 		public bool IsPieOnly
 | |
| 		{
 | |
|  			get
 | |
|  			{
 | |
| 				bool hasPie = false;
 | |
|  				foreach ( CurveItem curve in this )
 | |
|  				{
 | |
|  					if ( !curve.IsPie )
 | |
|  						return false;
 | |
| 					else
 | |
| 						hasPie = true;
 | |
|  				}
 | |
| 				return hasPie;
 | |
|  			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Determine if there is any data in any of the <see cref="CurveItem"/>
 | |
| 		/// objects for this graph.  This method does not verify valid data, it
 | |
| 		/// only checks to see if <see cref="CurveItem.NPts"/> > 0.
 | |
| 		/// </summary>
 | |
| 		/// <returns>true if there is any data, false otherwise</returns>
 | |
| 		public bool HasData()
 | |
| 		{
 | |
| 			foreach( CurveItem curve in this )
 | |
| 			{
 | |
| 				if ( curve.Points.Count > 0 )
 | |
| 					return true;
 | |
| 			}
 | |
| 			return false;
 | |
| 		}
 | |
| 	#endregion
 | |
| 	
 | |
| 	#region Constructors
 | |
| 	
 | |
| 		/// <summary>
 | |
| 		/// Default constructor for the collection class
 | |
| 		/// </summary>
 | |
| 		public CurveList()
 | |
| 		{
 | |
| 			maxPts = 1;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// The Copy Constructor
 | |
| 		/// </summary>
 | |
| 		/// <param name="rhs">The XAxis object from which to copy</param>
 | |
| 		public CurveList( CurveList rhs )
 | |
| 		{
 | |
| 			this.maxPts = rhs.maxPts;
 | |
| 
 | |
| 			foreach ( CurveItem item in rhs )
 | |
| 			{
 | |
| 				this.Add( (CurveItem) ((ICloneable)item).Clone() );
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Implement the <see cref="ICloneable" /> interface in a typesafe manner by just
 | |
| 		/// calling the typed version of <see cref="Clone" />
 | |
| 		/// </summary>
 | |
| 		/// <returns>A deep copy of this object</returns>
 | |
| 		object ICloneable.Clone()
 | |
| 		{
 | |
| 			return this.Clone();
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Typesafe, deep-copy clone method.
 | |
| 		/// </summary>
 | |
| 		/// <returns>A new, independent copy of this class</returns>
 | |
| 		public CurveList Clone()
 | |
| 		{
 | |
| 			return new CurveList( this );
 | |
| 		}
 | |
| 
 | |
| 		
 | |
| 	#endregion
 | |
| 
 | |
| 	#region IEnumerable Methods
 | |
| 
 | |
| 		//CJBL
 | |
| 		/// <summary>
 | |
| 		/// Iterate backwards through the <see cref="CurveList" /> items.
 | |
| 		/// </summary>
 | |
| 		public IEnumerable<CurveItem> Backward
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				for ( int i = this.Count - 1; i >= 0; i-- )
 | |
| 					yield return this[i];
 | |
| 			}
 | |
| 		}
 | |
| 		/// <summary>
 | |
| 		/// Iterate forward through the <see cref="CurveList" /> items.
 | |
| 		/// </summary>
 | |
| 		public IEnumerable<CurveItem> Forward
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				for ( int i = 0; i < this.Count; i++ )
 | |
| 					yield return this[i];
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	#endregion
 | |
| 
 | |
| 	#region List Methods
 | |
| /*
 | |
| 		/// <summary>
 | |
| 		/// Indexer to access the specified <see cref="CurveItem"/> object by
 | |
| 		/// its ordinal position in the list.
 | |
| 		/// </summary>
 | |
| 		/// <param name="index">The ordinal position (zero-based) of the
 | |
| 		/// <see cref="CurveItem"/> object to be accessed.</param>
 | |
| 		/// <value>A <see cref="CurveItem"/> object reference.</value>
 | |
| 		public CurveItem this[ int index ]  
 | |
| 		{
 | |
| 			get { return( (CurveItem) List[index] ); }
 | |
| 			set { List[index] = value; }
 | |
| 		}
 | |
| */
 | |
| 		/// <summary>
 | |
| 		/// Indexer to access the specified <see cref="CurveItem"/> object by
 | |
| 		/// its <see cref="CurveItem.Label"/> string.
 | |
| 		/// </summary>
 | |
| 		/// <param name="label">The string label of the
 | |
| 		/// <see cref="CurveItem"/> object to be accessed.</param>
 | |
| 		/// <value>A <see cref="CurveItem"/> object reference.</value>
 | |
| 		public CurveItem this[ string label ]  
 | |
| 		{
 | |
| 			get
 | |
| 			{
 | |
| 				int index = IndexOf( label );
 | |
| 				if ( index >= 0 )
 | |
| 					return( this[index]  );
 | |
| 				else
 | |
| 					return null;
 | |
| 			}
 | |
| 		}
 | |
| /*
 | |
| 		/// <summary>
 | |
| 		/// Add a <see cref="CurveItem"/> object to the collection at the end of the list.
 | |
| 		/// </summary>
 | |
| 		/// <param name="curve">A reference to the <see cref="CurveItem"/> object to
 | |
| 		/// be added</param>
 | |
| 		/// <seealso cref="IList.Add"/>
 | |
| 		public void Add( CurveItem curve )
 | |
| 		{
 | |
| 			List.Add( curve );
 | |
| 		}
 | |
| */
 | |
| /*
 | |
| 		/// <summary>
 | |
| 		/// Remove a <see cref="CurveItem"/> object from the collection based on an object reference.
 | |
| 		/// </summary>
 | |
| 		/// <param name="curve">A reference to the <see cref="CurveItem"/> object that is to be
 | |
| 		/// removed.</param>
 | |
| 		/// <seealso cref="IList.Remove"/>
 | |
| 		public void Remove( CurveItem curve )
 | |
| 		{
 | |
| 			List.Remove( curve );
 | |
| 		}
 | |
| */
 | |
| /*
 | |
| 		/// <summary>
 | |
| 		/// Insert a <see cref="CurveItem"/> object into the collection at the specified
 | |
| 		/// zero-based index location.
 | |
| 		/// </summary>
 | |
| 		/// <param name="index">The zero-based index location for insertion.</param>
 | |
| 		/// <param name="curve">A reference to the <see cref="CurveItem"/> object that is to be
 | |
| 		/// inserted.</param>
 | |
| 		/// <seealso cref="IList.Insert"/>
 | |
| 		public void Insert( int index, CurveItem curve )
 | |
| 		{
 | |
| 			List.Insert( index, curve );
 | |
| 		}
 | |
| */
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Return the zero-based position index of the
 | |
| 		/// <see cref="CurveItem"/> with the specified <see cref="CurveItem.Label"/>.
 | |
| 		/// </summary>
 | |
| 		/// <param name="label">The <see cref="String"/> label that is in the
 | |
| 		/// <see cref="CurveItem.Label"/> attribute of the item to be found.
 | |
| 		/// </param>
 | |
| 		/// <returns>The zero-based index of the specified <see cref="CurveItem"/>,
 | |
| 		/// or -1 if the <see cref="CurveItem"/> is not in the list</returns>
 | |
| 		/// <seealso cref="IndexOfTag"/>
 | |
| 		public int IndexOf( string label )
 | |
| 		{
 | |
| 			int index = 0;
 | |
| 			foreach ( CurveItem p in this )
 | |
| 			{
 | |
| 				if ( String.Compare( p._label._text, label, true ) == 0 )
 | |
| 					return index;
 | |
| 				index++;
 | |
| 			}
 | |
| 
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Return the zero-based position index of the
 | |
| 		/// <see cref="CurveItem"/> with the specified <see cref="CurveItem.Tag"/>.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>In order for this method to work, the <see cref="CurveItem.Tag"/>
 | |
| 		/// property must be of type <see cref="String"/>.</remarks>
 | |
| 		/// <param name="tag">The <see cref="String"/> tag that is in the
 | |
| 		/// <see cref="CurveItem.Tag"/> attribute of the item to be found.
 | |
| 		/// </param>
 | |
| 		/// <returns>The zero-based index of the specified <see cref="CurveItem"/>,
 | |
| 		/// or -1 if the <see cref="CurveItem"/> is not in the list</returns>
 | |
| 		public int IndexOfTag( string tag )
 | |
| 		{
 | |
| 			int index = 0;
 | |
| 			foreach ( CurveItem p in this )
 | |
| 			{
 | |
| 				if ( p.Tag is string &&
 | |
| 							String.Compare( (string) p.Tag, tag, true ) == 0 )
 | |
| 					return index;
 | |
| 				index++;
 | |
| 			}
 | |
| 
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Sorts the list according to the point values at the specified index and
 | |
| 		/// for the specified axis.
 | |
| 		/// </summary>
 | |
| 		public void Sort( SortType type, int index )
 | |
| 		{
 | |
| 			this.Sort( new CurveItem.Comparer( type, index ) );
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Move the position of the object at the specified index
 | |
| 		/// to the new relative position in the list.</summary>
 | |
| 		/// <remarks>For Graphic type objects, this method controls the
 | |
| 		/// Z-Order of the items.  Objects at the beginning of the list
 | |
| 		/// appear in front of objects at the end of the list.</remarks>
 | |
| 		/// <param name="index">The zero-based index of the object
 | |
| 		/// to be moved.</param>
 | |
| 		/// <param name="relativePos">The relative number of positions to move
 | |
| 		/// the object.  A value of -1 will move the
 | |
| 		/// object one position earlier in the list, a value
 | |
| 		/// of 1 will move it one position later.  To move an item to the
 | |
| 		/// beginning of the list, use a large negative value (such as -999).
 | |
| 		/// To move it to the end of the list, use a large positive value.
 | |
| 		/// </param>
 | |
| 		/// <returns>The new position for the object, or -1 if the object
 | |
| 		/// was not found.</returns>
 | |
| 		public int Move( int index, int relativePos )
 | |
| 		{
 | |
| 			if ( index < 0 || index >= Count )
 | |
| 				return -1;
 | |
| 
 | |
| 			CurveItem curve = this[index];
 | |
| 			this.RemoveAt( index );
 | |
| 
 | |
| 			index += relativePos;
 | |
| 			if ( index < 0 )
 | |
| 				index = 0;
 | |
| 			if ( index > Count )
 | |
| 				index = Count;
 | |
| 
 | |
| 			Insert( index, curve );
 | |
| 			return index;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	#endregion
 | |
| 
 | |
| 	#region Rendering Methods
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Go through each <see cref="CurveItem"/> object in the collection,
 | |
| 		/// calling the <see cref="CurveItem.GetRange"/> member to 
 | |
| 		/// determine the minimum and maximum values in the
 | |
| 		/// <see cref="CurveItem.Points"/> list of data value pairs.  If the curves include 
 | |
| 		/// a stack bar, handle within the current GetRange method. In the event that no
 | |
| 		/// data are available, a default range of min=0.0 and max=1.0 are returned.
 | |
| 		/// If the Y axis has a valid data range and the Y2 axis not, then the Y2
 | |
| 		/// range will be a duplicate of the Y range.  Vice-versa for the Y2 axis
 | |
| 		/// having valid data when the Y axis does not.
 | |
| 		/// If any <see cref="CurveItem"/> in the list has a missing
 | |
| 		/// <see cref="PointPairList"/>, a new empty one will be generated.
 | |
| 		/// </summary>
 | |
| 		/// <param name="bIgnoreInitial">ignoreInitial is a boolean value that
 | |
| 		/// affects the data range that is considered for the automatic scale
 | |
| 		/// ranging (see <see cref="GraphPane.IsIgnoreInitial"/>).  If true, then initial
 | |
| 		/// data points where the Y value is zero are not included when
 | |
| 		/// automatically determining the scale <see cref="Scale.Min"/>,
 | |
| 		/// <see cref="Scale.Max"/>, and <see cref="Scale.MajorStep"/> size.  All data after
 | |
| 		/// the first non-zero Y value are included.
 | |
| 		/// </param>
 | |
| 		/// <param name="isBoundedRanges">
 | |
| 		/// Determines if the auto-scaled axis ranges will subset the
 | |
| 		/// data points based on any manually set scale range values.
 | |
| 		/// </param>
 | |
| 		/// <param name="pane">
 | |
| 		/// A reference to the <see cref="GraphPane"/> object that is the parent or
 | |
| 		/// owner of this object.
 | |
| 		/// </param>
 | |
| 		/// <seealso cref="GraphPane.IsBoundedRanges"/>
 | |
| 		public void GetRange( bool bIgnoreInitial, bool isBoundedRanges, GraphPane pane )
 | |
| 		{
 | |
| 			double	tXMinVal,
 | |
| 						tXMaxVal,
 | |
| 						tYMinVal,
 | |
| 						tYMaxVal;
 | |
| 
 | |
| 			InitScale( pane.XAxis.Scale, isBoundedRanges );
 | |
| 			InitScale( pane.X2Axis.Scale, isBoundedRanges );
 | |
| 
 | |
| 			foreach ( YAxis axis in pane.YAxisList )
 | |
| 				InitScale( axis.Scale, isBoundedRanges );
 | |
| 
 | |
| 			foreach ( Y2Axis axis in pane.Y2AxisList )
 | |
| 				InitScale( axis.Scale, isBoundedRanges );
 | |
| 
 | |
| 			maxPts = 1;
 | |
| 			
 | |
| 			// Loop over each curve in the collection and examine the data ranges
 | |
| 			foreach ( CurveItem curve in this )
 | |
| 			{
 | |
| 				if ( curve.IsVisible )
 | |
| 				{
 | |
| 					// For stacked types, use the GetStackRange() method which accounts for accumulated values
 | |
| 					// rather than simple curve values.
 | |
| 					if ( ( ( curve is BarItem ) && ( pane._barSettings.Type == BarType.Stack ||
 | |
| 							pane._barSettings.Type == BarType.PercentStack ) ) ||
 | |
| 						( ( curve is LineItem ) && pane.LineType == LineType.Stack ) )
 | |
| 					{
 | |
| 						GetStackRange( pane, curve, out tXMinVal, out tYMinVal,
 | |
| 										out tXMaxVal, out tYMaxVal );
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						// Call the GetRange() member function for the current
 | |
| 						// curve to get the min and max values
 | |
| 						curve.GetRange( out tXMinVal, out tXMaxVal,
 | |
| 										out tYMinVal, out tYMaxVal, bIgnoreInitial, true, pane );
 | |
| 					}
 | |
| 
 | |
| 					// isYOrd is true if the Y axis is an ordinal type
 | |
| 					Scale yScale = curve.GetYAxis( pane ).Scale;
 | |
| 
 | |
| 					Scale xScale = curve.GetXAxis( pane ).Scale;
 | |
| 					bool isYOrd = yScale.IsAnyOrdinal;
 | |
| 					// isXOrd is true if the X axis is an ordinal type
 | |
| 					bool isXOrd = xScale.IsAnyOrdinal;
 | |
| 
 | |
| 					// For ordinal Axes, the data range is just 1 to Npts
 | |
| 					if ( isYOrd && !curve.IsOverrideOrdinal )
 | |
| 					{
 | |
| 						tYMinVal = 1.0;
 | |
| 						tYMaxVal = curve.NPts;
 | |
| 					}
 | |
| 					if ( isXOrd && !curve.IsOverrideOrdinal )
 | |
| 					{
 | |
| 						tXMinVal = 1.0;
 | |
| 						tXMaxVal = curve.NPts;
 | |
| 					}
 | |
| 
 | |
| 					// Bar types always include the Y=0 value
 | |
| 					if ( curve.IsBar )
 | |
| 					{
 | |
| 						if ( pane._barSettings.Base == BarBase.X )
 | |
| 						{
 | |
| 							if ( pane._barSettings.Type != BarType.ClusterHiLow )
 | |
| 							{
 | |
| 								if ( tYMinVal > 0 )
 | |
| 									tYMinVal = 0;
 | |
| 								else if ( tYMaxVal < 0 )
 | |
| 									tYMaxVal = 0;
 | |
| 							}
 | |
| 
 | |
| 							// for non-ordinal axes, expand the data range slightly for bar charts to
 | |
| 							// account for the fact that the bar clusters have a width
 | |
| 							if ( !isXOrd )
 | |
| 							{
 | |
| 								tXMinVal -= pane._barSettings._clusterScaleWidth / 2.0;
 | |
| 								tXMaxVal += pane._barSettings._clusterScaleWidth / 2.0;
 | |
| 							}
 | |
| 						}
 | |
| 						else
 | |
| 						{
 | |
| 							if ( pane._barSettings.Type != BarType.ClusterHiLow )
 | |
| 							{
 | |
| 								if ( tXMinVal > 0 )
 | |
| 									tXMinVal = 0;
 | |
| 								else if ( tXMaxVal < 0 )
 | |
| 									tXMaxVal = 0;
 | |
| 							}
 | |
| 
 | |
| 							// for non-ordinal axes, expand the data range slightly for bar charts to
 | |
| 							// account for the fact that the bar clusters have a width
 | |
| 							if ( !isYOrd )
 | |
| 							{
 | |
| 								tYMinVal -= pane._barSettings._clusterScaleWidth / 2.0;
 | |
| 								tYMaxVal += pane._barSettings._clusterScaleWidth / 2.0;
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					// determine which curve has the maximum number of points
 | |
| 					if ( curve.NPts > maxPts )
 | |
| 						maxPts = curve.NPts;
 | |
| 
 | |
| 					// If the min and/or max values from the current curve
 | |
| 					// are the absolute min and/or max, then save the values
 | |
| 					// Also, differentiate between Y and Y2 values
 | |
| 
 | |
| 					if ( tYMinVal < yScale._rangeMin )
 | |
| 						yScale._rangeMin = tYMinVal;
 | |
| 					if ( tYMaxVal > yScale._rangeMax )
 | |
| 						yScale._rangeMax = tYMaxVal;
 | |
| 
 | |
| 
 | |
| 					if ( tXMinVal < xScale._rangeMin )
 | |
| 						xScale._rangeMin = tXMinVal;
 | |
| 					if ( tXMaxVal > xScale._rangeMax )
 | |
| 						xScale._rangeMax = tXMaxVal;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			pane.XAxis.Scale.SetRange( pane, pane.XAxis );
 | |
| 			pane.X2Axis.Scale.SetRange( pane, pane.X2Axis );
 | |
| 
 | |
| 			foreach ( YAxis axis in pane.YAxisList )
 | |
| 				axis.Scale.SetRange( pane, axis );
 | |
| 			foreach ( Y2Axis axis in pane.Y2AxisList )
 | |
| 				axis.Scale.SetRange( pane, axis );
 | |
| 		}
 | |
| 
 | |
| 		private void InitScale( Scale scale, bool isBoundedRanges )
 | |
| 		{
 | |
| 			scale._rangeMin = double.MaxValue;
 | |
| 			scale._rangeMax = double.MinValue;
 | |
| 			scale._lBound = ( isBoundedRanges && !scale._minAuto ) ?
 | |
| 				scale._min : double.MinValue;
 | |
| 			scale._uBound = ( isBoundedRanges && !scale._maxAuto ) ?
 | |
| 				scale._max : double.MaxValue;
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Calculate the range for stacked bars and lines.
 | |
| 		/// </summary>
 | |
| 		/// <remarks>This method is required for the stacked
 | |
| 		/// types because (for bars), the negative values are a separate stack than the positive
 | |
| 		/// values.  If you just sum up the bars, you will get the sum of the positive plus negative,
 | |
| 		/// which is less than the maximum positive value and greater than the maximum negative value.
 | |
| 		/// </remarks>
 | |
| 		/// <param name="pane">
 | |
| 		/// A reference to the <see cref="GraphPane"/> object that is the parent or
 | |
| 		/// owner of this object.
 | |
| 		/// </param>
 | |
| 		/// <param name="curve">The <see cref="CurveItem"/> for which to calculate the range</param>
 | |
| 		/// <param name="tXMinVal">The minimum X value so far</param>
 | |
| 		/// <param name="tYMinVal">The minimum Y value so far</param>
 | |
| 		/// <param name="tXMaxVal">The maximum X value so far</param>
 | |
| 		/// <param name="tYMaxVal">The maximum Y value so far</param>
 | |
| 		/// <seealso cref="GraphPane.IsBoundedRanges"/>
 | |
| 		private void GetStackRange( GraphPane pane, CurveItem curve, out double tXMinVal,
 | |
| 									out double tYMinVal, out double tXMaxVal, out double tYMaxVal )
 | |
| 		{
 | |
| 			// initialize the values to outrageous ones to start
 | |
| 			tXMinVal = tYMinVal = Double.MaxValue;
 | |
| 			tXMaxVal = tYMaxVal = Double.MinValue;
 | |
| 
 | |
| 			ValueHandler valueHandler = new ValueHandler( pane, false );
 | |
| 			Axis baseAxis = curve.BaseAxis( pane );
 | |
| 			bool isXBase = baseAxis is XAxis || baseAxis is X2Axis;
 | |
| 
 | |
| 			double lowVal, baseVal, hiVal;
 | |
| 
 | |
| 			for ( int i=0; i<curve.Points.Count; i++ )
 | |
| 			{
 | |
| 				valueHandler.GetValues( curve, i, out baseVal, out lowVal, out hiVal );
 | |
| 				double x = isXBase ? baseVal : hiVal;
 | |
| 				double y = isXBase ? hiVal : baseVal;
 | |
| 
 | |
| 				if ( x != PointPair.Missing && y != PointPair.Missing && lowVal != PointPair.Missing )
 | |
| 				{
 | |
| 					if ( x < tXMinVal )
 | |
| 						tXMinVal = x;
 | |
| 					if ( x > tXMaxVal )
 | |
| 						tXMaxVal = x;
 | |
| 					if ( y < tYMinVal )
 | |
| 						tYMinVal = y;
 | |
| 					if ( y > tYMaxVal )
 | |
| 						tYMaxVal = y;
 | |
| 
 | |
| 					if ( !isXBase )
 | |
| 					{
 | |
| 						if ( lowVal < tXMinVal )
 | |
| 							tXMinVal = lowVal;
 | |
| 						if ( lowVal > tXMaxVal )
 | |
| 							tXMaxVal = lowVal;
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						if ( lowVal < tYMinVal )
 | |
| 							tYMinVal = lowVal;
 | |
| 						if ( lowVal > tYMaxVal )
 | |
| 							tYMaxVal = lowVal;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Render all the <see cref="CurveItem"/> objects in the list to the
 | |
| 		/// specified <see cref="Graphics"/>
 | |
| 		/// device by calling the <see cref="CurveItem.Draw"/> member function of
 | |
| 		/// each <see cref="CurveItem"/> object.
 | |
| 		/// </summary>
 | |
| 		/// <param name="g">
 | |
| 		/// A graphic device object to be drawn into.  This is normally e.Graphics from the
 | |
| 		/// PaintEventArgs argument to the Paint() method.
 | |
| 		/// </param>
 | |
| 		/// <param name="pane">
 | |
| 		/// A reference to the <see cref="GraphPane"/> object that is the parent or
 | |
| 		/// owner of this object.
 | |
| 		/// </param>
 | |
| 		/// <param name="scaleFactor">
 | |
| 		/// The scaling factor to be used for rendering objects.  This is calculated and
 | |
| 		/// passed down by the parent <see cref="GraphPane"/> object using the
 | |
| 		/// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust
 | |
| 		/// font sizes, etc. according to the actual size of the graph.
 | |
| 		/// </param>
 | |
| 		public void Draw( Graphics g, GraphPane pane, float scaleFactor )
 | |
| 		{
 | |
| 			// Configure the accumulator for stacked bars
 | |
| 			//Bar.ResetBarStack();
 | |
| 
 | |
| 			// Count the number of BarItems in the curvelist
 | |
| 			int pos = this.NumBars;
 | |
| 			
 | |
| 			// sorted overlay bars are a special case, since they are sorted independently at each
 | |
| 			// ordinal position.
 | |
| 			if ( pane._barSettings.Type == BarType.SortedOverlay )
 | |
| 			{
 | |
| 				// First, create a new curveList with references (not clones) of the curves
 | |
| 				CurveList tempList = new CurveList();
 | |
| 				foreach ( CurveItem curve in this )
 | |
| 					if ( curve.IsBar )
 | |
| 						tempList.Add( (CurveItem) curve );
 | |
| 				
 | |
| 				// Loop through the bars, graphing each ordinal position separately
 | |
| 				for ( int i=0; i<this.maxPts; i++ )
 | |
| 				{
 | |
| 					// At each ordinal position, sort the curves according to the value axis value
 | |
| 					tempList.Sort( pane._barSettings.Base == BarBase.X ? SortType.YValues : SortType.XValues, i );
 | |
| 					// plot the bars for the current ordinal position, in sorted order
 | |
| 					foreach ( BarItem barItem in tempList )
 | |
| 						barItem.Bar.DrawSingleBar( g, pane, barItem,
 | |
| 							((BarItem)barItem).BaseAxis( pane ),
 | |
| 							((BarItem)barItem).ValueAxis( pane ),
 | |
| 							0, i, ( (BarItem)barItem ).GetBarWidth( pane ), scaleFactor );
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			// Loop for each curve in reverse order to pick up the remaining curves
 | |
| 			// The reverse order is done so that curves that are later in the list are plotted behind
 | |
| 			// curves that are earlier in the list
 | |
| 
 | |
| 			for ( int i = this.Count - 1; i >= 0; i-- )
 | |
| 			{
 | |
| 				CurveItem curve = this[i];
 | |
| 				
 | |
| 				if ( curve.IsBar )
 | |
| 					pos--;
 | |
| 					
 | |
| 				// Render the curve
 | |
| 
 | |
| 				//	if it's a sorted overlay bar type, it's already been done above
 | |
| 				if ( !( curve.IsBar && pane._barSettings.Type == BarType.SortedOverlay ) )
 | |
| 				{
 | |
| 					curve.Draw( g, pane, pos, scaleFactor );
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		/// <summary>
 | |
| 		/// Find the ordinal position of the specified <see cref="BarItem" /> within
 | |
| 		/// the <see cref="CurveList" />.  This position only counts <see cef="BarItem" />
 | |
| 		/// types, ignoring all other types.
 | |
| 		/// </summary>
 | |
| 		/// <param name="pane">The <see cref="GraphPane" /> of interest</param>
 | |
| 		/// <param name="barItem">The <see cref="BarItem" /> for which to search.</param>
 | |
| 		/// <returns>The ordinal position of the specified bar, or -1 if the bar
 | |
| 		/// was not found.</returns>
 | |
| 		public int GetBarItemPos( GraphPane pane, BarItem barItem )
 | |
| 		{
 | |
| 			if (	pane._barSettings.Type == BarType.Overlay ||
 | |
| 					pane._barSettings.Type == BarType.Stack ||
 | |
| 					pane._barSettings.Type == BarType.PercentStack)
 | |
| 				return 0;
 | |
| 
 | |
| 			int i = 0;
 | |
| 			foreach ( CurveItem curve in this )
 | |
| 			{
 | |
| 				if ( curve == barItem )
 | |
| 					return i;
 | |
| 				else if ( curve is BarItem )
 | |
| 					i++;
 | |
| 			}
 | |
| 
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 	#endregion
 | |
| 
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 |