Hi John, here are my modifications on 5.0.2 to
PaneBase.cs CurveList.cs Legend.cs ZedGraphWeb.cs ZedGraphWebData.cs
search for CJBL, DrawFrameBorder, Backward, sReversed to locate changes
I have copied the full methods below and marked them
added field _isDrawFrameBorder to PaneBase:
/// <summary> /// CJBL /// Private field that controls whether or not a frame border is drawn around the /// graph. /// </summary> /// <value>true (default) to draw the frame border, /// false otherwise.</value> protected bool _isDrawFrameBorder;
added default for _isDrawFrameBorder to PaneBase:
/// <summary> /// CJBL /// Private field that controls whether or not a frame border is drawn around the /// graph. /// </summary> /// <value>true (default) to draw the frame border, /// false otherwise.</value> public static bool IsDrawFrameBorder = true;
added property for _isDrawFrameBorder to PaneBase:
/// <summary> /// CJBL /// Private field that controls whether or not a frame border is drawn around the /// graph. /// </summary> /// <value>true (default) to draw the frame border, /// false otherwise.</value> public bool IsDrawFrameBorder { get { return _isDrawFrameBorder; } set { _isDrawFrameBorder = value; } }
added assignment of default in constructor:
/// <summary> /// Default constructor for the <see cref="PaneBase"/> class. Specifies the <see cref="Title"/> of /// the <see cref="PaneBase"/>, and the size of the <see cref="Rect"/>. /// </summary> public PaneBase( string title, RectangleF paneRect ) { _rect = paneRect; _legend = new Legend(); _baseDimension = Default.BaseDimension; _margin = new Margin(); _titleGap = Default.TitleGap; _isFontsScaled = Default.IsFontsScaled; _isDrawFrameBorder = Default.IsDrawFrameBorder; //CJBL _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; }
added copy assignment to copy constructor:
/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The <see cref="PaneBase"/> object from which to copy</param> public PaneBase( PaneBase rhs ) { // copy over all the value types _isFontsScaled = rhs._isFontsScaled; _isDrawFrameBorder = rhs._isDrawFrameBorder; //CJBL _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; }
added this attribute to serialization/deserialization:
/// <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 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" ); _isDrawFrameBorder = info.GetBoolean("isDrawFrameBorder"); //CJBL _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) ); } /// <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( "rect", _rect ); info.AddValue( "legend", _legend ); info.AddValue( "title", _title ); //info.AddValue( "isShowTitle", isShowTitle ); info.AddValue( "isFontsScaled", _isFontsScaled ); info.AddValue("isDrawFrameBorder", _isDrawFrameBorder); //CJBL 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 ); }
and finally used this attribute in DrawPaneFRame:
/// <summary> /// Draw the border _border around the <see cref="Rect"/> area. /// </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="scaleFactor"> /// The scaling factor for the features of the graph based on the <see cref="BaseDimension"/>. This /// scaling factor is calculated by the <see cref="CalcScaleFactor"/> method. The scale factor /// represents a linear multiple to be applied to font sizes, symbol sizes, etc. /// </param> 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. if (_isDrawFrameBorder) //CJBL { RectangleF rect = new RectangleF(_rect.X, _rect.Y, _rect.Width - 1, _rect.Height - 1); _border.Draw(g, IsPenWidthScaled, scaleFactor, rect); } }
#region IEnumerable Methods //CJBL public IEnumerable<CurveItem> Backward { get { for (int i = this.Count - 1; i >= 0; i--) yield return this[i]; } } public IEnumerable<CurveItem> Forward { get { for (int i = 0; i < this.Count; i++) yield return this[i]; } } #endregion
added field _isReversed to Legend:
/// <summary> /// CJBL /// Private field to select output order of legend entries. /// </summary> private bool _isReversed;
added default IsReversed to Legend:
/// <summary> /// CJBL /// </summary> public static bool IsReversed = false;
added property IsReversed to Legend:
/// <summary> /// CJBL /// </summary> public bool IsReversed { get { return _isReversed; } set { _isReversed = value; } }
assigned default in constructor:
/// <summary> /// Default constructor that sets all <see cref="Legend"/> properties to default /// values as defined in the <see cref="Default"/> class. /// </summary> public Legend() { _position = Default.Position; _isHStack = Default.IsHStack; _isVisible = Default.IsVisible; this.Location = new Location( 0, 0, CoordType.PaneFraction ); _fontSpec = new FontSpec( Default.FontFamily, Default.FontSize, Default.FontColor, Default.FontBold, Default.FontItalic, Default.FontUnderline, Default.FontFillColor, Default.FontFillBrush, Default.FontFillType ); _fontSpec.Border.IsVisible = false; _border = new Border( Default.IsBorderVisible, Default.BorderColor, Default.BorderWidth ); _fill = new Fill( Default.FillColor, Default.FillBrush, Default.FillType ); _gap = Default.Gap; _isReversed = Default.IsReversed; //CJBL }
copied it in copy constructor:
/// <summary> /// The Copy Constructor /// </summary> /// <param name="rhs">The XAxis object from which to copy</param> public Legend( Legend rhs ) { _rect = rhs.Rect; _position = rhs.Position; _isHStack = rhs.IsHStack; _isVisible = rhs.IsVisible; _location = rhs.Location; _border = rhs.Border.Clone(); _fill = rhs.Fill.Clone(); _fontSpec = rhs.FontSpec.Clone(); _gap = rhs._gap; _isReversed = rhs._isReversed; //CJBL }
added this attribute to serialization/deserialization:
/// <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 Legend( 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" ); _position = (LegendPos) info.GetValue( "position", typeof(LegendPos) ); _isHStack = info.GetBoolean( "isHStack" ); _isVisible = info.GetBoolean( "isVisible" ); _fill = (Fill) info.GetValue( "fill", typeof(Fill) ); _border = (Border) info.GetValue( "border", typeof(Border) ); _fontSpec = (FontSpec) info.GetValue( "fontSpec", typeof(FontSpec) ); _location = (Location) info.GetValue( "location", typeof(Location) ); _gap = info.GetSingle( "gap" ); _isReversed = info.GetBoolean("_isReversed"); //CJBL } /// <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( "position", _position ); info.AddValue( "isHStack", _isHStack ); info.AddValue( "isVisible", _isVisible ); info.AddValue( "fill", _fill ); info.AddValue( "border", _border ); info.AddValue( "fontSpec", _fontSpec ); info.AddValue( "location", _location ); info.AddValue( "gap", _gap ); info.AddValue( "isReversed", _isReversed); //CJBL }
added a private method to the render region that gives the iterator depending on the attribute
//CJBL private IEnumerable<CurveItem> GetIterator(CurveList c, bool forward) { if (forward) { return c.Forward; } else { return c.Backward; } }
used in Draw():
/// <summary> /// Render the <see cref="Legend"/> to the specified <see cref="Graphics"/> device. /// </summary> /// <remarks> /// This method is normally only called by the Draw method /// of the parent <see cref="GraphPane"/> object. /// </remarks> /// <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="pane"> /// A reference to the <see cref="PaneBase"/> object that is the parent or /// owner of this object. /// </param> /// <param name="scaleFactor"> /// The scaling factor to be used for rendering objects. This is calculated and /// passed down by the parent <see cref="GraphPane"/> object using the /// <see cref="PaneBase.CalcScaleFactor"/> method, and is used to proportionally adjust /// font sizes, etc. according to the actual size of the graph. /// </param> public void Draw( Graphics g, PaneBase pane, float scaleFactor ) { // if the legend is not visible, do nothing if ( ! _isVisible ) return; // Fill the background with the specified color if required _fill.Draw( g, _rect ); PaneList paneList = GetPaneList( pane ); float halfGap = _tmpSize / 2.0F; // Check for bad data values if ( _hStack <= 0 ) _hStack = 1; if ( _legendItemWidth <= 0 ) _legendItemWidth = 100; if ( _legendItemHeight <= 0 ) _legendItemHeight = _tmpSize; //float gap = pane.ScaledGap( scaleFactor ); int iEntry = 0; float x, y; // Get a brush for the legend label text SolidBrush brushB = new SolidBrush( Color.Black ); foreach ( GraphPane tmpPane in paneList ) { foreach (CurveItem curve in GetIterator(tmpPane.CurveList, _isReversed)) //CJBL { if (curve._label._text != "" && curve._label._isVisible) { // Calculate the x,y (TopLeft) location of the current // curve legend label // assuming: // charHeight/2 for the left margin, plus legendWidth for each // horizontal column // legendHeight is the line spacing, with no extra margin above x = _rect.Left + halfGap / 2.0F + (iEntry % _hStack) * _legendItemWidth; y = _rect.Top + (int)(iEntry / _hStack) * _legendItemHeight; // Draw the legend label for the current curve FontSpec tmpFont = (curve._label._fontSpec != null) ? curve._label._fontSpec : this.FontSpec; tmpFont.Draw(g, pane.IsPenWidthScaled, curve._label._text, x + 2.5F * _tmpSize, y + _legendItemHeight / 2.0F, AlignH.Left, AlignV.Center, scaleFactor); RectangleF rect = new RectangleF(x, y + _legendItemHeight / 4.0F, 2 * _tmpSize, _legendItemHeight / 2.0F); curve.DrawLegendKey(g, tmpPane, rect, scaleFactor); // maintain a curve count for positioning iEntry++; } //} } if ( pane is MasterPane && ((MasterPane)pane).IsUniformLegendEntries ) break ; } // Draw a border around the legend if required if ( iEntry > 0 ) this.Border.Draw( g, pane.IsPenWidthScaled, scaleFactor, _rect ); }
added IsReversed to ZedGraphWebLegend default and copy constructors:
/// <summary> /// Default constructor /// </summary> public ZedGraphWebLegend() : base() { //Register( 'r', typeof( ZedGraphWebRect ) ); Register( 'F', typeof( ZedGraphWebFontSpec ) ); Register( 'b', typeof( ZedGraphWebBorder ) ); Register( 'f', typeof( ZedGraphWebFill ) ); Register( 'l', typeof( ZedGraphWebLocation ) ); this.Border.Color = Legend.Default.BorderColor; this.Border.PenWidth = Legend.Default.BorderWidth; this.Border.IsVisible = Legend.Default.IsBorderVisible; this.Fill.Brush = Legend.Default.FillBrush; this.Fill.Color = Legend.Default.FillColor; this.Fill.Type = Legend.Default.FillType; this.FontSpec.IsBold = Legend.Default.FontBold; this.FontSpec.FontColor = Legend.Default.FontColor; this.FontSpec.Family = Legend.Default.FontFamily; this.FontSpec.Fill.Brush = Legend.Default.FontFillBrush; this.FontSpec.Fill.Color = Legend.Default.FontFillColor; this.FontSpec.IsItalic = Legend.Default.FontItalic; this.FontSpec.Size = Legend.Default.FontSize; this.IsReversed = Legend.Default.IsReversed; //CJBL } /// <summary> /// Copy the properties of this <see cref="ZedGraphWebLegend"/> to the specified /// <see cref="ZedGraph.Legend"/> object. /// </summary> /// <param name="item">The destination <see cref="ZedGraph.Legend"/> object</param> internal void CopyTo(Legend item) { item.IsVisible = this.IsVisible; item.Position = this.Position; item.IsHStack = this.IsHStack; item.IsReversed = this.IsReversed; //CJBL //this.Rect.CopyTo( item.Rect ); this.FontSpec.CopyTo(item.FontSpec); this.Border.CopyTo(item.Border); this.Fill.CopyTo(item.Fill); this.Location.CopyTo(item.Location); }
added a property to ZedGraphWebLegend for IsReversed:
/// <summary> /// CJBL /// Proxy property that gets or sets the value of <see cref="ZedGraph.Legend.IsReversed"/> /// </summary> [ NotifyParentProperty(true), Description("True to reverse order of legend items") ] public bool IsReversed { get { object x = ViewState["IsReversed"]; return (null == x) ? Legend.Default.IsReversed : (bool)x; } set { ViewState["IsReversed"] = value; } }
added an IsDrawFrameBorder view state property to GraphPane:
/// <summary> /// CJBL /// Proxy property that gets or sets the value of <see cref="PaneBase.IsDrawFrameBorder"/>. /// </summary> [ Bindable(true), Category("GraphPane"), NotifyParentProperty(true), Description("true to draw the frame border") ] public bool IsDrawFrameBorder { get { object x = ViewState["IsDrawFrameBorder"]; return (null == x) ? true : (bool)x; } set { ViewState["IsDrawFrameBorder"] = value; } }
added an assignment for IsDrawFrameBorder in SetWebProperties:
/// <summary> /// Adds content to the <see cref="GraphPane"/> instance based on the web controls state elements. /// This requires applying each <see cref="ZedGraphWebCurveItem"/> to the <see cref="GraphPane"/> /// including all the values and sub objects. /// </summary> /// <param name="g"><see cref="Graphics"/></param> /// <param name="pane"><see cref="GraphPane"/></param> protected void SetWebProperties( Graphics g, GraphPane pane ) { try { pane.Title.IsVisible = this.IsShowTitle; pane.BarSettings.Type = this.BarType; XAxis.CopyTo( pane.XAxis ); YAxis.CopyTo( pane.YAxis ); Y2Axis.CopyTo( pane.Y2Axis ); pane.IsIgnoreInitial = this.IsIgnoreInitial; pane.IsIgnoreMissing = this.IsIgnoreMissing; pane.LineType = this.LineType; this.ChartBorder.CopyTo( pane.Chart.Border ); this.ChartFill.CopyTo( pane.Chart.Fill ); pane.BarSettings.MinClusterGap = this.MinClusterGap; pane.BarSettings.MinBarGap = this.MinBarGap; pane.BarSettings.Base = this.BarBase; this.Legend.CopyTo( pane.Legend ); this.FontSpec.CopyTo( pane.Title.FontSpec ); pane.Title.Text = this.Title; this.PaneBorder.CopyTo( pane.Border ); this.PaneFill.CopyTo( pane.Fill ); pane.Margin.Left = this.Margins.Left; pane.Margin.Right = this.Margins.Right; pane.Margin.Top = this.Margins.Top; pane.Margin.Bottom = this.Margins.Bottom; pane.BaseDimension = this.BaseDimension; pane.IsFontsScaled = this.IsFontsScaled; pane.IsPenWidthScaled = this.IsPenWidthScaled; pane.IsDrawFrameBorder = this.IsDrawFrameBorder; //CJBL } catch ( Exception ) { throw; } }
finally two other things I hacked together and for which no doubt better alternatives exist:
in MakeImageMap I append a point's Tag if string to the url that is passed to MakeAreaTag(...)
like this:
+ "&" + curve.Points[i].Tag
to suppress the image border I hacked this into Render():
output.AddAttribute( HtmlTextWriterAttribute.Border, "0"); //CJBL
Logged In: YES
user_id=957634
Originator: NO
Carel,
Thanks for submitting this. I've put the IsReverse property into the legend, posted the tags (if string) into the url, and set Border=0. One question:
Isn't IsDrawFrameBorder already implemented as pane.Border.IsVisible = false?
Thanks,
John
Logged In: YES
user_id=1682700
Originator: YES
Concerning IsDrawFrameBorder, in the version I looked at (5.0.2) a rect was drawn unconditionally (PaneBase::DrawPaneFrame). It might well be my change overlaps with a similar feature added to a later version.