//============================================================================
//ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C#
//Copyright ?2006 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.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace DrawGraph
{
///
/// Class that handles the global settings for bar charts
///
///
/// John Champion
/// $Revision: 3.4 $ $Date: 2007/06/02 06:56:03 $
[Serializable]
public class BarSettings : ISerializable
{
#region Fields
/// Private field that determines the size of the gap between bar clusters
/// for bar charts. This gap is expressed as a fraction of the bar size (1.0 means
/// leave a 1-barwidth gap between clusters).
/// Use the public property to access this value.
private float _minClusterGap;
/// Private field that determines the size of the gap between individual bars
/// within a bar cluster for bar charts. This gap is expressed as a fraction of the
/// bar size (1.0 means leave a 1-barwidth gap between each bar).
/// Use the public property to access this value.
private float _minBarGap;
/// Private field that determines the base axis from which
/// graphs will be displayed. The base axis is the axis from which the bars grow with
/// increasing value. The value is of the enumeration type .
/// To access this value, use the public property .
///
///
private BarBase _base;
/// Private field that determines how the
/// graphs will be displayed. See the enum
/// for the individual types available.
/// To access this value, use the public property .
///
///
private BarType _type;
/// Private field that determines the width of a bar cluster (for bar charts)
/// in user scale units. Normally, this value is 1.0 because bar charts are typically
/// or , and the bars are
/// defined at ordinal values (1.0 scale units apart). For
/// or other scale types, you can use this value to scale the bars to an arbitrary
/// user scale. Use the public property to access this
/// value.
internal double _clusterScaleWidth;
///
/// Private field that determines if the will be
/// calculated automatically. Use the public property
/// to access this value.
///
internal bool _clusterScaleWidthAuto;
///
/// private field that stores the owner GraphPane that contains this BarSettings instance.
///
internal GraphPane _ownerPane;
#endregion
#region Constructors
///
/// Constructor to build a instance from the defaults.
///
public BarSettings( GraphPane parentPane )
{
_minClusterGap = Default.MinClusterGap;
_minBarGap = Default.MinBarGap;
_clusterScaleWidth = Default.ClusterScaleWidth;
_clusterScaleWidthAuto = Default.ClusterScaleWidthAuto;
_base = Default.Base;
_type = Default.Type;
_ownerPane = parentPane;
}
///
/// Copy constructor
///
/// the instance to be copied.
/// The that will be the
/// parent of this new BarSettings object.
public BarSettings( BarSettings rhs, GraphPane parentPane )
{
_minClusterGap = rhs._minClusterGap;
_minBarGap = rhs._minBarGap;
_clusterScaleWidth = rhs._clusterScaleWidth;
_clusterScaleWidthAuto = rhs._clusterScaleWidthAuto;
_base = rhs._base;
_type = rhs._type;
_ownerPane = parentPane;
}
#endregion
#region Bar Properties
///
/// The minimum space between clusters, expressed as a
/// fraction of the bar size.
///
///
///
///
public float MinClusterGap
{
get { return _minClusterGap; }
set { _minClusterGap = value; }
}
///
/// The minimum space between individual Bars
/// within a cluster, expressed as a
/// fraction of the bar size.
///
///
///
///
public float MinBarGap
{
get { return _minBarGap; }
set { _minBarGap = value; }
}
/// Determines the base axis from which
/// graphs will be displayed.
///
/// The base axis is the axis from which the bars grow with
/// increasing value. The value is of the enumeration type .
///
///
public BarBase Base
{
get { return _base; }
set { _base = value; }
}
/// Determines how the
/// graphs will be displayed. See the enum
/// for the individual types available.
///
///
public BarType Type
{
get { return _type; }
set { _type = value; }
}
///
/// The width of an individual bar cluster on a graph.
/// This value only applies to bar graphs plotted on non-ordinal X axis
/// types (, , and
/// .
///
///
/// This value can be calculated automatically if
/// is set to true. In this case, ClusterScaleWidth will be calculated if
/// refers to an of a non-ordinal type
/// ( is false). The ClusterScaleWidth is calculated
/// from the minimum difference found between any two points on the
/// for any in the
/// . The ClusterScaleWidth is set automatically
/// each time is called. Calculations are
/// done by the method.
///
///
///
///
///
public double ClusterScaleWidth
{
get { return _clusterScaleWidth; }
set { _clusterScaleWidth = value; _clusterScaleWidthAuto = false; }
}
///
/// Gets or sets a property that determines if the will be
/// calculated automatically.
///
/// true for the to be calculated
/// automatically based on the available data, false otherwise. This value will
/// be set to false automatically if the value
/// is changed by the user.
///
///
///
public bool ClusterScaleWidthAuto
{
get { return _clusterScaleWidthAuto; }
set { _clusterScaleWidthAuto = value; }
}
#endregion
#region Serialization
///
/// Current schema value that defines the version of the serialized file
///
public const int schema = 10;
///
/// Constructor for deserializing objects
///
///
/// You MUST set the _ownerPane property after deserializing a BarSettings object.
///
/// A instance that defines the
/// serialized data
///
/// A instance that contains
/// the serialized data
///
internal BarSettings( 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" );
_minClusterGap = info.GetSingle( "minClusterGap" );
_minBarGap = info.GetSingle( "minBarGap" );
_clusterScaleWidth = info.GetDouble( "clusterScaleWidth" );
_clusterScaleWidthAuto = info.GetBoolean( "clusterScaleWidthAuto" );
_base = (BarBase)info.GetValue( "base", typeof( BarBase ) );
_type = (BarType)info.GetValue( "type", typeof( BarType ) );
}
///
/// 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( "minClusterGap", _minClusterGap );
info.AddValue( "minBarGap", _minBarGap );
info.AddValue( "clusterScaleWidth", _clusterScaleWidth );
info.AddValue( "clusterScaleWidthAuto", _clusterScaleWidthAuto );
info.AddValue( "base", _base );
info.AddValue( "type", _type );
}
#endregion
#region Methods
///
/// Calculate the width of an individual bar cluster on a graph.
/// This value only applies to bar graphs plotted on non-ordinal X axis
/// types ( is false).
///
///
/// This value can be calculated automatically if
/// is set to true. In this case, ClusterScaleWidth will be calculated if
/// refers to an of a non-ordinal type
/// ( is false). The ClusterScaleWidth is calculated
/// from the minimum difference found between any two points on the
/// for any in the
/// . The ClusterScaleWidth is set automatically
/// each time is called.
///
///
///
///
///
public void CalcClusterScaleWidth()
{
Axis baseAxis = BarBaseAxis();
// First, calculate the clusterScaleWidth for BarItem objects
if ( _clusterScaleWidthAuto && !baseAxis.Scale.IsAnyOrdinal )
{
double minStep = Double.MaxValue;
foreach ( CurveItem curve in _ownerPane.CurveList )
{
IPointList list = curve.Points;
if ( curve is BarItem )
{
double step = GetMinStepSize( curve.Points, baseAxis );
minStep = step < minStep ? step : minStep;
}
}
if ( minStep == Double.MaxValue )
minStep = 1.0;
_clusterScaleWidth = minStep;
}
// Second, calculate the sizes of any HiLowBarItem and JapaneseCandleStickItem objects
foreach ( CurveItem curve in _ownerPane.CurveList )
{
IPointList list = curve.Points;
if ( curve is HiLowBarItem &&
(curve as HiLowBarItem).Bar.IsAutoSize )
{
( curve as HiLowBarItem ).Bar._userScaleSize =
GetMinStepSize( list, baseAxis );
}
else if ( curve is JapaneseCandleStickItem &&
(curve as JapaneseCandleStickItem).Stick.IsAutoSize )
{
( curve as JapaneseCandleStickItem ).Stick._userScaleSize =
GetMinStepSize( list, baseAxis );
}
}
}
///
/// Determine the minimum increment between individual points to be used for
/// calculating a bar size that fits without overlapping
///
/// The list of points for the bar
/// of interest
/// The base axis for the bar
/// The minimum increment between bars along the base axis
internal static double GetMinStepSize( IPointList list, Axis baseAxis )
{
double minStep = Double.MaxValue;
if ( list.Count <= 0 || baseAxis._scale.IsAnyOrdinal )
return 1.0;
PointPair lastPt = list[0];
for ( int i = 1; i < list.Count; i++ )
{
PointPair pt = list[i];
if ( !pt.IsInvalid || !lastPt.IsInvalid )
{
double step;
if ( baseAxis is XAxis || baseAxis is X2Axis )
step = pt.X - lastPt.X;
else
step = pt.Y - lastPt.Y;
if ( step > 0 && step < minStep )
minStep = step;
}
lastPt = pt;
}
double range = baseAxis.Scale._maxLinearized - baseAxis.Scale._minLinearized;
if ( range <= 0 )
minStep = 1.0;
else if ( minStep <= 0 || minStep < 0.001 * range || minStep > range )
minStep = 0.1 * range;
return minStep;
}
///
/// Determine the width, in screen pixel units, of each bar cluster including
/// the cluster gaps and bar gaps.
///
/// This method calls the
/// method for the base for graphs
/// (the base is assigned by the
/// property).
///
///
///
///
///
/// The width of each bar cluster, in pixel units
public float GetClusterWidth()
{
return BarBaseAxis()._scale.GetClusterWidth( _ownerPane );
}
///
/// Determine the from which the charts are based.
///
///
///
///
///
/// The class for the axis from which the bars are based
public Axis BarBaseAxis()
{
Axis barAxis;
if ( _base == BarBase.Y )
barAxis = _ownerPane.YAxis;
else if ( _base == BarBase.Y2 )
barAxis = _ownerPane.Y2Axis;
else if ( _base == BarBase.X2 )
barAxis = _ownerPane.X2Axis;
else
barAxis = _ownerPane.XAxis;
return barAxis;
}
#endregion
#region Defaults
///
/// A simple struct that defines the
/// default property values for the class.
///
public struct Default
{
///
/// The default dimension gap between clusters of bars on a
/// graph.
/// This dimension is expressed in terms of the normal bar width.
///
///
///
public static float MinClusterGap = 1.0F;
///
/// The default dimension gap between each individual bar within a bar cluster
/// on a graph.
/// This dimension is expressed in terms of the normal bar width.
///
///
///
public static float MinBarGap = 0.2F;
/// The default value for the , which determines the base
/// from which the graphs will be displayed.
///
///
public static BarBase Base = BarBase.X;
/// The default value for the property, which
/// determines if the bars are drawn overlapping eachother in a "stacked" format,
/// or side-by-side in a "cluster" format. See the
/// for more information.
///
///
public static BarType Type = BarType.Cluster;
///
/// The default width of a bar cluster
/// on a graph. This value only applies to
/// graphs, and only when the
/// is ,
/// or .
/// This dimension is expressed in terms of X scale user units.
///
///
///
public static double ClusterScaleWidth = 1.0;
///
/// The default value for .
///
public static bool ClusterScaleWidthAuto = true;
}
#endregion
}
}