ASP.NET 简单的柱形图实现(附带示例)
对于一些内部系统的项目,各种图表是在所难免的,因为图表可以更加清晰的表达出想看到的数据。
因为之前从来没有做过关于图表的东西,唯一能想到的就是“验证码”,所以应该是一个思路,用GDI去搞。
数据懒着去搞了,记得前些日子在亚航官网查机票,就想到这些数据还挺适合做这个DEMO的,所以就先借用一下亚航的数据喽。
数据大概就是这样子的,日期及价钱。
我选了其中“9月27日-10月10日”正好两周的数据作为此次Demo的测试数据。
原理就是跟实现验证码一模一样,通过给<img>标签修改src属性来操作柱形图的变化,src属性导向的页面是另外一个页,非显示柱形图本页。
然后就是如何利用GDI画柱形图。
先上一下效果图:
下面看一下部分代码片段
html代码:
<body>
<form id="form1" runat="server">
<div>
<asp:ImageButton ID="img_last" runat="server" ImageUrl="~/Left.jpg" AlternateText="Left" OnClientClick="return false;" />
<img id="img_bar" src="GenerateImage.aspx?page_num=0&from=北京&to=清迈" alt="" />
<asp:ImageButton ID="img_next" runat="server" ImageUrl="~/Right.jpg" AlternateText="Right" OnClientClick="return false;" />
</div>
<asp:HiddenField ID="hf_pagenum" runat="server" Value="0" />
<asp:HiddenField ID="hf_recordnum" runat="server" />
</form>
</body>
js代码:
$(function () { var $pagenum = $("#hf_pagenum");
var $recordnum = $("#hf_recordnum"); $("#img_last").click(function () {
if (parseInt($pagenum.val()) - 1 >= 0) {
$pagenum.val(parseInt($pagenum.val()) - 1);
$("#img_bar").attr("src", "GenerateImage.aspx?page_num=" + $pagenum.val() + "&from=北京&to=清迈");
}
}) $("#img_next").click(function () {
if (parseInt($pagenum.val()) + 1 < parseInt($recordnum.val())/7) {
$pagenum.val(parseInt($pagenum.val()) + 1);
$("#img_bar").attr("src", "GenerateImage.aspx?page_num=" + $pagenum.val() + "&from=北京&to=清迈");
}
}) })
后台代码:
1、一些坐标点的声明
private readonly int WEEKDAYS = 7;//一周的天数
private readonly int Y_UNIT_NUM = 10;
private readonly int CHAR_X_LEFT = 110;
private readonly int CHAR_X_TOP = 388; private readonly int CHAR_Y_LEFT = 30;
private readonly int CHAR_Y_TOP = 79; private readonly int TITLE_LEFT = 140;//柱形图标题 起始X坐标
private readonly int TITLE_TOP = 18;//柱形图标题 起始Y坐标
private readonly int TIME_LEFT = 170;//柱形图日期 起始X坐标
private readonly int TIME_TOP = 48;//柱形图日期 起始Y坐标 private readonly int GRID_X_LEFT = 150;//背景网格 X左边位移
private readonly int GRID_X_TOP = 80;//背景网格 X上边位移
private readonly int GRID_X_BOTTOM = 380;//背景网格 X下边位移 private readonly int GRID_Y_TOP = 110;
private readonly int GRID_Y_LEFT = 100;
private readonly int GRID_Y_RIGHT = 580; private readonly int GRID_UNIT_WIDTH = 50;//网格单元宽度
private readonly int GRID_UNIT_HEIGHT = 30;//网格单元高度
private readonly int DATA_UNIT_WIDTH = 40;//柱单元宽度
private readonly int DATA_UNIT_HEIGHT = 30;//柱单元高度
2、筛选当页数据方法
为了是通过点击下一页,上一页按钮,对数据进行筛选,选出当页显示数据进行绘制
protected DataSet QueryDisplayRecord(int pagenum)
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("date"));
dt.Columns.Add(new DataColumn("price"));
for (int i = 7 * pagenum; i < (goStr.Count >= WEEKDAYS * (pagenum + 1) ? WEEKDAYS * (pagenum + 1) : goStr.Count); i++)
{
DataRow dr = dt.NewRow();
dr["date"] = goStr.Keys.Take(i + 1).Last(); ;
dr["price"] = goStr.Values.Take(i + 1).Last(); ;
dt.Rows.Add(dr);
}
ds.Tables.Add(dt);
return ds;
}
哦,对了,这里用的是dictionary<string, string>暂时存的模拟数据,正常情况当然要是通过数据库了。
3、生成图片
protected void CreateImage(string from, string to, int pagenum, DataSet ds)
{
Font font_Note = new System.Drawing.Font("Arial", 9, FontStyle.Regular);//x轴,y轴,解释内容字体 小字
Font font_GraphicName = new System.Drawing.Font("微软雅黑", 18, FontStyle.Regular);//图表名称 字体 大字
Font font_GraphicTime = new System.Drawing.Font("微软雅黑", 14, FontStyle.Regular);//图表时间 字体 大字
Brush brush_Blue = new SolidBrush(Color.Black);//蓝色线条
if (ds != null)
{
int height = 620, width = 650; System.Drawing.Bitmap image = new System.Drawing.Bitmap(width, height);
Graphics g = Graphics.FromImage(image);
g.Clear(Color.White);
System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, image.Width, image.Height), Color.LightGray, Color.LightGray, 1.2f, true);
//调用FillRectangle方法使用指定颜色填充柱形图的内部
g.FillRectangle(Brushes.WhiteSmoke, 0, 0, width, height);
Brush brush1 = new SolidBrush(Color.Black);
//应用DrawString方法输出文字信息
g.DrawString(from + " 至 " + to + " 机票分析图 (单位:CNY)", font_GraphicName, brush_Blue, new PointF(TITLE_LEFT, TITLE_TOP));
//画图片的边框线
g.DrawRectangle(new Pen(Color.Black), 0, 0, image.Width - 1, image.Height - 1);
Pen mypen = new Pen(brush, 1); //绘制横向线条
for (int i = 0; i < WEEKDAYS; i++)
{
g.DrawLine(mypen, GRID_X_LEFT + GRID_UNIT_WIDTH * i, GRID_X_TOP, GRID_X_LEFT + GRID_UNIT_WIDTH * i, GRID_X_BOTTOM);
}
Pen mypen1 = new Pen(Color.Black, 2);
g.DrawLine(mypen1, GRID_X_LEFT - GRID_UNIT_WIDTH, GRID_X_TOP, GRID_X_LEFT - GRID_UNIT_WIDTH, GRID_X_BOTTOM);
for (int i = 0; i < Y_UNIT_NUM; i++)
{
g.DrawLine(mypen, GRID_Y_LEFT, GRID_Y_TOP + GRID_UNIT_HEIGHT * i, GRID_Y_RIGHT, GRID_Y_TOP + GRID_UNIT_HEIGHT * i);
}
g.DrawLine(mypen1, GRID_Y_LEFT, GRID_Y_TOP + GRID_UNIT_HEIGHT * (Y_UNIT_NUM - 1), GRID_Y_RIGHT, GRID_Y_TOP + GRID_UNIT_HEIGHT * (Y_UNIT_NUM - 1));
//x轴
for (int i = 0; i < WEEKDAYS; i++)
{
g.DrawString(ds.Tables[0].Rows[i][0].ToString().Substring(ds.Tables[0].Rows[i][0].ToString().LastIndexOf(',') + 1), font_Note, Brushes.Black, CHAR_X_LEFT + GRID_UNIT_WIDTH * i, CHAR_X_TOP);
}
//y轴
string[] money = { "5000CNY", "4500CNY", "4000CNY", "3500CNY", "3000CNY", "2500CNY", "2000CNY", "1500CNY", "1000CNY", "500CNY" };
for (int i = 0; i < Y_UNIT_NUM; i++)
{
g.DrawString(money[i].ToString(), font_Note, Brushes.Black, CHAR_Y_LEFT, CHAR_Y_TOP + DATA_UNIT_HEIGHT * i);
} int[] Count = new int[WEEKDAYS];
int j = 0;
for (j = 0; j < WEEKDAYS; j++)
{
Count[j] = Convert.ToInt32(ds.Tables[0].Rows[j][1].ToString());
}
//显示柱状效果
ImageAttributes imgAtt = new ImageAttributes();
imgAtt.SetWrapMode(WrapMode.TileFlipXY);//为了使柱形图片无渐变色效果
for (int i = 0; i < WEEKDAYS; i++)
{
g.DrawImage(bitmap, new Rectangle(GRID_Y_LEFT + GRID_UNIT_WIDTH * i + (GRID_UNIT_WIDTH - DATA_UNIT_WIDTH) / 2, (int)(380 - (Count[i] > 5000 ? 5000 : Count[i]) * 3F / 50F), 40, (int)(Count[i] * 3F / 50F)), 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, imgAtt);
}
//创建其支持存储区为内存的流
System.IO.MemoryStream ms = new System.IO.MemoryStream();
//将此图像以指定格式保存到指定流中
image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
//清除缓冲区流中的所有内容输出
Response.ClearContent();
//设置输出MIME类型
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());
}
else
{
int height = 380, width = 570;
System.Drawing.Bitmap image = new System.Drawing.Bitmap(width, height);
Graphics g = Graphics.FromImage(image);
g.Clear(Color.White);
//应用DrawString方法输出文字信息
g.DrawString("无符合搜索条件数据", font_GraphicName, brush_Blue, new PointF(140, 20));
//创建其支持存储区为内存的流
System.IO.MemoryStream ms = new System.IO.MemoryStream();
//将此图像以指定格式保存到指定流中
image.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
//清除缓冲区流中的所有内容输出
Response.ClearContent();
//设置输出MIME类型
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());
}
}
可能大家看的比较晕,因为全是一些坐标的计算,这个大家就不用太多考虑,就知道图表和柱形的一个思路就行了。
最后总结一下,其实画图指定是离不开一些点在图中位移的计算,这里最好是自己能在草纸上比划一下,设计一下,这样会画的更快一些,同时也不容易被一大堆的数据搞晕。另外一点就是数据这块,柱形的比例搞好就行了,公式大概就是H(格子的实际高度)/h(单位刻度表示的价钱)=X(柱形的高度,我们所有求的)/price(当前柱的实际表示价钱,数据库中存的)。最后也就是X= H*price/h 这样。
想做出更加完美,智能的图表还有许多地方可以改进:
1、y轴展示的刻度我们可以动态变化,根据所查询出数据的最大值进行刻度计算,找出合适的单位刻度
2、x轴可以做一个额外的注释(当然,这里就是星期,也不太用到),但是如果是一些内容的话,可以根据坐标范围做鼠标移上有提示那种。
3、可以把柱形做的再美一点,更加立体一些,当然,这是需要依靠美工的力量。
Demo地址:http://files.cnblogs.com/zhouhongyu1989/%E6%9F%B1%E5%BD%A2%E5%9B%BEDEMO.rar 或者 http://down.51cto.com/data/1878284
ASP.NET 简单的柱形图实现(附带示例)的更多相关文章
- 【第四篇】ASP.NET MVC快速入门之完整示例(MVC5+EF6)
目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...
- C#仿google日历asp.net简单三层版本
网上搜了很多xgcalendar的例子都是Php开发的,而且官方站上的asp.net/MVC版 在vs10 08 都报错. 所以自己重新用三层写了一下希望对大家有帮助 废话不多说了 先看看它都有些什么 ...
- Nginx 简单的负载均衡配置示例(转载)
原文地址:Nginx 简单的负载均衡配置示例(转载) 作者:水中游于 www.s135.com 和 blog.s135.com 域名均指向 Nginx 所在的服务器IP. 用户访问http://www ...
- 用ASP实现简单的繁简转换
用ASP实现简单的繁简转换 国际化似乎是一个很流行的口号了,一个站点没有英文版至少也要弄个繁体版,毕竟都是汉字,翻译起来不会那么麻烦:P 一般的繁简转换是使用字典,通过GB的内码算出BIG5字符在字典 ...
- 最简单的视音频播放示例7:SDL2播放RGB/YUV
本文记录SDL播放视频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API ...
- 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)
本文记录OpenGL播放视频的技术.上一篇文章中,介绍了一种简单的使用OpenGL显示视频的方式.但是那还不是OpenGL显示视频技术的精髓.和Direct3D一样,OpenGL更好的显示视频的方式也 ...
- SpringMVC之简单的增删改查示例(SSM整合)
本篇文章主要介绍了SpringMVC之简单的增删改查示例(SSM整合),这个例子是基于SpringMVC+Spring+Mybatis实现的.有兴趣的可以了解一下. 虽然已经在做关于SpringMVC ...
- 最简单的基于DirectShow的示例:获取Filter信息
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
- 最简单的基于DirectShow的示例:视频播放器自定义版
===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...
随机推荐
- “全栈2019”Java多线程第三章:创建多线程之实现Runnable接口
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Jzoj 初中2249 蒸发学水(并查集)
题目描述 众所周知,TerryHu 是一位大佬,他平时最喜欢做的事就是蒸发学水. 机房的位置一共有n 行m 列,一开始每个位置都有一滴学水,TerryHu 决定在每一个时刻选择 一滴学水进行蒸发,直到 ...
- [javascript]——移动端 HTML5 图片上传预览和压缩
在开发移动端web网页中,我们不可避免的会遇到文件上传的功能,但由于手机图片尺寸太大,上传时间过长导致用户体验太差,就需要在上传前对图片进行一定的压缩. 在代码之前,有必要先了解我们即将使用到的几个A ...
- jQuery的隔行换色
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- SpringBoot整合MyBatis及Thymeleaf
http://www.cnblogs.com/ludashi/archive/2017/05/08/6669133.html 上篇博客我们聊了<JavaEE开发之SpringBoot工程的创建. ...
- 关于Hibernate的一个简单小程序
本人根据视频学习了一下三大框架中比较简单的一个Hibernate,并简单完成了一个运用Hibernate的小程序 Hibernate是一个简化web程序Dao层的一个框架,应用他,可以完全脱离sql语 ...
- STM32-RS232通信软硬件实现
OS:Windows 64 Development kit:MDK5.14 IDE:UV4 MCU:STM32F103C8T6/VET6 AD:Altium Designer 18.0.12 1.RS ...
- 2.CentOS6.5下的DNS主从区域传送配置
接着<1.CentOS6.5下的基础DNS配置>来说,主从区域传送只能让从服务器来进行传送,不给任何人传送,我们看看上一章节<1.CentOS6.5下的基础DNS配置>是否可传 ...
- [Xamarin]測試帳號申請與到期後如何續用 (转帖)
在Xamarin網站上可以申請30天試用的測試帳號.試用期內,Xamarin會提供完整的功能試用. 30天試用時間到期後,在Visual Studio裡面你載入你的專案的時候,專案旁會標註(無法使用) ...
- MVC3权限验证,诡异的OnAuthorization
mvc3权限验证 protected override void OnAuthorization(AuthorizationContext filterContext) { if (//开始权限验证返 ...