#region copyright info
//
// Written by Anup. V (anupshubha@yahoo.com)
// Copyright (c) 2006.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is not sold for
// for profit without the authors written consent, and providing that
// this notice and the authors name is included. If the source code in
// this file is used in any commercial application then acknowledgement
// must be made to the author of this file (in whatever form you wish).
//
// This file is provided "as is" with no expressed or implied warranty.
//
// Please use and enjoy. Please let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into
// this file.
#endregion copyright info
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;
using System.Diagnostics;
using System.Globalization;
namespace GraphComponents
{
/// <summary>
/// Summary description for StackedBarGraph.
/// </summary>
public class StackedBarGraph : Graph
{
#region variables
/// <summary>
/// The left side margin width of the graph
/// </summary>
private int graphMarginLeft = 50;
/// <summary>
/// The upper margin width of the graph
/// </summary>
private int graphMarginTop = 20;
/// <summary>
/// The right side margin width of the graph
/// </summary>
private int graphMarginRight = 20;
/// <summary>
/// The lower margin width of the graph
/// </summary>
private int graphMarginBottom = 20;
/// <summary>
/// Maximum value of the bar
/// </summary>
private float maximumValue = 100;
/// <summary>
/// Minimum value of the bar
/// </summary>
private float minimumValue;
/// <summary>
/// Color of the bar
/// </summary>
private Color barColor = Color.Lime;
/// <summary>
/// The color to display if the value is above normal
/// </summary>
private Color aboveRangeColor = Color.Salmon;
/// <summary>
/// The color to display if the value is below normal
/// </summary>
private Color belowRangeColor = Color.Thistle;
/// <summary>
/// Bar orientation, whether horizontal or vertical
/// </summary>
private Orientation barOrientation = Orientation.Vertical;
/// <summary>
/// Color of the graph's border that includes only the area
/// that is filled up and not the entire rectangle
/// </summary>
private Color graphBorderColor = Color.Black;
/// <summary>
/// The alignment of the value text
/// </summary>
private TextAlignment valueAlignment = TextAlignment.Smart;
/// <summary>
/// The collection that contains all the individual bars
/// </summary>
private BarCollection barCollection;
/// <summary>
/// Used to draw the gridline
/// </summary>
private Gridline gridline;
/// <summary>
/// Used to draw the x and y axis line
/// </summary>
private AxisLine axisLineXandY;
private RectangleF aboveRangeRect;
private RectangleF belowRangeRect;
/// <summary>
/// Number of bars to display in the stacked bar graph
/// </summary>
private int barCount = 4;
/// <summary>
/// A ratio that defines the ratio between the width of each bar
/// to the spacing from its adjacent bar
/// </summary>
private float barWidthToSpacingRatio = 1;
/// <summary>
/// The basic bar object that does the actual rendering.
/// </summary>
private BasicBar basicBar;
/// <summary>
/// A value beyond which the readings are above normal.
/// The graph can be displayed in a different color if it
/// goes above this range
/// Eg. body temp. above 40 degree C
/// </summary>
private float aboveRangeValue = 70;
/// <summary>
/// A value beyond which the readings are below normal.
/// The graph can be displayed in a different color if it
/// goes below this range
/// Eg. body temp. below 35 degree C
private float belowRangeValue = 30;
/// <summary>
/// Flag indicating whether lines for above and below normal limits are to be displayed
/// </summary>
private bool showRangeLines = true;
/// <summary>
/// Flag indicating whether the values of above and below ranges are to be displayed
/// </summary>
private bool showRangeValues;
#endregion variables
#region properties
#region ShowRangeLines
/// <summary>
/// Flag indicating whether lines for above and below normal limits are to be displayed
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("Flag indicating whether lines for above and below normal limits are to be displayed")
]
public bool ShowRangeLines
{
get { return showRangeLines; }
set
{
showRangeLines = value;
RefreshDisplay ();
}
}
#endregion ShowRangeLines
#region ShowRangeValues
/// <summary>
/// Flag indicating whether the values of above and below ranges are to be displayed
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("Flag indicating whether the values of above and below ranges are to be displayed")
]
public bool ShowRangeValues
{
get { return showRangeValues; }
set
{
showRangeValues = value;
RefreshDisplay ();
}
}
#endregion ShowRangeValues
#region AboveRangeValue
/// <summary>
/// A value beyond which the readings are above normal.
/// The bar can be displayed in a different color if it
/// goes above this range
/// Eg. body temp. above 40 degree C
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("A value beyond which the readings are above normal. The bar can be displayed in a different color if it goes above this range.")
]
public float AboveRangeValue
{
get { return aboveRangeValue; }
set
{
aboveRangeValue = value;
RefreshDisplay ();
}
}
#endregion AboveRangeValue
#region BelowRangeValue
/// <summary>
/// A value beyond which the readings are below normal.
/// The bar can be displayed in a different color if it
/// goes below this range
/// Eg. body temp. below 35 degree C
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("A value beyond which the readings are below normal. The bar can be displayed in a different color if it goes below this range")
]
public float BelowRangeValue
{
get { return belowRangeValue; }
set
{
belowRangeValue = value;
RefreshDisplay ();
}
}
#endregion BelowRangeValue
#region Bars
[
Browsable(false)
]
public BarCollection Bars
{
get { return barCollection; }
}
#endregion Bars
#region GraphMargin
/// <summary>
/// The left side margin width of the graph
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("The left side margin width of the graph")
]
public int GraphMarginLeft
{
get { return graphMarginLeft; }
set
{
if (value < 0)
throw new ArgumentException ("Invalid property value. Margin cannot be negative.");
graphMarginLeft = value;
RefreshDisplay ();
}
}
/// <summary>
/// The upper margin width of the graph
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("The upper margin width of the graph")
]
public int GraphMarginTop
{
get { return graphMarginTop; }
set
{
if (value < 0)
throw new ArgumentException ("Invalid property value. Margin cannot be negative.");
graphMarginTop = value;
RefreshDisplay ();
}
}
/// <summary>
/// The right side margin width of the graph
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("The right side margin width of the graph")
]
public int GraphMarginRight
{
get { return graphMarginRight; }
set
{
if (value < 0)
throw new ArgumentException ("Invalid property value. Margin cannot be negative.");
graphMarginRight = value;
RefreshDisplay ();
}
}
/// <summary>
/// The lower margin width of the graph
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("The lower margin width of the graph")
]
public int GraphMarginBottom
{
get { return graphMarginBottom; }
set
{
if (value < 0)
throw new ArgumentException ("Invalid property value. Margin cannot be negative.");
graphMarginBottom = value;
RefreshDisplay ();
}
}
#endregion GraphMargin
#region AboveRangeColor
/// <summary>
/// The color to display if the value is above normal
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("The color to display if the value is above normal")
]
public Color AboveRangeColor
{
get { return aboveRangeColor; }
set
{
aboveRangeColor = value;
RefreshDisplay ();
}
}
#endregion AboveRangeColor
#region BelowRangeColor
/// <summary>
/// The color to display if the value is below normal
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("The color to display if the value is below normal")
]
public Color BelowRangeColor
{
get { return belowRangeColor; }
set
{
belowRangeColor = value;
RefreshDisplay ();
}
}
#endregion BelowRangeColor
#region MaximumValue
/// <summary>
/// Maximum value of the bar
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("Maximum value of the bar")
]
public float MaximumValue
{
get { return maximumValue; }
set
{
maximumValue = value;
RefreshDisplay ();
}
}
#endregion MaximumValue
#region MinimumValue
/// <summary>
/// Minimum value of the bar
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("Minimum value of the bar")
]
public float MinimumValue
{
get { return minimumValue; }
set
{
minimumValue = value;
RefreshDisplay ();
}
}
#endregion MinimumValue
#region BarColor
/// <summary>
/// Color of the bar
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("Color of the bar")
]
public Color BarColor
{
get { return barColor; }
set
{
barColor = value;
RefreshDisplay ();
}
}
#endregion BarColor
#region BarWidthToSpacingRatio
/// <summary>
/// A ratio that defines the ratio between the width
/// of each bar to the spacing from its adjacent bar
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
NotifyParentProperty(true),
Category("Appearance"),
Description("A ratio that defines the ratio between the width of each bar to the spacing from its adjacent bar")
]
public float BarWidthToSpacingRatio
{
get { return barWidthToSpacingRatio; }
set
{
if (value <= 0)
throw new ArgumentException ("Invalid property value. Ratio has to be greater than 0.");
barWidthToSpacingRatio = value;
RefreshDisplay ();
}
}
#endregion BarWidthToSpacingRatio
#region BarCount
/// <summary>
/// Number of bars to display on the stacked bar graph
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("Number of bars to display on the stacked bar graph")
]
public int BarCount
{
get { return barCount; }
set
{
if (value < 0)
throw new ArgumentException ("Invalid property value. Bar count cannot be negative.");
if (barCount < value)
{
// we need to add a few bars here...
int numOfNewBars = value - barCount;
for (int i = 0; i < numOfNewBars; i ++)
Bars.Add (new Bar (i.ToString (CultureInfo.CurrentUICulture), 50));
}
else if (barCount > value)
{
// we need to remove a few bars from the back side..
int numOfBarsToRemove = value - barCount;
for (int i = 0; i < numOfBarsToRemove; i ++)
Bars.RemoveAt (barCount - 1 - i);
}
barCount = value;
// Bars.Clear ();
// for (int i = 0; i < barCount; i ++)
// Bars.Add (new Bar (i.ToString (CultureInfo.CurrentUICulture), 50));
RefreshDisplay ();
}
}
#endregion BarCount
#region BarOrientation
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("Bar orientation, whether horizontal or vertical")
]
public Orientation BarOrientation
{
get { return barOrientation; }
set
{
barOrientation = value;
RefreshDisplay ();
}
}
#endregion BarOrientation
#region TextAlignment
/// <summary>
/// The alignment of the value's text
/// </summary>
[
Browsable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
Category("Appearance"),
Description("The alignment of the value's text")
]
public TextAlignment ValueAlignment
{
get { return valueAlignment; }
set
{
valueAlignment = value;
RefreshDisplay ();
}
}
#endregion TextAlignment
#endregion properties
#region methods
/// <summary>
/// Creates a stacked bar graph user control with default properties
/// </summary>
public StackedBarGraph()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
// TODO: Add any initialization after the InitComponent call
basicBar = new BasicBar ();
basicBar.ShowRangeLines = false;
basicBar.ShowRangeValues = false;
basicBar.BarGraduation = Graduation.None;
gridline = new Gridline (this);
axisLineXandY = new AxisLine (this);
barCollection = new BarCollection ();
for (int i = 0; i < barCount; i ++)
{
Bars.Add (new Bar (i.ToString (CultureInfo.CurrentUICulture), 50));
}
this.SetStyle (ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
this.UpdateStyles ();
GraphArea = new Rectangle (ClientRectangle.Left + graphMarginLeft,
ClientRectangle.Top + graphMarginTop,
ClientRectangle.Width - graphMarginRight - graphMarginLeft,
ClientRectangle.Height - graphMarginBottom - graphMarginTop);
Debug.Assert (GraphArea.Height == (GraphArea.Bottom - GraphArea.Top), "Problem Ctor");
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// StackedBarGraph
//
this.Name = "StackedBarGraph";
this.Size = new System.Drawing.Size(344, 256);
}
#endregion
protected override void OnPaint(PaintEventArgs e)
{
if (! Visible)
return;
Graphics graphics = e.Graphics;
Draw (graphics);
base.OnPaint (e);
}
#region IGraphElement Members
public override void Draw(Graphics graphics)
{
// TODO: Add StackedBarGraph.Draw implementation
graphics.SmoothingMode = SmoothingMode.AntiAlias;
CalculateGraphArea ();
if (GraphArea.Width == 0 || GraphArea.Height == 0)
return;
if (MinimumValue >= MaximumValue)
return;
graphics.SetClip (GraphArea);
gridline.Draw (graphics);
DrawRangeLinesAndValues (graphics);
#region comments describing bar spacing
// For a vertical bar orientation...
// We need to leave some gap at the left edge of the Y axis, otherwise,
// the bar graph will look ugly
// suppose we have a barWidthToSpacingRatio of 1.5 and barCount is 5,
// then if the graphArea.Width is 100, we need the bars to be as follows
// space Bar1 space1 Bar2 space2 Bar3 space3 Bar4 space4 Bar5 space5
// So, we have 5 bars and 6 space regions
// and barWidth = 1.5 times barSpacing
// so, barSpacing is calculated as follows
// 6*barSpacing + 1.5*5*barSpacing = 100
// 13.5*barSpacing = 100
#endregion comments describing bar spacing
float x = ( (float) BarCount * barWidthToSpacingRatio ) + (BarCount + 1);
float barSpacing = 0F;
if (barOrientation == Orientation.Vertical)
{
barSpacing = (float) GraphArea.Width / x;
}
else
{
barSpacing = (float) GraphArea.Height / x;
}
float barWidth = barSpacing * barWidthToSpacingRatio;
float barArea = barWidth + barSpacing;
float currentBarOffset = 0;
if (barOrientation == Orientation.Vertical)
{
currentBarOffset = GraphArea.Left + barSpacing;
}
else
{
currentBarOffset = GraphArea.Bottom - barSpacing - barWidth;
}
basicBar.MaximumValue = minimumValue;
basicBar.MaximumValue = maximumValue;
for (int i = 0; i < barCount; i ++)
{
float barValue = barCollection[i].BarValue;
#region bar color
Color graphColor = barColor;
if (barValue > aboveRangeValue)
graphColor = aboveRangeColor;
else if (barValue < belowRangeValue)
graphColor = belowRangeColor;
graphColor = Color.FromArgb (Transparency, graphColor);
#endregion bar color
#region draw bar
if (barOrientation == Orientation.Vertical)
{
basicBar.ClientRectangle = new Rectangle ((int) currentBarOffset, GraphArea.Top, (int) barWidth, GraphArea.Height);
}
else
{
basicBar.ClientRectangle = new Rectangle (GraphArea.Left, (int) currentBarOffset, GraphArea.Width, (int) barWidth);
}
basicBar.BarColor = graphColor;
basicBar.BarValue = barValue;
basicBar.BarOrientation = barOrientation;
basicBar.ForeColor = this.ForeColor;
basicBar.ValueFormat = ValueFormat;
basicBar.ValueAlignment = valueAlignment;
basicBar.TextFont = this.Font;
basicBar.BorderColor = graphBorderColor;
basicBar.OutOfRangeArrowColor = BarColor;
basicBar.Draw (graphics);
if (barOrientation == Orientation.Vertical)
{
currentBarOffset += barArea;
}
else
{
currentBarOffset -= barArea;
}
#endregion draw bar
}
axisLineXandY.Draw (graphics);
DrawBarNames (graphics, barArea, barSpacing);
DrawBarAxisValues (graphics);
}
private void DrawBarAxisValues (Graphics graphics)
{
graphics.SetClip (ClientRectangle);
if (barOrientation == Orientation.Vertical)
{
StringFormat sf = new StringFormat ();
sf.Trimming = StringTrimming.Character;
sf.FormatFlags = StringFormatFlags.NoWrap;
sf.Alignment = StringAlignment.Far;
sf.LineAlignment = StringAlignment.Center;
Brush textBrush = new SolidBrush (YAxisColor);
float offset = GraphArea.Top - Font.Height / 2;
float graduationPixelDiff = GraphArea.Height / GraduationsY;
float valueOffset = 0;
float graduationDiff = (maximumValue - minimumValue) / GraduationsY;
for (int i = GraduationsY; i >= 0; i --)
{
RectangleF axisValuesRect = new RectangleF (ClientRectangle.Left, offset, GraphMarginLeft - Font.Height / 2, Font.Height);
float graduationValue = maximumValue - graduationDiff * valueOffset;
valueOffset ++;
if (axisValuesRect.IntersectsWith (aboveRangeRect) ||
axisValuesRect.IntersectsWith (belowRangeRect) )
{
offset += graduationPixelDiff;
continue;
}
string val = "";
if (ValueFormat.Length != 0)
val = string.Format (CultureInfo.CurrentUICulture, ValueFormat, graduationValue);
else
val = graduationValue.ToString (CultureInfo.CurrentUICulture);
graphics.DrawString (val, Font, textBrush, axisValuesRect, sf);
offset += graduationPixelDiff;
}
}
else
{
StringFormat sf = new StringFormat ();
sf.Trimming = StringTrimming.Character;
sf.FormatFlags = StringFormatFlags.NoWrap;
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
Brush textBrush = new SolidBrush (XAxisColor);
float offset = GraphArea.Left;
float graduationPixelDiff = GraphArea.Width / GraduationsX;
float graduationDiff = (maximumValue - minimumValue) / GraduationsX;
for (int i = 0; i <= GraduationsX; i ++)
{
float graduationValue = minimumValue + graduationDiff * i;
string val = "";
if (ValueFormat.Length != 0)
val = string.Format (CultureInfo.CurrentUICulture, ValueFormat, graduationValue);
else
val = graduationValue.ToString (CultureInfo.CurrentUICulture);
SizeF numberSize = graphics.MeasureString (val, Font, (int) graduationPixelDiff);
RectangleF axisValuesRect = new RectangleF (offset - numberSize.Width / 2, GraphArea.Bottom + 2, numberSize.Width, Font.Height);
if (axisValuesRect.IntersectsWith (aboveRangeRect) ||
axisValuesRect.IntersectsWith (belowRangeRect) )
{
offset += graduationPixelDiff;
continue;
}
graphics.DrawString (val, Font, textBrush, axisValuesRect, sf);
offset += graduationPixelDiff;
}
}
}
private void DrawBarNames (Graphics graphics, float barArea, float barSpacing)
{
graphics.SetClip (ClientRectangle);
StringFormat sf = new StringFormat ();
sf.Trimming = StringTrimming.Character;
sf.FormatFlags = StringFormatFlags.NoWrap;
sf.LineAlignment = StringAlignment.Center;
float offset = 0;
if (barOrientation == Orientation.Vertical)
{
Brush textBrush = new SolidBrush (XAxisColor);
sf.Alignment = StringAlignment.Center;
offset = GraphArea.Left + barSpacing / 2;
for (int i = 0; i < barCount; i ++)
{
string name = barCollection[i].Name;
RectangleF nameRect = new RectangleF (offset, GraphArea.Bottom, barArea, Font.Height * 2F);
graphics.DrawString (name, Font, textBrush, nameRect, sf);
offset += barArea;
}
textBrush.Dispose ();
}
else
{
Brush textBrush = new SolidBrush (YAxisColor);
sf.Alignment = StringAlignment.Far;
float barWidth = barArea - barSpacing;
offset = GraphArea.Bottom - barSpacing - (barWidth / 2) - (FontHeight / 2);
for (int i = 0; i < barCount; i ++)
{
string name = barCollection[i].Name;
RectangleF nameRect = new RectangleF (ClientRectangle.Left, offset, GraphMarginLeft - FontHeight / 2, Font.Height);
graphics.DrawString (name, Font, textBrush, nameRect, sf);
offset -= barArea;
}
textBrush.Dispose ();
}
}
private void CalculateGraphArea ()
{
GraphArea = new Rectangle (
ClientRectangle.Left + graphMarginLeft,
ClientRectangle.Top + graphMarginTop,
ClientRectangle.Width - graphMarginRight - graphMarginLeft,
ClientRectangle.Height - graphMarginBottom - graphMarginTop);
}
private void DrawRangeLinesAndValues (Graphics graphics)
{
graphics.SetClip (ClientRectangle);
#region draw range lines
if (ShowRangeLines)
{
if (barOrientation == Orientation.Vertical)
{
float aboveRangeHeight = (float) GraphArea.Height * ( (AboveRangeValue - minimumValue) / (maximumValue - minimumValue) );
float belowRangeHeight = (float) GraphArea.Height * ( (BelowRangeValue - minimumValue) / (maximumValue - minimumValue) );
Pen pen = new Pen (Color.Black);
pen.DashStyle = DashStyle.Dash;
graphics.DrawLine (pen, GraphArea.Left, GraphArea.Bottom - aboveRangeHeight, GraphArea.Right, GraphArea.Bottom - aboveRangeHeight);
graphics.DrawLine (pen, GraphArea.Left, GraphArea.Bottom - belowRangeHeight, GraphArea.Right, GraphArea.Bottom - belowRangeHeight);
}
else
{
float aboveRangeWidth = (float) GraphArea.Width * ( (AboveRangeValue - minimumValue) / (maximumValue - minimumValue) );
float belowRangeWidth = (float) GraphArea.Width * ( (BelowRangeValue - minimumValue) / (maximumValue - minimumValue) );
Pen pen = new Pen (Color.Black);
pen.DashStyle = DashStyle.Dash;
graphics.DrawLine (pen, GraphArea.Left + aboveRangeWidth, GraphArea.Top, GraphArea.Left + aboveRangeWidth, GraphArea.Bottom);
graphics.DrawLine (pen, GraphArea.Left + belowRangeWidth, GraphArea.Top, GraphArea.Left + belowRangeWidth, GraphArea.Bottom);
}
}
#endregion draw range lines
#region draw range values
if (ShowRangeValues)
{
StringFormat sf = new StringFormat ();
Brush textBrush = new SolidBrush (this.ForeColor);
if (barOrientation == Orientation.Vertical)
{
float aboveRangeHeight = (float) GraphArea.Height * ( (AboveRangeValue - minimumValue) / (maximumValue - minimumValue));
float belowRangeHeight = (float) GraphArea.Height * ( (BelowRangeValue - minimumValue) / (maximumValue - minimumValue));
aboveRangeRect = new RectangleF (ClientRectangle.Left, GraphArea.Bottom - aboveRangeHeight - Font.Height / 2, GraphMarginLeft - Font.Height / 2, Font.Height);
belowRangeRect = new RectangleF (ClientRectangle.Left, GraphArea.Bottom - belowRangeHeight - Font.Height / 2, GraphMarginLeft - Font.Height / 2, Font.Height);
sf.Trimming = StringTrimming.Character;
sf.FormatFlags = StringFormatFlags.NoWrap;
sf.Alignment = StringAlignment.Far;
sf.LineAlignment = StringAlignment.Center;
string above = "";
string below = "";
if (ValueFormat.Length != 0)
{
above = string.Format (CultureInfo.CurrentUICulture, ValueFormat, aboveRangeValue);
below = string.Format (CultureInfo.CurrentUICulture, ValueFormat, belowRangeValue);
}
else
{
above = aboveRangeValue.ToString (CultureInfo.CurrentUICulture);
below = belowRangeValue.ToString (CultureInfo.CurrentUICulture);
}
graphics.DrawString (above, Font, textBrush, aboveRangeRect, sf);
graphics.DrawString (below, Font, textBrush, belowRangeRect, sf);
}
else
{
float aboveRangeWidth = (float) GraphArea.Width * ( (AboveRangeValue - minimumValue) / (maximumValue - minimumValue));
float belowRangeWidth = (float) GraphArea.Width * ( (BelowRangeValue - minimumValue) / (maximumValue - minimumValue));
string above = "";
string below = "";
if (ValueFormat.Length != 0)
{
above = string.Format (CultureInfo.CurrentUICulture, ValueFormat, aboveRangeValue);
below = string.Format (CultureInfo.CurrentUICulture, ValueFormat, belowRangeValue);
}
else
{
above = aboveRangeValue.ToString (CultureInfo.CurrentUICulture);
below = belowRangeValue.ToString (CultureInfo.CurrentUICulture);
}
SizeF aboveSize = graphics.MeasureString (above, Font);
SizeF belowSize = graphics.MeasureString (below, Font);
aboveRangeRect = new RectangleF (GraphArea.Left + aboveRangeWidth - aboveSize.Width / 2, GraphArea.Bottom + 2, aboveSize.Width, Font.Height);
belowRangeRect = new RectangleF (GraphArea.Left + belowRangeWidth - belowSize.Width / 2, GraphArea.Bottom + 2, belowSize.Width, Font.Height);
sf.Alignment = StringAlignment.Far;
sf.LineAlignment = StringAlignment.Center;
graphics.DrawString (above, Font, textBrush, aboveRangeRect, sf);
graphics.DrawString (below, Font, textBrush, belowRangeRect, sf);
}
}
#endregion draw range values
}
/// <summary>
/// Updates the display of the graph. Call this method once you
/// set all the values so that the changes are reflected on the
/// graph
/// </summary>
public void UpdateDisplay ()
{
RefreshDisplay ();
}
#endregion
#endregion methods
}
}