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=清迈"  />
        <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://down.51cto.com/data/1878284

时间: 2024-08-13 18:20:22

ASP.NET 简单的柱形图实现(附带示例)的相关文章

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

目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策略(MVC5+EF6) [第四篇]ASP.NET MVC快速入门之完整示例(MVC5+EF6) [番外篇]ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6) 请关注三石的博客:http://cnblogs.com/sanshi 完善数据注解 到目前为止的表格页面效果: 我们需

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

===================================================== 最简单的基于DirectShow的示例文章列表: 最简单的基于DirectShow的示例:视频播放器 最简单的基于DirectShow的示例:视频播放器图形界面版 最简单的基于DirectShow的示例:视频播放器自定义版 最简单的基于DirectShow的示例:获取Filter信息 =====================================================

asp.net_01 简单介绍

1.静态网页和动态网页 刚开始一直概念很模糊,分不清,今天晚上看视频,查资料终于弄明白点儿了.静态网页和动态网页的区别可以说是使用语言的区别. 静态网页:使用语言—html,不包含服务器运行代码;没有数据库,数据量大时,制作和维护困难:访问速度快:内容稳定,容易被搜索引擎检索:不含程序,不可交互,适合更新较少的展示型网站. 动态网页:使用语言--以超文本标记语言(html)为主,结合其他服务器端语言:有数据库,方便维护:访问速度慢:不容易被搜索引擎检索:交互性强.动态网页首先获得用户的指令,然后

C# 如何实现简单的Socket通信(附示例)

上周由于有个项目需要用到网络通信这块,然后就花了点时间研究了一下,本来想上周就写出来的,但是突然要忙,所以等到现在. 话说对于网络通信,以前写C++的时候,天天面对着线程和Socket,所以换成C#也就没那么怕了,虽然C++下也没有掌握的多好,但毕竟只是一个小Demo,只作为了解一下过程. 自己写了一个服务端和一个客户端,刚开始比较简单,只是能达到连通,收发信息的目的,但是很粗糙.而后稍加改进呢~加上了多线程,所以能感觉更科学一些,不过自己真的很菜,代码写的不是很好看,下面分两个版本给大家表出来

用ASP实现简单的繁简转换

国际化似乎是一个非常流行的口号了,一个网站没有英文版至少也要弄个繁体版,毕竟都是汉字,翻译起来不会那么麻烦:P 一般的繁简转换是使用字典,通过GB的内码算出BIG5字符在字典中的位置,读取显示之,用fso应该可以实现.这里介绍的方法思路更简单一些,用Dictionary对象,就是字典,呵呵,dicGb2Big5(gb)就是对应的BIG5.比起计算内码再按照位置读取字符简单的多吧:) 为了减少开销,把字典放在Application中,即在global.asa中建立两个application的字典对

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

本文记录OpenGL播放视频的技术.上一篇文章中,介绍了一种简单的使用OpenGL显示视频的方式.但是那还不是OpenGL显示视频技术的精髓.和Direct3D一样,OpenGL更好的显示视频的方式也是通过纹理(Texture).本文介绍OpenGL通过纹理的方式显示视频的技术. OpenGL中坐标和Direct3D坐标的不同 OpenGL中的纹理的坐标和Direct3D中的坐标是不一样的. 在Direct3D中.纹理坐标如下图所示.取值是0到1.坐标系原点在左上角. 物体表面坐标如下图所示.取

二、Java语言的简单认识及Hello World示例

1. Java语言的简单认识 (1) Java有三个版本: a. JAVA SE (以前称J2SE):Standard Environment 标准版本: b. JAVA EE (以前称J2EE):Enterprise Environment 企业版: c. JAVA ME (以前称J2ME):Eicro Environment 微型版; (2) Java的安装目录 在前一讲中,提到安装目录中有两个文件夹,分别是jdk1.7.0_45和jre7.在"jdk1.7.0_45"文件夹的bi

JAVA简单Swing图形界面应用示例

package org.rui.hello; import javax.swing.JFrame; /** * 简单的swing窗口 * @author lenovo * */ public class HelloSwing { public static void main(String[] args) { JFrame frame=new JFrame("hello Swing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLO

asp.net简单读取xml文件信息

xml文件格式如下:     <?xml   version="1.0"   encoding="utf-8"?>         <userdata   createuser="false">         <dataconnection>             <server>localhost</server>             <uid>sa</uid