Menu

#18 IsDrawFrameBoder, IsReversed e.a.

closed
nobody
None
5
2015-02-27
2007-01-04
Carel
No

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


- Draw Frame Border Option (PaneBase.cs)

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);
    }
}

- Forward and Backward iterators, used when rendering Legend (CurveList.cs)

#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

- Render Reversal Option (Legend.cs)

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 );
}

- (ZedGraphWebData.cs)

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; }
}

- (ZedGraphWeb.cs)

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

- the end

Discussion

  • John Champion

    John Champion - 2007-01-05

    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

     
  • Carel

    Carel - 2007-01-06

    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.

     

Log in to post a comment.