Click here to Skip to main content
15,892,005 members
Articles / Multimedia / GDI+

A flexible charting library for .NET

Rate me:
Please Sign up or sign in to vote.
4.70/5 (1,112 votes)
6 Jun 200730 min read 9M   180.2K   2.1K  
Looking for a way to draw 2D line graphs with C#? Here's yet another charting class library with a high degree of configurability, that is also easy to use.
//============================================================================
//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.Drawing.Imaging;
using System.Runtime.Serialization;
using System.Security.Permissions;

namespace ZedGraph
{
	/// <summary>
	/// A class that encapsulates color-fill properties for an object.  The <see cref="Fill"/> class
	/// is used in <see cref="PaneBase.Rect"/>, <see cref="Chart.Rect"/>, <see cref="Legend"/>,
	/// <see cref="Bar"/>, and <see cref="Line"/> objects.
	/// </summary>
	/// 
	/// <author> John Champion </author>
	/// <version> $Revision: 3.22 $ $Date: 2007/01/26 09:01:49 $ </version>
	[Serializable]
	public class Fill : ISerializable, ICloneable
	{
	#region Fields

		/// <summary>
		/// Private field that stores the fill color.  Use the public
		/// property <see cref="Color"/> to access this value.  This property is
		/// only applicable if the <see cref="Type"/> is not <see cref="ZedGraph.FillType.None"/>.
		/// </summary>
		private Color _color;
		/// <summary>
		/// Private field that stores the secondary color for gradientByValue fills.  Use the public
		/// property <see cref="SecondaryValueGradientColor"/> to access this value.  This property is
		/// only applicable if the <see cref="Type"/> is <see cref="ZedGraph.FillType.GradientByX"/>,
		/// <see cref="ZedGraph.FillType.GradientByY"/>, or <see cref="ZedGraph.FillType.GradientByZ"/>.
		/// </summary>
		private Color _secondaryValueGradientColor;
		/// <summary>
		/// Private field that stores the custom fill brush.  Use the public
		/// property <see cref="Brush"/> to access this value.  This property is
		/// only applicable if the 
		/// <see cref="Type"/> property is set to <see cref="ZedGraph.FillType.Brush"/>.
		/// </summary>
		protected Brush	_brush;
		/// <summary>
		/// Private field that determines the type of color fill.  Use the public
		/// property <see cref="Type"/> to access this value.  The fill color
		/// is determined by the property <see cref="Color"/> or
		/// <see cref="Brush"/>.
		/// </summary>
		private FillType	_type;
		/// <summary>
		/// Private field that determines if the brush will be scaled to the bounding box
		/// of the filled object.  If this value is false, then the brush will only be aligned
		/// with the filled object based on the <see cref="AlignH"/> and <see cref="AlignV"/>
		/// properties.
		/// </summary>
		private bool		_isScaled;
		/// <summary>
		/// Private field that determines how the brush will be aligned with the filled object
		/// in the horizontal direction.  This value is a <see cref="ZedGraph.AlignH"/> enumeration.
		/// This field only applies if <see cref="IsScaled"/> is false.
		/// properties.
		/// </summary>
		/// <seealso cref="AlignH"/>
		/// <seealso cref="AlignV"/>
		private AlignH		_alignH;
		/// <summary>
		/// Private field that determines how the brush will be aligned with the filled object
		/// in the vertical direction.  This value is a <see cref="ZedGraph.AlignV"/> enumeration.
		/// This field only applies if <see cref="IsScaled"/> is false.
		/// properties.
		/// </summary>
		/// <seealso cref="AlignH"/>
		/// <seealso cref="AlignV"/>
		private AlignV		_alignV;

		private double	_rangeMin;
		private double	_rangeMax;
		private double _rangeDefault;
		private Bitmap	_gradientBM;

		/// <summary>
		/// Private field that saves the image passed to the constructor.
		/// This is used strictly for serialization.
		/// </summary>
		private Image	_image;
		/// <summary>
		/// Private field that saves the image wrapmode passed to the constructor.
		/// This is used strictly for serialization.
		/// </summary>
		private WrapMode _wrapMode;
		/// <summary>
		/// Private field that saves the list of colors used to create the
		/// <see cref="LinearGradientBrush"/> in the constructor.  This is used strictly
		/// for serialization.
		/// </summary>
		private Color[] _colorList;
		/// <summary>
		/// Private field that saves the list of positions used to create the
		/// <see cref="LinearGradientBrush"/> in the constructor.  This is used strictly
		/// for serialization.
		/// </summary>
		private float[] _positionList;
		/// <summary>
		/// Private field the saves the angle of the fill.  This is used strictly for serialization.
		/// </summary>
		private float _angle;


	#endregion

	#region Defaults
		/// <summary>
		/// A simple struct that defines the
		/// default property values for the <see cref="Fill"/> class.
		/// </summary>
		public struct Default
		{
			// Default Fill properties
			/// <summary>
			/// The default scaling mode for <see cref="Brush"/> fills.
			/// This is the default value for the <see cref="Fill.IsScaled"/> property.
			/// </summary>
			public static bool IsScaled = true;
			/// <summary>
			/// The default horizontal alignment for <see cref="Brush"/> fills.
			/// This is the default value for the <see cref="Fill.AlignH"/> property.
			/// </summary>
			public static AlignH AlignH = AlignH.Center;
			/// <summary>
			/// The default vertical alignment for <see cref="Brush"/> fills.
			/// This is the default value for the <see cref="Fill.AlignV"/> property.
			/// </summary>
			public static AlignV AlignV = AlignV.Center;
		}
	#endregion
	
	#region Constructors
		/// <summary>
		/// Generic initializer to default values
		/// </summary>
		private void Init()
		{
			_color = Color.White;
			_secondaryValueGradientColor = Color.White;
			_brush = null;
			_type = FillType.None;
			_isScaled = Default.IsScaled;
			_alignH = Default.AlignH;
			_alignV = Default.AlignV;
			_rangeMin = 0.0;
			_rangeMax = 1.0;
			_rangeDefault = double.MaxValue;
			_gradientBM = null;

			_colorList = null;
			_positionList = null;
			_angle = 0;
			_image = null;
			_wrapMode = WrapMode.Tile;

		}

		/// <summary>
		/// The default constructor.  Initialized to no fill.
		/// </summary>
		public Fill()
		{
			Init();
		}
		
		/// <summary>
		/// Constructor that specifies the color, brush, and type for this fill.
		/// </summary>
		/// <param name="color">The color of the fill for solid fills</param>
		/// <param name="brush">A custom brush for fills.  Can be a <see cref="SolidBrush"/>,
		/// <see cref="LinearGradientBrush"/>, or <see cref="TextureBrush"/>.</param>
		/// <param name="type">The <see cref="FillType"/> for this fill.</param>
		public Fill( Color color, Brush brush, FillType type )
		{
			Init();
			_color = color;
			_brush = brush;
			_type = type;
		}
		
		/// <summary>
		/// Constructor that creates a solid color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Solid"/>, and setting <see cref="Color"/> to the
		/// specified color value.
		/// </summary>
		/// <param name="color">The color of the solid fill</param>
		public Fill( Color color )
		{
			Init();
			_color = color;
			if ( color != Color.Empty )
				_type = FillType.Solid;
		}
		
		/// <summary>
		/// Constructor that creates a linear gradient color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors and angle.
		/// </summary>
		/// <param name="color1">The first color for the gradient fill</param>
		/// <param name="color2">The second color for the gradient fill</param>
		/// <param name="angle">The angle (degrees) of the gradient fill</param>
		public Fill( Color color1, Color color2, float angle )
		{
			Init();
			_color = color2;

			ColorBlend blend = new ColorBlend( 2 );
			blend.Colors[0] = color1;
			blend.Colors[1] = color2;
			blend.Positions[0] = 0.0f;
			blend.Positions[1] = 1.0f;
			_type = FillType.Brush;

			this.CreateBrushFromBlend( blend, angle );
		}
		
		/// <summary>
		/// Constructor that creates a linear gradient color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.
		/// </summary>
		/// <param name="color1">The first color for the gradient fill</param>
		/// <param name="color2">The second color for the gradient fill</param>
		public Fill( Color color1, Color color2 ) : this( color1, color2, 0.0F )
		{
		}
		
		/// <summary>
		/// Constructor that creates a linear gradient color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of three colors.
		/// </summary>
		/// <param name="color1">The first color for the gradient fill</param>
		/// <param name="color2">The second color for the gradient fill</param>
		/// <param name="color3">The third color for the gradient fill</param>
		public Fill( Color color1, Color color2, Color color3 ) :
			this( color1, color2, color3, 0.0f )
		{
		}

		/// <summary>
		/// Constructor that creates a linear gradient color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of three colors
		/// </summary>
		/// <param name="color1">The first color for the gradient fill</param>
		/// <param name="color2">The second color for the gradient fill</param>
		/// <param name="color3">The third color for the gradient fill</param>
		/// <param name="angle">The angle (degrees) of the gradient fill</param>
		public Fill( Color color1, Color color2, Color color3, float angle )
		{
			Init();
			_color = color3;

			ColorBlend blend = new ColorBlend( 3 );
			blend.Colors[0] = color1;
			blend.Colors[1] = color2;
			blend.Colors[2] = color3;
			blend.Positions[0] = 0.0f;
			blend.Positions[1] = 0.5f;
			blend.Positions[2] = 1.0f;
			_type = FillType.Brush;
			
			this.CreateBrushFromBlend( blend, angle );
		}
		
		/// <summary>
		/// Constructor that creates a linear gradient multi-color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of many colors based on a <see cref="ColorBlend"/> object.  The gradient
		/// angle is defaulted to zero.
		/// </summary>
		/// <param name="blend">The <see cref="ColorBlend"/> object that defines the colors
		/// and positions along the gradient.</param>
		public Fill( ColorBlend blend ) :
			this( blend, 0.0F )
		{
		}

		/// <summary>
		/// Constructor that creates a linear gradient multi-color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of many colors based on a <see cref="ColorBlend"/> object, drawn at the
		/// specified angle (degrees).
		/// </summary>
		/// <param name="blend">The <see cref="ColorBlend"/> object that defines the colors
		/// and positions along the gradient.</param>
		/// <param name="angle">The angle (degrees) of the gradient fill</param>
		public Fill( ColorBlend blend, float angle )
		{
			Init();
			_type = FillType.Brush;
			this.CreateBrushFromBlend( blend, angle );
		}

		/// <summary>
		/// Constructor that creates a linear gradient multi-color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of many colors based on an array of <see cref="Color"/> objects, drawn at an
		/// angle of zero (degrees).  The <see paramref="colors"/> array is used to create
		/// a <see cref="ColorBlend"/> object assuming a even linear distribution of the colors
		/// across the gradient.
		/// </summary>
		/// <param name="colors">The array of <see cref="Color"/> objects that defines the colors
		/// along the gradient.</param>
		public Fill( Color[] colors ) :
			this( colors, 0.0F )
		{
		}

		/// <summary>
		/// Constructor that creates a linear gradient multi-color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of many colors based on an array of <see cref="Color"/> objects, drawn at the
		/// specified angle (degrees).  The <see paramref="colors"/> array is used to create
		/// a <see cref="ColorBlend"/> object assuming a even linear distribution of the colors
		/// across the gradient.
		/// </summary>
		/// <param name="colors">The array of <see cref="Color"/> objects that defines the colors
		/// along the gradient.</param>
		/// <param name="angle">The angle (degrees) of the gradient fill</param>
		public Fill( Color[] colors, float angle )
		{
			Init();
			_color = colors[ colors.Length - 1 ];

			ColorBlend blend = new ColorBlend();
			blend.Colors = colors;
			blend.Positions = new float[colors.Length];
			blend.Positions[0] = 0.0F;
			for ( int i=1; i<colors.Length; i++ )
				blend.Positions[i] = (float) i / (float)( colors.Length - 1 );
			_type = FillType.Brush;

			this.CreateBrushFromBlend( blend, angle );
		}

		/// <summary>
		/// Constructor that creates a linear gradient multi-color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of many colors based on an array of <see cref="Color"/> objects, drawn at the
		/// an angle of zero (degrees).  The <see paramref="colors"/> array is used to create
		/// a <see cref="ColorBlend"/> object assuming a even linear distribution of the colors
		/// across the gradient.
		/// </summary>
		/// <param name="colors">The array of <see cref="Color"/> objects that defines the colors
		/// along the gradient.</param>
		/// <param name="positions">The array of floating point values that defines the color
		/// positions along the gradient.  Values should range from 0 to 1.</param>
		public Fill( Color[] colors, float[] positions ) :
			this( colors, positions, 0.0F )
		{
		}

		/// <summary>
		/// Constructor that creates a linear gradient multi-color-fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> using the specified colors.  This gradient fill
		/// consists of many colors based on an array of <see cref="Color"/> objects, drawn at the
		/// specified angle (degrees).  The <see paramref="colors"/> array is used to create
		/// a <see cref="ColorBlend"/> object assuming a even linear distribution of the colors
		/// across the gradient.
		/// </summary>
		/// <param name="colors">The array of <see cref="Color"/> objects that defines the colors
		/// along the gradient.</param>
		/// <param name="positions">The array of floating point values that defines the color
		/// positions along the gradient.  Values should range from 0 to 1.</param>
		/// <param name="angle">The angle (degrees) of the gradient fill</param>
		public Fill( Color[] colors, float[] positions, float angle )
		{
			Init();
			_color = colors[ colors.Length - 1 ];

			ColorBlend blend = new ColorBlend();
			blend.Colors = colors;
			blend.Positions = positions;
			_type = FillType.Brush;

			this.CreateBrushFromBlend( blend, angle );
		}

		/// <summary>
		/// Constructor that creates a texture fill, setting <see cref="Type"/> to
		/// <see cref="FillType.Brush"/> and using the specified image.
		/// </summary>
		/// <param name="image">The <see cref="Image"/> to use for filling</param>
		/// <param name="wrapMode">The <see cref="WrapMode"/> class that controls the image wrapping properties</param>
		public Fill( Image image, WrapMode wrapMode )
		{
			Init();
			_color = Color.White;
			_brush = new TextureBrush( image, wrapMode );
			_type = FillType.Brush;
			_image = image;
			_wrapMode = wrapMode;
		}
		
		/// <summary>
		/// Constructor that creates a <see cref="Brush"/> fill, using a user-supplied, custom
		/// <see cref="Brush"/>.  The brush will be scaled to fit the destination screen object
		/// unless you manually change <see cref="IsScaled"/> to false;
		/// </summary>
		/// <param name="brush">The <see cref="Brush"/> to use for fancy fills.  Typically, this would
		/// be a <see cref="LinearGradientBrush"/> or a <see cref="TextureBrush"/> class</param>
		public Fill( Brush brush ) : this( brush, Default.IsScaled )
		{
		}
		
		/// <summary>
		/// Constructor that creates a <see cref="Brush"/> fill, using a user-supplied, custom
		/// <see cref="Brush"/>.  The brush will be scaled to fit the destination screen object
		/// according to the <see paramref="isScaled"/> parameter.
		/// </summary>
		/// <param name="brush">The <see cref="Brush"/> to use for fancy fills.  Typically, this would
		/// be a <see cref="LinearGradientBrush"/> or a <see cref="TextureBrush"/> class</param>
		/// <param name="isScaled">Determines if the brush will be scaled to fit the bounding box
		/// of the destination object.  true to scale it, false to leave it unscaled</param>
		public Fill( Brush brush, bool isScaled )
		{
			Init();
			_isScaled = isScaled;
			_color = Color.White;
			_brush = (Brush) brush.Clone();
			_type = FillType.Brush;
		}
		
		/// <summary>
		/// Constructor that creates a <see cref="Brush"/> fill, using a user-supplied, custom
		/// <see cref="Brush"/>.  This constructor will make the brush unscaled (see <see cref="IsScaled"/>),
		/// but it provides <see paramref="alignH"/> and <see paramref="alignV"/> parameters to control
		/// alignment of the brush with respect to the filled object.
		/// </summary>
		/// <param name="brush">The <see cref="Brush"/> to use for fancy fills.  Typically, this would
		/// be a <see cref="LinearGradientBrush"/> or a <see cref="TextureBrush"/> class</param>
		/// <param name="alignH">Controls the horizontal alignment of the brush within the filled object
		/// (see <see cref="AlignH"/></param>
		/// <param name="alignV">Controls the vertical alignment of the brush within the filled object
		/// (see <see cref="AlignV"/></param>
		public Fill( Brush brush, AlignH alignH, AlignV alignV )
		{
			Init();
			_alignH = alignH;
			_alignV = alignV;
			_isScaled = false;
			_color = Color.White;
			_brush = (Brush) brush.Clone();
			_type = FillType.Brush;
		}

		/// <summary>
		/// The Copy Constructor
		/// </summary>
		/// <param name="rhs">The Fill object from which to copy</param>
		public Fill( Fill rhs )
		{
			_color = rhs._color;
			_secondaryValueGradientColor = rhs._color;

			if ( rhs._brush != null )
				_brush = (Brush) rhs._brush.Clone();
			else
				_brush = null;
			_type = rhs._type;
			_alignH = rhs.AlignH;
			_alignV = rhs.AlignV;
            _isScaled = rhs.IsScaled;
			_rangeMin = rhs._rangeMin;
			_rangeMax = rhs._rangeMax;
			_rangeDefault = rhs._rangeDefault;
			_gradientBM = null;

			if ( rhs._colorList != null )
				_colorList = (Color[]) rhs._colorList.Clone();
			else
				_colorList = null;

			if ( rhs._positionList != null )
			{
				_positionList = (float[]) rhs._positionList.Clone();
			}
			else
				_positionList = null;

			if ( rhs._image != null )
				_image = (Image) rhs._image.Clone();
			else
				_image = null;

			_angle = rhs._angle;
			_wrapMode = rhs._wrapMode;
		}

		/// <summary>
		/// Implement the <see cref="ICloneable" /> interface in a typesafe manner by just
		/// calling the typed version of <see cref="Clone" />
		/// </summary>
		/// <returns>A deep copy of this object</returns>
		object ICloneable.Clone()
		{
			return this.Clone();
		}

		/// <summary>
		/// Typesafe, deep-copy clone method.
		/// </summary>
		/// <returns>A new, independent copy of this class</returns>
		public Fill Clone()
		{
			return new Fill( this );
		}

		private void CreateBrushFromBlend( ColorBlend blend, float angle )
		{
			_angle = angle;

			_colorList = (Color[]) blend.Colors.Clone();
			_positionList = (float[]) blend.Positions.Clone();

			_brush = new LinearGradientBrush( new Rectangle( 0, 0, 100, 100 ),
				Color.Red, Color.White, angle );
			((LinearGradientBrush)_brush).InterpolationColors = blend;
		}

	#endregion

	#region Serialization
		/// <summary>
		/// Current schema value that defines the version of the serialized file
		/// </summary>
		public const int schema = 10;
		// schema changed to 2 with addition of rangeDefault
		// schema changed to 10 with version 5 refactor -- not backwards compatible

		/// <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 Fill( SerializationInfo info, StreamingContext context )
		{
			Init();

			// 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" );

			_color = (Color) info.GetValue( "color", typeof(Color) );
			_secondaryValueGradientColor = (Color) info.GetValue( "secondaryValueGradientColor", typeof( Color ) );
			//brush = (Brush) info.GetValue( "brush", typeof(Brush) );
			//brushHolder = (BrushHolder) info.GetValue( "brushHolder", typeof(BrushHolder) );
			_type = (FillType) info.GetValue( "type", typeof(FillType) );
			_isScaled = info.GetBoolean( "isScaled" );
			_alignH = (AlignH) info.GetValue( "alignH", typeof(AlignH) );
			_alignV = (AlignV) info.GetValue( "alignV", typeof(AlignV) );
			_rangeMin = info.GetDouble( "rangeMin" );
			_rangeMax = info.GetDouble( "rangeMax" );

			//BrushHolder brushHolder = (BrushHolder) info.GetValue( "brushHolder", typeof( BrushHolder ) );
			//brush = brush;

			_colorList = (Color[]) info.GetValue( "colorList", typeof(Color[]) );
			_positionList = (float[]) info.GetValue( "positionList", typeof(float[]) );
			_angle = info.GetSingle( "angle" );
			_image = (Image) info.GetValue( "image", typeof(Image) );
			_wrapMode = (WrapMode) info.GetValue( "wrapMode", typeof(WrapMode) );

			if ( _colorList != null && _positionList != null )
			{
				ColorBlend blend = new ColorBlend();
				blend.Colors = _colorList;
				blend.Positions = _positionList;
				CreateBrushFromBlend( blend, _angle );
			}
			else if ( _image != null )
			{
				_brush = new TextureBrush( _image, _wrapMode );
			}

			_rangeDefault = info.GetDouble( "rangeDefault" );
		}
		/// <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( "color", _color );
			info.AddValue( "secondaryValueGradientColor", _secondaryValueGradientColor );
			//info.AddValue( "brush", brush );
			//info.AddValue( "brushHolder", brushHolder );
			info.AddValue( "type", _type );
			info.AddValue( "isScaled", _isScaled );
			info.AddValue( "alignH", _alignH );
			info.AddValue( "alignV", _alignV );
			info.AddValue( "rangeMin", _rangeMin );
			info.AddValue( "rangeMax", _rangeMax );

			//BrushHolder brushHolder = new BrushHolder();
			//brush = brush;
			//info.AddValue( "brushHolder", brushHolder );

			info.AddValue( "colorList", _colorList );
			info.AddValue( "positionList", _positionList );
			info.AddValue( "angle", _angle );
			info.AddValue( "image", _image );
			info.AddValue( "wrapMode", _wrapMode );

			info.AddValue( "rangeDefault", _rangeDefault );
		}
	#endregion

	#region Properties

		/// <summary>
		/// The fill color.  This property is used as a single color to make a solid fill
		/// (<see cref="Type"/> is <see cref="FillType.Solid"/>), or it can be used in 
		/// combination with <see cref="System.Drawing.Color.White"/> to make a
		/// <see cref="LinearGradientBrush"/>
		/// when <see cref="Type"/> is <see cref="FillType.Brush"/> and <see cref="Brush"/>
		/// is null.
		/// </summary>
		/// <seealso cref="Type"/>
		public Color Color
		{
			get { return _color; }
			set { _color = value; }
		}

		/// <summary>
		/// Gets or sets the secondary color for gradientByValue fills.
		/// </summary>
		/// <remarks>
		/// This property is only applicable if the <see cref="Type"/> is
		/// <see cref="ZedGraph.FillType.GradientByX"/>,
		/// <see cref="ZedGraph.FillType.GradientByY"/>, or
		/// <see cref="ZedGraph.FillType.GradientByZ"/>.  Once the gradient-by-value logic picks
		/// a color, a new gradient will be created using the SecondaryValueGradientColor, the
		/// resulting gradient-by-value color, and the angle setting for this
		/// <see cref="Fill" />. Use a value of <see cref="System.Drawing.Color.Empty">Color.Empty</see> to have
		/// a solid-color <see cref="Fill" /> resulting from a gradient-by-value
		/// <see cref="FillType" />.
		/// </remarks>
		public Color SecondaryValueGradientColor
		{
			get { return _secondaryValueGradientColor; }
			set { _secondaryValueGradientColor = value; }
		}

		/// <summary>
		/// The custom fill brush.  This can be a <see cref="SolidBrush"/>, a
		/// <see cref="LinearGradientBrush"/>, or a <see cref="TextureBrush"/>.  This property is
		/// only applicable if the <see cref="Type"/> property is set
		/// to <see cref="FillType.Brush"/>.
		/// </summary>
		public Brush Brush
		{
			get { return _brush; }
			set { _brush = value; }
		}
		/// <summary>
		/// Determines the type of fill, which can be either solid
		/// color (<see cref="ZedGraph.FillType.Solid"/>) or a custom brush
		/// (<see cref="ZedGraph.FillType.Brush"/>).  See <see cref="Type"/> for
		/// more information.
		/// </summary>
		/// <seealso cref="ZedGraph.Fill.Color"/>
		public FillType Type
		{
			get { return _type; }
			set { _type = value; }
		}
		/// <summary>
		/// This property determines the type of color fill. 
		/// Returns true if the <see cref="Type"/> property is either
		/// <see cref="FillType.Solid"/> or
		/// <see cref="FillType.Brush"/>.  If set to true, this property
		/// will automatically set the <see cref="Type"/> to
		/// <see cref="FillType.Brush"/>.  If set to false, this property
		/// will automatically set the <see cref="Type"/> to
		/// <see cref="FillType.None"/>.  In order to get a regular
		/// solid-color fill, you have to manually set <see cref="Type"/>
		/// to <see cref="FillType.Solid"/>.
		/// </summary>
		/// <seealso cref="Color"/>
		/// <seealso cref="Brush"/>
		/// <seealso cref="Type"/>
		public bool IsVisible
		{
			get { return _type != FillType.None; }
			set { _type = value ? ( _type == FillType.None ? FillType.Brush : _type ) : FillType.None; }
		}

		/// <summary>
		/// Determines if the brush will be scaled to the bounding box
		/// of the filled object.  If this value is false, then the brush will only be aligned
		/// with the filled object based on the <see cref="AlignH"/> and <see cref="AlignV"/>
		/// properties.
		/// </summary>
		public bool IsScaled
		{
			get { return _isScaled; }
			set { _isScaled = value; }
		}
		
		/// <summary>
		/// Determines how the brush will be aligned with the filled object
		/// in the horizontal direction.  This value is a <see cref="ZedGraph.AlignH"/> enumeration.
		/// This field only applies if <see cref="IsScaled"/> is false.
		/// </summary>
		/// <seealso cref="AlignV"/>
		public AlignH AlignH
		{
			get { return _alignH; }
			set { _alignH = value; }
		}
		
		/// <summary>
		/// Determines how the brush will be aligned with the filled object
		/// in the vertical direction.  This value is a <see cref="ZedGraph.AlignV"/> enumeration.
		/// This field only applies if <see cref="IsScaled"/> is false.
		/// </summary>
		/// <seealso cref="AlignH"/>
		public AlignV AlignV
		{
			get { return _alignV; }
			set { _alignV = value; }
		}

		/// <summary>
		/// Returns a boolean value indicating whether or not this fill is a "Gradient-By-Value"
		/// type.  This is true for <see cref="FillType.GradientByX"/>, <see cref="FillType.GradientByY"/>,
		/// or <see cref="FillType.GradientByZ"/>.
		/// </summary>
		/// <remarks>
		/// The gradient by value fill method allows the fill color for each point or bar to
		/// be based on a value for that point (either X, Y, or Z in the <see cref="IPointList"/>.
		/// For example, assume a <see cref="Fill"/> class is defined with a linear gradient ranging from
		/// <see cref="System.Drawing.Color.Blue"/> to <see cref="System.Drawing.Color.Red"/> and the <see cref="Fill.Type"/>
		/// is set to <see cref="FillType.GradientByY"/>.  If <see cref="RangeMin"/> is set to 
		/// 100.0 and <see cref="RangeMax"/> is set to 200.0, then a point that has a Y value of
		/// 100 or less will be colored blue, a point with a Y value of 200 or more will be
		/// colored red, and a point between 100 and 200 will have a color based on a linear scale
		/// between blue and red.  Note that the fill color is always solid for any given point.
		/// You can use the Z value from <see cref="IPointList"/> along with
		/// <see cref="FillType.GradientByZ"/> to color individual points according to some
		/// property that is independent of the X,Y point pair.
		/// </remarks>
		/// <value>true if this is a Gradient-by-value type, false otherwise</value>
		/// <seealso cref="FillType.GradientByX"/>
		/// <seealso cref="FillType.GradientByY"/>
		/// <seealso cref="FillType.GradientByZ"/>
		public bool IsGradientValueType
		{
			get { return _type == FillType.GradientByX || _type == FillType.GradientByY ||
					_type == FillType.GradientByZ || _type == FillType.GradientByColorValue; }
		}

		/// <summary>
		/// The minimum user-scale value for the gradient-by-value determination.  This defines
		/// the user-scale value for the start of the gradient.
		/// </summary>
		/// <seealso cref="FillType.GradientByX"/>
		/// <seealso cref="FillType.GradientByY"/>
		/// <seealso cref="FillType.GradientByZ"/>
		/// <seealso cref="IsGradientValueType"/>
		/// <seealso cref="RangeMax"/>
		/// <seealso cref="RangeDefault"/>
		/// <value>A double value, in user scale unit</value>
		public double RangeMin
		{
			get { return _rangeMin; }
			set { _rangeMin = value; }
		}
		/// <summary>
		/// The maximum user-scale value for the gradient-by-value determination.  This defines
		/// the user-scale value for the end of the gradient.
		/// </summary>
		/// <seealso cref="FillType.GradientByX"/>
		/// <seealso cref="FillType.GradientByY"/>
		/// <seealso cref="FillType.GradientByZ"/>
		/// <seealso cref="IsGradientValueType"/>
		/// <seealso cref="RangeMin"/>
		/// <seealso cref="RangeDefault"/>
		/// <value>A double value, in user scale unit</value>
		public double RangeMax
		{
			get { return _rangeMax; }
			set { _rangeMax = value; }
		}

		/// <summary>
		/// The default user-scale value for the gradient-by-value determination.  This defines the
		/// value that will be used when there is no point value available, or the actual point value
		/// is invalid.
		/// </summary>
		/// <remarks>
		/// Note that this value, when defined, will determine the color that is used in the legend.
		/// If this value is set to double.MaxValue, then it remains "undefined."  In this case, the
		/// legend symbols will actually be filled with a color gradient representing the range of
		/// colors.
		/// </remarks>
		/// <seealso cref="FillType.GradientByX"/>
		/// <seealso cref="FillType.GradientByY"/>
		/// <seealso cref="FillType.GradientByZ"/>
		/// <seealso cref="IsGradientValueType"/>
		/// <seealso cref="RangeMin"/>
		/// <seealso cref="RangeMax"/>
		/// <value>A double value, in user scale unit</value>
		public double RangeDefault
		{
			get { return _rangeDefault; }
			set { _rangeDefault = value; }
		}

	#endregion

	#region Methods

		/// <summary>
		/// Create a fill brush using current properties.  This method will construct a brush based on the
		/// settings of <see cref="ZedGraph.Fill.Type"/>, <see cref="ZedGraph.Fill.Color"/>
		/// and <see cref="ZedGraph.Fill.Brush"/>.  If
		/// <see cref="ZedGraph.Fill.Type"/> is set to <see cref="ZedGraph.FillType.Brush"/> and
		/// <see cref="ZedGraph.Fill.Brush"/>
		/// is null, then a <see cref="LinearGradientBrush"/> will be created between the colors of
		/// <see cref="System.Drawing.Color.White"/> and <see cref="ZedGraph.Fill.Color"/>.
		/// </summary>
		/// <param name="rect">A rectangle that bounds the object to be filled.  This determines
		/// the start and end of the gradient fill.</param>
		/// <returns>A <see cref="System.Drawing.Brush"/> class representing the fill brush</returns>
		public Brush MakeBrush( RectangleF rect )
		{
			// just provide a default value for the valueFraction
			// return MakeBrush( rect, new PointPair( 0.5, 0.5, 0.5 ) );
			return MakeBrush( rect, null );
		}

		/// <summary>
		/// Create a fill brush using current properties.  This method will construct a brush based on the
		/// settings of <see cref="ZedGraph.Fill.Type"/>, <see cref="ZedGraph.Fill.Color"/>
		/// and <see cref="ZedGraph.Fill.Brush"/>.  If
		/// <see cref="ZedGraph.Fill.Type"/> is set to <see cref="ZedGraph.FillType.Brush"/> and
		/// <see cref="ZedGraph.Fill.Brush"/>
		/// is null, then a <see cref="LinearGradientBrush"/> will be created between the colors of
		/// <see cref="System.Drawing.Color.White"/> and <see cref="ZedGraph.Fill.Color"/>.
		/// </summary>
		/// <param name="rect">A rectangle that bounds the object to be filled.  This determines
		/// the start and end of the gradient fill.</param>
		/// <param name="dataValue">The data value to be used for a value-based
		/// color gradient.  This is only applicable for <see cref="FillType.GradientByX"/>,
		/// <see cref="FillType.GradientByY"/> or <see cref="FillType.GradientByZ"/>.</param>
		/// <returns>A <see cref="System.Drawing.Brush"/> class representing the fill brush</returns>
		public Brush MakeBrush( RectangleF rect, PointPair dataValue )
		{
			// get a brush
			if ( this.IsVisible && ( !_color.IsEmpty || _brush != null ) )
			{
				if ( rect.Height < 1.0F )
					rect.Height = 1.0F;
				if ( rect.Width < 1.0F )
					rect.Width = 1.0F;
					
				//Brush	brush;
				if ( _type == FillType.Brush )
				{
					return ScaleBrush( rect, _brush, _isScaled );
				}
				else if ( IsGradientValueType )
				{
					if ( dataValue != null )
					{
						if ( !_secondaryValueGradientColor.IsEmpty )
						{
							// Go ahead and create a new Fill so we can do all the scaling, etc.,
							// that is associated with a gradient
							Fill tmpFill = new Fill( _secondaryValueGradientColor,
									GetGradientColor( dataValue ), _angle );
							return tmpFill.MakeBrush( rect );
						}
						else
							return new SolidBrush( GetGradientColor( dataValue ) );
					}
					else if ( _rangeDefault != double.MaxValue )
					{
						if ( !_secondaryValueGradientColor.IsEmpty )
						{
							// Go ahead and create a new Fill so we can do all the scaling, etc.,
							// that is associated with a gradient
							Fill tmpFill = new Fill( _secondaryValueGradientColor,
									GetGradientColor( _rangeDefault ), _angle );
							return tmpFill.MakeBrush( rect );
						}
						else
							return new SolidBrush( GetGradientColor( _rangeDefault ) );
					}
					else
						return ScaleBrush( rect, _brush, true );
				}
				else
					return new SolidBrush( _color );
			}

			// Always return a suitable default
			return new SolidBrush( Color.White );
		}

		internal Color GetGradientColor( PointPair dataValue )
		{
			double val;

			if ( dataValue == null )
				val = _rangeDefault;
			else if ( _type == FillType.GradientByColorValue )
				val = dataValue.ColorValue;
			else if ( _type == FillType.GradientByZ )
				val = dataValue.Z;
			else if ( _type == FillType.GradientByY )
				val = dataValue.Y;
			else
				val = dataValue.X;

			return GetGradientColor( val );
		}

		internal Color GetGradientColor( double val )
		{
			double valueFraction;

			if ( Double.IsInfinity( val ) || double.IsNaN( val ) || val == PointPair.Missing )
				val = _rangeDefault;

			if ( _rangeMax - _rangeMin < 1e-20 || val == double.MaxValue )
				valueFraction = 0.5;
			else			
				valueFraction = ( val - _rangeMin ) / ( _rangeMax - _rangeMin );

			if ( valueFraction < 0.0 )
				valueFraction = 0.0;
			else if ( valueFraction > 1.0 )
				valueFraction = 1.0;

			if ( _gradientBM == null )
			{
				RectangleF rect = new RectangleF( 0, 0, 100, 1 );
				_gradientBM = new Bitmap( 100, 1 );
				Graphics gBM = Graphics.FromImage( _gradientBM );

				Brush tmpBrush = ScaleBrush( rect, _brush, true );
				gBM.FillRectangle( tmpBrush, rect );
			}

			return _gradientBM.GetPixel( (int) (99.9 * valueFraction), 0 );
		}

		private Brush ScaleBrush( RectangleF rect, Brush brush, bool isScaled )
		{
			if ( brush != null )
			{
				if ( brush is SolidBrush )
				{
					return (Brush) brush.Clone();
				}
				else if ( brush is LinearGradientBrush )
				{
					LinearGradientBrush linBrush = (LinearGradientBrush) brush.Clone();
					
					if ( isScaled )
					{
						linBrush.ScaleTransform( rect.Width / linBrush.Rectangle.Width,
							rect.Height / linBrush.Rectangle.Height, MatrixOrder.Append );
						linBrush.TranslateTransform( rect.Left - linBrush.Rectangle.Left,
							rect.Top - linBrush.Rectangle.Top, MatrixOrder.Append );
					}
					else
					{
						float	dx = 0,
								dy = 0;
						switch ( _alignH )
						{
						case AlignH.Left:
							dx = rect.Left - linBrush.Rectangle.Left;
							break;
						case AlignH.Center:
							dx = ( rect.Left + rect.Width / 2.0F ) - linBrush.Rectangle.Left;
							break;
						case AlignH.Right:
							dx = ( rect.Left + rect.Width ) - linBrush.Rectangle.Left;
							break;
						}
						
						switch ( _alignV )
						{
						case AlignV.Top:
							dy = rect.Top - linBrush.Rectangle.Top;
							break;
						case AlignV.Center:
							dy = ( rect.Top + rect.Height / 2.0F ) - linBrush.Rectangle.Top;
							break;
						case AlignV.Bottom:
							dy = ( rect.Top + rect.Height) - linBrush.Rectangle.Top;
							break;
						}

						linBrush.TranslateTransform( dx, dy, MatrixOrder.Append );
					}
					
					return linBrush;
					
				} // LinearGradientBrush
				else if ( brush is TextureBrush )
				{
					TextureBrush texBrush = (TextureBrush) brush.Clone();
					
					if ( isScaled )
					{
						texBrush.ScaleTransform( rect.Width / texBrush.Image.Width,
							rect.Height / texBrush.Image.Height, MatrixOrder.Append );
						texBrush.TranslateTransform( rect.Left, rect.Top, MatrixOrder.Append );
					}
					else
					{
						float	dx = 0,
								dy = 0;
						switch ( _alignH )
						{
						case AlignH.Left:
							dx = rect.Left;
							break;
						case AlignH.Center:
							dx = ( rect.Left + rect.Width / 2.0F );
							break;
						case AlignH.Right:
							dx = ( rect.Left + rect.Width );
							break;
						}
						
						switch ( _alignV )
						{
						case AlignV.Top:
							dy = rect.Top;
							break;
						case AlignV.Center:
							dy = ( rect.Top + rect.Height / 2.0F );
							break;
						case AlignV.Bottom:
							dy = ( rect.Top + rect.Height);
							break;
						}

						texBrush.TranslateTransform( dx, dy, MatrixOrder.Append );
					}
					
					return texBrush;
				}
				else // other brush type
				{
					return (Brush) brush.Clone();
				}
			}
			else
				// If they didn't provide a brush, make one using the fillcolor gradient to white
				return new LinearGradientBrush( rect, Color.White, _color, 0F );
		}

		/// <summary>
		/// Fill the background of the <see cref="RectangleF"/> area, using the
		/// fill type from this <see cref="Fill"/>.
		/// </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="rect">The <see cref="RectangleF"/> struct specifying the area
		/// to be filled</param>
		public void Draw( Graphics g, RectangleF rect )
		{
			Draw( g, rect, null );
			/*
			if ( this.IsVisible )
			{
				using( Brush brush = this.MakeBrush( rect ) )
				{
					g.FillRectangle( brush, rect );
					//brush.Dispose();
				}
			}
			*/
		}

		/// <summary>
		/// Fill the background of the <see cref="RectangleF"/> area, using the
		/// fill type from this <see cref="Fill"/>.
		/// </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="rect">The <see cref="RectangleF"/> struct specifying the area
		/// to be filled</param>
		/// <param name="pt">The data value to be used in case it's a
		/// <see cref="FillType.GradientByX" />, <see cref="FillType.GradientByY" />, or
		/// <see cref="FillType.GradientByZ" /> <see cref="FillType" />.</param>
		public void Draw( Graphics g, RectangleF rect, PointPair pt )
		{
			if ( this.IsVisible )
			{
				using ( Brush brush = this.MakeBrush( rect, pt ) )
				{
					g.FillRectangle( brush, rect );
				}
			}
		}


	#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Engineer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions