//============================================================================ //GasGaugeNeedle Class //Copyright ?2006 Jay Mistry // //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.Runtime.Serialization; using System.Drawing.Drawing2D; using System; using System.Text; using System.Drawing; using System.Security.Permissions; namespace DrawGraph { /// /// A class representing a needle on the GasGuage chart /// s. /// /// Jay Mistry /// $Revision: 1.1 $ $Date: 2007/04/29 02:07:03 $ [Serializable] public class GasGaugeNeedle : CurveItem, ICloneable, ISerializable { #region Fields /// /// Value of this needle /// private double _needleValue; /// /// Width of the line being drawn /// private float _needleWidth; /// /// Color of the needle line /// private Color _color; /// /// Internally calculated angle that places this needle relative to the MinValue and /// MaxValue of 180 degree GasGuage /// private float _sweepAngle; /// /// Private field that stores the data for this /// . Use the public property to /// access this value. /// private Fill _fill; /// /// A which will customize the label display of this /// /// private TextObj _labelDetail; /// /// 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; /// /// The bounding rectangle for this . /// private RectangleF _boundingRectangle; /// /// Private field to hold the GraphicsPath of this to be /// used for 'hit testing'. /// private GraphicsPath _slicePath; #endregion #region Constructors /// /// Create a new /// /// The value associated with this /// instance. /// The display color for this /// instance. /// The value of this . public GasGaugeNeedle( string label, double val, Color color ) : base( label ) { NeedleValue = val; NeedleColor = color; NeedleWidth = Default.NeedleWidth; SweepAngle = 0f; _border = new Border( Default.BorderColor, Default.BorderWidth ); _labelDetail = new TextObj(); _labelDetail.FontSpec.Size = Default.FontSize; _slicePath = null; } /// /// The Copy Constructor /// /// The object from which to copy public GasGaugeNeedle( GasGaugeNeedle ggn ) : base( ggn ) { NeedleValue = ggn.NeedleValue; NeedleColor = ggn.NeedleColor; NeedleWidth = ggn.NeedleWidth; SweepAngle = ggn.SweepAngle; _border = ggn.Border.Clone(); _labelDetail = ggn.LabelDetail.Clone(); _labelDetail.FontSpec.Size = ggn.LabelDetail.FontSpec.Size; } /// /// 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 GasGaugeNeedle Clone() { return new GasGaugeNeedle( this ); } #endregion #region Properties /// /// Gets or Sets the NeedleWidth of this /// public float NeedleWidth { get { return _needleWidth; } set { _needleWidth = value; } } /// /// Gets or Sets the Border of this /// public Border Border { get { return ( _border ); } set { _border = value; } } /// /// Gets or Sets the SlicePath of this /// public GraphicsPath SlicePath { get { return _slicePath; } } /// /// Gets or Sets the LableDetail of this /// public TextObj LabelDetail { get { return _labelDetail; } set { _labelDetail = value; } } /// /// Gets or Sets the NeedelColor of this /// public Color NeedleColor { get { return _color; } set { _color = value; Fill = new Fill( _color ); } } /// /// Gets or Sets the Fill of this /// public Fill Fill { get { return _fill; } set { _fill = value; } } /// /// Private property that Gets or Sets the SweepAngle of this /// private float SweepAngle { get { return _sweepAngle; } set { _sweepAngle = value; } } /// /// Gets or Sets the NeedleValue of this /// public double NeedleValue { get { return ( _needleValue ); } set { _needleValue = value > 0 ? value : 0; } } /// /// Gets a flag indicating if the Z data range should be included in the axis scaling calculations. /// /// The parent of this . /// /// true if the Z data are included, false otherwise override internal bool IsZIncluded( GraphPane pane ) { return false; } /// /// Gets a flag indicating if the X axis is the independent axis for this /// /// The parent of this . /// /// true if the X axis is independent, false otherwise override internal bool IsXIndependent( GraphPane pane ) { return true; } #endregion #region Serialization /// /// Current schema value that defines the version of the serialized file /// public const int schema2 = 10; /// /// Constructor for deserializing objects /// /// A instance that defines the serialized data /// /// A instance that contains the serialized data /// protected GasGaugeNeedle( SerializationInfo info, StreamingContext context ) : base( info, 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( "schema2" ); _labelDetail = (TextObj)info.GetValue( "labelDetail", typeof( TextObj ) ); _fill = (Fill)info.GetValue( "fill", typeof( Fill ) ); _border = (Border)info.GetValue( "border", typeof( Border ) ); _needleValue = info.GetDouble( "needleValue" ); _boundingRectangle = (RectangleF)info.GetValue( "boundingRectangle", typeof( RectangleF ) ); _slicePath = (GraphicsPath)info.GetValue( "slicePath", typeof( GraphicsPath ) ); _sweepAngle = (float)info.GetDouble( "sweepAngle" ); _color = (Color)info.GetValue( "color", typeof( Color ) ); } /// /// 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 override void GetObjectData( SerializationInfo info, StreamingContext context ) { base.GetObjectData( info, context ); info.AddValue( "schema2", schema2 ); info.AddValue( "labelDetail", _labelDetail ); info.AddValue( "fill", _fill ); info.AddValue( "border", _border ); info.AddValue( "needleValue", _needleValue ); info.AddValue( "boundingRectangle", _boundingRectangle ); info.AddValue( "slicePath", _slicePath ); info.AddValue( "sweepAngle", _sweepAngle ); } #endregion #region Default /// /// Specify the default property values for the class. /// public struct Default { /// /// The default width of the gas gauge needle. Units are points, scaled according /// to /// public static float NeedleWidth = 10.0F; /// /// The default pen width to be used for drawing the border around the GasGaugeNeedle /// ( property). Units are points. /// public static float BorderWidth = 1.0F; /// /// The default border mode for GasGaugeNeedle ( /// property). /// true to display frame around GasGaugeNeedle, false otherwise /// public static bool IsBorderVisible = true; /// /// The default color for drawing frames around GasGaugeNeedle /// ( property). /// public static Color BorderColor = Color.Gray; /// /// The default fill type for filling the GasGaugeNeedle. /// public static FillType FillType = FillType.Brush; /// /// The default color for filling in the GasGaugeNeedle /// ( property). /// public static Color FillColor = Color.Empty; /// /// The default custom brush for filling in the GasGaugeNeedle. /// ( property). /// public static Brush FillBrush = null; /// ///Default value for controlling display. /// public static bool isVisible = true; // /// // /// Default value for . // /// // public static PieLabelType LabelType = PieLabelType.Name; /// /// The default font size for entries /// ( property). Units are /// in points (1/72 inch). /// public static float FontSize = 10; } #endregion Defaults #region Methods /// /// Do all rendering associated with this item to the specified /// device. This method is normally only /// called by the Draw method of the parent /// collection object. /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// /// A reference to the object that is the parent or /// owner of this object. /// /// Not used for rendering GasGaugeNeedle /// Not used for rendering GasGaugeNeedle public override void Draw( Graphics g, GraphPane pane, int pos, float scaleFactor ) { if ( pane.Chart._rect.Width <= 0 && pane.Chart._rect.Height <= 0 ) { _slicePath = null; } else { CalcRectangle( g, pane, scaleFactor, pane.Chart._rect ); _slicePath = new GraphicsPath(); if ( !_isVisible ) return; RectangleF tRect = _boundingRectangle; if ( tRect.Width >= 1 && tRect.Height >= 1 ) { SmoothingMode sMode = g.SmoothingMode; g.SmoothingMode = SmoothingMode.AntiAlias; Matrix matrix = new Matrix(); matrix.Translate( tRect.X + ( tRect.Width / 2 ), tRect.Y + ( tRect.Height / 2 ), MatrixOrder.Prepend ); PointF[] pts = new PointF[2]; pts[0] = new PointF( ( ( tRect.Height * .10f ) / 2.0f ) * (float)Math.Cos( -SweepAngle * Math.PI / 180.0f ), ( ( tRect.Height * .10f ) / 2.0f ) * (float)Math.Sin( -SweepAngle * Math.PI / 180.0f ) ); pts[1] = new PointF( ( tRect.Width / 2.0f ) * (float)Math.Cos( -SweepAngle * Math.PI / 180.0f ), ( tRect.Width / 2.0f ) * (float)Math.Sin( -SweepAngle * Math.PI / 180.0f ) ); matrix.TransformPoints( pts ); Pen p = new Pen( NeedleColor, ( ( tRect.Height * .10f ) / 2.0f ) ); p.EndCap = LineCap.ArrowAnchor; g.DrawLine( p, pts[0].X, pts[0].Y, pts[1].X, pts[1].Y ); //Fill center 10% with Black dot; Fill f = new Fill( Color.Black ); RectangleF r = new RectangleF( ( tRect.X + ( tRect.Width / 2 ) ) - 1.0f, ( tRect.Y + ( tRect.Height / 2 ) ) - 1.0f, 1.0f, 1.0f ); r.Inflate( ( tRect.Height * .10f ), ( tRect.Height * .10f ) ); Brush b = f.MakeBrush( r ); g.FillPie( b, r.X, r.Y, r.Width, r.Height, 0.0f, -180.0f ); Pen borderPen = new Pen( Color.White, 2.0f ); g.DrawPie( borderPen, r.X, r.Y, r.Width, r.Height, 0.0f, -180.0f ); g.SmoothingMode = sMode; } } } /// /// Render the label for this . /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// Bounding rectangle for this . /// /// 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 override void DrawLegendKey( Graphics g, GraphPane pane, RectangleF rect, float scaleFactor ) { if ( !_isVisible ) return; float yMid = rect.Top + rect.Height / 2.0F; Pen pen = new Pen( NeedleColor, pane.ScaledPenWidth( NeedleWidth / 2, scaleFactor ) ); pen.StartCap = LineCap.Round; pen.EndCap = LineCap.ArrowAnchor; pen.DashStyle = DashStyle.Solid; g.DrawLine( pen, rect.Left, yMid, rect.Right, yMid ); } /// /// Determine the coords for the rectangle associated with a specified point for /// this /// /// The to which this curve belongs /// The index of the point of interest /// A list of coordinates that represents the "rect" for /// this point (used in an html AREA tag) /// true if it's a valid point, false otherwise public override bool GetCoords( GraphPane pane, int i, out string coords ) { coords = String.Empty; return false; } /// /// Calculate the values needed to properly display this . /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// public static void CalculateGasGuageParameters( GraphPane pane ) { //loop thru slices and get total value and maxDisplacement double minVal = 0; double maxVal = 0; foreach ( CurveItem curve in pane.CurveList ) if ( curve is GasGaugeRegion ) { GasGaugeRegion ggr = (GasGaugeRegion)curve; if ( maxVal < ggr.MaxValue ) maxVal = ggr.MaxValue; if ( minVal > ggr.MinValue ) minVal = ggr.MinValue; } //Set Needle Sweep angle values here based on the min and max values of the GasGuage foreach ( CurveItem curve in pane.CurveList ) { if ( curve is GasGaugeNeedle ) { GasGaugeNeedle ggn = (GasGaugeNeedle)curve; float sweep = ( ( (float)ggn.NeedleValue ) - ( (float)minVal ) ) / ( (float)maxVal ) * 180.0f; ggn.SweepAngle = sweep; } } } /// /// Calculate the that will be used to define the bounding rectangle of /// the GasGaugeNeedle. /// /// This rectangle always lies inside of the , and it is /// normally a square so that the pie itself is not oval-shaped. /// /// 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 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. /// /// The (normally the ) /// that bounds this pie. /// public static RectangleF CalcRectangle( Graphics g, GraphPane pane, float scaleFactor, RectangleF chartRect ) { RectangleF nonExpRect = chartRect; if ( ( 2 * nonExpRect.Height ) > nonExpRect.Width ) { //Scale based on width float percentS = ( ( nonExpRect.Height * 2 ) - nonExpRect.Width ) / ( nonExpRect.Height * 2 ); nonExpRect.Height = ( ( nonExpRect.Height * 2 ) - ( ( nonExpRect.Height * 2 ) * percentS ) ); } else { nonExpRect.Height = nonExpRect.Height * 2; } nonExpRect.Width = nonExpRect.Height; float xDelta = ( chartRect.Width / 2 ) - ( nonExpRect.Width / 2 ); //Align Horizontally nonExpRect.X += xDelta; nonExpRect.Inflate( -(float)0.05F * nonExpRect.Height, -(float)0.05 * nonExpRect.Width ); GasGaugeNeedle.CalculateGasGuageParameters( pane ); foreach ( CurveItem curve in pane.CurveList ) { if ( curve is GasGaugeNeedle ) { GasGaugeNeedle ggn = (GasGaugeNeedle)curve; ggn._boundingRectangle = nonExpRect; } } return nonExpRect; } #endregion } }