ModernUO/Scripts/Engines/Reports/Rendering/BarGraphRenderer.cs

934 lines
No EOL
32 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
namespace Server.Engines.Reports
{
// Modified from MS sample
//*********************************************************************
//
// BarGraph Class
//
// This class uses GDI+ to render Bar Chart.
//
//*********************************************************************
public class BarRegion
{
public string m_Name;
public int m_RangeFrom, m_RangeTo;
public BarRegion(int rangeFrom, int rangeTo, string name)
{
m_RangeFrom = rangeFrom;
m_RangeTo = rangeTo;
m_Name = name;
}
}
public class BarGraphRenderer : ChartRenderer
{
private const float _graphLegendSpacer = 15F;
private const float _labelFontSize = 7f;
private const int _legendFontSize = 9;
private const float _legendRectangleSize = 10F;
private const float _spacer = 5F;
// Overall related members
private Color _backColor;
// Graph related members
private float _barWidth;
private float _bottomBuffer; // Space from bottom to x axis
private Color _fontColor;
private float _graphHeight;
private float _graphWidth;
//*********************************************************************
//
// This method draws all the bars for the graph.
//
//*********************************************************************
public int _interval;
// Legend related members
private float _legendWidth;
private string _longestLabel = string.Empty; // Used to calculate legend width
private string _longestTickValue = string.Empty; // Used to calculate max value width
private float _maxLabelWidth;
private float _maxTickValueWidth; // Used to calculate left offset of bar graph
private float _maxValue; // = final tick value * tick count
public BarRegion[] _regions;
private float _scaleFactor; // = _maxValue / _graphHeight
private float _spaceBtwBars; // For now same as _barWidth
private float _topBuffer; // Space from top to the top of y axis
private float _totalHeight;
private float _totalWidth;
private float _xOrigin; // x position where graph starts drawing
private string _xTitle, _yTitle;
private float _yOrigin; // y position where graph starts drawing
private float _yTickValue; // Value for each tick = _maxValue/_yTickCount
public BarGraphRenderer()
{
AssignDefaultSettings();
}
public BarGraphRenderer(Color bgColor)
{
AssignDefaultSettings();
BackgroundColor = bgColor;
}
public string FontFamily{ get; set; }
public BarGraphRenderMode RenderMode{ get; set; }
public Color BackgroundColor
{
set => _backColor = value;
}
public int BottomBuffer
{
set => _bottomBuffer = Convert.ToSingle(value);
}
public Color FontColor
{
set => _fontColor = value;
}
public int Height
{
get => Convert.ToInt32(_totalHeight);
set => _totalHeight = Convert.ToSingle(value);
}
public int Width
{
get => Convert.ToInt32(_totalWidth);
set => _totalWidth = Convert.ToSingle(value);
}
public bool ShowLegend{ get; set; }
public bool ShowData{ get; set; }
public int TopBuffer
{
set => _topBuffer = Convert.ToSingle(value);
}
public string VerticalLabel{ get; set; }
public int VerticalTickCount{ get; set; }
public void SetTitles(string xTitle, string yTitle)
{
_xTitle = xTitle;
_yTitle = yTitle;
}
//*********************************************************************
//
// This method collects all data points and calculate all the necessary dimensions
// to draw the bar graph. It is the method called before invoking the Draw() method.
// labels is the x values.
// values is the y values.
//
//*********************************************************************
public void CollectDataPoints(string[] labels, string[] values)
{
if (labels.Length == values.Length)
{
for (int i = 0; i < labels.Length; i++)
{
float temp = Convert.ToSingle(values[i]);
string shortLbl = MakeShortLabel(labels[i]);
// For now put 0.0 for start position and sweep size
DataPoints.Add(new DataItem(shortLbl, labels[i], temp, 0.0f, 0.0f, GetColor(i)));
// Find max value from data; this is only temporary _maxValue
if (_maxValue < temp) _maxValue = temp;
// Find the longest description
if (ShowLegend)
{
string currentLbl = labels[i] + " (" + shortLbl + ")";
float currentWidth = CalculateImgFontWidth(currentLbl, _legendFontSize, FontFamily);
if (_maxLabelWidth < currentWidth)
{
_longestLabel = currentLbl;
_maxLabelWidth = currentWidth;
}
}
}
CalculateTickAndMax();
CalculateGraphDimension();
CalculateBarWidth(DataPoints.Count, _graphWidth);
CalculateSweepValues();
}
else
{
throw new Exception("X data count is different from Y data count");
}
}
//*********************************************************************
//
// Same as above; called when user doesn't care about the x values
//
//*********************************************************************
public void CollectDataPoints(string[] values)
{
string[] labels = values;
CollectDataPoints(labels, values);
}
public void DrawRegions(Graphics gfx)
{
if (_regions == null)
return;
using (StringFormat textFormat = new StringFormat())
{
textFormat.Alignment = StringAlignment.Center;
textFormat.LineAlignment = StringAlignment.Center;
using (Font font = new Font(FontFamily, _labelFontSize))
{
using (Brush textBrush = new SolidBrush(_fontColor))
{
using (Pen solidPen = new Pen(_fontColor))
{
using (Pen lightPen = new Pen(Color.FromArgb(128, _fontColor)))
{
float labelWidth = _barWidth + _spaceBtwBars;
for (int i = 0; i < _regions.Length; ++i)
{
BarRegion reg = _regions[i];
RectangleF rc = new RectangleF(_xOrigin + reg.m_RangeFrom * labelWidth, _yOrigin,
(reg.m_RangeTo - reg.m_RangeFrom + 1) * labelWidth, _graphHeight);
if (rc.X + rc.Width > _xOrigin + _graphWidth)
rc.Width = _xOrigin + _graphWidth - rc.X;
using (SolidBrush brsh = new SolidBrush(Color.FromArgb(48, GetColor(i))))
{
gfx.FillRectangle(brsh, rc);
}
rc.Offset((rc.Width - 200.0f) * 0.5f, -16.0f);
rc.Width = 200.0f;
rc.Height = 20.0f;
gfx.DrawString(reg.m_Name, font, textBrush, rc, textFormat);
}
}
}
}
}
}
}
//*********************************************************************
//
// This method returns a bar graph bitmap to the calling function. It is called after
// all dimensions and data points are calculated.
//
//*********************************************************************
public override Bitmap Draw()
{
int height = Convert.ToInt32(_totalHeight);
int width = Convert.ToInt32(_totalWidth);
Bitmap bmp = new Bitmap(width, height);
using (Graphics graph = Graphics.FromImage(bmp))
{
graph.CompositingQuality = CompositingQuality.HighQuality;
graph.SmoothingMode = SmoothingMode.AntiAlias;
using (SolidBrush brsh = new SolidBrush(_backColor))
{
graph.FillRectangle(brsh, -1, -1, bmp.Width + 1, bmp.Height + 1);
}
DrawRegions(graph);
DrawVerticalLabelArea(graph);
DrawXLabelBack(graph);
DrawBars(graph);
DrawXLabelArea(graph);
if (ShowLegend)
DrawLegend(graph);
}
return bmp;
}
private void DrawBars(Graphics graph)
{
SolidBrush brsFont = null;
Font valFont = null;
StringFormat sfFormat = null;
try
{
brsFont = new SolidBrush(_fontColor);
valFont = new Font(FontFamily, _labelFontSize);
sfFormat = new StringFormat();
sfFormat.Alignment = StringAlignment.Center;
int i = 0;
PointF[] linePoints = null;
if (RenderMode == BarGraphRenderMode.Lines)
linePoints = new PointF[DataPoints.Count];
int pointIndex = 0;
// Draw bars and the value above each bar
using (Pen pen = new Pen(_fontColor, 0.15f))
{
using (SolidBrush whiteBrsh = new SolidBrush(Color.FromArgb(128, Color.White)))
{
foreach (DataItem item in DataPoints)
using (SolidBrush barBrush = new SolidBrush(item.ItemColor))
{
float itemY = _yOrigin + _graphHeight - item.SweepSize;
if (RenderMode == BarGraphRenderMode.Lines)
{
linePoints[pointIndex++] = new PointF(_xOrigin + item.StartPos + _barWidth / 2, itemY);
}
else if (RenderMode == BarGraphRenderMode.Bars)
{
float ox = _xOrigin + item.StartPos;
float oy = itemY;
float ow = _barWidth;
float oh = item.SweepSize;
float of = 9.5f;
PointF[] pts =
{
new PointF(ox, oy),
new PointF(ox + ow, oy),
new PointF(ox + of, oy + of),
new PointF(ox + of + ow, oy + of),
new PointF(ox, oy + oh),
new PointF(ox + of, oy + of + oh),
new PointF(ox + of + ow, oy + of + oh)
};
graph.FillPolygon(barBrush, new[] { pts[2], pts[3], pts[6], pts[5] });
using (SolidBrush ltBrsh = new SolidBrush(ControlPaint.Light(item.ItemColor, 0.1f)))
{
graph.FillPolygon(ltBrsh, new[] { pts[0], pts[2], pts[5], pts[4] });
}
using (SolidBrush drkBrush = new SolidBrush(ControlPaint.Dark(item.ItemColor, 0.05f)))
{
graph.FillPolygon(drkBrush, new[] { pts[0], pts[1], pts[3], pts[2] });
}
graph.DrawLine(pen, pts[0], pts[1]);
graph.DrawLine(pen, pts[0], pts[2]);
graph.DrawLine(pen, pts[1], pts[3]);
graph.DrawLine(pen, pts[2], pts[3]);
graph.DrawLine(pen, pts[2], pts[5]);
graph.DrawLine(pen, pts[0], pts[4]);
graph.DrawLine(pen, pts[4], pts[5]);
graph.DrawLine(pen, pts[5], pts[6]);
graph.DrawLine(pen, pts[3], pts[6]);
// Draw data value
if (ShowData && i % _interval == 0)
{
float sectionWidth = _barWidth + _spaceBtwBars;
float startX =
_xOrigin + i * sectionWidth +
sectionWidth / 2; // This draws the value on center of the bar
float startY =
itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels
RectangleF recVal = new RectangleF(startX - sectionWidth * _interval / 2, startY,
sectionWidth * _interval, valFont.Height);
SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"), valFont, recVal.Size,
sfFormat);
//using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 180, 255, 255, 255 ) ) )
// graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) );
//graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, sfFormat);
for (int box = -1; box <= 1; ++box)
for (int boy = -1; boy <= 1; ++boy)
{
if (box == 0 && boy == 0)
continue;
RectangleF rco = new RectangleF(recVal.X + box, recVal.Y + boy, recVal.Width,
recVal.Height);
graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco,
sfFormat);
}
graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal,
sfFormat);
}
}
i++;
}
if (RenderMode == BarGraphRenderMode.Lines)
{
if (linePoints.Length >= 2)
using (Pen linePen = new Pen(Color.FromArgb(220, Color.Red), 2.5f))
{
graph.DrawCurve(linePen, linePoints, 0.5f);
}
using (Pen linePen = new Pen(Color.FromArgb(40, _fontColor), 0.8f))
{
for (int j = 0; j < linePoints.Length; ++j)
{
graph.DrawLine(linePen, linePoints[j],
new PointF(linePoints[j].X, _yOrigin + _graphHeight));
DataItem item = DataPoints[j];
float itemY = _yOrigin + _graphHeight - item.SweepSize;
// Draw data value
if (ShowData && j % _interval == 0)
{
graph.FillEllipse(brsFont,
new RectangleF(linePoints[j].X - 2.0f, linePoints[j].Y - 2.0f, 4.0f, 4.0f));
float sectionWidth = _barWidth + _spaceBtwBars;
float startX =
_xOrigin + j * sectionWidth +
sectionWidth / 2; // This draws the value on center of the bar
float startY =
itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels
RectangleF recVal = new RectangleF(startX - sectionWidth * _interval / 2, startY,
sectionWidth * _interval, valFont.Height);
SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"), valFont, recVal.Size,
sfFormat);
//using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 48, 255, 255, 255 ) ) )
// graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) );
for (int box = -1; box <= 1; ++box)
for (int boy = -1; boy <= 1; ++boy)
{
if (box == 0 && boy == 0)
continue;
RectangleF rco = new RectangleF(recVal.X + box, recVal.Y + boy, recVal.Width,
recVal.Height);
graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco,
sfFormat);
}
graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal,
sfFormat);
}
}
}
}
}
}
}
finally
{
brsFont?.Dispose();
valFont?.Dispose();
sfFormat?.Dispose();
}
}
//*********************************************************************
//
// This method draws the y label, tick marks, tick values, and the y axis.
//
//*********************************************************************
private void DrawVerticalLabelArea(Graphics graph)
{
Font lblFont = null;
SolidBrush brs = null;
StringFormat lblFormat = null;
Pen pen = null;
StringFormat sfVLabel = null;
float fo = _yTitle == null ? 0.0f : 20.0f;
try
{
brs = new SolidBrush(_fontColor);
lblFormat = new StringFormat();
pen = new Pen(_fontColor);
if (_yTitle != null)
{
sfVLabel = new StringFormat();
sfVLabel.Alignment = StringAlignment.Center;
sfVLabel.LineAlignment = StringAlignment.Center;
sfVLabel.FormatFlags = StringFormatFlags.DirectionVertical;
lblFont = new Font(FontFamily, _labelFontSize + 4.0f);
graph.DrawString(_yTitle, lblFont, brs, new RectangleF(0.0f, _yOrigin, 20.0f, _graphHeight), sfVLabel);
lblFont.Dispose();
}
sfVLabel = new StringFormat();
lblFormat.Alignment = StringAlignment.Far;
lblFormat.FormatFlags |= StringFormatFlags.NoClip;
// Draw vertical label at the top of y-axis and place it in the middle top of y-axis
lblFont = new Font(FontFamily, _labelFontSize + 2.0f, FontStyle.Bold);
RectangleF recVLabel =
new RectangleF(0, _yOrigin - 2 * _spacer - lblFont.Height, _xOrigin * 2, lblFont.Height);
sfVLabel.Alignment = StringAlignment.Center;
sfVLabel.FormatFlags |= StringFormatFlags.NoClip;
//graph.DrawRectangle(Pens.Black,Rectangle.Truncate(recVLabel));
graph.DrawString(VerticalLabel, lblFont, brs, recVLabel, sfVLabel);
lblFont.Dispose();
lblFont = new Font(FontFamily, _labelFontSize);
// Draw all tick values and tick marks
using (Pen smallPen = new Pen(Color.FromArgb(96, _fontColor), 0.8f))
{
for (int i = 0; i < VerticalTickCount; i++)
{
float currentY = _topBuffer + i * _yTickValue / _scaleFactor; // Position for tick mark
float labelY = currentY - lblFont.Height / 2; // Place label in the middle of tick
RectangleF lblRec = new RectangleF(_spacer + fo - 6, labelY, _maxTickValueWidth, lblFont.Height);
float currentTick = _maxValue - i * _yTickValue; // Calculate tick value from top to bottom
graph.DrawString(currentTick.ToString("#,###.##"), lblFont, brs, lblRec,
lblFormat); // Draw tick value
graph.DrawLine(pen, _xOrigin, currentY, _xOrigin - 4.0f, currentY); // Draw tick mark
graph.DrawLine(smallPen, _xOrigin, currentY, _xOrigin + _graphWidth, currentY);
}
}
// Draw y axis
graph.DrawLine(pen, _xOrigin, _yOrigin, _xOrigin, _yOrigin + _graphHeight);
}
finally
{
lblFont?.Dispose();
brs?.Dispose();
lblFormat?.Dispose();
pen?.Dispose();
sfVLabel?.Dispose();
}
}
//*********************************************************************
//
// This method draws x axis and all x labels
//
//*********************************************************************
private void DrawXLabelBack(Graphics graph)
{
Font lblFont = null;
SolidBrush brs = null;
StringFormat lblFormat = null;
Pen pen = null;
try
{
lblFont = new Font(FontFamily, _labelFontSize);
brs = new SolidBrush(_fontColor);
lblFormat = new StringFormat();
pen = new Pen(_fontColor);
lblFormat.Alignment = StringAlignment.Center;
// Draw x axis
graph.DrawLine(pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + _graphWidth, _yOrigin + _graphHeight);
}
finally
{
lblFont?.Dispose();
brs?.Dispose();
lblFormat?.Dispose();
pen?.Dispose();
}
}
private void DrawXLabelArea(Graphics graph)
{
Font lblFont = null;
SolidBrush brs = null;
StringFormat lblFormat = null;
Pen pen = null;
try
{
brs = new SolidBrush(_fontColor);
pen = new Pen(_fontColor);
if (_xTitle != null)
{
lblFormat = new StringFormat();
lblFormat.Alignment = StringAlignment.Center;
lblFormat.LineAlignment = StringAlignment.Center;
// sfVLabel.FormatFlags=StringFormatFlags.DirectionVertical;
lblFont = new Font(FontFamily, _labelFontSize + 2.0f, FontStyle.Bold);
graph.DrawString(_xTitle, lblFont, brs,
new RectangleF(_xOrigin,
_yOrigin + _graphHeight + 14.0f + (RenderMode == BarGraphRenderMode.Bars ? 10.0f : 0.0f) +
(DataPoints.Count / _interval > 24 ? 16.0f : 0.0f), _graphWidth, 20.0f), lblFormat);
}
lblFont = new Font(FontFamily, _labelFontSize);
lblFormat = new StringFormat();
lblFormat.Alignment = StringAlignment.Center;
lblFormat.FormatFlags |= StringFormatFlags.NoClip;
lblFormat.Trimming = StringTrimming.None;
//lblFormat.FormatFlags |= StringFormatFlags.NoWrap;
float of = 0.0f;
if (RenderMode == BarGraphRenderMode.Bars)
{
of = 10.0f;
// Draw x axis
graph.DrawLine(pen, _xOrigin + of, _yOrigin + _graphHeight + of, _xOrigin + _graphWidth + of,
_yOrigin + _graphHeight + of);
graph.DrawLine(pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + of, _yOrigin + _graphHeight + of);
graph.DrawLine(pen, _xOrigin + _graphWidth, _yOrigin + _graphHeight, _xOrigin + of + _graphWidth,
_yOrigin + _graphHeight + of);
}
float currentX;
float currentY = _yOrigin + _graphHeight + 2.0f; // All x labels are drawn 2 pixels below x-axis
float labelWidth = _barWidth + _spaceBtwBars; // Fits exactly below the bar
int i = 0;
// Draw x labels
foreach (DataItem item in DataPoints)
{
if (i % _interval == 0)
{
currentX = _xOrigin + i * labelWidth + of + labelWidth / 2;
RectangleF recLbl = new RectangleF(currentX - labelWidth * _interval / 2, currentY + of,
labelWidth * _interval, lblFont.Height * 2);
string lblString = ShowLegend ? item.Label : item.Description; // Decide what to show: short or long
graph.DrawString(lblString, lblFont, brs, recLbl, lblFormat);
}
i++;
}
}
finally
{
lblFont?.Dispose();
brs?.Dispose();
lblFormat?.Dispose();
pen?.Dispose();
}
}
//*********************************************************************
//
// This method determines where to place the legend box.
// It draws the legend border, legend description, and legend color code.
//
//*********************************************************************
private void DrawLegend(Graphics graph)
{
Font lblFont = null;
SolidBrush brs = null;
StringFormat lblFormat = null;
Pen pen = null;
try
{
lblFont = new Font(FontFamily, _legendFontSize);
brs = new SolidBrush(_fontColor);
lblFormat = new StringFormat();
pen = new Pen(_fontColor);
lblFormat.Alignment = StringAlignment.Near;
// Calculate Legend drawing start point
float startX = _xOrigin + _graphWidth + _graphLegendSpacer;
float startY = _yOrigin;
float xColorCode = startX + _spacer;
float xLegendText = xColorCode + _legendRectangleSize + _spacer;
float legendHeight = 0.0f;
for (int i = 0; i < DataPoints.Count; i++)
{
DataItem point = DataPoints[i];
string text = point.Description + " (" + point.Label + ")";
float currentY = startY + _spacer + i * (lblFont.Height + _spacer);
legendHeight += lblFont.Height + _spacer;
// Draw legend description
graph.DrawString(text, lblFont, brs, xLegendText, currentY, lblFormat);
// Draw color code
using (SolidBrush brsh = new SolidBrush(DataPoints[i].ItemColor))
{
graph.FillRectangle(brsh, xColorCode, currentY + 3f, _legendRectangleSize, _legendRectangleSize);
}
}
// Draw legend border
graph.DrawRectangle(pen, startX, startY, _legendWidth, legendHeight + _spacer);
}
finally
{
lblFont?.Dispose();
brs?.Dispose();
lblFormat?.Dispose();
pen?.Dispose();
}
}
//*********************************************************************
//
// This method calculates all measurement aspects of the bar graph from the given data points
//
//*********************************************************************
private void CalculateGraphDimension()
{
FindLongestTickValue();
// Need to add another character for spacing; this is not used for drawing, just for calculation
_longestTickValue += "0";
//_maxTickValueWidth = CalculateImgFontWidth(_longestTickValue, _labelFontSize, FontFamily);
_maxTickValueWidth = 0.0f;
float currentTick;
string tickString;
for (int i = 0; i < VerticalTickCount; i++)
{
currentTick = _maxValue - i * _yTickValue;
tickString = currentTick.ToString("#,###.##");
float measured = CalculateImgFontWidth(tickString, _labelFontSize, FontFamily);
if (measured > _maxTickValueWidth)
_maxTickValueWidth = measured;
}
float leftOffset = _spacer + _maxTickValueWidth + (_yTitle == null ? 0.0f : 20.0f);
float rtOffset = 0.0f;
if (ShowLegend)
{
_legendWidth = _spacer + _legendRectangleSize + _spacer + _maxLabelWidth + _spacer;
rtOffset = _graphLegendSpacer + _legendWidth + _spacer;
}
else
{
rtOffset = _spacer; // Make graph in the middle
}
if (RenderMode == BarGraphRenderMode.Bars)
rtOffset += 10.0f;
rtOffset += 10.0f;
_graphHeight =
_totalHeight - _topBuffer - _bottomBuffer -
(_xTitle == null ? 0.0f : 20.0f); // Buffer spaces are used to print labels
_graphWidth = _totalWidth - leftOffset - rtOffset;
_xOrigin = leftOffset;
_yOrigin = _topBuffer;
// Once the correct _maxValue is determined, then calculate _scaleFactor
_scaleFactor = _maxValue / _graphHeight;
}
//*********************************************************************
//
// This method determines the longest tick value from the given data points.
// The result is needed to calculate the correct graph dimension.
//
//*********************************************************************
private void FindLongestTickValue()
{
float currentTick;
string tickString;
for (int i = 0; i < VerticalTickCount; i++)
{
currentTick = _maxValue - i * _yTickValue;
tickString = currentTick.ToString("#,###.##");
if (_longestTickValue.Length < tickString.Length)
_longestTickValue = tickString;
}
}
//*********************************************************************
//
// This method calculates the image width in pixel for a given text
//
//*********************************************************************
private float CalculateImgFontWidth(string text, float size, string family)
{
Bitmap bmp = null;
Graphics graph = null;
Font font = null;
try
{
font = new Font(family, size);
// Calculate the size of the string.
bmp = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
graph = Graphics.FromImage(bmp);
SizeF oSize = graph.MeasureString(text, font);
oSize.Width = 4 + (float)Math.Ceiling(oSize.Width);
return oSize.Width;
}
finally
{
graph?.Dispose();
bmp?.Dispose();
font?.Dispose();
}
}
//*********************************************************************
//
// This method creates abbreviation from long description; used for making legend
//
//*********************************************************************
private string MakeShortLabel(string text)
{
string label = text;
if (text.Length > 2)
{
int midPostition = Convert.ToInt32(Math.Floor(text.Length / 2.0));
label = text.Substring(0, 1) + text.Substring(midPostition, 1) + text.Substring(text.Length - 1, 1);
}
return label;
}
//*********************************************************************
//
// This method calculates the max value and each tick mark value for the bar graph.
//
//*********************************************************************
private void CalculateTickAndMax()
{
float tempMax = 0.0f;
// Give graph some head room first about 10% of current max
_maxValue *= 1.1f;
if (_maxValue != 0.0f)
{
// Find a rounded value nearest to the current max value
// Calculate this max first to give enough space to draw value on each bar
double exp = Convert.ToDouble(Math.Floor(Math.Log10(_maxValue)));
tempMax = Convert.ToSingle(Math.Ceiling(_maxValue / Math.Pow(10, exp)) * Math.Pow(10, exp));
}
else
{
tempMax = 1.0f;
}
// Once max value is calculated, tick value can be determined; tick value should be a whole number
_yTickValue = tempMax / VerticalTickCount;
double expTick = Convert.ToDouble(Math.Floor(Math.Log10(_yTickValue)));
_yTickValue = Convert.ToSingle(Math.Ceiling(_yTickValue / Math.Pow(10, expTick)) * Math.Pow(10, expTick));
// Re-calculate the max value with the new tick value
_maxValue = _yTickValue * VerticalTickCount;
}
//*********************************************************************
//
// This method calculates the height for each bar in the graph
//
//*********************************************************************
private void CalculateSweepValues()
{
// Called when all values and scale factor are known
// All values calculated here are relative from (_xOrigin, _yOrigin)
int i = 0;
foreach (DataItem item in DataPoints)
{
// This implementation does not support negative value
if (item.Value >= 0) item.SweepSize = item.Value / _scaleFactor;
// (_spaceBtwBars/2) makes half white space for the first bar
item.StartPos = _spaceBtwBars / 2 + i * (_barWidth + _spaceBtwBars);
i++;
}
}
//*********************************************************************
//
// This method calculates the width for each bar in the graph
//
//*********************************************************************
private void CalculateBarWidth(int dataCount, float barGraphWidth)
{
// White space between each bar is the same as bar width itself
_barWidth = barGraphWidth / (dataCount * 2); // Each bar has 1 white space
//_barWidth =/* (float)Math.Floor(*/_barWidth/*)*/;
_spaceBtwBars = _barWidth;
}
//*********************************************************************
//
// This method assigns default value to the bar graph properties and is only
// called from BarGraph constructors
//
//*********************************************************************
private void AssignDefaultSettings()
{
// default values
_totalWidth = 680f;
_totalHeight = 450f;
FontFamily = "Verdana";
_backColor = Color.White;
_fontColor = Color.Black;
_topBuffer = 30f;
_bottomBuffer = 30f;
VerticalTickCount = 2;
ShowLegend = false;
ShowData = false;
}
}
}