Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
970
Scripts/Services/Reports/Rendering/BarGraphRenderer.cs
Normal file
970
Scripts/Services/Reports/Rendering/BarGraphRenderer.cs
Normal file
@@ -0,0 +1,970 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
// Modified from MS sample
|
||||
//*********************************************************************
|
||||
//
|
||||
// BarGraph Class
|
||||
//
|
||||
// This class uses GDI+ to render Bar Chart.
|
||||
//
|
||||
//*********************************************************************
|
||||
public class BarRegion
|
||||
{
|
||||
public int m_RangeFrom, m_RangeTo;
|
||||
public string m_Name;
|
||||
public BarRegion(int rangeFrom, int rangeTo, string name)
|
||||
{
|
||||
this.m_RangeFrom = rangeFrom;
|
||||
this.m_RangeTo = rangeTo;
|
||||
this.m_Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class BarGraphRenderer : ChartRenderer
|
||||
{
|
||||
public BarRegion[] _regions;
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method draws all the bars for the graph.
|
||||
//
|
||||
//*********************************************************************
|
||||
public int _interval;
|
||||
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;
|
||||
private BarGraphRenderMode _renderMode;
|
||||
// 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;
|
||||
private string _xTitle, _yTitle;
|
||||
public BarGraphRenderer()
|
||||
{
|
||||
this.AssignDefaultSettings();
|
||||
}
|
||||
|
||||
public BarGraphRenderer(Color bgColor)
|
||||
{
|
||||
this.AssignDefaultSettings();
|
||||
this.BackgroundColor = bgColor;
|
||||
}
|
||||
|
||||
public string FontFamily
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._fontFamily;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._fontFamily = value;
|
||||
}
|
||||
}
|
||||
public BarGraphRenderMode RenderMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._renderMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._renderMode = value;
|
||||
}
|
||||
}
|
||||
public Color BackgroundColor
|
||||
{
|
||||
set
|
||||
{
|
||||
this._backColor = value;
|
||||
}
|
||||
}
|
||||
public int BottomBuffer
|
||||
{
|
||||
set
|
||||
{
|
||||
this._bottomBuffer = Convert.ToSingle(value);
|
||||
}
|
||||
}
|
||||
public Color FontColor
|
||||
{
|
||||
set
|
||||
{
|
||||
this._fontColor = value;
|
||||
}
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get
|
||||
{
|
||||
return Convert.ToInt32(this._totalHeight);
|
||||
}
|
||||
set
|
||||
{
|
||||
this._totalHeight = Convert.ToSingle(value);
|
||||
}
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get
|
||||
{
|
||||
return Convert.ToInt32(this._totalWidth);
|
||||
}
|
||||
set
|
||||
{
|
||||
this._totalWidth = Convert.ToSingle(value);
|
||||
}
|
||||
}
|
||||
public bool ShowLegend
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._displayLegend;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._displayLegend = value;
|
||||
}
|
||||
}
|
||||
public bool ShowData
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._displayBarData;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._displayBarData = value;
|
||||
}
|
||||
}
|
||||
public int TopBuffer
|
||||
{
|
||||
set
|
||||
{
|
||||
this._topBuffer = Convert.ToSingle(value);
|
||||
}
|
||||
}
|
||||
public string VerticalLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._yLabel;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._yLabel = value;
|
||||
}
|
||||
}
|
||||
public int VerticalTickCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._yTickCount;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._yTickCount = value;
|
||||
}
|
||||
}
|
||||
public void SetTitles(string xTitle, string yTitle)
|
||||
{
|
||||
this._xTitle = xTitle;
|
||||
this._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 = this.MakeShortLabel(labels[i]);
|
||||
|
||||
// For now put 0.0 for start position and sweep size
|
||||
this.DataPoints.Add(new DataItem(shortLbl, labels[i], temp, 0.0f, 0.0f, this.GetColor(i)));
|
||||
|
||||
// Find max value from data; this is only temporary _maxValue
|
||||
if (this._maxValue < temp)
|
||||
this._maxValue = temp;
|
||||
|
||||
// Find the longest description
|
||||
if (this._displayLegend)
|
||||
{
|
||||
string currentLbl = labels[i] + " (" + shortLbl + ")";
|
||||
float currentWidth = this.CalculateImgFontWidth(currentLbl, _legendFontSize, this.FontFamily);
|
||||
if (this._maxLabelWidth < currentWidth)
|
||||
{
|
||||
this._longestLabel = currentLbl;
|
||||
this._maxLabelWidth = currentWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.CalculateTickAndMax();
|
||||
this.CalculateGraphDimension();
|
||||
this.CalculateBarWidth(this.DataPoints.Count, this._graphWidth);
|
||||
this.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;
|
||||
this.CollectDataPoints(labels, values);
|
||||
}
|
||||
|
||||
public void DrawRegions(Graphics gfx)
|
||||
{
|
||||
if (this._regions == null)
|
||||
return;
|
||||
|
||||
using (StringFormat textFormat = new StringFormat())
|
||||
{
|
||||
textFormat.Alignment = StringAlignment.Center;
|
||||
textFormat.LineAlignment = StringAlignment.Center;
|
||||
|
||||
using (Font font = new Font(this._fontFamily, _labelFontSize))
|
||||
{
|
||||
using (Brush textBrush = new SolidBrush(this._fontColor))
|
||||
{
|
||||
using (Pen solidPen = new Pen(this._fontColor))
|
||||
{
|
||||
using (Pen lightPen = new Pen(Color.FromArgb(128, this._fontColor)))
|
||||
{
|
||||
float labelWidth = this._barWidth + this._spaceBtwBars;
|
||||
|
||||
for (int i = 0; i < this._regions.Length; ++i)
|
||||
{
|
||||
BarRegion reg = this._regions[i];
|
||||
|
||||
RectangleF rc = new RectangleF(this._xOrigin + (reg.m_RangeFrom * labelWidth), this._yOrigin, (reg.m_RangeTo - reg.m_RangeFrom + 1) * labelWidth, this._graphHeight);
|
||||
|
||||
if (rc.X + rc.Width > this._xOrigin + this._graphWidth)
|
||||
rc.Width = this._xOrigin + this._graphWidth - rc.X;
|
||||
|
||||
using (SolidBrush brsh = new SolidBrush(Color.FromArgb(48, this.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(this._totalHeight);
|
||||
int width = Convert.ToInt32(this._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(this._backColor))
|
||||
graph.FillRectangle(brsh, -1, -1, bmp.Width + 1, bmp.Height + 1);
|
||||
|
||||
this.DrawRegions(graph);
|
||||
this.DrawVerticalLabelArea(graph);
|
||||
this.DrawXLabelBack(graph);
|
||||
this.DrawBars(graph);
|
||||
this.DrawXLabelArea(graph);
|
||||
|
||||
if (this._displayLegend)
|
||||
this.DrawLegend(graph);
|
||||
}
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private void DrawBars(Graphics graph)
|
||||
{
|
||||
SolidBrush brsFont = null;
|
||||
Font valFont = null;
|
||||
StringFormat sfFormat = null;
|
||||
|
||||
try
|
||||
{
|
||||
brsFont = new SolidBrush(this._fontColor);
|
||||
valFont = new Font(this._fontFamily, _labelFontSize);
|
||||
sfFormat = new StringFormat();
|
||||
sfFormat.Alignment = StringAlignment.Center;
|
||||
int i = 0;
|
||||
|
||||
PointF[] linePoints = null;
|
||||
|
||||
if (this._renderMode == BarGraphRenderMode.Lines)
|
||||
linePoints = new PointF[this.DataPoints.Count];
|
||||
|
||||
int pointIndex = 0;
|
||||
|
||||
// Draw bars and the value above each bar
|
||||
using (Pen pen = new Pen(this._fontColor,0.15f))
|
||||
{
|
||||
using (SolidBrush whiteBrsh = new SolidBrush(Color.FromArgb(128, Color.White)))
|
||||
{
|
||||
foreach (DataItem item in this.DataPoints)
|
||||
{
|
||||
using (SolidBrush barBrush = new SolidBrush(item.ItemColor))
|
||||
{
|
||||
float itemY = this._yOrigin + this._graphHeight - item.SweepSize;
|
||||
|
||||
if (this._renderMode == BarGraphRenderMode.Lines)
|
||||
{
|
||||
linePoints[pointIndex++] = new PointF(this._xOrigin + item.StartPos + (this._barWidth / 2), itemY);
|
||||
}
|
||||
else if (this._renderMode == BarGraphRenderMode.Bars)
|
||||
{
|
||||
float ox = this._xOrigin + item.StartPos;
|
||||
float oy = itemY;
|
||||
float ow = this._barWidth;
|
||||
float oh = item.SweepSize;
|
||||
float of = 9.5f;
|
||||
|
||||
PointF[] pts = new PointF[]
|
||||
{
|
||||
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 PointF[] { pts[2], pts[3], pts[6], pts[5] });
|
||||
|
||||
using (SolidBrush ltBrsh = new SolidBrush(System.Windows.Forms.ControlPaint.Light(item.ItemColor, 0.1f)))
|
||||
graph.FillPolygon(ltBrsh, new PointF[] { pts[0], pts[2], pts[5], pts[4] });
|
||||
|
||||
using (SolidBrush drkBrush = new SolidBrush(System.Windows.Forms.ControlPaint.Dark(item.ItemColor, 0.05f)))
|
||||
graph.FillPolygon(drkBrush, new PointF[] { 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 (this._displayBarData && (i % this._interval) == 0)
|
||||
{
|
||||
float sectionWidth = (this._barWidth + this._spaceBtwBars);
|
||||
float startX = this._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 * this._interval) / 2), startY, sectionWidth * this._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 (this._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, this._fontColor), 0.8f))
|
||||
{
|
||||
for (int j = 0; j < linePoints.Length; ++j)
|
||||
{
|
||||
graph.DrawLine(linePen, linePoints[j], new PointF(linePoints[j].X, this._yOrigin + this._graphHeight));
|
||||
|
||||
DataItem item = this.DataPoints[j];
|
||||
float itemY = this._yOrigin + this._graphHeight - item.SweepSize;
|
||||
|
||||
// Draw data value
|
||||
if (this._displayBarData && (j % this._interval) == 0)
|
||||
{
|
||||
graph.FillEllipse(brsFont, new RectangleF(linePoints[j].X - 2.0f, linePoints[j].Y - 2.0f, 4.0f, 4.0f));
|
||||
|
||||
float sectionWidth = (this._barWidth + this._spaceBtwBars);
|
||||
float startX = this._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 * this._interval) / 2), startY, sectionWidth * this._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
|
||||
{
|
||||
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;
|
||||
|
||||
float fo = (this._yTitle == null ? 0.0f : 20.0f);
|
||||
|
||||
try
|
||||
{
|
||||
brs = new SolidBrush(this._fontColor);
|
||||
lblFormat = new StringFormat();
|
||||
pen = new Pen(this._fontColor);
|
||||
|
||||
if (this._yTitle != null)
|
||||
{
|
||||
sfVLabel = new StringFormat();
|
||||
sfVLabel.Alignment = StringAlignment.Center;
|
||||
sfVLabel.LineAlignment = StringAlignment.Center;
|
||||
sfVLabel.FormatFlags = StringFormatFlags.DirectionVertical;
|
||||
|
||||
lblFont = new Font(this._fontFamily, _labelFontSize + 4.0f);
|
||||
graph.DrawString(this._yTitle, lblFont, brs, new RectangleF(0.0f, this._yOrigin, 20.0f, this._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(this._fontFamily, _labelFontSize + 2.0f,FontStyle.Bold);
|
||||
RectangleF recVLabel = new RectangleF(0, this._yOrigin - 2 * _spacer - lblFont.Height, this._xOrigin * 2, lblFont.Height);
|
||||
sfVLabel.Alignment = StringAlignment.Center;
|
||||
sfVLabel.FormatFlags |= StringFormatFlags.NoClip;
|
||||
//graph.DrawRectangle(Pens.Black,Rectangle.Truncate(recVLabel));
|
||||
graph.DrawString(this._yLabel, lblFont, brs, recVLabel, sfVLabel);
|
||||
lblFont.Dispose();
|
||||
|
||||
lblFont = new Font(this._fontFamily, _labelFontSize);
|
||||
// Draw all tick values and tick marks
|
||||
using (Pen smallPen = new Pen(Color.FromArgb(96, this._fontColor),0.8f))
|
||||
{
|
||||
for (int i = 0; i < this._yTickCount; i++)
|
||||
{
|
||||
float currentY = this._topBuffer + (i * this._yTickValue / this._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, this._maxTickValueWidth, lblFont.Height);
|
||||
|
||||
float currentTick = this._maxValue - i * this._yTickValue; // Calculate tick value from top to bottom
|
||||
graph.DrawString(currentTick.ToString("#,###.##"), lblFont, brs, lblRec, lblFormat); // Draw tick value
|
||||
graph.DrawLine(pen, this._xOrigin, currentY, this._xOrigin - 4.0f, currentY); // Draw tick mark
|
||||
|
||||
graph.DrawLine(smallPen, this._xOrigin, currentY, this._xOrigin + this._graphWidth, currentY);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw y axis
|
||||
graph.DrawLine(pen, this._xOrigin, this._yOrigin, this._xOrigin, this._yOrigin + this._graphHeight);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lblFont != null)
|
||||
lblFont.Dispose();
|
||||
if (brs != null)
|
||||
brs.Dispose();
|
||||
if (lblFormat != null)
|
||||
lblFormat.Dispose();
|
||||
if (pen != null)
|
||||
pen.Dispose();
|
||||
if (sfVLabel != null)
|
||||
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(this._fontFamily, _labelFontSize);
|
||||
brs = new SolidBrush(this._fontColor);
|
||||
lblFormat = new StringFormat();
|
||||
pen = new Pen(this._fontColor);
|
||||
|
||||
lblFormat.Alignment = StringAlignment.Center;
|
||||
|
||||
// Draw x axis
|
||||
graph.DrawLine(pen, this._xOrigin, this._yOrigin + this._graphHeight, this._xOrigin + this._graphWidth, this._yOrigin + this._graphHeight);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lblFont != null)
|
||||
lblFont.Dispose();
|
||||
if (brs != null)
|
||||
brs.Dispose();
|
||||
if (lblFormat != null)
|
||||
lblFormat.Dispose();
|
||||
if (pen != null)
|
||||
pen.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawXLabelArea(Graphics graph)
|
||||
{
|
||||
Font lblFont = null;
|
||||
SolidBrush brs = null;
|
||||
StringFormat lblFormat = null;
|
||||
Pen pen = null;
|
||||
|
||||
try
|
||||
{
|
||||
brs = new SolidBrush(this._fontColor);
|
||||
pen = new Pen(this._fontColor);
|
||||
|
||||
if (this._xTitle != null)
|
||||
{
|
||||
lblFormat = new StringFormat();
|
||||
lblFormat.Alignment = StringAlignment.Center;
|
||||
lblFormat.LineAlignment = StringAlignment.Center;
|
||||
// sfVLabel.FormatFlags=StringFormatFlags.DirectionVertical;
|
||||
|
||||
lblFont = new Font(this._fontFamily, _labelFontSize + 2.0f, FontStyle.Bold);
|
||||
graph.DrawString(this._xTitle, lblFont, brs, new RectangleF(this._xOrigin, this._yOrigin + this._graphHeight + 14.0f + (this._renderMode == BarGraphRenderMode.Bars ? 10.0f : 0.0f) + ((this.DataPoints.Count / this._interval) > 24 ? 16.0f : 0.0f), this._graphWidth, 20.0f), lblFormat);
|
||||
}
|
||||
|
||||
lblFont = new Font(this._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 (this._renderMode == BarGraphRenderMode.Bars)
|
||||
{
|
||||
of = 10.0f;
|
||||
|
||||
// Draw x axis
|
||||
graph.DrawLine(pen, this._xOrigin + of, this._yOrigin + this._graphHeight + of, this._xOrigin + this._graphWidth + of, this._yOrigin + this._graphHeight + of);
|
||||
|
||||
graph.DrawLine(pen, this._xOrigin, this._yOrigin + this._graphHeight, this._xOrigin + of, this._yOrigin + this._graphHeight + of);
|
||||
graph.DrawLine(pen, this._xOrigin + this._graphWidth, this._yOrigin + this._graphHeight, this._xOrigin + of + this._graphWidth, this._yOrigin + this._graphHeight + of);
|
||||
}
|
||||
|
||||
float currentX;
|
||||
float currentY = this._yOrigin + this._graphHeight + 2.0f; // All x labels are drawn 2 pixels below x-axis
|
||||
float labelWidth = this._barWidth + this._spaceBtwBars; // Fits exactly below the bar
|
||||
int i = 0;
|
||||
|
||||
// Draw x labels
|
||||
foreach (DataItem item in this.DataPoints)
|
||||
{
|
||||
if ((i % this._interval) == 0)
|
||||
{
|
||||
currentX = this._xOrigin + (i * labelWidth) + of + (labelWidth / 2);
|
||||
RectangleF recLbl = new RectangleF(currentX - ((labelWidth * this._interval) / 2), currentY + of, labelWidth * this._interval, lblFont.Height * 2);
|
||||
string lblString = this._displayLegend ? item.Label : item.Description; // Decide what to show: short or long
|
||||
|
||||
graph.DrawString(lblString, lblFont, brs, recLbl, lblFormat);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lblFont != null)
|
||||
lblFont.Dispose();
|
||||
if (brs != null)
|
||||
brs.Dispose();
|
||||
if (lblFormat != null)
|
||||
lblFormat.Dispose();
|
||||
if (pen != null)
|
||||
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(this._fontFamily, _legendFontSize);
|
||||
brs = new SolidBrush(this._fontColor);
|
||||
lblFormat = new StringFormat();
|
||||
pen = new Pen(this._fontColor);
|
||||
lblFormat.Alignment = StringAlignment.Near;
|
||||
|
||||
// Calculate Legend drawing start point
|
||||
float startX = this._xOrigin + this._graphWidth + _graphLegendSpacer;
|
||||
float startY = this._yOrigin;
|
||||
|
||||
float xColorCode = startX + _spacer;
|
||||
float xLegendText = xColorCode + _legendRectangleSize + _spacer;
|
||||
float legendHeight = 0.0f;
|
||||
for (int i = 0; i < this.DataPoints.Count; i++)
|
||||
{
|
||||
DataItem point = this.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(this.DataPoints[i].ItemColor))
|
||||
graph.FillRectangle(brsh, xColorCode, currentY + 3f, _legendRectangleSize, _legendRectangleSize);
|
||||
}
|
||||
|
||||
// Draw legend border
|
||||
graph.DrawRectangle(pen, startX, startY, this._legendWidth, legendHeight + _spacer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lblFont != null)
|
||||
lblFont.Dispose();
|
||||
if (brs != null)
|
||||
brs.Dispose();
|
||||
if (lblFormat != null)
|
||||
lblFormat.Dispose();
|
||||
if (pen != null)
|
||||
pen.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates all measurement aspects of the bar graph from the given data points
|
||||
//
|
||||
//*********************************************************************
|
||||
private void CalculateGraphDimension()
|
||||
{
|
||||
this.FindLongestTickValue();
|
||||
|
||||
// Need to add another character for spacing; this is not used for drawing, just for calculation
|
||||
this._longestTickValue += "0";
|
||||
//_maxTickValueWidth = CalculateImgFontWidth(_longestTickValue, _labelFontSize, FontFamily);
|
||||
this._maxTickValueWidth = 0.0f;
|
||||
|
||||
float currentTick;
|
||||
string tickString;
|
||||
for (int i = 0; i < this._yTickCount; i++)
|
||||
{
|
||||
currentTick = this._maxValue - i * this._yTickValue;
|
||||
tickString = currentTick.ToString("#,###.##");
|
||||
|
||||
float measured = this.CalculateImgFontWidth(tickString, _labelFontSize, this.FontFamily);
|
||||
|
||||
if (measured > this._maxTickValueWidth)
|
||||
this._maxTickValueWidth = measured;
|
||||
}
|
||||
|
||||
float leftOffset = _spacer + this._maxTickValueWidth + (this._yTitle == null ? 0.0f : 20.0f);
|
||||
float rtOffset = 0.0f;
|
||||
|
||||
if (this._displayLegend)
|
||||
{
|
||||
this._legendWidth = _spacer + _legendRectangleSize + _spacer + this._maxLabelWidth + _spacer;
|
||||
rtOffset = _graphLegendSpacer + this._legendWidth + _spacer;
|
||||
}
|
||||
else
|
||||
rtOffset = _spacer; // Make graph in the middle
|
||||
|
||||
if (this._renderMode == BarGraphRenderMode.Bars)
|
||||
rtOffset += 10.0f;
|
||||
|
||||
rtOffset += 10.0f;
|
||||
|
||||
this._graphHeight = this._totalHeight - this._topBuffer - this._bottomBuffer - (this._xTitle == null ? 0.0f : 20.0f); // Buffer spaces are used to print labels
|
||||
this._graphWidth = this._totalWidth - leftOffset - rtOffset;
|
||||
this._xOrigin = leftOffset;
|
||||
this._yOrigin = this._topBuffer;
|
||||
|
||||
// Once the correct _maxValue is determined, then calculate _scaleFactor
|
||||
this._scaleFactor = this._maxValue / this._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 < this._yTickCount; i++)
|
||||
{
|
||||
currentTick = this._maxValue - i * this._yTickValue;
|
||||
tickString = currentTick.ToString("#,###.##");
|
||||
if (this._longestTickValue.Length < tickString.Length)
|
||||
this._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
|
||||
{
|
||||
if (graph != null)
|
||||
graph.Dispose();
|
||||
if (bmp != null)
|
||||
bmp.Dispose();
|
||||
if (font != null)
|
||||
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
|
||||
this._maxValue *= 1.1f;
|
||||
|
||||
if (this._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(this._maxValue)));
|
||||
tempMax = Convert.ToSingle(Math.Ceiling(this._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
|
||||
this._yTickValue = tempMax / this._yTickCount;
|
||||
double expTick = Convert.ToDouble(Math.Floor(Math.Log10(this._yTickValue)));
|
||||
this._yTickValue = Convert.ToSingle(Math.Ceiling(this._yTickValue / Math.Pow(10, expTick)) * Math.Pow(10, expTick));
|
||||
|
||||
// Re-calculate the max value with the new tick value
|
||||
this._maxValue = this._yTickValue * this._yTickCount;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// 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 this.DataPoints)
|
||||
{
|
||||
// This implementation does not support negative value
|
||||
if (item.Value >= 0)
|
||||
item.SweepSize = item.Value / this._scaleFactor;
|
||||
|
||||
// (_spaceBtwBars/2) makes half white space for the first bar
|
||||
item.StartPos = (this._spaceBtwBars / 2) + i * (this._barWidth + this._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
|
||||
this._barWidth = barGraphWidth / (dataCount * 2); // Each bar has 1 white space
|
||||
//_barWidth =/* (float)Math.Floor(*/_barWidth/*)*/;
|
||||
this._spaceBtwBars = this._barWidth;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method assigns default value to the bar graph properties and is only
|
||||
// called from BarGraph constructors
|
||||
//
|
||||
//*********************************************************************
|
||||
private void AssignDefaultSettings()
|
||||
{
|
||||
// default values
|
||||
this._totalWidth = 680f;
|
||||
this._totalHeight = 450f;
|
||||
this._fontFamily = "Verdana";
|
||||
this._backColor = Color.White;
|
||||
this._fontColor = Color.Black;
|
||||
this._topBuffer = 30f;
|
||||
this._bottomBuffer = 30f;
|
||||
this._yTickCount = 2;
|
||||
this._displayLegend = false;
|
||||
this._displayBarData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Scripts/Services/Reports/Rendering/ChartRenderer.cs
Normal file
70
Scripts/Services/Reports/Rendering/ChartRenderer.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
//*********************************************************************
|
||||
//
|
||||
// Chart Class
|
||||
//
|
||||
// Base class implementation for BarChart and PieChart
|
||||
//
|
||||
//*********************************************************************
|
||||
public abstract class ChartRenderer
|
||||
{
|
||||
private const int _colorLimit = 9;
|
||||
private readonly Color[] _color =
|
||||
{
|
||||
Color.Firebrick,
|
||||
Color.SkyBlue,
|
||||
Color.MediumSeaGreen,
|
||||
Color.MediumOrchid,
|
||||
Color.Chocolate,
|
||||
Color.SlateBlue,
|
||||
Color.LightPink,
|
||||
Color.LightGreen,
|
||||
Color.Khaki
|
||||
};
|
||||
// Represent collection of all data points for the chart
|
||||
private ChartItemsCollection _dataPoints = new ChartItemsCollection();
|
||||
public ChartItemsCollection DataPoints
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._dataPoints;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._dataPoints = value;
|
||||
}
|
||||
}
|
||||
// The implementation of this method is provided by derived classes
|
||||
public abstract Bitmap Draw();
|
||||
|
||||
public void SetColor(int index, Color NewColor)
|
||||
{
|
||||
if (index < _colorLimit)
|
||||
{
|
||||
this._color[index] = NewColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Color Limit is " + _colorLimit);
|
||||
}
|
||||
}
|
||||
|
||||
public Color GetColor(int index)
|
||||
{
|
||||
//return _color[index%_colorLimit];
|
||||
if (index < _colorLimit)
|
||||
{
|
||||
return this._color[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return this._color[(index + 2) % _colorLimit];
|
||||
//throw new Exception("Color Limit is " + _colorLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
Scripts/Services/Reports/Rendering/DataItem.cs
Normal file
143
Scripts/Services/Reports/Rendering/DataItem.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
// Modified from MS sample
|
||||
//*********************************************************************
|
||||
//
|
||||
// ChartItem Class
|
||||
//
|
||||
// This class represents a data point in a chart
|
||||
//
|
||||
//*********************************************************************
|
||||
public class DataItem
|
||||
{
|
||||
private string _label;
|
||||
private string _description;
|
||||
private float _value;
|
||||
private Color _color;
|
||||
private float _startPos;
|
||||
private float _sweepSize;
|
||||
public DataItem(string label, string desc, float data, float start, float sweep, Color clr)
|
||||
{
|
||||
this._label = label;
|
||||
this._description = desc;
|
||||
this._value = data;
|
||||
this._startPos = start;
|
||||
this._sweepSize = sweep;
|
||||
this._color = clr;
|
||||
}
|
||||
|
||||
private DataItem()
|
||||
{
|
||||
}
|
||||
|
||||
public string Label
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._label;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._label = value;
|
||||
}
|
||||
}
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._description;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._description = value;
|
||||
}
|
||||
}
|
||||
public float Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
}
|
||||
public Color ItemColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._color;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._color = value;
|
||||
}
|
||||
}
|
||||
public float StartPos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._startPos;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._startPos = value;
|
||||
}
|
||||
}
|
||||
public float SweepSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._sweepSize;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._sweepSize = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// Custom Collection for ChartItems
|
||||
//
|
||||
//*********************************************************************
|
||||
public class ChartItemsCollection : CollectionBase
|
||||
{
|
||||
public DataItem this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DataItem)(this.List[index]);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.List[index] = value;
|
||||
}
|
||||
}
|
||||
public int Add(DataItem value)
|
||||
{
|
||||
return this.List.Add(value);
|
||||
}
|
||||
|
||||
public int IndexOf(DataItem value)
|
||||
{
|
||||
return this.List.IndexOf(value);
|
||||
}
|
||||
|
||||
public bool Contains(DataItem value)
|
||||
{
|
||||
return this.List.Contains(value);
|
||||
}
|
||||
|
||||
public void Remove(DataItem value)
|
||||
{
|
||||
this.List.Remove(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
539
Scripts/Services/Reports/Rendering/HtmlRenderer.cs
Normal file
539
Scripts/Services/Reports/Rendering/HtmlRenderer.cs
Normal file
@@ -0,0 +1,539 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Web.UI;
|
||||
using HtmlAttr = System.Web.UI.HtmlTextWriterAttribute;
|
||||
using HtmlTag = System.Web.UI.HtmlTextWriterTag;
|
||||
using Server.Misc;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class HtmlRenderer
|
||||
{
|
||||
private static readonly string FtpHost = null;
|
||||
private static readonly string FtpUsername = null;
|
||||
private static readonly string FtpPassword = null;
|
||||
private static readonly string FtpStatsDirectory = null;
|
||||
private static readonly string FtpStaffDirectory = null;
|
||||
private readonly string m_Type;
|
||||
private readonly string m_Title;
|
||||
private readonly string m_OutputDirectory;
|
||||
private readonly DateTime m_TimeStamp;
|
||||
private readonly ObjectCollection m_Objects;
|
||||
public HtmlRenderer(string outputDirectory, Snapshot ss, SnapshotHistory history)
|
||||
: this(outputDirectory)
|
||||
{
|
||||
this.m_TimeStamp = ss.TimeStamp;
|
||||
|
||||
this.m_Objects = new ObjectCollection();
|
||||
|
||||
for (int i = 0; i < ss.Children.Count; ++i)
|
||||
this.m_Objects.Add(ss.Children[i]);
|
||||
|
||||
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Clients", 1, 100, 6));
|
||||
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Items", 24, 9, 1));
|
||||
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Players", 24, 9, 1));
|
||||
this.m_Objects.Add(BarGraph.OverTime(history, "General Stats", "NPCs", 24, 9, 1));
|
||||
this.m_Objects.Add(BarGraph.DailyAverage(history, "General Stats", "Clients"));
|
||||
this.m_Objects.Add(BarGraph.Growth(history, "General Stats", "Clients"));
|
||||
}
|
||||
|
||||
public HtmlRenderer(string outputDirectory, StaffHistory history)
|
||||
: this(outputDirectory)
|
||||
{
|
||||
this.m_TimeStamp = DateTime.UtcNow;
|
||||
|
||||
this.m_Objects = new ObjectCollection();
|
||||
|
||||
history.Render(this.m_Objects);
|
||||
}
|
||||
|
||||
private HtmlRenderer(string outputDirectory)
|
||||
{
|
||||
this.m_Type = outputDirectory;
|
||||
this.m_Title = (this.m_Type == "staff" ? "Staff" : "Stats");
|
||||
this.m_OutputDirectory = Path.Combine(Core.BaseDirectory, Config.Get("Reports.Path", "reports"));
|
||||
|
||||
if (!Directory.Exists(this.m_OutputDirectory))
|
||||
Directory.CreateDirectory(this.m_OutputDirectory);
|
||||
|
||||
this.m_OutputDirectory = Path.Combine(this.m_OutputDirectory, outputDirectory);
|
||||
|
||||
if (!Directory.Exists(this.m_OutputDirectory))
|
||||
Directory.CreateDirectory(this.m_OutputDirectory);
|
||||
}
|
||||
|
||||
public static string SafeFileName(string name)
|
||||
{
|
||||
return name.ToLower().Replace(' ', '_');
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
Console.WriteLine("Reports: {0}: Render started", this.m_Title);
|
||||
|
||||
this.RenderFull();
|
||||
|
||||
for (int i = 0; i < this.m_Objects.Count; ++i)
|
||||
this.RenderSingle(this.m_Objects[i]);
|
||||
|
||||
Console.WriteLine("Reports: {0}: Render complete", this.m_Title);
|
||||
}
|
||||
|
||||
public void Upload()
|
||||
{
|
||||
if (FtpHost == null)
|
||||
return;
|
||||
|
||||
Console.WriteLine("Reports: {0}: Upload started", this.m_Title);
|
||||
|
||||
string filePath = Path.Combine(this.m_OutputDirectory, "upload.ftp");
|
||||
|
||||
using (StreamWriter op = new StreamWriter(filePath))
|
||||
{
|
||||
op.WriteLine("open \"{0}\"", FtpHost);
|
||||
op.WriteLine(FtpUsername);
|
||||
op.WriteLine(FtpPassword);
|
||||
op.WriteLine("cd \"{0}\"", (this.m_Type == "staff" ? FtpStaffDirectory : FtpStatsDirectory));
|
||||
op.WriteLine("mput \"{0}\"", Path.Combine(this.m_OutputDirectory, "*.html"));
|
||||
op.WriteLine("mput \"{0}\"", Path.Combine(this.m_OutputDirectory, "*.css"));
|
||||
op.WriteLine("binary");
|
||||
op.WriteLine("mput \"{0}\"", Path.Combine(this.m_OutputDirectory, "*.png"));
|
||||
op.WriteLine("disconnect");
|
||||
op.Write("quit");
|
||||
}
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
|
||||
psi.FileName = "ftp";
|
||||
psi.Arguments = String.Format("-i -s:\"{0}\"", filePath);
|
||||
|
||||
psi.CreateNoWindow = true;
|
||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
//psi.UseShellExecute = true;
|
||||
|
||||
try
|
||||
{
|
||||
Process p = Process.Start(psi);
|
||||
|
||||
p.WaitForExit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
Console.WriteLine("Reports: {0}: Upload complete", this.m_Title);
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderFull()
|
||||
{
|
||||
string filePath = Path.Combine(this.m_OutputDirectory, "reports.html");
|
||||
|
||||
using (StreamWriter op = new StreamWriter(filePath))
|
||||
{
|
||||
using (HtmlTextWriter html = new HtmlTextWriter(op, "\t"))
|
||||
this.RenderFull(html);
|
||||
}
|
||||
|
||||
string cssPath = Path.Combine(this.m_OutputDirectory, "styles.css");
|
||||
|
||||
if (File.Exists(cssPath))
|
||||
return;
|
||||
|
||||
using (StreamWriter css = new StreamWriter(cssPath))
|
||||
{
|
||||
css.WriteLine("body { background-color: #FFFFFF; font-family: verdana, arial; font-size: 11px; }");
|
||||
css.WriteLine("a { color: #28435E; }");
|
||||
css.WriteLine("a:hover { color: #4878A9; }");
|
||||
css.WriteLine("td.header { background-color: #9696AA; font-weight: bold; font-size: 12px; }");
|
||||
css.WriteLine("td.lentry { background-color: #D7D7EB; width: 10%; }");
|
||||
css.WriteLine("td.rentry { background-color: #FFFFFF; width: 90%; }");
|
||||
css.WriteLine("td.entry { background-color: #FFFFFF; }");
|
||||
css.WriteLine("td { font-size: 11px; }");
|
||||
css.Write(".tbl-border { background-color: #46465A; }");
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderFull(HtmlTextWriter html)
|
||||
{
|
||||
html.RenderBeginTag(HtmlTag.Html);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Head);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Title);
|
||||
html.Write("{0} Statistics", ServerList.ServerName);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.AddAttribute("rel", "stylesheet");
|
||||
html.AddAttribute(HtmlAttr.Type, "text/css");
|
||||
html.AddAttribute(HtmlAttr.Href, "styles.css");
|
||||
html.RenderBeginTag(HtmlTag.Link);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Body);
|
||||
|
||||
for (int i = 0; i < this.m_Objects.Count; ++i)
|
||||
{
|
||||
this.RenderDirect(this.m_Objects[i], html);
|
||||
html.Write("<br><br>");
|
||||
}
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Center);
|
||||
TimeZoneInfo tz = TimeZoneInfo.Local;
|
||||
bool isDaylight = tz.IsDaylightSavingTime(this.m_TimeStamp);
|
||||
TimeSpan utcOffset = tz.GetUtcOffset(this.m_TimeStamp);
|
||||
|
||||
html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", this.m_TimeStamp, tz.StandardName);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
public void RenderSingle(PersistableObject obj)
|
||||
{
|
||||
string filePath = Path.Combine(this.m_OutputDirectory, SafeFileName(this.FindNameFrom(obj)) + ".html");
|
||||
|
||||
using (StreamWriter op = new StreamWriter(filePath))
|
||||
{
|
||||
using (HtmlTextWriter html = new HtmlTextWriter(op, "\t"))
|
||||
this.RenderSingle(obj, html);
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderSingle(PersistableObject obj, HtmlTextWriter html)
|
||||
{
|
||||
html.RenderBeginTag(HtmlTag.Html);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Head);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Title);
|
||||
html.Write("{0} Statistics - {1}", ServerList.ServerName, this.FindNameFrom(obj));
|
||||
html.RenderEndTag();
|
||||
|
||||
html.AddAttribute("rel", "stylesheet");
|
||||
html.AddAttribute(HtmlAttr.Type, "text/css");
|
||||
html.AddAttribute(HtmlAttr.Href, "styles.css");
|
||||
html.RenderBeginTag(HtmlTag.Link);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Body);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Center);
|
||||
|
||||
this.RenderDirect(obj, html);
|
||||
|
||||
html.Write("<br>");
|
||||
|
||||
TimeZoneInfo tz = TimeZoneInfo.Local;
|
||||
bool isDaylight = tz.IsDaylightSavingTime(this.m_TimeStamp);
|
||||
TimeSpan utcOffset = tz.GetUtcOffset(this.m_TimeStamp);
|
||||
|
||||
html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", this.m_TimeStamp, tz.StandardName);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
public void RenderDirect(PersistableObject obj, HtmlTextWriter html)
|
||||
{
|
||||
if (obj is Report)
|
||||
this.RenderReport(obj as Report, html);
|
||||
else if (obj is BarGraph)
|
||||
this.RenderBarGraph(obj as BarGraph, html);
|
||||
else if (obj is PieChart)
|
||||
this.RenderPieChart(obj as PieChart, html);
|
||||
}
|
||||
|
||||
private string FindNameFrom(PersistableObject obj)
|
||||
{
|
||||
if (obj is Report)
|
||||
return (obj as Report).Name;
|
||||
else if (obj is Chart)
|
||||
return (obj as Chart).Name;
|
||||
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
private void RenderPieChart(PieChart chart, HtmlTextWriter html)
|
||||
{
|
||||
PieChartRenderer pieChart = new PieChartRenderer(Color.White);
|
||||
|
||||
pieChart.ShowPercents = chart.ShowPercents;
|
||||
|
||||
string[] labels = new string[chart.Items.Count];
|
||||
string[] values = new string[chart.Items.Count];
|
||||
|
||||
for (int i = 0; i < chart.Items.Count; ++i)
|
||||
{
|
||||
ChartItem item = chart.Items[i];
|
||||
|
||||
labels[i] = item.Name;
|
||||
values[i] = item.Value.ToString();
|
||||
}
|
||||
|
||||
pieChart.CollectDataPoints(labels, values);
|
||||
|
||||
Bitmap bmp = pieChart.Draw();
|
||||
|
||||
string fileName = chart.FileName + ".png";
|
||||
bmp.Save(Path.Combine(this.m_OutputDirectory, fileName), ImageFormat.Png);
|
||||
|
||||
html.Write("<!-- ");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Href, "#");
|
||||
html.AddAttribute(HtmlAttr.Onclick, String.Format("javascript:window.open('{0}.html','ChildWindow','width={1},height={2},resizable=no,status=no,toolbar=no')", SafeFileName(this.FindNameFrom(chart)), bmp.Width + 30, bmp.Height + 80));
|
||||
html.RenderBeginTag(HtmlTag.A);
|
||||
html.Write(chart.Name);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.Write(" -->");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
||||
html.AddAttribute(HtmlAttr.Border, "0");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
html.Write(chart.Name);
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "entry");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString());
|
||||
html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString());
|
||||
html.AddAttribute(HtmlAttr.Src, fileName);
|
||||
html.RenderBeginTag(HtmlTag.Img);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
bmp.Dispose();
|
||||
}
|
||||
|
||||
private void RenderBarGraph(BarGraph graph, HtmlTextWriter html)
|
||||
{
|
||||
BarGraphRenderer barGraph = new BarGraphRenderer(Color.White);
|
||||
|
||||
barGraph.RenderMode = graph.RenderMode;
|
||||
|
||||
barGraph._regions = graph.Regions;
|
||||
barGraph.SetTitles(graph.xTitle, null);
|
||||
|
||||
if (graph.yTitle != null)
|
||||
barGraph.VerticalLabel = graph.yTitle;
|
||||
|
||||
barGraph.FontColor = Color.Black;
|
||||
barGraph.ShowData = (graph.Interval == 1);
|
||||
barGraph.VerticalTickCount = graph.Ticks;
|
||||
|
||||
string[] labels = new string[graph.Items.Count];
|
||||
string[] values = new string[graph.Items.Count];
|
||||
|
||||
for (int i = 0; i < graph.Items.Count; ++i)
|
||||
{
|
||||
ChartItem item = graph.Items[i];
|
||||
|
||||
labels[i] = item.Name;
|
||||
values[i] = item.Value.ToString();
|
||||
}
|
||||
|
||||
barGraph._interval = graph.Interval;
|
||||
barGraph.CollectDataPoints(labels, values);
|
||||
|
||||
Bitmap bmp = barGraph.Draw();
|
||||
|
||||
string fileName = graph.FileName + ".png";
|
||||
bmp.Save(Path.Combine(this.m_OutputDirectory, fileName), ImageFormat.Png);
|
||||
|
||||
html.Write("<!-- ");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Href, "#");
|
||||
html.AddAttribute(HtmlAttr.Onclick, String.Format("javascript:window.open('{0}.html','ChildWindow','width={1},height={2},resizable=no,status=no,toolbar=no')", SafeFileName(this.FindNameFrom(graph)), bmp.Width + 30, bmp.Height + 80));
|
||||
html.RenderBeginTag(HtmlTag.A);
|
||||
html.Write(graph.Name);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.Write(" -->");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
||||
html.AddAttribute(HtmlAttr.Border, "0");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
html.Write(graph.Name);
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "entry");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString());
|
||||
html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString());
|
||||
html.AddAttribute(HtmlAttr.Src, fileName);
|
||||
html.RenderBeginTag(HtmlTag.Img);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
bmp.Dispose();
|
||||
}
|
||||
|
||||
private void RenderReport(Report report, HtmlTextWriter html)
|
||||
{
|
||||
html.AddAttribute(HtmlAttr.Width, report.Width);
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
||||
html.AddAttribute(HtmlAttr.Border, "0");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
html.Write(report.Name);
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
bool isNamed = false;
|
||||
|
||||
for (int i = 0; i < report.Columns.Count && !isNamed; ++i)
|
||||
isNamed = (report.Columns[i].Name != null);
|
||||
|
||||
if (isNamed)
|
||||
{
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
for (int i = 0; i < report.Columns.Count; ++i)
|
||||
{
|
||||
ReportColumn column = report.Columns[i];
|
||||
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.AddAttribute(HtmlAttr.Width, column.Width);
|
||||
html.AddAttribute(HtmlAttr.Align, column.Align);
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.Write(column.Name);
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
for (int i = 0; i < report.Items.Count; ++i)
|
||||
{
|
||||
ReportItem item = report.Items[i];
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
for (int j = 0; j < item.Values.Count; ++j)
|
||||
{
|
||||
if (!isNamed && j == 0)
|
||||
html.AddAttribute(HtmlAttr.Width, report.Columns[j].Width);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Align, report.Columns[j].Align);
|
||||
html.AddAttribute(HtmlAttr.Class, "entry");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
if (item.Values[j].Format == null)
|
||||
html.Write(item.Values[j].Value);
|
||||
else
|
||||
html.Write(int.Parse(item.Values[j].Value).ToString(item.Values[j].Format));
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
}
|
||||
}
|
||||
}
|
||||
259
Scripts/Services/Reports/Rendering/PieChartRenderer.cs
Normal file
259
Scripts/Services/Reports/Rendering/PieChartRenderer.cs
Normal file
@@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
// Modified from MS sample
|
||||
//*********************************************************************
|
||||
//
|
||||
// PieChart Class
|
||||
//
|
||||
// This class uses GDI+ to render Pie Chart.
|
||||
//
|
||||
//*********************************************************************
|
||||
public class PieChartRenderer : ChartRenderer
|
||||
{
|
||||
private const int _bufferSpace = 125;
|
||||
private readonly ArrayList _chartItems;
|
||||
private readonly Color _backgroundColor;
|
||||
private readonly Color _borderColor;
|
||||
private readonly string _legendFontStyle;
|
||||
private readonly float _legendFontSize;
|
||||
private int _perimeter;
|
||||
private float _total;
|
||||
private int _legendWidth;
|
||||
private int _legendHeight;
|
||||
private int _legendFontHeight;
|
||||
private bool _showPercents;
|
||||
public PieChartRenderer()
|
||||
{
|
||||
this._chartItems = new ArrayList();
|
||||
this._perimeter = 250;
|
||||
this._backgroundColor = Color.White;
|
||||
this._borderColor = Color.FromArgb(63, 63, 63);
|
||||
this._legendFontSize = 8;
|
||||
this._legendFontStyle = "Verdana";
|
||||
}
|
||||
|
||||
public PieChartRenderer(Color bgColor)
|
||||
{
|
||||
this._chartItems = new ArrayList();
|
||||
this._perimeter = 250;
|
||||
this._backgroundColor = bgColor;
|
||||
this._borderColor = Color.FromArgb(63, 63, 63);
|
||||
this._legendFontSize = 8;
|
||||
this._legendFontStyle = "Verdana";
|
||||
}
|
||||
|
||||
public bool ShowPercents
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._showPercents;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._showPercents = value;
|
||||
}
|
||||
}
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method collects all data points and calculate all the necessary dimensions
|
||||
// to draw the chart. It is the first method called before invoking the Draw() method.
|
||||
//
|
||||
//*********************************************************************
|
||||
public void CollectDataPoints(string[] xValues, string[] yValues)
|
||||
{
|
||||
this._total = 0.0f;
|
||||
|
||||
for (int i = 0; i < xValues.Length; i++)
|
||||
{
|
||||
float ftemp = Convert.ToSingle(yValues[i]);
|
||||
this._chartItems.Add(new DataItem(xValues[i], xValues.ToString(), ftemp, 0, 0, Color.AliceBlue));
|
||||
this._total += ftemp;
|
||||
}
|
||||
|
||||
float nextStartPos = 0.0f;
|
||||
int counter = 0;
|
||||
foreach (DataItem item in this._chartItems)
|
||||
{
|
||||
item.StartPos = nextStartPos;
|
||||
item.SweepSize = item.Value / this._total * 360;
|
||||
nextStartPos = item.StartPos + item.SweepSize;
|
||||
item.ItemColor = this.GetColor(counter++);
|
||||
}
|
||||
|
||||
this.CalculateLegendWidthHeight();
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method returns a bitmap to the calling function. This is the method
|
||||
// that actually draws the pie chart and the legend with it.
|
||||
//
|
||||
//*********************************************************************
|
||||
public override Bitmap Draw()
|
||||
{
|
||||
int perimeter = this._perimeter;
|
||||
Rectangle pieRect = new Rectangle(0, 0, perimeter, perimeter - 1);
|
||||
Bitmap bmp = new Bitmap(perimeter + this._legendWidth, perimeter);
|
||||
Font fnt = null;
|
||||
Pen pen = null;
|
||||
Graphics grp = null;
|
||||
StringFormat sf = null, sfp = null;
|
||||
|
||||
try
|
||||
{
|
||||
grp = Graphics.FromImage(bmp);
|
||||
grp.CompositingQuality = CompositingQuality.HighQuality;
|
||||
grp.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
sf = new StringFormat();
|
||||
|
||||
//Paint Back ground
|
||||
using (SolidBrush brsh = new SolidBrush(this._backgroundColor))
|
||||
grp.FillRectangle(brsh, -1, -1, perimeter + this._legendWidth + 1, perimeter + 1);
|
||||
|
||||
//Align text to the right
|
||||
sf.Alignment = StringAlignment.Far;
|
||||
|
||||
//Draw all wedges and legends
|
||||
for (int i = 0; i < this._chartItems.Count; i++)
|
||||
{
|
||||
DataItem item = (DataItem)this._chartItems[i];
|
||||
SolidBrush brs = null;
|
||||
try
|
||||
{
|
||||
brs = new SolidBrush(item.ItemColor);
|
||||
grp.FillPie(brs, pieRect, item.StartPos, item.SweepSize);
|
||||
|
||||
//grp.DrawPie(new Pen(_borderColor,1.2f),pieRect,item.StartPos,item.SweepSize);
|
||||
|
||||
if (fnt == null)
|
||||
fnt = new Font(this._legendFontStyle, this._legendFontSize);
|
||||
|
||||
if (this._showPercents && item.SweepSize > 10)
|
||||
{
|
||||
if (sfp == null)
|
||||
{
|
||||
sfp = new StringFormat();
|
||||
sfp.Alignment = StringAlignment.Center;
|
||||
sfp.LineAlignment = StringAlignment.Center;
|
||||
}
|
||||
|
||||
float perc = (item.SweepSize * 100.0f) / 360.0f;
|
||||
string percString = String.Format("{0:F0}%", perc);
|
||||
|
||||
float px = pieRect.X + (pieRect.Width / 2);
|
||||
float py = pieRect.Y + (pieRect.Height / 2);
|
||||
|
||||
double angle = item.StartPos + (item.SweepSize / 2);
|
||||
double rads = (angle / 180.0) * Math.PI;
|
||||
|
||||
px += (float)(Math.Cos(rads) * perimeter / 3);
|
||||
py += (float)(Math.Sin(rads) * perimeter / 3);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30 - 1, py - 20, 60, 40), sfp);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30 + 1, py - 20, 60, 40), sfp);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30, py - 20 - 1, 60, 40), sfp);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30, py - 20 + 1, 60, 40), sfp);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.White,
|
||||
new RectangleF(px - 30, py - 20, 60, 40), sfp);
|
||||
}
|
||||
|
||||
if (pen == null)
|
||||
pen = new Pen(this._borderColor, 0.5f);
|
||||
|
||||
grp.FillRectangle(brs, perimeter + _bufferSpace, i * this._legendFontHeight + 15, 10, 10);
|
||||
grp.DrawRectangle(pen, perimeter + _bufferSpace, i * this._legendFontHeight + 15, 10, 10);
|
||||
|
||||
grp.DrawString(item.Label, fnt,
|
||||
Brushes.Black, perimeter + _bufferSpace + 20, i * this._legendFontHeight + 13);
|
||||
|
||||
grp.DrawString(item.Value.ToString("#,###.##"), fnt,
|
||||
Brushes.Black, perimeter + _bufferSpace + 200, i * this._legendFontHeight + 13, sf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (brs != null)
|
||||
brs.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < this._chartItems.Count; i++)
|
||||
{
|
||||
DataItem item = (DataItem)this._chartItems[i];
|
||||
SolidBrush brs = null;
|
||||
try
|
||||
{
|
||||
grp.DrawPie(new Pen(this._borderColor,0.5f), pieRect, item.StartPos, item.SweepSize);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (brs != null)
|
||||
brs.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//draws the border around Pie
|
||||
using (Pen pen2 = new Pen(this._borderColor, 2))
|
||||
grp.DrawEllipse(pen2, pieRect);
|
||||
|
||||
//draw border around legend
|
||||
using (Pen pen1 = new Pen(this._borderColor, 1))
|
||||
grp.DrawRectangle(pen1, perimeter + _bufferSpace - 10, 10, 220, this._chartItems.Count * this._legendFontHeight + 25);
|
||||
|
||||
//Draw Total under legend
|
||||
using (Font fntb = new Font(this._legendFontStyle, this._legendFontSize, FontStyle.Bold))
|
||||
{
|
||||
grp.DrawString("Total", fntb,
|
||||
Brushes.Black, perimeter + _bufferSpace + 30, (this._chartItems.Count + 1) * this._legendFontHeight, sf);
|
||||
grp.DrawString(this._total.ToString("#,###.##"), fntb,
|
||||
Brushes.Black, perimeter + _bufferSpace + 200, (this._chartItems.Count + 1) * this._legendFontHeight, sf);
|
||||
}
|
||||
|
||||
grp.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (sf != null)
|
||||
sf.Dispose();
|
||||
if (grp != null)
|
||||
grp.Dispose();
|
||||
if (sfp != null)
|
||||
sfp.Dispose();
|
||||
if (fnt != null)
|
||||
fnt.Dispose();
|
||||
if (pen != null)
|
||||
pen.Dispose();
|
||||
}
|
||||
return bmp;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates the space required to draw the chart legend.
|
||||
//
|
||||
//*********************************************************************
|
||||
private void CalculateLegendWidthHeight()
|
||||
{
|
||||
Font fontLegend = new Font(this._legendFontStyle, this._legendFontSize);
|
||||
this._legendFontHeight = fontLegend.Height + 3;
|
||||
this._legendHeight = fontLegend.Height * (this._chartItems.Count + 1);
|
||||
if (this._legendHeight > this._perimeter)
|
||||
this._perimeter = this._legendHeight;
|
||||
|
||||
this._legendWidth = this._perimeter + _bufferSpace;
|
||||
fontLegend.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user