📄 bargraph.cs
字号:
using System;
using System.Drawing;
using System.Collections;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
namespace ASPNET.StarterKit.Chart
{
//*********************************************************************
//
// BarGraph Class
//
// This class uses GDI+ to render Bar Chart.
//
//*********************************************************************
public class BarGraph : Chart
{
private const float _graphLegendSpacer = 15F;
private const int _labelFontSize = 7;
private const int _legendFontSize = 9;
private const float _legendRectangleSize = 10F;
private const float _spacer = 5F;
// Overall related members
private Color _backColor;
private string _fontFamily;
private string _longestTickValue = string.Empty; // Used to calculate max value width
private float _maxTickValueWidth; // Used to calculate left offset of bar graph
private float _totalHeight;
private float _totalWidth;
// Graph related members
private float _barWidth;
private float _bottomBuffer; // Space from bottom to x axis
private bool _displayBarData;
private Color _fontColor;
private float _graphHeight;
private float _graphWidth;
private float _maxValue = 0.0f; // = final tick value * tick count
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 _xOrigin; // x position where graph starts drawing
private float _yOrigin; // y position where graph starts drawing
private string _yLabel;
private int _yTickCount;
private float _yTickValue; // Value for each tick = _maxValue/_yTickCount
// Legend related members
private bool _displayLegend;
private float _legendWidth;
private string _longestLabel = string.Empty; // Used to calculate legend width
private float _maxLabelWidth = 0.0f;
public string FontFamily {
get{ return _fontFamily; }
set{ _fontFamily = value; }
}
public Color BackgroundColor {
set{ _backColor = value; }
}
public int BottomBuffer {
set { _bottomBuffer = Convert.ToSingle(value); }
}
public Color FontColor {
set{ _fontColor = value; }
}
public int Height {
get{ return Convert.ToInt32(_totalHeight); }
set{ _totalHeight = Convert.ToSingle(value); }
}
public int Width {
get{ return Convert.ToInt32(_totalWidth); }
set{ _totalWidth = Convert.ToSingle(value); }
}
public bool ShowLegend {
get{ return _displayLegend; }
set{ _displayLegend = value; }
}
public bool ShowData {
get{ return _displayBarData; }
set{ _displayBarData = value; }
}
public int TopBuffer {
set { _topBuffer = Convert.ToSingle(value); }
}
public string VerticalLabel {
get{ return _yLabel; }
set{ _yLabel = value; }
}
public int VerticalTickCount {
get{ return _yTickCount; }
set{ _yTickCount = value; }
}
public BarGraph()
{
AssignDefaultSettings();
}
public BarGraph(Color bgColor)
{
AssignDefaultSettings();
BackgroundColor = bgColor;
}
//*********************************************************************
//
// 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 ChartItem(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 (_displayLegend)
{
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);
}
//*********************************************************************
//
// 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;
// Set the background: need to draw one pixel larger than the bitmap to cover all area
graph.FillRectangle(new SolidBrush(_backColor), -1, -1, bmp.Width+1, bmp.Height+1);
DrawVerticalLabelArea(graph);
DrawBars(graph);
DrawXLabelArea(graph);
if (_displayLegend) DrawLegend(graph);
}
return bmp;
}
//*********************************************************************
//
// This method draws all the bars for the graph.
//
//*********************************************************************
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;
// Draw bars and the value above each bar
foreach(ChartItem item in DataPoints)
{
using(SolidBrush barBrush = new SolidBrush(item.ItemColor))
{
float itemY = _yOrigin + _graphHeight - item.SweepSize;
// When drawing, all position is relative to (_xOrigin, _yOrigin)
graph.FillRectangle(barBrush, _xOrigin + item.StartPos, itemY, _barWidth, item.SweepSize);
// Draw data value
if (_displayBarData)
{
float startX = _xOrigin + (i * (_barWidth + _spaceBtwBars)); // 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, startY, _barWidth + _spaceBtwBars, valFont.Height);
graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, sfFormat);
}
i++;
}
}
}
finally
{
if (brsFont != null) brsFont.Dispose();
if (valFont != null) valFont.Dispose();
if (sfFormat != null) 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;
try
{
lblFont = new Font(_fontFamily, _labelFontSize);
brs = new SolidBrush(_fontColor);
lblFormat = new StringFormat();
pen = new Pen(_fontColor);
sfVLabel = new StringFormat();
lblFormat.Alignment = StringAlignment.Near;
// Draw vertical label at the top of y-axis and place it in the middle top of y-axis
RectangleF recVLabel = new RectangleF(0f, _yOrigin-2*_spacer-lblFont.Height, _xOrigin*2, lblFont.Height);
sfVLabel.Alignment = StringAlignment.Center;
graph.DrawString(_yLabel, lblFont, brs, recVLabel, sfVLabel);
// Draw all tick values and tick marks
for (int i=0; i<_yTickCount; 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, 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
}
// Draw y axis
graph.DrawLine(pen, _xOrigin, _yOrigin, _xOrigin, _yOrigin + _graphHeight);
}
finally
{
if (lblFont != null) lblFont.Dispose();
if (brs != null) brs.Dispose();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -