ASP.net曲线图生成程序
这是我写的一个生成简单曲线图的程序,效果还是不错的,不过其中也有一些问题,比如如果数据中出现负数,特别是很大的负数就会使得一部分曲线不能够显示出来,还有就是如何才能保证曲线处于坐标轴的中间部位?请知道的朋友帮忙看一下,谢谢。
出现问题时的曲线图:
public static string draw(IList<TargerAnalyse.AggregativeDataSet> ds, string Field, string Title)
{
if (ds == null) return null;
if (Field == "" || Field == string.Empty || Field == null) return null;
//取得记录数量
int count = ds.Count;
if (count < 2) return null;
//图表高度
int height = 600;
//记算图表宽度
int wd = 80 + 12 * (count - 1);
//设置最小宽度为800
if (wd < 800) wd = 800;
//生成Bitmap对像
Bitmap img = new Bitmap(wd, height);
//生成绘图对像
Graphics g = Graphics.FromImage(img);
//定义黑色画笔
Pen Bp = new Pen(Color.Black);
//定义红色画笔
Pen Rp = new Pen(Color.Red);
//定义银灰色画笔
Pen Sp = new Pen(Color.Silver);
//定义大标题字体
Font Bfont = new Font("Arial", 12, FontStyle.Bold);
//定义一般字体
Font font = new Font("Arial", 8);
//定义大点的字体
Font Tfont = new Font("Arial", 10);
//绘制底色
g.DrawRectangle(new Pen(Color.White, height), 0, 0, img.Width, img.Height);
//定义黑色过渡型笔刷
LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, img.Width, img.Height), Color.Black, Color.Black, 1.2F, true);
//定义蓝色过渡型笔刷
LinearGradientBrush Bluebrush = new LinearGradientBrush(new Rectangle(0, 0, img.Width, img.Height), Color.Blue, Color.Blue, 1.2F, true);
//绘制大标题
g.DrawString(Title, Bfont, brush, 300, 5);
//左边距
int zuobian = 40;
//右边距
int youbian = 40;
//上边距
int shangbian = 60;
//下边距
int xiabian = 40;
//间隔
int xjiange = (wd - zuobian - youbian) / count; // 60;
int yjiange = (height - shangbian - xiabian) / count; //60;
//图示位置
int ts = zuobian + xjiange * (count - 1) + 20;
//取得合计数
double nums = 0;
//取得最小值
double min = 0;
//取得最大值
double max = 0;
bool IsHasNegative = false;
for (int i = 0; i < count; i++)
{
nums += Math.Abs(Convert.ToDouble(ds[i][Field]));
if (Convert.ToDouble(ds[i][Field]) < min)
{
min = Convert.ToDouble(ds[i][Field]);
}
if (Convert.ToDouble(ds[i][Field]) > max)
{
max = Math.Abs(Convert.ToDouble(ds[i][Field]));
}
if (Convert.ToDouble(ds[i][Field]) < 0) IsHasNegative = true;
}
//绘制图片边框
g.DrawRectangle(Bp, 0, 0, img.Width - 1, img.Height - 1);
//绘制竖坐标线
for (int i = 0; i < count; i++)
{
g.DrawLine(Sp, zuobian + xjiange * i, shangbian, zuobian + xjiange * i, height - xiabian);
if (i % 2 == 1)
{
string st = Convert.ToString(ds[i]["bbny"]);
g.DrawString(st, font, brush, zuobian + xjiange * i - 20, height - xiabian + 5);
}
}
//绘制时间轴坐标标签
//for (int i = 0; i < count; i += 2)
//{
// string st = Convert.ToString(ds.Tables[0].Rows[i]["bbny"]);
// g.DrawString(st, font, brush, zuobian + xjiange * i - 20, height - xiabian+5);
//}
//绘制横坐标线
for (int i = 0; i < count; i++)
{
if (height - xiabian - yjiange * i > shangbian)
g.DrawLine(Sp, zuobian, height - xiabian - yjiange * i, zuobian + xjiange * (count - 1), height - xiabian - yjiange * i);
}
//绘制竖坐标轴
g.DrawLine(Bp, zuobian, shangbian - 15, zuobian, height - xiabian);
//绘制横坐标轴
if (!IsHasNegative)
g.DrawLine(Bp, zuobian, height - xiabian, zuobian + xjiange * (count - 1) + 15, height - xiabian);
else
g.DrawLine(Bp, zuobian, 300, zuobian + xjiange * (count - 1) + 15, 300);
//均值所对应得Y坐标
int zhy = (int)(((double)(height - shangbian - xiabian)) * nums / count / max) - (height - shangbian - xiabian) / 2;
//定义曲线转折点
Point[] p = new Point[count];
for (int i = 0; i < count; i++)
{
p[i].X = zuobian + xjiange * i;
//p[i].Y = 360 - Convert.ToInt32(ds.Tables[0].Rows[i][Field]) / 5 * 3 / 5;
//p[i].Y =Convert.ToInt32( System.Math.Round(Convert.ToDouble(height-shangbian-xiabian)*(Convert.ToDouble(ds.Tables[0].Rows[i][Field])) / nums))+shangbian ;
if (!IsHasNegative)
p[i].Y = height - (int)((double)(height - shangbian - xiabian) * (Convert.ToDouble(ds[i][Field])) / max) + shangbian + zhy - xiabian;
else
{
if (Convert.ToDouble(ds[i][Field]) > 0)
p[i].Y = height / 2 - (int)((double)(height / 2 - shangbian) * (Convert.ToDouble(ds[i][Field])) / max) + shangbian;
else
p[i].Y = height / 2 + (int)((double)(height / 2 - xiabian) * (Math.Abs(Convert.ToDouble(ds[i][Field]))) / max);
}
}
//绘制曲线
g.DrawCurve(Rp, p);
for (int i = 0; i < count; i++)
{
//绘制数据
g.DrawString(ds[i][Field].ToString(), font, Bluebrush, p[i].X - 5, p[i].Y - 10);
//绘制数据点
g.DrawRectangle(Rp, p[i].X - 1, p[i].Y - 1, 2, 2);
}
//绘制竖坐标标题
g.DrawString("指标", Tfont, brush, 5, shangbian - 20);
//绘制横坐标标题
g.DrawString("月度", Tfont, brush, zuobian + xjiange * (count - 1) + 20, height - xiabian + 5);
//保存绘制的图片
//MemoryStream stream = new MemoryStream();
//img.Save(stream, ImageFormat.Jpeg);
Random r = new Random(1);
string filepath = System.Web.Hosting.HostingEnvironment.MapPath("~\\chart\\") + r.Next().ToString() + ".jpg";
img.Save(filepath, ImageFormat.Jpeg);
g.Dispose();
img.Dispose();
//return stream;
return filepath;
}
正常情况下的曲线图:{
if (ds == null) return null;
if (Field == "" || Field == string.Empty || Field == null) return null;
//取得记录数量
int count = ds.Count;
if (count < 2) return null;
//图表高度
int height = 600;
//记算图表宽度
int wd = 80 + 12 * (count - 1);
//设置最小宽度为800
if (wd < 800) wd = 800;
//生成Bitmap对像
Bitmap img = new Bitmap(wd, height);
//生成绘图对像
Graphics g = Graphics.FromImage(img);
//定义黑色画笔
Pen Bp = new Pen(Color.Black);
//定义红色画笔
Pen Rp = new Pen(Color.Red);
//定义银灰色画笔
Pen Sp = new Pen(Color.Silver);
//定义大标题字体
Font Bfont = new Font("Arial", 12, FontStyle.Bold);
//定义一般字体
Font font = new Font("Arial", 8);
//定义大点的字体
Font Tfont = new Font("Arial", 10);
//绘制底色
g.DrawRectangle(new Pen(Color.White, height), 0, 0, img.Width, img.Height);
//定义黑色过渡型笔刷
LinearGradientBrush brush = new LinearGradientBrush(new Rectangle(0, 0, img.Width, img.Height), Color.Black, Color.Black, 1.2F, true);
//定义蓝色过渡型笔刷
LinearGradientBrush Bluebrush = new LinearGradientBrush(new Rectangle(0, 0, img.Width, img.Height), Color.Blue, Color.Blue, 1.2F, true);
//绘制大标题
g.DrawString(Title, Bfont, brush, 300, 5);
//左边距
int zuobian = 40;
//右边距
int youbian = 40;
//上边距
int shangbian = 60;
//下边距
int xiabian = 40;
//间隔
int xjiange = (wd - zuobian - youbian) / count; // 60;
int yjiange = (height - shangbian - xiabian) / count; //60;
//图示位置
int ts = zuobian + xjiange * (count - 1) + 20;
//取得合计数
double nums = 0;
//取得最小值
double min = 0;
//取得最大值
double max = 0;
bool IsHasNegative = false;
for (int i = 0; i < count; i++)
{
nums += Math.Abs(Convert.ToDouble(ds[i][Field]));
if (Convert.ToDouble(ds[i][Field]) < min)
{
min = Convert.ToDouble(ds[i][Field]);
}
if (Convert.ToDouble(ds[i][Field]) > max)
{
max = Math.Abs(Convert.ToDouble(ds[i][Field]));
}
if (Convert.ToDouble(ds[i][Field]) < 0) IsHasNegative = true;
}
//绘制图片边框
g.DrawRectangle(Bp, 0, 0, img.Width - 1, img.Height - 1);
//绘制竖坐标线
for (int i = 0; i < count; i++)
{
g.DrawLine(Sp, zuobian + xjiange * i, shangbian, zuobian + xjiange * i, height - xiabian);
if (i % 2 == 1)
{
string st = Convert.ToString(ds[i]["bbny"]);
g.DrawString(st, font, brush, zuobian + xjiange * i - 20, height - xiabian + 5);
}
}
//绘制时间轴坐标标签
//for (int i = 0; i < count; i += 2)
//{
// string st = Convert.ToString(ds.Tables[0].Rows[i]["bbny"]);
// g.DrawString(st, font, brush, zuobian + xjiange * i - 20, height - xiabian+5);
//}
//绘制横坐标线
for (int i = 0; i < count; i++)
{
if (height - xiabian - yjiange * i > shangbian)
g.DrawLine(Sp, zuobian, height - xiabian - yjiange * i, zuobian + xjiange * (count - 1), height - xiabian - yjiange * i);
}
//绘制竖坐标轴
g.DrawLine(Bp, zuobian, shangbian - 15, zuobian, height - xiabian);
//绘制横坐标轴
if (!IsHasNegative)
g.DrawLine(Bp, zuobian, height - xiabian, zuobian + xjiange * (count - 1) + 15, height - xiabian);
else
g.DrawLine(Bp, zuobian, 300, zuobian + xjiange * (count - 1) + 15, 300);
//均值所对应得Y坐标
int zhy = (int)(((double)(height - shangbian - xiabian)) * nums / count / max) - (height - shangbian - xiabian) / 2;
//定义曲线转折点
Point[] p = new Point[count];
for (int i = 0; i < count; i++)
{
p[i].X = zuobian + xjiange * i;
//p[i].Y = 360 - Convert.ToInt32(ds.Tables[0].Rows[i][Field]) / 5 * 3 / 5;
//p[i].Y =Convert.ToInt32( System.Math.Round(Convert.ToDouble(height-shangbian-xiabian)*(Convert.ToDouble(ds.Tables[0].Rows[i][Field])) / nums))+shangbian ;
if (!IsHasNegative)
p[i].Y = height - (int)((double)(height - shangbian - xiabian) * (Convert.ToDouble(ds[i][Field])) / max) + shangbian + zhy - xiabian;
else
{
if (Convert.ToDouble(ds[i][Field]) > 0)
p[i].Y = height / 2 - (int)((double)(height / 2 - shangbian) * (Convert.ToDouble(ds[i][Field])) / max) + shangbian;
else
p[i].Y = height / 2 + (int)((double)(height / 2 - xiabian) * (Math.Abs(Convert.ToDouble(ds[i][Field]))) / max);
}
}
//绘制曲线
g.DrawCurve(Rp, p);
for (int i = 0; i < count; i++)
{
//绘制数据
g.DrawString(ds[i][Field].ToString(), font, Bluebrush, p[i].X - 5, p[i].Y - 10);
//绘制数据点
g.DrawRectangle(Rp, p[i].X - 1, p[i].Y - 1, 2, 2);
}
//绘制竖坐标标题
g.DrawString("指标", Tfont, brush, 5, shangbian - 20);
//绘制横坐标标题
g.DrawString("月度", Tfont, brush, zuobian + xjiange * (count - 1) + 20, height - xiabian + 5);
//保存绘制的图片
//MemoryStream stream = new MemoryStream();
//img.Save(stream, ImageFormat.Jpeg);
Random r = new Random(1);
string filepath = System.Web.Hosting.HostingEnvironment.MapPath("~\\chart\\") + r.Next().ToString() + ".jpg";
img.Save(filepath, ImageFormat.Jpeg);
g.Dispose();
img.Dispose();
//return stream;
return filepath;
}
出现问题时的曲线图: