//============================================================================
//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;
using System.Runtime.Serialization;
using System.Security.Permissions;
#if ( !DOTNET1 ) // Is this a .Net 2 compilation?
using System.Collections.Generic;
#endif
namespace DrawGraph
{
///
/// This class contains the data and methods for an individual curve within
/// a graph pane. It carries the settings for the curve including the
/// key and item names, colors, symbols and sizes, linetypes, etc.
///
///
/// John Champion
/// modified by Jerry Vos
/// $Revision: 3.40 $ $Date: 2007/04/16 00:03:01 $
[Serializable]
abstract public class CurveItem : ISerializable, ICloneable
{
#region Fields
///
/// protected field that stores a instance for this
/// , which is used for the
/// label. Use the public
/// property to access this value.
///
internal Label _label;
///
/// protected field that stores the boolean value that determines whether this
/// is on the bottom X axis or the top X axis (X2).
/// Use the public property to access this value.
///
protected bool _isX2Axis;
///
/// protected field that stores the boolean value that determines whether this
/// is on the left Y axis or the right Y axis (Y2).
/// Use the public property to access this value.
///
protected bool _isY2Axis;
///
/// protected field that stores the index number of the Y Axis to which this
/// belongs. Use the public property
/// to access this value.
///
protected int _yAxisIndex;
///
/// protected field that stores the boolean value that determines whether this
/// is visible on the graph.
/// Use the public property to access this value.
/// Note that this value turns the curve display on or off, but it does not
/// affect the display of the legend entry. To hide the legend entry, you
/// have to set to false.
///
protected bool _isVisible;
// Revision: JCarpenter 10/06
///
/// Protected field that stores the boolean value that determines whether this
/// is selected on the graph.
/// Use the public property to access this value.
/// Note that this value changes the curve display color, but it does not
/// affect the display of the legend entry. To hide the legend entry, you
/// have to set to false.
///
protected bool _isSelected;
// Revision: JCarpenter 10/06
///
/// Protected field that stores the boolean value that determines whether this
/// can be selected in the graph.
///
protected bool _isSelectable;
///
/// protected field that stores a boolean value which allows you to override the normal
/// ordinal axis behavior. Use the public property to
/// access this value.
///
protected bool _isOverrideOrdinal;
///
/// The of value sets that
/// represent this .
/// The size of this list determines the number of points that are
/// plotted. Note that values defined as
/// System.Double.MaxValue are considered "missing" values
/// (see ),
/// and are not plotted. The curve will have a break at these points
/// to indicate the values are missing.
///
protected IPointList _points;
///
/// A tag object for use by the user. This can be used to store additional
/// information associated with the . ZedGraph does
/// not use this value for any purpose.
///
///
/// Note that, if you are going to Serialize ZedGraph data, then any type
/// that you store in must be a serializable type (or
/// it will cause an exception).
///
public object Tag;
///
/// Protected field that stores the hyperlink information for this object.
///
internal Link _link;
#endregion
#region Constructors
///
/// constructor the pre-specifies the curve label, the
/// x and y data values as a , the curve
/// type (Bar or Line/Symbol), the , and the
/// . Other properties of the curve are
/// defaulted to the values in the class.
///
/// A string label (legend entry) for this curve
/// An array of double precision values that define
/// the independent (X axis) values for this curve
/// An array of double precision values that define
/// the dependent (Y axis) values for this curve
public CurveItem( string label, double[] x, double[] y ) :
this( label, new PointPairList( x, y ) )
{
}
/*
public CurveItem( string _label, int y ) : this( _label, new IPointList( ) )
{
}
*/
///
/// constructor the pre-specifies the curve label, the
/// x and y data values as a , the curve
/// type (Bar or Line/Symbol), the , and the
/// . Other properties of the curve are
/// defaulted to the values in the class.
///
/// A string label (legend entry) for this curve
/// A of double precision value pairs that define
/// the X and Y values for this curve
public CurveItem( string label, IPointList points )
{
Init( label );
if ( points == null )
_points = new PointPairList();
else
//this.points = (IPointList) _points.Clone();
_points = points;
}
///
/// Internal initialization routine thats sets some initial values to defaults.
///
/// A string label (legend entry) for this curve
private void Init( string label )
{
_label = new Label( label, null );
_isY2Axis = false;
_isX2Axis = false;
_isVisible = true;
_isOverrideOrdinal = false;
this.Tag = null;
_yAxisIndex = 0;
_link = new Link();
}
///
/// constructor that specifies the label of the CurveItem.
/// This is the same as CurveItem(label, null, null).
///
///
/// A string label (legend entry) for this curve
public CurveItem( string label ): this( label, null )
{
}
///
///
///
public CurveItem( )
{
Init( null );
}
///
/// The Copy Constructor
///
/// The CurveItem object from which to copy
public CurveItem( CurveItem rhs )
{
_label = rhs._label.Clone();
_isY2Axis = rhs.IsY2Axis;
_isX2Axis = rhs.IsX2Axis;
_isVisible = rhs.IsVisible;
_isOverrideOrdinal = rhs._isOverrideOrdinal;
_yAxisIndex = rhs._yAxisIndex;
if ( rhs.Tag is ICloneable )
this.Tag = ((ICloneable) rhs.Tag).Clone();
else
this.Tag = rhs.Tag;
_points = (IPointList) rhs.Points.Clone();
_link = rhs._link.Clone();
}
///
/// Implement the interface in a typesafe manner by just
/// calling the typed version of Clone.
///
///
/// Note that this method must be called with an explicit cast to ICloneable, and
/// that it is inherently virtual. For example:
///
/// ParentClass foo = new ChildClass();
/// ChildClass bar = (ChildClass) ((ICloneable)foo).Clone();
///
/// Assume that ChildClass is inherited from ParentClass. Even though foo is declared with
/// ParentClass, it is actually an instance of ChildClass. Calling the ICloneable implementation
/// of Clone() on foo actually calls ChildClass.Clone() as if it were a virtual function.
///
/// A deep copy of this object
object ICloneable.Clone()
{
throw new NotImplementedException( "Can't clone an abstract base type -- child types must implement ICloneable" );
//return new PaneBase( this );
}
#endregion
#region Serialization
///
/// Current schema value that defines the version of the serialized file
///
public const int schema = 11;
///
/// Constructor for deserializing objects
///
/// A instance that defines the serialized data
///
/// A instance that contains the serialized data
///
protected CurveItem( SerializationInfo info, StreamingContext context )
{
// The schema value is just a file version parameter. You can use it to make future versions
// backwards compatible as new member variables are added to classes
int sch = info.GetInt32( "schema" );
_label = (Label) info.GetValue( "label", typeof(Label) );
_isY2Axis = info.GetBoolean( "isY2Axis" );
if ( sch >= 11 )
_isX2Axis = info.GetBoolean( "isX2Axis" );
else
_isX2Axis = false;
_isVisible = info.GetBoolean( "isVisible" );
_isOverrideOrdinal = info.GetBoolean( "isOverrideOrdinal" );
// Data Points are always stored as a PointPairList, regardless of the
// actual original type (which could be anything that supports IPointList).
_points = (PointPairList) info.GetValue( "points", typeof(PointPairList) );
Tag = info.GetValue( "Tag", typeof(object) );
_yAxisIndex = info.GetInt32( "yAxisIndex" );
_link = (Link) info.GetValue( "link", typeof(Link) );
}
///
/// Populates a instance with the data needed to serialize the target object
///
/// A instance that defines the serialized data
/// A instance that contains the serialized data
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public virtual void GetObjectData( SerializationInfo info, StreamingContext context )
{
info.AddValue( "schema", schema );
info.AddValue( "label", _label );
info.AddValue( "isY2Axis", _isY2Axis );
info.AddValue( "isX2Axis", _isX2Axis );
info.AddValue( "isVisible", _isVisible );
info.AddValue( "isOverrideOrdinal", _isOverrideOrdinal );
// if points is already a PointPairList, use it
// otherwise, create a new PointPairList so it can be serialized
PointPairList list;
if ( _points is PointPairList )
list = _points as PointPairList;
else
list = new PointPairList( _points );
info.AddValue( "points", list );
info.AddValue( "Tag", Tag );
info.AddValue( "yAxisIndex", _yAxisIndex );
info.AddValue( "link", _link );
}
#endregion
#region Properties
///
/// A instance that represents the
/// entry for the this object
///
public Label Label
{
get { return _label; }
set { _label = value;}
}
///
/// The //
/// color (FillColor for the Bar). This is a common access to
/// Line.Color,
/// Border.Color, and
/// Fill.Color properties for this curve.
///
public Color Color
{
get
{
if ( this is BarItem )
return ((BarItem) this).Bar.Fill.Color;
else if ( this is LineItem && ((LineItem) this).Line.IsVisible )
return ((LineItem) this).Line.Color;
else if ( this is LineItem )
return ((LineItem) this).Symbol.Border.Color;
else if ( this is ErrorBarItem )
return ((ErrorBarItem) this).Bar.Color;
else if ( this is HiLowBarItem )
return ((HiLowBarItem) this).Bar.Fill.Color;
else
return Color.Empty;
}
set
{
if ( this is BarItem )
{
((BarItem) this).Bar.Fill.Color = value;
}
else if ( this is LineItem )
{
((LineItem) this).Line.Color = value;
((LineItem) this).Symbol.Border.Color = value;
((LineItem) this).Symbol.Fill.Color = value;
}
else if ( this is ErrorBarItem )
((ErrorBarItem) this).Bar.Color = value;
else if ( this is HiLowBarItem )
((HiLowBarItem) this).Bar.Fill.Color = value;
}
}
///
/// Determines whether this is visible on the graph.
/// Note that this value turns the curve display on or off, but it does not
/// affect the display of the legend entry. To hide the legend entry, you
/// have to set to false.
///
public bool IsVisible
{
get { return _isVisible; }
set { _isVisible = value; }
}
// Revision: JCarpenter 10/06
///
/// Determines whether this is selected on the graph.
/// Note that this value changes the curve displayed color, but it does not
/// affect the display of the legend entry. To hide the legend entry, you
/// have to set to false.
///
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
/*
if ( this is BarItem )
{
( (BarItem)this ).Bar.Fill.UseInactiveColor = !value;
}
else if ( this is LineItem )
{
( (LineItem)this ).Line.Fill.UseInactiveColor = !value;
( (LineItem)this ).Symbol.Fill.UseInactiveColor = !value;
( (LineItem)this ).Symbol.Fill.UseInactiveColor = !value;
}
else if ( this is HiLowBarItem )
( (HiLowBarItem)this ).Bar.Fill.UseInactiveColor = !value;
else if ( this is PieItem )
( (PieItem)this ).Fill.UseInactiveColor = !value;
*/
}
}
// Revision: JCarpenter 10/06
///
/// Determines whether this can be selected in the graph.
///
public bool IsSelectable
{
get { return _isSelectable; }
set { _isSelectable = value; }
}
///
/// Gets or sets a value which allows you to override the normal
/// ordinal axis behavior.
///
///
/// Normally for an ordinal axis type, the actual data values corresponding to the ordinal
/// axis will be ignored (essentially they are replaced by ordinal values, e.g., 1, 2, 3, etc).
/// If IsOverrideOrdinal is true, then the user data values will be used (even if they don't
/// make sense). Fractional values are allowed, such that a value of 1.5 is between the first and
/// second ordinal position, etc.
///
///
///
public bool IsOverrideOrdinal
{
get { return _isOverrideOrdinal; }
set { _isOverrideOrdinal = value; }
}
///
/// Gets or sets a value that determines which X axis this
/// is assigned to.
///
///
/// The
/// is on the bottom side of the graph and the
/// is on the top side. Assignment to an axis
/// determines the scale that is used to draw the curve on the graph.
///
/// true to assign the curve to the ,
/// false to assign the curve to the
public bool IsX2Axis
{
get { return _isX2Axis; }
set { _isX2Axis = value; }
}
///
/// Gets or sets a value that determines which Y axis this
/// is assigned to.
///
///
/// The
/// is on the left side of the graph and the
/// is on the right side. Assignment to an axis
/// determines the scale that is used to draw the curve on the graph. Note that
/// this value is used in combination with the to determine
/// which of the Y Axes (if there are multiples) this curve belongs to.
///
/// true to assign the curve to the ,
/// false to assign the curve to the
public bool IsY2Axis
{
get { return _isY2Axis; }
set { _isY2Axis = value; }
}
///
/// Gets or sets the index number of the Y Axis to which this
/// belongs.
///
///
/// This value is essentially an index number into the
/// or , depending on the setting of
/// .
///
public int YAxisIndex
{
get { return _yAxisIndex; }
set { _yAxisIndex = value; }
}
///
/// Determines whether this
/// is a . This does not include 's
/// or 's.
///
/// true for a bar chart, or false for a line or pie graph
public bool IsBar
{
get { return this is BarItem; }
}
///
/// Determines whether this
/// is a .
///
/// true for a pie chart, or false for a line or bar graph
public bool IsPie
{
get { return this is PieItem; }
}
///
/// Determines whether this
/// is a .
///
/// true for a line chart, or false for a bar type
public bool IsLine
{
get { return this is LineItem; }
}
///
/// Gets a flag indicating if the Z data range should be included in the axis scaling calculations.
///
/// The parent of this .
///
/// true if the Z data are included, false otherwise
abstract internal bool IsZIncluded( GraphPane pane );
///
/// Gets a flag indicating if the X axis is the independent axis for this
///
/// The parent of this .
///
/// true if the X axis is independent, false otherwise
abstract internal bool IsXIndependent( GraphPane pane );
///
/// Readonly property that gives the number of points that define this
/// object, which is the number of points in the
/// data collection.
///
public int NPts
{
get
{
if ( _points == null )
return 0;
else
return _points.Count;
}
}
///
/// The of X,Y point sets that represent this
/// .
///
public IPointList Points
{
get { return _points; }
set { _points = value; }
}
///
/// An accessor for the datum for this .
/// Index is the ordinal reference (zero based) of the point.
///
public PointPair this[int index]
{
get
{
if ( _points == null )
return new PointPair( PointPair.Missing, PointPair.Missing );
else
return ( _points )[index];
}
}
///
/// Gets or sets the hyperlink information for this .
///
// ///
public Link Link
{
get { return _link; }
set { _link = value; }
}
#endregion
#region Rendering Methods
///
/// Do all rendering associated with this to the specified
/// device. This method is normally only
/// called by the Draw method of the parent
/// collection object.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
/// A reference to the object that is the parent or
/// owner of this object.
///
/// The ordinal position of the current
/// curve.
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
abstract public void Draw( Graphics g, GraphPane pane, int pos, float scaleFactor );
///
/// Draw a legend key entry for this at the specified location.
/// This abstract base method passes through to or
/// to do the rendering.
///
///
/// A graphic device object to be drawn into. This is normally e.Graphics from the
/// PaintEventArgs argument to the Paint() method.
///
///
/// A reference to the object that is the parent or
/// owner of this object.
///
/// The struct that specifies the
/// location for the legend key
///
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent object using the
/// method, and is used to proportionally adjust
/// font sizes, etc. according to the actual size of the graph.
///
abstract public void DrawLegendKey( Graphics g, GraphPane pane, RectangleF rect, float scaleFactor );
#endregion
#region Utility Methods
///
/// Add a single x,y coordinate point to the end of the points collection for this curve.
///
/// The X coordinate value
/// The Y coordinate value
public void AddPoint( double x, double y )
{
this.AddPoint( new PointPair( x, y ) );
}
///
/// Add a object to the end of the points collection for this curve.
///
///
/// This method will only work if the instance reference
/// at supports the interface.
/// Otherwise, it does nothing.
///
/// A reference to the object to
/// be added
public void AddPoint( PointPair point )
{
if ( _points == null )
this.Points = new PointPairList();
if ( _points is IPointListEdit )
( _points as IPointListEdit ).Add( point );
else
throw new NotImplementedException();
}
///
/// Clears the points from this . This is the same
/// as CurveItem.Points.Clear().
///
///
/// This method will only work if the instance reference
/// at supports the interface.
/// Otherwise, it does nothing.
///
public void Clear()
{
if ( _points is IPointListEdit )
(_points as IPointListEdit).Clear();
else
throw new NotImplementedException();
}
///
/// Removes a single point from this .
///
///
/// This method will only work if the instance reference
/// at supports the interface.
/// Otherwise, it does nothing.
///
/// The ordinal position of the point to be removed.
public void RemovePoint( int index )
{
if ( _points is IPointListEdit )
(_points as IPointListEdit).RemoveAt( index );
else
throw new NotImplementedException();
}
///
/// Get the X Axis instance (either or ) to
/// which this belongs.
///
/// The object to which this curve belongs.
/// Either a or to which this
/// belongs.
///
public Axis GetXAxis( GraphPane pane )
{
if ( _isX2Axis )
return pane.X2Axis;
else
return pane.XAxis;
}
///
/// Get the Y Axis instance (either or ) to
/// which this belongs.
///
///
/// This method safely retrieves a Y Axis instance from either the
/// or the using the values of and
/// . If the value of is out of bounds, the
/// default or is used.
///
/// The object to which this curve belongs.
/// Either a or to which this
/// belongs.
///
public Axis GetYAxis( GraphPane pane )
{
if ( _isY2Axis )
{
if ( _yAxisIndex < pane.Y2AxisList.Count )
return pane.Y2AxisList[_yAxisIndex];
else
return pane.Y2AxisList[0];
}
else
{
if ( _yAxisIndex < pane.YAxisList.Count )
return pane.YAxisList[_yAxisIndex];
else
return pane.YAxisList[0];
}
}
///
/// Get the index of the Y Axis in the or list to
/// which this belongs.
///
///
/// This method safely retrieves a Y Axis index into either the
/// or the using the values of and
/// . If the value of is out of bounds, the
/// default or is used, which is index zero.
///
/// The object to which this curve belongs.
/// An integer value indicating which index position in the list applies to this
///
///
public int GetYAxisIndex( GraphPane pane )
{
if ( _yAxisIndex >= 0 &&
_yAxisIndex < ( _isY2Axis ? pane.Y2AxisList.Count : pane.YAxisList.Count ) )
return _yAxisIndex;
else
return 0;
}
///
/// Loads some pseudo unique colors/symbols into this CurveItem. This
/// is the same as MakeUnique(ColorSymbolRotator.StaticInstance).
///
///
///
///
public void MakeUnique()
{
this.MakeUnique( ColorSymbolRotator.StaticInstance );
}
///
/// Loads some pseudo unique colors/symbols into this CurveItem. This
/// is mainly useful for differentiating a set of new CurveItems without
/// having to pick your own colors/symbols.
///
///
///
/// The that is used to pick the color
/// and symbol for this method call.
///
virtual public void MakeUnique( ColorSymbolRotator rotator )
{
this.Color = rotator.NextColor;
}
///
/// Go through the list of data values for this
/// and determine the minimum and maximum values in the data.
///
/// The minimum X value in the range of data
/// The maximum X value in the range of data
/// The minimum Y value in the range of data
/// The maximum Y value in the range of data
/// ignoreInitial is a boolean value that
/// affects the data range that is considered for the automatic scale
/// ranging (see ). If true, then initial
/// data points where the Y value is zero are not included when
/// automatically determining the scale ,
/// , and size. All data after
/// the first non-zero Y value are included.
///
///
/// Determines if the auto-scaled axis ranges will subset the
/// data points based on any manually set scale range values.
///
///
/// A reference to the object that is the parent or
/// owner of this object.
///
///
virtual public void GetRange( out double xMin, out double xMax,
out double yMin, out double yMax,
bool ignoreInitial,
bool isBoundedRanges,
GraphPane pane )
{
// The lower and upper bounds of allowable data for the X values. These
// values allow you to subset the data values. If the X range is bounded, then
// the resulting range for Y will reflect the Y values for the points within the X
// bounds.
double xLBound = double.MinValue;
double xUBound = double.MaxValue;
double yLBound = double.MinValue;
double yUBound = double.MaxValue;
// initialize the values to outrageous ones to start
xMin = yMin = Double.MaxValue;
xMax = yMax = Double.MinValue;
Axis yAxis = this.GetYAxis( pane );
Axis xAxis = this.GetXAxis( pane );
if ( yAxis == null || xAxis == null )
return;
if ( isBoundedRanges )
{
xLBound = xAxis._scale._lBound;
xUBound = xAxis._scale._uBound;
yLBound = yAxis._scale._lBound;
yUBound = yAxis._scale._uBound;
}
bool isZIncluded = this.IsZIncluded( pane );
bool isXIndependent = this.IsXIndependent( pane );
bool isXLog = xAxis.Scale.IsLog;
bool isYLog = yAxis.Scale.IsLog;
// Loop over each point in the arrays
//foreach ( PointPair point in this.Points )
for ( int i=0; i xUBound ||
curY < yLBound || curY > yUBound ||
( isZIncluded && isXIndependent && ( curZ < yLBound || curZ > yUBound ) ) ||
( isZIncluded && !isXIndependent && ( curZ < xLBound || curZ > xUBound ) ) ||
( curX <= 0 && isXLog ) || ( curY <= 0 && isYLog );
// ignoreInitial becomes false at the first non-zero
// Y value
if ( ignoreInitial && curY != 0 &&
curY != PointPair.Missing )
ignoreInitial = false;
if ( !ignoreInitial &&
!outOfBounds &&
curX != PointPair.Missing &&
curY != PointPair.Missing )
{
if ( curX < xMin )
xMin = curX;
if ( curX > xMax )
xMax = curX;
if ( curY < yMin )
yMin = curY;
if ( curY > yMax )
yMax = curY;
if ( isZIncluded && isXIndependent && curZ != PointPair.Missing )
{
if ( curZ < yMin )
yMin = curZ;
if ( curZ > yMax )
yMax = curZ;
}
else if ( isZIncluded && curZ != PointPair.Missing )
{
if ( curZ < xMin )
xMin = curZ;
if ( curZ > xMax )
xMax = curZ;
}
}
}
}
/// Returns a reference to the object that is the "base"
/// (independent axis) from which the values are drawn.
///
/// This property is determined by the value of for
/// , , and
/// types. It is always the X axis for regular types.
/// Note that the setting can override the
/// and settings for bar types
/// (this is because all the bars that are clustered together must share the
/// same base axis).
///
///
///
public virtual Axis BaseAxis( GraphPane pane )
{
BarBase barBase;
if ( this is BarItem || this is ErrorBarItem || this is HiLowBarItem )
barBase = pane._barSettings.Base;
else
barBase = _isX2Axis ? BarBase.X2 : BarBase.X;
if ( barBase == BarBase.X )
return pane.XAxis;
else if ( barBase == BarBase.X2 )
return pane.X2Axis;
else if ( barBase == BarBase.Y )
return pane.YAxis;
else
return pane.Y2Axis;
}
/// Returns a reference to the object that is the "value"
/// (dependent axis) from which the points are drawn.
///
/// This property is determined by the value of for
/// , , and
/// types. It is always the Y axis for regular types.
///
///
///
public virtual Axis ValueAxis( GraphPane pane )
{
BarBase barBase;
if ( this is BarItem || this is ErrorBarItem || this is HiLowBarItem )
barBase = pane._barSettings.Base;
else
barBase = BarBase.X;
if ( barBase == BarBase.X || barBase == BarBase.X2 )
{
return GetYAxis( pane );
}
else
return GetXAxis( pane );
}
///
/// Calculate the width of each bar, depending on the actual bar type
///
/// The width for an individual bar, in pixel units
public float GetBarWidth( GraphPane pane )
{
// Total axis width =
// npts * ( nbars * ( bar + bargap ) - bargap + clustgap )
// cg * bar = cluster gap
// npts = max number of points in any curve
// nbars = total number of curves that are of type IsBar
// bar = bar width
// bg * bar = bar gap
// therefore:
// totwidth = npts * ( nbars * (bar + bg*bar) - bg*bar + cg*bar )
// totwidth = bar * ( npts * ( nbars * ( 1 + bg ) - bg + cg ) )
// solve for bar
float barWidth;
if ( this is ErrorBarItem )
barWidth = (float) ( ((ErrorBarItem)this).Bar.Symbol.Size *
pane.CalcScaleFactor() );
else if ( this is HiLowBarItem )
// barWidth = (float) ( ((HiLowBarItem)this).Bar.GetBarWidth( pane,
// ((HiLowBarItem)this).BaseAxis(pane), pane.CalcScaleFactor() ) );
barWidth = (float) ( ((HiLowBarItem)this).Bar.Size *
pane.CalcScaleFactor() );
else // BarItem or LineItem
{
// For stacked bar types, the bar width will be based on a single bar
float numBars = 1.0F;
if ( pane._barSettings.Type == BarType.Cluster || pane._barSettings.Type == BarType.ClusterHiLow )
numBars = pane.CurveList.NumBars;
float denom = numBars * ( 1.0F + pane._barSettings.MinBarGap ) -
pane._barSettings.MinBarGap + pane._barSettings.MinClusterGap;
if ( denom <= 0 )
denom = 1;
barWidth = pane.BarSettings.GetClusterWidth() / denom;
}
if ( barWidth <= 0 )
return 1;
return barWidth;
}
///
/// Determine the coords for the rectangle associated with a specified point for
/// this
///
/// The to which this curve belongs
/// The index of the point of interest
/// A list of coordinates that represents the "rect" for
/// this point (used in an html AREA tag)
/// true if it's a valid point, false otherwise
abstract public bool GetCoords( GraphPane pane, int i, out string coords );
#endregion
#region Inner classes
#if ( DOTNET1 ) // Is this a .Net 1.1 compilation?
///
/// Compares 's based on the point value at the specified
/// index and for the specified axis.
///
///
public class Comparer : IComparer
{
private int index;
private SortType sortType;
///
/// Constructor for Comparer.
///
/// The axis type on which to sort.
/// The index number of the point on which to sort
public Comparer( SortType type, int index )
{
this.sortType = type;
this.index = index;
}
///
/// Compares two s using the previously specified index value
/// and axis. Sorts in descending order.
///
/// Curve to the left.
/// Curve to the right.
/// -1, 0, or 1 depending on l.X's relation to r.X
public int Compare( object l, object r )
{
CurveItem cl = (CurveItem) l;
CurveItem cr = (CurveItem) r;
if (cl == null && cr == null )
return 0;
else if (cl == null && cr != null )
return -1;
else if (cl != null && cr == null)
return 1;
if ( cr != null && cr.NPts <= index )
cr = null;
if ( cl != null && cl.NPts <= index )
cl = null;
double lVal, rVal;
if ( sortType == SortType.XValues )
{
lVal = ( l != null ) ? System.Math.Abs( cl[index].X ) : PointPair.Missing;
rVal = ( r != null ) ? System.Math.Abs( cr[index].X ) : PointPair.Missing;
}
else
{
lVal = ( l != null ) ? System.Math.Abs( cl[index].Y ) : PointPair.Missing;
rVal = ( r != null ) ? System.Math.Abs( cr[index].Y ) : PointPair.Missing;
}
if ( lVal == PointPair.Missing || Double.IsInfinity( lVal ) || Double.IsNaN( lVal ) )
cl = null;
if ( rVal == PointPair.Missing || Double.IsInfinity( rVal ) || Double.IsNaN( rVal ) )
cr = null;
if ( ( cl == null && cr == null) || ( System.Math.Abs( lVal - rVal ) < 1e-10 ) )
return 0;
else if ( cl == null && cr != null )
return -1;
else if ( cl != null && r == null )
return 1;
else
return rVal < lVal ? -1 : 1;
}
}
#else // Otherwise, it's .Net 2.0 so use generics
///
/// Compares 's based on the point value at the specified
/// index and for the specified axis.
///
///
public class Comparer : IComparer
{
private int index;
private SortType sortType;
///
/// Constructor for Comparer.
///
/// The axis type on which to sort.
/// The index number of the point on which to sort
public Comparer( SortType type, int index )
{
this.sortType = type;
this.index = index;
}
///
/// Compares two s using the previously specified index value
/// and axis. Sorts in descending order.
///
/// Curve to the left.
/// Curve to the right.
/// -1, 0, or 1 depending on l.X's relation to r.X
public int Compare( CurveItem l, CurveItem r )
{
if (l == null && r == null )
return 0;
else if (l == null && r != null )
return -1;
else if (l != null && r == null)
return 1;
if ( r != null && r.NPts <= index )
r = null;
if ( l != null && l.NPts <= index )
l = null;
double lVal, rVal;
if ( sortType == SortType.XValues )
{
lVal = ( l != null ) ? System.Math.Abs( l[index].X ) : PointPair.Missing;
rVal = ( r != null ) ? System.Math.Abs( r[index].X ) : PointPair.Missing;
}
else
{
lVal = ( l != null ) ? System.Math.Abs( l[index].Y ) : PointPair.Missing;
rVal = ( r != null ) ? System.Math.Abs( r[index].Y ) : PointPair.Missing;
}
if ( lVal == PointPair.Missing || Double.IsInfinity( lVal ) || Double.IsNaN( lVal ) )
l = null;
if ( rVal == PointPair.Missing || Double.IsInfinity( rVal ) || Double.IsNaN( rVal ) )
r = null;
if ( (l == null && r == null) || ( System.Math.Abs( lVal - rVal ) < 1e-10 ) )
return 0;
else if (l == null && r != null )
return -1;
else if (l != null && r == null)
return 1;
else
return rVal < lVal ? -1 : 1;
}
}
#endif
#endregion
}
}