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;
}
正常情况下的曲线图:

出现问题时的曲线图:




































































































































































出现问题时的曲线图:

分类:
.Net开发
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现