//============================================================================ //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 //============================================================================= #region Using directives using System; using System.Text; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Runtime.Serialization; using System.Security.Permissions; using System.IO; #endregion namespace DrawGraph { /// /// An abstract base class that defines basic functionality for handling a pane. This class is the /// parent class for and . /// /// /// John Champion /// $Revision: 3.30 $ $Date: 2007/05/18 13:28:17 $ abstract public class PaneBase : ICloneable { #region Fields /// /// The rectangle that defines the full area into which the pane is rendered. Units are pixels. /// Use the public property to access this value. /// protected RectangleF _rect; /// Private field that holds the main title of the pane. Use the /// public property to access this value. /// protected GapLabel _title; /// Private field instance of the class. Use the /// public property to access this class. protected Legend _legend; /// /// Private field that stores the user-defined tag for this . This tag /// can be any user-defined value. If it is a type, it can be used as /// a parameter to the method. Use the public property /// to access this value. /// protected object _tag; /// /// private field to store the margin values for this . Use the /// public property to access this property. /// internal Margin _margin; /// Private field that determines whether or not the fonts, tics, gaps, etc. /// will be scaled according to the actual graph size. true for font and feature scaling /// with graph size, false for fixed font sizes (scaleFactor = 1.0 constant). /// Use the public property to access this value. /// /// protected bool _isFontsScaled; /// /// Private field that controls whether or not pen widths are scaled according to the /// size of the graph. This value is only applicable if /// is true. If is false, then no scaling will be done, /// regardless of the value of . /// /// true to scale the pen widths according to the size of the graph, /// false otherwise. /// /// protected bool _isPenWidthScaled; /// /// Private field that stores the data for the /// background. Use the public property to /// access this value. /// protected Fill _fill; /// /// Private field that stores the data for the /// border. Use the public property to /// access this value. /// protected Border _border; /// Private field instance of the class. Use the /// public property to access this class. protected GraphObjList _graphObjList; /// Private field that determines the base size of the pane, in inches. /// Fonts, tics, gaps, etc. are scaled according to this base size. /// Use the public property to access this value. /// /// protected float _baseDimension; /// /// private field that stores the gap between the bottom of the pane title and the /// client area of the pane. This is expressed as a fraction of the title character height. /// protected float _titleGap; #endregion #region Defaults /// /// A simple struct that defines the default property values for the class. /// public struct Default { // Default GraphPane properties /// /// The default display mode for the title at the top of the pane /// ( property). true to /// display a title, false otherwise. /// public static bool IsShowTitle = true; /// /// The default font family for the title /// ( property). /// public static string FontFamily = "Arial"; /// /// The default font size (points) for the /// ( property). /// public static float FontSize = 16; /// /// The default font color for the /// /// ( property). /// public static Color FontColor = Color.Black; /// /// The default font bold mode for the /// /// ( property). true /// for a bold typeface, false otherwise. /// public static bool FontBold = true; /// /// The default font italic mode for the /// /// ( property). true /// for an italic typeface, false otherwise. /// public static bool FontItalic = false; /// /// The default font underline mode for the /// /// ( property). true /// for an underlined typeface, false otherwise. /// public static bool FontUnderline = false; /// /// The default border mode for the . /// ( property). true /// to draw a border around the , /// false otherwise. /// public static bool IsBorderVisible = true; /// /// The default color for the border. /// ( property). /// public static Color BorderColor = Color.Black; /// /// The default color for the background. /// ( property). /// public static Color FillColor = Color.White; /// /// The default pen width for the border. /// ( property). Units are in points (1/72 inch). /// public static float BorderPenWidth = 1; /// /// The default dimension of the , which /// defines a normal sized plot. This dimension is used to scale the /// fonts, symbols, etc. according to the actual size of the /// . /// /// public static float BaseDimension = 8.0F; /// /// The default setting for the option. /// true to have all pen widths scaled according to , /// false otherwise. /// /// public static bool IsPenWidthScaled = false; /// /// The default setting for the option. /// true to have all fonts scaled according to , /// false otherwise. /// /// public static bool IsFontsScaled = true; /// /// The default value for the property, expressed as /// a fraction of the scaled character height. /// public static float TitleGap = 0.5f; } #endregion #region Properties /// /// The rectangle that defines the full area into which all graphics /// will be rendered. /// /// Note that this rectangle has x, y, width, and height. Most of the /// GDI+ graphic primitive actually draw one pixel beyond those dimensions. For /// example, for a rectangle of ( X=0, Y=0, Width=100, Height=100 ), GDI+ would /// draw into pixels 0 through 100, which is actually 101 pixels. For the /// ZedGraph Rect, a Width of 100 pixels means that pixels 0 through 99 are used /// Units are pixels. /// public RectangleF Rect { get { return _rect; } set { _rect = value; } } /// /// Accesses the for this /// /// A reference to a object public Legend Legend { get { return _legend; } } /// /// Gets the instance that contains the text and attributes of the title. /// This text can be multiple lines separated by newline characters ('\n'). /// /// /// /// /// /// /// /// public Label Title { get { return _title; } } /// /// Gets or sets the user-defined tag for this . This tag /// can be any user-defined value. If it is a type, it can be used as /// a parameter to the method. /// /// /// Note that, if you are going to Serialize ZedGraph data, then any type /// that you store in must be a serializable type (or /// it will cause an exception). /// public object Tag { get { return _tag; } set { _tag = value; } } /// /// Gets or sets the class for drawing the border /// border around the /// /// /// public Border Border { get { return _border; } set { _border = value; } } /// /// Gets or sets the data for the /// filling the background of the . /// public Fill Fill { get { return _fill; } set { _fill = value; } } /// /// Gets or sets the list of items for this /// /// A reference to a collection object public GraphObjList GraphObjList { get { return _graphObjList; } set { _graphObjList = value; } } /// /// Gets or sets the instance that controls the space between /// the edge of the and the rendered content of the graph. /// public Margin Margin { get { return _margin; } set { _margin = value; } } /// /// BaseDimension is a double precision value that sets "normal" pane size on /// which all the settings are based. The BaseDimension is in inches. For /// example, if the BaseDimension is 8.0 inches and the /// size is 14 points. Then the pane title font /// will be 14 points high when the is approximately 8.0 /// inches wide. If the Rect is 4.0 inches wide, the pane title font will be /// 7 points high. Most features of the graph are scaled in this manner. /// /// The base dimension reference for the , in inches /// /// /// public float BaseDimension { get { return _baseDimension; } set { _baseDimension = value; } } /// /// Gets or sets the gap between the bottom of the pane title and the /// client area of the pane. This is expressed as a fraction of the scaled /// character height. /// public float TitleGap { get { return _titleGap; } set { _titleGap = value; } } /// /// Determines if the font sizes, tic sizes, gap sizes, etc. will be scaled according to /// the size of the and the . If this /// value is set to false, then the font sizes and tic sizes will always be exactly as /// specified, without any scaling. /// /// True to have the fonts and tics scaled, false to have them constant /// public bool IsFontsScaled { get { return _isFontsScaled; } set { _isFontsScaled = value; } } /// /// Gets or sets the property that controls whether or not pen widths are scaled for this /// . /// /// This value is only applicable if /// is true. If is false, then no scaling will be done, /// regardless of the value of . Note that scaling the pen /// widths can cause "artifacts" to appear at typical screen resolutions. This occurs /// because of roundoff differences; in some cases the pen width may round to 1 pixel wide /// and in another it may round to 2 pixels wide. The result is typically undesirable. /// Therefore, this option defaults to false. This option is primarily useful for high /// resolution output, such as printer output or high resolution bitmaps (from /// ) where it is desirable to have the pen width /// be consistent with the screen image. /// /// true to scale the pen widths according to the size of the graph, /// false otherwise. /// /// public bool IsPenWidthScaled { get { return _isPenWidthScaled; } set { _isPenWidthScaled = value; } } #endregion #region Constructors /// /// Default constructor for the class. Leaves the empty. /// public PaneBase() : this( "", new RectangleF( 0, 0, 0, 0 ) ) { } /// /// Default constructor for the class. Specifies the of /// the , and the size of the . /// public PaneBase( string title, RectangleF paneRect ) { _rect = paneRect; _legend = new Legend(); _baseDimension = Default.BaseDimension; _margin = new Margin(); _titleGap = Default.TitleGap; _isFontsScaled = Default.IsFontsScaled; _isPenWidthScaled = Default.IsPenWidthScaled; _fill = new Fill( Default.FillColor ); _border = new Border( Default.IsBorderVisible, Default.BorderColor, Default.BorderPenWidth ); _title = new GapLabel( title, Default.FontFamily, Default.FontSize, Default.FontColor, Default.FontBold, Default.FontItalic, Default.FontUnderline ); _title._fontSpec.Fill.IsVisible = false; _title._fontSpec.Border.IsVisible = false; _graphObjList = new GraphObjList(); _tag = null; } /// /// The Copy Constructor /// /// The object from which to copy public PaneBase( PaneBase rhs ) { // copy over all the value types _isFontsScaled = rhs._isFontsScaled; _isPenWidthScaled = rhs._isPenWidthScaled; _titleGap = rhs._titleGap; _baseDimension = rhs._baseDimension; _margin = rhs._margin.Clone(); _rect = rhs._rect; // Copy the reference types by cloning _fill = rhs._fill.Clone(); _border = rhs._border.Clone(); _title = rhs._title.Clone(); _legend = rhs.Legend.Clone(); _title = rhs._title.Clone(); _graphObjList = rhs._graphObjList.Clone(); if ( rhs._tag is ICloneable ) _tag = ((ICloneable) rhs._tag).Clone(); else _tag = rhs._tag; } //abstract public object ShallowClone(); /// /// Implement the interface in a typesafe manner by just /// calling the typed version of Clone /// /// /// Note that this method must be called with an explicit cast to ICloneable, and /// that it is inherently virtual. For example: /// /// ParentClass foo = new ChildClass(); /// ChildClass bar = (ChildClass) ((ICloneable)foo).Clone(); /// /// 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. /// /// A deep copy of this object object ICloneable.Clone() { throw new NotImplementedException( "Can't clone an abstract base type -- child types must implement ICloneable" ); //return new PaneBase( this ); } /// /// Create a shallow, memberwise copy of this class. /// /// /// Note that this method uses MemberWiseClone, which will copy all /// members (shallow) including those of classes derived from this class. /// a new copy of the class public PaneBase ShallowClone() { // return a shallow copy return this.MemberwiseClone() as PaneBase; } #endregion #region Serialization /// /// Current schema value that defines the version of the serialized file /// // schema changed to 2 when Label Class added public const int schema = 10; /// /// Constructor for deserializing objects /// /// A instance that defines the serialized data /// /// A instance that contains the serialized data /// protected PaneBase( 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" ); _rect = (RectangleF) info.GetValue( "rect", typeof(RectangleF) ); _legend = (Legend) info.GetValue( "legend", typeof(Legend) ); _title = (GapLabel) info.GetValue( "title", typeof(GapLabel) ); //this.isShowTitle = info.GetBoolean( "isShowTitle" ); _isFontsScaled = info.GetBoolean( "isFontsScaled" ); _isPenWidthScaled = info.GetBoolean( "isPenWidthScaled" ); //this.fontSpec = (FontSpec) info.GetValue( "fontSpec" , typeof(FontSpec) ); _titleGap = info.GetSingle( "titleGap" ); _fill = (Fill) info.GetValue( "fill", typeof(Fill) ); _border = (Border) info.GetValue( "border", typeof(Border) ); _baseDimension = info.GetSingle( "baseDimension" ); _margin = (Margin)info.GetValue( "margin", typeof( Margin ) ); _graphObjList = (GraphObjList) info.GetValue( "graphObjList", typeof(GraphObjList) ); _tag = info.GetValue( "tag", typeof(object) ); } /// /// 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( "rect", _rect ); info.AddValue( "legend", _legend ); info.AddValue( "title", _title ); //info.AddValue( "isShowTitle", isShowTitle ); info.AddValue( "isFontsScaled", _isFontsScaled ); info.AddValue( "isPenWidthScaled", _isPenWidthScaled ); info.AddValue( "titleGap", _titleGap ); //info.AddValue( "fontSpec", fontSpec ); info.AddValue( "fill", _fill ); info.AddValue( "border", _border ); info.AddValue( "baseDimension", _baseDimension ); info.AddValue( "margin", _margin ); info.AddValue( "graphObjList", _graphObjList ); info.AddValue( "tag", _tag ); } #endregion #region Methods /// /// Do all rendering associated with this to the specified /// device. This abstract method is implemented by the child /// classes. /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// public virtual void Draw( Graphics g ) { if ( _rect.Width <= 1 || _rect.Height <= 1 ) return; // calculate scaleFactor on "normal" pane size (BaseDimension) float scaleFactor = this.CalcScaleFactor(); // Fill the pane background and draw a border around it DrawPaneFrame( g, scaleFactor ); // Clip everything to the rect g.SetClip( _rect ); // Draw the GraphItems that are behind everything _graphObjList.Draw( g, this, scaleFactor, ZOrder.H_BehindAll ); // Draw the Pane Title DrawTitle( g, scaleFactor ); // Draw the Legend //this.Legend.Draw( g, this, scaleFactor ); // Reset the clipping g.ResetClip(); } /// /// Calculate the client area rectangle based on the . /// /// The client rectangle is the actual area available for /// or items after taking out space for the margins and the title. /// This method does not take out the area required for the . /// To do so, you must separately call . /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// /// 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. /// /// The calculated chart rect, in pixel coordinates. public RectangleF CalcClientRect( Graphics g, float scaleFactor ) { // get scaled values for the paneGap and character height //float scaledOuterGap = (float) ( Default.OuterPaneGap * scaleFactor ); float charHeight = _title._fontSpec.GetHeight( scaleFactor ); // chart rect starts out at the full pane rect. It gets reduced to make room for the legend, // scales, titles, etc. RectangleF innerRect = new RectangleF( _rect.Left + _margin.Left * scaleFactor, _rect.Top + _margin.Top * scaleFactor, _rect.Width - scaleFactor * ( _margin.Left + _margin.Right ), _rect.Height - scaleFactor * ( _margin.Top + _margin.Bottom ) ); // Leave room for the title if ( _title._isVisible && _title._text != string.Empty ) { SizeF titleSize = _title._fontSpec.BoundingBox( g, _title._text, scaleFactor ); // Leave room for the title height, plus a line spacing of charHeight * _titleGap innerRect.Y += titleSize.Height + charHeight * _titleGap; innerRect.Height -= titleSize.Height + charHeight * _titleGap; } // Calculate the legend rect, and back it out of the current ChartRect //this.legend.CalcRect( g, this, scaleFactor, ref innerRect ); return innerRect; } /// /// Draw the border _border around the area. /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// /// 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. /// public void DrawPaneFrame( Graphics g, float scaleFactor ) { // Erase the pane background, filling it with the specified brush _fill.Draw( g, _rect ); // Reduce the rect width and height by 1 pixel so that for a rect of // new RectangleF( 0, 0, 100, 100 ), which should be 100 pixels wide, we cover // from 0 through 99. The draw routines normally cover from 0 through 100, which is // actually 101 pixels wide. RectangleF rect = new RectangleF( _rect.X, _rect.Y, _rect.Width - 1, _rect.Height - 1 ); _border.Draw( g, this, scaleFactor, rect ); } /// /// Draw the on the graph, centered at the top of the pane. /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// /// 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. /// public void DrawTitle( Graphics g, float scaleFactor ) { // only draw the title if it's required if ( _title._isVisible ) { SizeF size = _title._fontSpec.BoundingBox( g, _title._text, scaleFactor ); // use the internal fontSpec class to draw the text using user-specified and/or // default attributes. _title._fontSpec.Draw( g, this, _title._text, ( _rect.Left + _rect.Right ) / 2, _rect.Top + _margin.Top * (float) scaleFactor + size.Height / 2.0F, AlignH.Center, AlignV.Center, scaleFactor ); } } /// /// Change the size of the . Override this method to handle resizing the contents /// as required. /// /// /// A graphic device object to be drawn into. This is normally e.Graphics from the /// PaintEventArgs argument to the Paint() method. /// /// The new size for the . public virtual void ReSize( Graphics g, RectangleF rect ) { _rect = rect; } /// /// Calculate the scaling factor based on the ratio of the current dimensions and /// the . /// /// This scaling factor is used to proportionally scale the /// features of the so that small graphs don't have huge fonts, and vice versa. /// The scale factor represents a linear multiple to be applied to font sizes, symbol sizes, tic sizes, /// gap sizes, pen widths, etc. The units of the scale factor are "World Pixels" per "Standard Point". /// If any object size, in points, is multiplied by this scale factor, the result is the size, in pixels, /// that the object should be drawn using the standard GDI+ drawing instructions. A "Standard Point" /// is a dimension based on points (1/72nd inch) assuming that the size /// matches the . /// Note that "World Pixels" will still be transformed by the GDI+ transform matrices to result /// in "Output Device Pixels", but "World Pixels" are the reference basis for the drawing commands. /// /// /// A value representing the scaling factor to use for the rendering calculations. /// /// public float CalcScaleFactor() { float scaleFactor; //, xInch, yInch; const float ASPECTLIMIT = 1.5F; // if font scaling is turned off, then always return a 1.0 scale factor if ( !_isFontsScaled ) return 1.0f; // Assume the standard width (BaseDimension) is 8.0 inches // Therefore, if the rect is 8.0 inches wide, then the fonts will be scaled at 1.0 // if the rect is 4.0 inches wide, the fonts will be half-sized. // if the rect is 16.0 inches wide, the fonts will be double-sized. // Scale the size depending on the client area width in linear fashion if ( _rect.Height <= 0 ) return 1.0F; float length = _rect.Width; float aspect = _rect.Width / _rect.Height; if ( aspect > ASPECTLIMIT ) length = _rect.Height * ASPECTLIMIT; if ( aspect < 1.0F / ASPECTLIMIT ) length = _rect.Width * ASPECTLIMIT; scaleFactor = length / ( _baseDimension * 72F ); // Don't let the scaleFactor get ridiculous if ( scaleFactor < 0.1F ) scaleFactor = 0.1F; return scaleFactor; } /// /// Calculate the scaled pen width, taking into account the scaleFactor and the /// setting of the property of the pane. /// /// The pen width, in points (1/72 inch) /// /// 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. /// /// The scaled pen width, in world pixels public float ScaledPenWidth( float penWidth, float scaleFactor ) { if ( _isPenWidthScaled ) return (float)( penWidth * scaleFactor ); else return penWidth; } /// /// Build a object containing the graphical rendering of /// all the objects in this list. /// /// A object rendered with the current graph. /// /// /// public Bitmap GetImage() { Bitmap bitmap = new Bitmap( (int)_rect.Width, (int)_rect.Height ); using ( Graphics bitmapGraphics = Graphics.FromImage( bitmap ) ) { bitmapGraphics.TranslateTransform( -_rect.Left, -_rect.Top ); this.Draw( bitmapGraphics ); } return bitmap; } /// /// Gets an image for the current GraphPane, scaled to the specified size and resolution. /// /// The scaled width of the bitmap in pixels /// The scaled height of the bitmap in pixels /// The resolution of the bitmap, in dots per inch /// /// /// /// public Bitmap GetImage( int width, int height, float dpi ) { Bitmap bitmap = new Bitmap( width, height ); bitmap.SetResolution( dpi, dpi ); using ( Graphics bitmapGraphics = Graphics.FromImage( bitmap ) ) { MakeImage( bitmapGraphics, width, height ); } return bitmap; } private void MakeImage( Graphics g, int width, int height ) { //g.SmoothingMode = SmoothingMode.AntiAlias; // This is actually a shallow clone, so we don't duplicate all the data, curveLists, etc. PaneBase tempPane = this.ShallowClone(); // Clone the Chart object for GraphPanes so we don't mess up the minPix and maxPix values or // the rect/ChartRect calculations of the original //RectangleF saveRect = new RectangleF(); //if ( this is GraphPane ) // saveRect = ( this as GraphPane ).Chart.Rect; tempPane.ReSize( g, new RectangleF( 0, 0, width, height ) ); tempPane.Draw( g ); //if ( this is GraphPane ) //{ // GraphPane gPane = this as GraphPane; // gPane.Chart.Rect = saveRect; // gPane.XAxis.Scale.SetupScaleData( gPane, gPane.XAxis ); // foreach ( Axis axis in gPane.YAxisList ) // axis.Scale.SetupScaleData( gPane, axis ); // foreach ( Axis axis in gPane.Y2AxisList ) // axis.Scale.SetupScaleData( gPane, axis ); //} // To restore all the various state variables, you must redraw the graph in it's // original form. For this we create a 1x1 bitmap (it doesn't matter what size you use, // since we're only mimicing the draw. If you use the 'bitmapGraphics' already created, // then you will be drawing back into the bitmap that will be returned. Bitmap bm = new Bitmap( 1, 1 ); using ( Graphics bmg = Graphics.FromImage( bm ) ) { this.ReSize( bmg, this.Rect ); this.Draw( bmg ); } } /// /// Gets an enhanced metafile image for the current GraphPane, scaled to the specified size. /// /// /// By definition, a Metafile is a vector drawing, and therefore scaling should not matter. /// However, this method is provided because certain options in Zedgraph, such as /// are affected by the size of the expected image. /// /// The "effective" scaled width of the bitmap in pixels /// The "effective" scaled height of the bitmap in pixels /// /// /// public Metafile GetMetafile( int width, int height ) { Bitmap bm = new Bitmap( 1, 1 ); using ( Graphics g = Graphics.FromImage( bm ) ) { IntPtr hdc = g.GetHdc(); Stream stream = new MemoryStream(); Metafile metafile = new Metafile( stream, hdc, _rect, MetafileFrameUnit.Pixel, EmfType.EmfPlusDual ); g.ReleaseHdc( hdc ); using ( Graphics metafileGraphics = Graphics.FromImage( metafile ) ) { //metafileGraphics.TranslateTransform( -_rect.Left, -_rect.Top ); metafileGraphics.PageUnit = System.Drawing.GraphicsUnit.Pixel; PointF P = new PointF( width, height ); PointF[] PA = new PointF[] { P }; metafileGraphics.TransformPoints( CoordinateSpace.Page, CoordinateSpace.Device, PA ); //metafileGraphics.PageScale = 1f; // output MakeImage( metafileGraphics, width, height ); //this.Draw( metafileGraphics ); return metafile; } } } /// /// Gets an enhanced metafile image for the current GraphPane. /// /// /// /// public Metafile GetMetafile() { Bitmap bm = new Bitmap( 1, 1 ); using ( Graphics g = Graphics.FromImage( bm ) ) { IntPtr hdc = g.GetHdc(); Stream stream = new MemoryStream(); Metafile metafile = new Metafile( stream, hdc, _rect, MetafileFrameUnit.Pixel, EmfType.EmfOnly ); using ( Graphics metafileGraphics = Graphics.FromImage( metafile ) ) { metafileGraphics.TranslateTransform( -_rect.Left, -_rect.Top ); metafileGraphics.PageUnit = System.Drawing.GraphicsUnit.Pixel; PointF P = new PointF( _rect.Width, _rect.Height ); PointF[] PA = new PointF[] { P }; metafileGraphics.TransformPoints( CoordinateSpace.Page, CoordinateSpace.Device, PA ); //metafileGraphics.PageScale = 1f; // output this.Draw( metafileGraphics ); g.ReleaseHdc( hdc ); return metafile; } } } /* System.Drawing.Imaging.Metafile metafile = null; // create a Metafile object that is compatible with the surface of this // form using ( Graphics graphics = this.CreateGraphics() ) { System.IntPtr hdc = graphics.GetHdc(); metafile = new Metafile(filename, hdc, new Rectangle( 0, 0, (((int) this.ClientRectangle.Width)), (((int) this.ClientRectangle.Height ))), MetafileFrameUnit.Point ); graphics.ReleaseHdc( hdc ); } // draw to the metafile using ( Graphics metafileGraphics = Graphics.FromImage( metafile ) ) { metafileGraphics.PageUnit=System.Drawing.GraphicsUnit.Point; PointF P=new Point(this.ClientRectangle.Width,this.ClientRectangle.Height); PointF[] PA=new PointF[]{P}; metafileGraphics.TransformPoints(CoordinateSpace.Page, CoordinateSpace.Device, PA); metafileGraphics.PageScale=1f; metafileGraphics.SmoothingMode = SmoothingMode.AntiAlias; // smooth the // output this.masterPane.Draw( metafileGraphics ); metafileGraphics.DrawRectangle(new System.Drawing.Pen( Color.Gray),this.ClientRectangle); metafile.Dispose(); } return true; } else { return false; } } else { //no directory given return false; } */ /* /// /// Function to export the Diagram as WMF file /// see http://www.codeproject.com/showcase/pdfrasterizer.asp?print=true /// /// /// filename is the name to export to /// public bool ExporttoWmf( string filename ) { string p; //FileInfo TheFile = new FileInfo(filename); p = Path.GetDirectoryName( filename ); if ( p != "" ) { DirectoryInfo TheDir = new DirectoryInfo( p ); if ( TheDir.Exists ) { System.Drawing.Imaging.Metafile metafile = null; // create a Metafile object that is compatible with the surface of this // form using ( Graphics graphics = this.CreateGraphics() ) { System.IntPtr hdc = graphics.GetHdc(); metafile = new Metafile( filename, hdc, new Rectangle( 0, 0, ( ( (int)this.ClientRectangle.Width ) ), ( ( (int)this.ClientRectangle.Height ) ) ), MetafileFrameUnit.Point ); graphics.ReleaseHdc( hdc ); } // draw to the metafile using ( Graphics metafileGraphics = Graphics.FromImage( metafile ) ) { metafileGraphics.PageUnit = System.Drawing.GraphicsUnit.Point; PointF P = new Point( this.ClientRectangle.Width, this.ClientRectangle.Height ); PointF[] PA = new PointF[] { P }; metafileGraphics.TransformPoints( CoordinateSpace.Page, CoordinateSpace.Device, PA ); metafileGraphics.PageScale = 1f; metafileGraphics.SmoothingMode = SmoothingMode.AntiAlias; // smooth the // output this.masterPane.Draw( metafileGraphics ); metafileGraphics.DrawRectangle( new System.Drawing.Pen( Color.Gray ), this.ClientRectangle ); metafile.Dispose(); } return true; } else { return false; } } else { //no directory given return false; } } */ internal PointF TransformCoord( double x, double y, CoordType coord ) { // If the Transformation is an illegal type, just stick it in the middle if ( !( this is GraphPane ) && !( coord == CoordType.PaneFraction ) ) { coord = CoordType.PaneFraction; x = 0.5; y = 0.5; } // Just to save some casts GraphPane gPane = null; RectangleF chartRect = new RectangleF( 0, 0, 1, 1 ); if ( this is GraphPane ) { gPane = this as GraphPane; chartRect = gPane.Chart._rect; } PointF ptPix = new PointF(); if ( coord == CoordType.ChartFraction ) { ptPix.X = (float)( chartRect.Left + x * chartRect.Width ); ptPix.Y = (float)( chartRect.Top + y * chartRect.Height ); } else if ( coord == CoordType.AxisXYScale ) { ptPix.X = gPane.XAxis.Scale.Transform( x ); ptPix.Y = gPane.YAxis.Scale.Transform( y ); } else if ( coord == CoordType.AxisXY2Scale ) { ptPix.X = gPane.XAxis.Scale.Transform( x ); ptPix.Y = gPane.Y2Axis.Scale.Transform( y ); } else if ( coord == CoordType.XScaleYChartFraction ) { ptPix.X = gPane.XAxis.Scale.Transform( x ); ptPix.Y = (float)( chartRect.Top + y * chartRect.Height ); } else if ( coord == CoordType.XChartFractionYScale ) { ptPix.X = (float)( chartRect.Left + x * chartRect.Width ); ptPix.Y = gPane.YAxis.Scale.Transform( y ); } else if ( coord == CoordType.XChartFractionY2Scale ) { ptPix.X = (float)( chartRect.Left + x * chartRect.Width ); ptPix.Y = gPane.Y2Axis.Scale.Transform( y ); } else if ( coord == CoordType.XChartFractionYPaneFraction ) { ptPix.X = (float)( chartRect.Left + x * chartRect.Width ); ptPix.Y = (float)( this.Rect.Top + y * _rect.Height ); } else if ( coord == CoordType.XPaneFractionYChartFraction ) { ptPix.X = (float)( this.Rect.Left + x * _rect.Width ); ptPix.Y = (float)( chartRect.Top + y * chartRect.Height ); } else // PaneFraction { ptPix.X = (float)( _rect.Left + x * _rect.Width ); ptPix.Y = (float)( _rect.Top + y * _rect.Height ); } return ptPix; } #endregion } }