对于一些内部系统的项目,各种图表是在所难免的,因为图表可以更加清晰的表达出想看到的数据。

因为之前从来没有做过关于图表的东西,唯一能想到的就是“验证码”,所以应该是一个思路,用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 简单的柱形图实现(附带示例)的更多相关文章

  1. 【第四篇】ASP.NET MVC快速入门之完整示例(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  2. C#仿google日历asp.net简单三层版本

    网上搜了很多xgcalendar的例子都是Php开发的,而且官方站上的asp.net/MVC版 在vs10 08 都报错. 所以自己重新用三层写了一下希望对大家有帮助 废话不多说了 先看看它都有些什么 ...

  3. Nginx 简单的负载均衡配置示例(转载)

    原文地址:Nginx 简单的负载均衡配置示例(转载) 作者:水中游于 www.s135.com 和 blog.s135.com 域名均指向 Nginx 所在的服务器IP. 用户访问http://www ...

  4. 用ASP实现简单的繁简转换

    用ASP实现简单的繁简转换 国际化似乎是一个很流行的口号了,一个站点没有英文版至少也要弄个繁体版,毕竟都是汉字,翻译起来不会那么麻烦:P 一般的繁简转换是使用字典,通过GB的内码算出BIG5字符在字典 ...

  5. 最简单的视音频播放示例7:SDL2播放RGB/YUV

    本文记录SDL播放视频的技术.在这里使用的版本是SDL2.实际上SDL本身并不提供视音频播放的功能,它只是封装了视音频播放的底层API.在Windows平台下,SDL封装了Direct3D这类的API ...

  6. 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)

    本文记录OpenGL播放视频的技术.上一篇文章中,介绍了一种简单的使用OpenGL显示视频的方式.但是那还不是OpenGL显示视频技术的精髓.和Direct3D一样,OpenGL更好的显示视频的方式也 ...

  7. SpringMVC之简单的增删改查示例(SSM整合)

    本篇文章主要介绍了SpringMVC之简单的增删改查示例(SSM整合),这个例子是基于SpringMVC+Spring+Mybatis实现的.有兴趣的可以了解一下. 虽然已经在做关于SpringMVC ...

  8. 最简单的基于DirectShow的示例:获取Filter信息

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

  9. 最简单的基于DirectShow的示例:视频播放器自定义版

    ===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视 ...

随机推荐

  1. “全栈2019”Java多线程第三章:创建多线程之实现Runnable接口

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  2. Jzoj 初中2249 蒸发学水(并查集)

    题目描述 众所周知,TerryHu 是一位大佬,他平时最喜欢做的事就是蒸发学水. 机房的位置一共有n 行m 列,一开始每个位置都有一滴学水,TerryHu 决定在每一个时刻选择 一滴学水进行蒸发,直到 ...

  3. [javascript]——移动端 HTML5 图片上传预览和压缩

    在开发移动端web网页中,我们不可避免的会遇到文件上传的功能,但由于手机图片尺寸太大,上传时间过长导致用户体验太差,就需要在上传前对图片进行一定的压缩. 在代码之前,有必要先了解我们即将使用到的几个A ...

  4. jQuery的隔行换色

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  5. SpringBoot整合MyBatis及Thymeleaf

    http://www.cnblogs.com/ludashi/archive/2017/05/08/6669133.html 上篇博客我们聊了<JavaEE开发之SpringBoot工程的创建. ...

  6. 关于Hibernate的一个简单小程序

    本人根据视频学习了一下三大框架中比较简单的一个Hibernate,并简单完成了一个运用Hibernate的小程序 Hibernate是一个简化web程序Dao层的一个框架,应用他,可以完全脱离sql语 ...

  7. STM32-RS232通信软硬件实现

    OS:Windows 64 Development kit:MDK5.14 IDE:UV4 MCU:STM32F103C8T6/VET6 AD:Altium Designer 18.0.12 1.RS ...

  8. 2.CentOS6.5下的DNS主从区域传送配置

    接着<1.CentOS6.5下的基础DNS配置>来说,主从区域传送只能让从服务器来进行传送,不给任何人传送,我们看看上一章节<1.CentOS6.5下的基础DNS配置>是否可传 ...

  9. [Xamarin]測試帳號申請與到期後如何續用 (转帖)

    在Xamarin網站上可以申請30天試用的測試帳號.試用期內,Xamarin會提供完整的功能試用. 30天試用時間到期後,在Visual Studio裡面你載入你的專案的時候,專案旁會標註(無法使用) ...

  10. MVC3权限验证,诡异的OnAuthorization

    mvc3权限验证 protected override void OnAuthorization(AuthorizationContext filterContext) { if (//开始权限验证返 ...