//============================================================================ //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.Drawing.Drawing2D; using System.Collections; using System.Runtime.Serialization; using System.Security.Permissions; namespace DrawGraph { /// /// A class representing all the characteristics of the bar /// segments that make up a curve on the graph. /// /// /// John Champion /// $Revision: 3.28 $ $Date: 2007/01/25 07:56:08 $ [Serializable] public class Bar : ICloneable, ISerializable { #region Fields /// /// Private field that stores the data for this /// . Use the public property to /// access this value. /// private Fill _fill; /// /// Private field that stores the class that defines the /// properties of the border around this . Use the public /// property to access this value. /// private Border _border; #endregion #region Defaults /// /// A simple struct that defines the /// default property values for the class. /// public struct Default { // Default Bar properties /// /// The default pen width to be used for drawing the border around the bars /// ( property). Units are points. /// public static float BorderWidth = 1.0F; /// /// The default fill mode for bars ( property). /// public static FillType FillType = FillType.Brush; /// /// The default border mode for bars ( property). /// true to display frames around bars, false otherwise /// public static bool IsBorderVisible = true; /// /// The default color for drawing frames around bars /// ( property). /// public static Color BorderColor = Color.Black; /// /// The default color for filling in the bars /// ( property). /// public static Color FillColor = Color.Red; /// /// The default custom brush for filling in the bars /// ( property). /// public static Brush FillBrush = null; //new LinearGradientBrush( new Rectangle(0,0,100,100), // Color.White, Color.Red, 0F ); } #endregion #region Constructors /// /// Default constructor that sets all properties to default /// values as defined in the class. /// public Bar() : this( Color.Empty ) { } /// /// Default constructor that sets the /// as specified, and the remaining /// properties to default /// values as defined in the class. /// The specified color is only applied to the /// , and the /// will be defaulted. /// /// A value indicating /// the /// of the Bar. /// public Bar( Color color ) { _border = new Border( Default.IsBorderVisible, Default.BorderColor, Default.BorderWidth ); _fill = new Fill( color.IsEmpty ? Default.FillColor : color, Default.FillBrush, Default.FillType ); } /// /// The Copy Constructor /// /// The Bar object from which to copy public Bar( Bar rhs ) { _border = (Border) rhs.Border.Clone(); _fill = (Fill) rhs.Fill.Clone(); } /// /// Implement the interface in a typesafe manner by just /// calling the typed version of /// /// A deep copy of this object object ICloneable.Clone() { return this.Clone(); } /// /// Typesafe, deep-copy clone method. /// /// A new, independent copy of this class public Bar Clone() { return new Bar( this ); } #endregion #region Serialization /// /// Current schema value that defines the version of the serialized file /// public const int schema = 10; /// /// Constructor for deserializing objects /// /// A instance that defines the serialized data /// /// A instance that contains the serialized data /// protected Bar( 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" ); _fill = (Fill) info.GetValue( "fill", typeof(Fill) ); _border = (Border) info.GetValue( "border", typeof(Border) ); } /// /// 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( "fill", _fill ); info.AddValue( "border", _border ); } #endregion #region Properties /// /// The object used to draw the border around the . /// /// /// /// public Border Border { get { return _border; } set { _border = value; } } /// /// Gets or sets the data for this /// . /// public Fill Fill { get { return _fill; } set { _fill = value; } } #endregion #region Rendering Methods /// /// Draw the to the specified device /// at the specified location. This routine draws a single bar. /// /// /// 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 x position of the left side of the bar in /// pixel units /// The x position of the right side of the bar in /// pixel units /// The y position of the top of the bar in /// pixel units /// The y position of the bottom of the bar in /// pixel units /// /// The scaling factor for the features of the graph based on the . This /// scaling factor is calculated by the method. The scale factor /// represents a linear multiple to be applied to font sizes, symbol sizes, etc. /// /// true to draw the bottom portion of the border around the /// bar (this is for legend entries) /// The data value to be used for a value-based /// color gradient. This is only applicable for , /// or . /// Indicates that the should be drawn /// with attributes from the class. /// public void Draw( Graphics g, GraphPane pane, float left, float right, float top, float bottom, float scaleFactor, bool fullFrame, bool isSelected, PointPair dataValue ) { // Do a sanity check to make sure the top < bottom. If not, reverse them if ( top > bottom ) { float junk = top; top = bottom; bottom = junk; } // Do a sanity check to make sure the left < right. If not, reverse them if ( left > right ) { float junk = right; right = left; left = junk; } if ( top < -10000 ) top = -10000; else if ( top > 10000 ) top = 10000; if ( left < -10000 ) left = -10000; else if ( left > 10000 ) left = 10000; if ( right < -10000 ) right = -10000; else if ( right > 10000 ) right = 10000; if ( bottom < -10000 ) bottom = -10000; else if ( bottom > 10000 ) bottom = 10000; // Make a rectangle for the bar and draw it RectangleF rect = new RectangleF( left, top, right - left, bottom - top ); Draw( g, pane, rect, scaleFactor, fullFrame, isSelected, dataValue ); } /// /// Draw the to the specified device /// at the specified location. This routine draws a single bar. /// /// /// 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 rectangle (pixels) to contain the bar /// /// The scaling factor for the features of the graph based on the . This /// scaling factor is calculated by the method. The scale factor /// represents a linear multiple to be applied to font sizes, symbol sizes, etc. /// /// true to draw the bottom portion of the border around the /// bar (this is for legend entries) /// The data value to be used for a value-based /// color gradient. This is only applicable for , /// or . /// Indicates that the should be drawn /// with attributes from the class. /// public void Draw( Graphics g, GraphPane pane, RectangleF rect, float scaleFactor, bool fullFrame, bool isSelected, PointPair dataValue ) { if ( isSelected ) { Selection.Fill.Draw( g, rect, dataValue ); Selection.Border.Draw( g, pane, scaleFactor, rect ); } else { _fill.Draw( g, rect, dataValue ); _border.Draw( g, pane, scaleFactor, rect ); } } /// /// Draw the this to the specified /// device as a bar at each defined point. This method /// is normally only called by the method of the /// 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. /// /// A object representing the /// 's to be drawn. /// The class instance that defines the base (independent) /// axis for the /// The class instance that defines the value (dependent) /// axis for the /// /// The width of each bar, in pixels. /// /// /// The ordinal position of the this bar series (0=first bar, 1=second bar, etc.) /// in the cluster of bars. /// /// /// 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. /// public void DrawBars( Graphics g, GraphPane pane, CurveItem curve, Axis baseAxis, Axis valueAxis, float barWidth, int pos, float scaleFactor ) { // For Overlay and Stack bars, the position is always zero since the bars are on top // of eachother if ( pane._barSettings.Type == BarType.Overlay || pane._barSettings.Type == BarType.Stack || pane._barSettings.Type == BarType.PercentStack ) pos = 0; // Loop over each defined point and draw the corresponding bar for ( int i=0; i /// Draw the specified single bar (an individual "point") of this series to the specified /// device. This method is not as efficient as /// , which draws the bars for all points. It is intended to be used /// only for , which requires special handling of each bar. /// /// /// 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. /// /// A object representing the /// 's to be drawn. /// The class instance that defines the base (independent) /// axis for the /// The class instance that defines the value (dependent) /// axis for the /// /// The ordinal position of the this bar series (0=first bar, 1=second bar, etc.) /// in the cluster of bars. /// /// /// The zero-based index number for the single bar to be drawn. /// /// /// The width of each bar, in pixels. /// /// /// 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. /// public void DrawSingleBar( Graphics g, GraphPane pane, CurveItem curve, Axis baseAxis, Axis valueAxis, int pos, int index, float barWidth, float scaleFactor ) { // Make sure that a bar value exists for the current curve and current ordinal position if ( index >= curve.Points.Count ) return; // For Overlay and Stack bars, the position is always zero since the bars are on top // of eachother if ( pane._barSettings.Type == BarType.Overlay || pane._barSettings.Type == BarType.Stack || pane._barSettings.Type == BarType.PercentStack ) pos = 0; // Draw the specified bar DrawSingleBar( g, pane, curve, index, pos, baseAxis, valueAxis, barWidth, scaleFactor ); } /// /// Protected internal routine that draws the specified single bar (an individual "point") /// of this series to the specified device. /// /// /// 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. /// /// A object representing the /// 's to be drawn. /// /// The zero-based index number for the single bar to be drawn. /// /// /// The ordinal position of the this bar series (0=first bar, 1=second bar, etc.) /// in the cluster of bars. /// /// The class instance that defines the base (independent) /// axis for the /// The class instance that defines the value (dependent) /// axis for the /// /// The width of each bar, in pixels. /// /// /// 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. /// virtual protected void DrawSingleBar( Graphics g, GraphPane pane, CurveItem curve, int index, int pos, Axis baseAxis, Axis valueAxis, float barWidth, float scaleFactor ) { // pixBase = pixel value for the bar center on the base axis // pixHiVal = pixel value for the bar top on the value axis // pixLowVal = pixel value for the bar bottom on the value axis float pixBase, pixHiVal, pixLowVal; float clusterWidth = pane.BarSettings.GetClusterWidth(); //float barWidth = curve.GetBarWidth( pane ); float clusterGap = pane._barSettings.MinClusterGap * barWidth; float barGap = barWidth * pane._barSettings.MinBarGap; // curBase = the scale value on the base axis of the current bar // curHiVal = the scale value on the value axis of the current bar // curLowVal = the scale value of the bottom of the bar double curBase, curLowVal, curHiVal; ValueHandler valueHandler = new ValueHandler( pane, false ); valueHandler.GetValues( curve, index, out curBase, out curLowVal, out curHiVal ); // Any value set to double max is invalid and should be skipped // This is used for calculated values that are out of range, divide // by zero, etc. // Also, any value <= zero on a log scale is invalid if ( !curve.Points[index].IsInvalid ) { // calculate a pixel value for the top of the bar on value axis pixLowVal = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, index, curLowVal ); pixHiVal = valueAxis.Scale.Transform( curve.IsOverrideOrdinal, index, curHiVal ); // calculate a pixel value for the center of the bar on the base axis pixBase = baseAxis.Scale.Transform( curve.IsOverrideOrdinal, index, curBase ); // Calculate the pixel location for the side of the bar (on the base axis) float pixSide = pixBase - clusterWidth / 2.0F + clusterGap / 2.0F + pos * ( barWidth + barGap ); // Draw the bar if ( pane._barSettings.Base == BarBase.X ) this.Draw( g, pane, pixSide, pixSide + barWidth, pixLowVal, pixHiVal, scaleFactor, true, curve.IsSelected, curve.Points[index] ); else this.Draw( g, pane, pixLowVal, pixHiVal, pixSide, pixSide + barWidth, scaleFactor, true, curve.IsSelected, curve.Points[index] ); } } #endregion } }