//============================================================================
//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 ZedGraph
{
/// <summary>
/// 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.
/// </summary>
///
/// <author> John Champion
/// modified by Jerry Vos </author>
/// <version> $Revision: 3.39 $ $Date: 2007/03/11 02:08:16 $ </version>
[Serializable]
abstract public class CurveItem : ISerializable, ICloneable
{
#region Fields
/// <summary>
/// protected field that stores a <see cref="Label" /> instance for this
/// <see cref="CurveItem"/>, which is used for the <see cref="Legend" />
/// label. Use the public
/// property <see cref="Label"/> to access this value.
/// </summary>
internal Label _label;
/// <summary>
/// protected field that stores the boolean value that determines whether this
/// <see cref="CurveItem"/> is on the left Y axis or the right Y axis (Y2).
/// Use the public property <see cref="IsY2Axis"/> to access this value.
/// </summary>
protected bool _isY2Axis;
/// <summary>
/// protected field that stores the index number of the Y Axis to which this
/// <see cref="CurveItem" /> belongs. Use the public property <see cref="YAxisIndex" />
/// to access this value.
/// </summary>
protected int _yAxisIndex;
/// <summary>
/// protected field that stores the boolean value that determines whether this
/// <see cref="CurveItem"/> is visible on the graph.
/// Use the public property <see cref="IsVisible"/> 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 <see cref="ZedGraph.Label.IsVisible"/> to false.
/// </summary>
protected bool _isVisible;
// Revision: JCarpenter 10/06
/// <summary>
/// Protected field that stores the boolean value that determines whether this
/// <see cref="CurveItem"/> is selected on the graph.
/// Use the public property <see cref="IsSelected"/> 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 <see cref="ZedGraph.Label.IsVisible"/> to false.
/// </summary>
protected bool _isSelected;
// Revision: JCarpenter 10/06
/// <summary>
/// Protected field that stores the boolean value that determines whether this
/// <see cref="CurveItem"/> can be selected in the graph.
/// </summary>
protected bool _isSelectable;
/// <summary>
/// protected field that stores a boolean value which allows you to override the normal
/// ordinal axis behavior. Use the public property <see cref="IsOverrideOrdinal"/> to
/// access this value.
/// </summary>
protected bool _isOverrideOrdinal;
/// <summary>
/// The <see cref="IPointList"/> of value sets that
/// represent this <see cref="CurveItem"/>.
/// 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 <see cref="PointPairBase.Missing"/>),
/// and are not plotted. The curve will have a break at these points
/// to indicate the values are missing.
/// </summary>
protected IPointList _points;
/// <summary>
/// A tag object for use by the user. This can be used to store additional
/// information associated with the <see cref="CurveItem"/>. ZedGraph does
/// not use this value for any purpose.
/// </summary>
/// <remarks>
/// Note that, if you are going to Serialize ZedGraph data, then any type
/// that you store in <see cref="Tag"/> must be a serializable type (or
/// it will cause an exception).
/// </remarks>
public object Tag;
/// <summary>
/// Protected field that stores the hyperlink information for this object.
/// </summary>
internal Link _link;
#endregion
#region Constructors
/// <summary>
/// <see cref="CurveItem"/> constructor the pre-specifies the curve label, the
/// x and y data values as a <see cref="IPointList"/>, the curve
/// type (Bar or Line/Symbol), the <see cref="Color"/>, and the
/// <see cref="SymbolType"/>. Other properties of the curve are
/// defaulted to the values in the <see cref="GraphPane.Default"/> class.
/// </summary>
/// <param name="label">A string label (legend entry) for this curve</param>
/// <param name="x">An array of double precision values that define
/// the independent (X axis) values for this curve</param>
/// <param name="y">An array of double precision values that define
/// the dependent (Y axis) values for this curve</param>
public CurveItem( string label, double[] x, double[] y ) :
this( label, new PointPairList( x, y ) )
{
}
/*
public CurveItem( string _label, int y ) : this( _label, new IPointList( ) )
{
}
*/
/// <summary>
/// <see cref="CurveItem"/> constructor the pre-specifies the curve label, the
/// x and y data values as a <see cref="IPointList"/>, the curve
/// type (Bar or Line/Symbol), the <see cref="Color"/>, and the
/// <see cref="SymbolType"/>. Other properties of the curve are
/// defaulted to the values in the <see cref="GraphPane.Default"/> class.
/// </summary>
/// <param name="label">A string label (legend entry) for this curve</param>
/// <param name="points">A <see cref="IPointList"/> of double precision value pairs that define
/// the X and Y values for this curve</param>
public CurveItem( string label, IPointList points )
{
Init( label );
if ( points == null )
_points = new PointPairList();
else
//this.points = (IPointList) _points.Clone();
_points = points;
}
/// <summary>
/// Internal initialization routine thats sets some initial values to defaults.
/// </summary>
/// <param name="label">A string label (legend entry) for this curve</param>
private void Init( string label )
{
_label = new Label( label, null );
_isY2Axis = false;
_isVisible = true;
_isOverrideOrdinal = false;
this.Tag = null;
_yAxisIndex = 0;
_link = new Link();
}
/// <summary>
/// <see cref="CurveItem"/> constructor that specifies the label of the CurveItem.
/// This is the same as <c>CurveItem(label, null, null)</c>.
/// <seealso cref="CurveItem( string, double[], double[] )"/>
/// </summary>
/// <param name="label">A string label (legend entry) for this curve</param>
public CurveItem( string label ): this( label, null )
{
}
/// <summary>
///
/// </summary>
public CurveItem( )
{
Init( null );
}
/// <summary>
/// The Copy Constructor
/// </summary>
/// <param name="rhs">The CurveItem object from which to copy</param>
public CurveItem( CurveItem rhs )
{
_label = rhs._label.Clone();
_isY2Axis = rhs.IsY2Axis;
_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();
}
/// <summary>
/// Implement the <see cref="ICloneable" /> interface in a typesafe manner by just
/// calling the typed version of Clone.
/// </summary>
/// <remarks>
/// Note that this method must be called with an explicit cast to ICloneable, and
/// that it is inherently virtual. For example:
/// <code>
/// ParentClass foo = new ChildClass();
/// ChildClass bar = (ChildClass) ((ICloneable)foo).Clone();
/// </code>
/// 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.
/// </remarks>
/// <returns>A deep copy of this object</returns>
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
/// <summary>
/// Current schema value that defines the version of the serialized file
/// </summary>
public const int schema = 10;
/// <summary>
/// Constructor for deserializing objects
/// </summary>
/// <param name="info">A <see cref="SerializationInfo"/> instance that defines the serialized data
/// </param>
/// <param name="context">A <see cref="StreamingContext"/> instance that contains the serialized data
/// </param>
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" );
_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) );
}
/// <summary>
/// Populates a <see cref="SerializationInfo"/> instance with the data needed to serialize the target object
/// </summary>
/// <param name="info">A <see cref="SerializationInfo"/> instance that defines the serialized data</param>
/// <param name="context">A <see cref="StreamingContext"/> instance that contains the serialized data</param>
[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( "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
/// <summary>
/// A <see cref="Label" /> instance that represents the <see cref="ZedGraph.Legend"/>
/// entry for the this <see cref="CurveItem"/> object
/// </summary>
public Label Label
{
get { return _label; }
set { _label = value;}
}
/// <summary>
/// The <see cref="Line"/>/<see cref="Symbol"/>/<see cref="Bar"/>
/// color (FillColor for the Bar). This is a common access to
/// <see cref="ZedGraph.LineBase.Color">Line.Color</see>,
/// <see cref="ZedGraph.LineBase.Color">Border.Color</see>, and
/// <see cref="ZedGraph.Fill.Color">Fill.Color</see> properties for this curve.
/// </summary>
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;
}
}
/// <summary>
/// Determines whether this <see cref="CurveItem"/> 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 <see cref="ZedGraph.Label.IsVisible"/> to false.
/// </summary>
public bool IsVisible
{
get { return _isVisible; }
set { _isVisible = value; }
}
// Revision: JCarpenter 10/06
/// <summary>
/// Determines whether this <see cref="CurveItem"/> 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 <see cref="ZedGraph.Label.IsVisible"/> to false.
/// </summary>
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
/// <summary>
/// Determines whether this <see cref="CurveItem"/> can be selected in the graph.
/// </summary>
public bool IsSelectable
{
get { return _isSelectable; }
set { _isSelectable = value; }
}
/// <summary>
/// Gets or sets a value which allows you to override the normal
/// ordinal axis behavior.
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <seealso cref="AxisType.Ordinal"/>
/// <seealso cref="AxisType.Text"/>
public bool IsOverrideOrdinal
{
get { return _isOverrideOrdinal; }
set { _isOverrideOrdinal = value; }
}
/// <summary>
/// Gets or sets a value that determines which Y axis this <see cref="CurveItem"/>
/// is assigned to.
/// </summary>
/// <remarks>
/// The
/// <see cref="ZedGraph.YAxis"/> is on the left side of the graph and the
/// <see cref="ZedGraph.Y2Axis"/> 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 <see cref="YAxisIndex" /> to determine
/// which of the Y Axes (if there are multiples) this curve belongs to.
/// </remarks>
/// <value>true to assign the curve to the <see cref="ZedGraph.Y2Axis"/>,
/// false to assign the curve to the <see cref="ZedGraph.YAxis"/></value>
public bool IsY2Axis
{
get { return _isY2Axis; }
set { _isY2Axis = value; }
}
/// <summary>
/// Gets or sets the index number of the Y Axis to which this
/// <see cref="CurveItem" /> belongs.
/// </summary>
/// <remarks>
/// This value is essentially an index number into the <see cref="GraphPane.YAxisList" />
/// or <see cref="GraphPane.Y2AxisList" />, depending on the setting of
/// <see cref="IsY2Axis" />.
/// </remarks>
public int YAxisIndex
{
get { return _yAxisIndex; }
set { _yAxisIndex = value; }
}
/// <summary>
/// Determines whether this <see cref="CurveItem"/>
/// is a <see cref="BarItem"/>. This does not include <see cref="HiLowBarItem"/>'s
/// or <see cref="ErrorBarItem"/>'s.
/// </summary>
/// <value>true for a bar chart, or false for a line or pie graph</value>
public bool IsBar
{
get { return this is BarItem; }
}
/// <summary>
/// Determines whether this <see cref="CurveItem"/>
/// is a <see cref="PieItem"/>.
/// </summary>
/// <value>true for a pie chart, or false for a line or bar graph</value>
public bool IsPie
{
get { return this is PieItem; }
}
/// <summary>
/// Determines whether this <see cref="CurveItem"/>
/// is a <see cref="LineItem"/>.
/// </summary>
/// <value>true for a line chart, or false for a bar type</value>
public bool IsLine
{
get { return this is LineItem; }
}
/// <summary>
/// Gets a flag indicating if the Z data range should be included in the axis scaling calculations.
/// </summary>
/// <param name="pane">The parent <see cref="GraphPane" /> of this <see cref="CurveItem" />.
/// </param>
/// <value>true if the Z data are included, false otherwise</value>
abstract internal bool IsZIncluded( GraphPane pane );
/// <summary>
/// Gets a flag indicating if the X axis is the independent axis for this <see cref="CurveItem" />
/// </summary>
/// <param name="pane">The parent <see cref="GraphPane" /> of this <see cref="CurveItem" />.
/// </param>
/// <value>true if the X axis is independent, false otherwise</value>
abstract internal bool IsXIndependent( GraphPane pane );
/// <summary>
/// Readonly property that gives the number of points that define this
/// <see cref="CurveItem"/> object, which is the number of points in the
/// <see cref="Points"/> data collection.
/// </summary>
public int NPts
{
get
{
if ( _points == null )
return 0;
else
return _points.Count;
}
}
/// <summary>
/// The <see cref="IPointList"/> of X,Y point sets that represent this
/// <see cref="CurveItem"/>.
/// </summary>
public IPointList Points
{
get { return _points; }
set { _points = value; }
}
/// <summary>
/// An accessor for the <see cref="PointPair"/> datum for this <see cref="CurveItem"/>.
/// Index is the ordinal reference (zero based) of the point.
/// </summary>
public PointPair this[int index]
{
get
{
if ( _points == null )
return new PointPair( PointPair.Missing, PointPair.Missing );
else
return ( _points )[index];
}
}
/// <summary>
/// Gets or sets the hyperlink information for this <see cref="CurveItem" />.
/// </summary>
// /// <seealso cref="ZedGraph.Web.IsImageMap" />
public Link Link
{
get { return _link; }
set { _link = value; }
}
#endregion
#region Rendering Methods
/// <summary>
/// Do all rendering associated with this <see cref="CurveItem"/> to the specified
/// <see cref="Graphics"/> device. This method is normally only
/// called by the Draw method of the parent <see cref="ZedGraph.CurveList"/>
/// collection 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="ZedGraph.GraphPane"/> object that is the parent or
/// owner of this object.
/// </param>
/// <param name="pos">The ordinal position of the current <see cref="Bar"/>
/// curve.</param>
/// <param name="scaleFactor">
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent <see cref="ZedGraph.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>
abstract public void Draw( Graphics g, GraphPane pane, int pos, float scaleFactor );
/// <summary>
/// Draw a legend key entry for this <see cref="CurveItem"/> at the specified location.
/// This abstract base method passes through to <see cref="BarItem.DrawLegendKey"/> or
/// <see cref="LineItem.DrawLegendKey"/> to do the rendering.
/// </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="ZedGraph.GraphPane"/> object that is the parent or
/// owner of this object.
/// </param>
/// <param name="rect">The <see cref="RectangleF"/> struct that specifies the
/// location for the legend key</param>
/// <param name="scaleFactor">
/// The scaling factor to be used for rendering objects. This is calculated and
/// passed down by the parent <see cref="ZedGraph.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>
abstract public void DrawLegendKey( Graphics g, GraphPane pane, RectangleF rect, float scaleFactor );
#endregion
#region Utility Methods
/// <summary>
/// Add a single x,y coordinate point to the end of the points collection for this curve.
/// </summary>
/// <param name="x">The X coordinate value</param>
/// <param name="y">The Y coordinate value</param>
public void AddPoint( double x, double y )
{
this.AddPoint( new PointPair( x, y ) );
}
/// <summary>
/// Add a <see cref="PointPair"/> object to the end of the points collection for this curve.
/// </summary>
/// <remarks>
/// This method will only work if the <see cref="IPointList" /> instance reference
/// at <see cref="Points" /> supports the <see cref="IPointListEdit" /> interface.
/// Otherwise, it does nothing.
/// </remarks>
/// <param name="point">A reference to the <see cref="PointPair"/> object to
/// be added</param>
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();
}
/// <summary>
/// Clears the points from this <see cref="CurveItem"/>. This is the same
/// as <c>CurveItem.Points.Clear()</c>.
/// </summary>
/// <remarks>
/// This method will only work if the <see cref="IPointList" /> instance reference
/// at <see cref="Points" /> supports the <see cref="IPointListEdit" /> interface.
/// Otherwise, it does nothing.
/// </remarks>
public void Clear()
{
if ( _points is IPointListEdit )
(_points as IPointListEdit).Clear();
else
throw new NotImplementedException();
}
/// <summary>
/// Removes a single point from this <see cref="CurveItem" />.
/// </summary>
/// <remarks>
/// This method will only work if the <see cref="IPointList" /> instance reference
/// at <see cref="Points" /> supports the <see cref="IPointListEdit" /> interface.
/// Otherwise, it does nothing.
/// </remarks>
/// <param name="index">The ordinal position of the point to be removed.</param>
public void RemovePoint( int index )
{
if ( _points is IPointListEdit )
(_points as IPointListEdit).RemoveAt( index );
else
throw new NotImplementedException();
}
/// <summary>
/// Get the Y Axis instance (either <see cref="YAxis" /> or <see cref="Y2Axis" />) to
/// which this <see cref="CurveItem" /> belongs.
/// </summary>
/// <remarks>
/// This method safely retrieves a Y Axis instance from either the <see cref="GraphPane.YAxisList" />
/// or the <see cref="GraphPane.Y2AxisList" /> using the values of <see cref="YAxisIndex" /> and
/// <see cref="IsY2Axis" />. If the value of <see cref="YAxisIndex" /> is out of bounds, the
/// default <see cref="YAxis" /> or <see cref="Y2Axis" /> is used.
/// </remarks>
/// <param name="pane">The <see cref="GraphPane" /> object to which this curve belongs.</param>
/// <returns>Either a <see cref="YAxis" /> or <see cref="Y2Axis" /> to which this
/// <see cref="CurveItem" /> belongs.
/// </returns>
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];
}
}
/// <summary>
/// Get the index of the Y Axis in the <see cref="YAxis" /> or <see cref="Y2Axis" /> list to
/// which this <see cref="CurveItem" /> belongs.
/// </summary>
/// <remarks>
/// This method safely retrieves a Y Axis index into either the <see cref="GraphPane.YAxisList" />
/// or the <see cref="GraphPane.Y2AxisList" /> using the values of <see cref="YAxisIndex" /> and
/// <see cref="IsY2Axis" />. If the value of <see cref="YAxisIndex" /> is out of bounds, the
/// default <see cref="YAxis" /> or <see cref="Y2Axis" /> is used, which is index zero.
/// </remarks>
/// <param name="pane">The <see cref="GraphPane" /> object to which this curve belongs.</param>
/// <returns>An integer value indicating which index position in the list applies to this
/// <see cref="CurveItem" />
/// </returns>
public int GetYAxisIndex( GraphPane pane )
{
if ( _yAxisIndex >= 0 &&
_yAxisIndex < ( _isY2Axis ? pane.Y2AxisList.Count : pane.YAxisList.Count ) )
return _yAxisIndex;
else
return 0;
}
/// <summary>
/// Loads some pseudo unique colors/symbols into this CurveItem. This
/// is the same as <c>MakeUnique(ColorSymbolRotator.StaticInstance)</c>.
/// <seealso cref="ColorSymbolRotator.StaticInstance"/>
/// <seealso cref="ColorSymbolRotator"/>
/// <seealso cref="MakeUnique(ColorSymbolRotator)"/>
/// </summary>
public void MakeUnique()
{
this.MakeUnique( ColorSymbolRotator.StaticInstance );
}
/// <summary>
/// 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.
/// <seealso cref="MakeUnique(ColorSymbolRotator)"/>
/// </summary>
/// <param name="rotator">
/// The <see cref="ColorSymbolRotator"/> that is used to pick the color
/// and symbol for this method call.
/// </param>
virtual public void MakeUnique( ColorSymbolRotator rotator )
{
this.Color = rotator.NextColor;
}
/// <summary>
/// Go through the list of <see cref="PointPair"/> data values for this <see cref="CurveItem"/>
/// and determine the minimum and maximum values in the data.
/// </summary>
/// <param name="xMin">The minimum X value in the range of data</param>
/// <param name="xMax">The maximum X value in the range of data</param>
/// <param name="yMin">The minimum Y value in the range of data</param>
/// <param name="yMax">The maximum Y value in the range of data</param>
/// <param name="ignoreInitial">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"/>
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 );
if ( yAxis == null )
return;
if ( isBoundedRanges )
{
xLBound = pane.XAxis._scale._lBound;
xUBound = pane.XAxis._scale._uBound;
yLBound = yAxis._scale._lBound;
yUBound = yAxis._scale._uBound;
}
bool isZIncluded = this.IsZIncluded( pane );
bool isXIndependent = this.IsXIndependent( pane );
bool isXLog = pane.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<this.Points.Count; i++ )
{
PointPair point = this.Points[i];
double curX = point.X;
double curY = point.Y;
double curZ = point.Z;
bool outOfBounds = curX < xLBound || curX > 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;
}
}
}
}
/// <summary>Returns a reference to the <see cref="Axis"/> object that is the "base"
/// (independent axis) from which the values are drawn. </summary>
/// <remarks>
/// This property is determined by the value of <see cref="BarSettings.Base"/> for
/// <see cref="BarItem"/>, <see cref="ErrorBarItem"/>, and <see cref="HiLowBarItem"/>
/// types. It is always the X axis for regular <see cref="LineItem"/> types.
/// Note that the <see cref="BarSettings.Base" /> setting can override the
/// <see cref="IsY2Axis" /> and <see cref="YAxisIndex" /> settings for bar types
/// (this is because all the bars that are clustered together must share the
/// same base axis).
/// </remarks>
/// <seealso cref="BarBase"/>
/// <seealso cref="ValueAxis"/>
public virtual Axis BaseAxis( 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 )
return pane.XAxis;
else if ( barBase == BarBase.Y )
return pane.YAxis;
else
return pane.Y2Axis;
}
/// <summary>Returns a reference to the <see cref="Axis"/> object that is the "value"
/// (dependent axis) from which the points are drawn. </summary>
/// <remarks>
/// This property is determined by the value of <see cref="BarSettings.Base"/> for
/// <see cref="BarItem"/>, <see cref="ErrorBarItem"/>, and <see cref="HiLowBarItem"/>
/// types. It is always the Y axis for regular <see cref="LineItem"/> types.
/// </remarks>
/// <seealso cref="BarBase"/>
/// <seealso cref="BaseAxis"/>
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 )
{
return GetYAxis( pane );
//if ( isY2Axis )
// return pane.Y2Axis;
//else
// return pane.YAxis;
}
else
return pane.XAxis;
}
/// <summary>
/// Calculate the width of each bar, depending on the actual bar type
/// </summary>
/// <returns>The width for an individual bar, in pixel units</returns>
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;
}
/// <summary>
/// Determine the coords for the rectangle associated with a specified point for
/// this <see cref="CurveItem" />
/// </summary>
/// <param name="pane">The <see cref="GraphPane" /> to which this curve belongs</param>
/// <param name="i">The index of the point of interest</param>
/// <param name="coords">A list of coordinates that represents the "rect" for
/// this point (used in an html AREA tag)</param>
/// <returns>true if it's a valid point, false otherwise</returns>
abstract public bool GetCoords( GraphPane pane, int i, out string coords );
#endregion
#region Inner classes
#if ( DOTNET1 ) // Is this a .Net 1.1 compilation?
/// <summary>
/// Compares <see cref="CurveItem"/>'s based on the point value at the specified
/// index and for the specified axis.
/// <seealso cref="System.Collections.ArrayList.Sort()"/>
/// </summary>
public class Comparer : IComparer
{
private int index;
private SortType sortType;
/// <summary>
/// Constructor for Comparer.
/// </summary>
/// <param name="type">The axis type on which to sort.</param>
/// <param name="index">The index number of the point on which to sort</param>
public Comparer( SortType type, int index )
{
this.sortType = type;
this.index = index;
}
/// <summary>
/// Compares two <see cref="CurveItem"/>s using the previously specified index value
/// and axis. Sorts in descending order.
/// </summary>
/// <param name="l">Curve to the left.</param>
/// <param name="r">Curve to the right.</param>
/// <returns>-1, 0, or 1 depending on l.X's relation to r.X</returns>
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 = System.Math.Abs( cl[index].X );
rVal = System.Math.Abs( cr[index].X );
}
else
{
lVal = System.Math.Abs( cl[index].Y );
rVal = System.Math.Abs( cr[index].Y );
}
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
/// <summary>
/// Compares <see cref="CurveItem"/>'s based on the point value at the specified
/// index and for the specified axis.
/// <seealso cref="System.Collections.ArrayList.Sort()"/>
/// </summary>
public class Comparer : IComparer<CurveItem>
{
private int index;
private SortType sortType;
/// <summary>
/// Constructor for Comparer.
/// </summary>
/// <param name="type">The axis type on which to sort.</param>
/// <param name="index">The index number of the point on which to sort</param>
public Comparer( SortType type, int index )
{
this.sortType = type;
this.index = index;
}
/// <summary>
/// Compares two <see cref="CurveItem"/>s using the previously specified index value
/// and axis. Sorts in descending order.
/// </summary>
/// <param name="l">Curve to the left.</param>
/// <param name="r">Curve to the right.</param>
/// <returns>-1, 0, or 1 depending on l.X's relation to r.X</returns>
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 = System.Math.Abs( l[index].X );
rVal = System.Math.Abs( r[index].X );
}
else
{
lVal = System.Math.Abs( l[index].Y );
rVal = System.Math.Abs( r[index].Y );
}
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
}
}