Google图表创建类 —— 高度封装!强力图表解决方案!

引言

Google图表API是一个免费的、非常强劲的图表生成工具,您可以仅凭一个Url地址,轻松生成一张具有专业水准的图表。

更为可贵的是,图表图形的计算和渲染完全由Google服务器处理,生成的图片也从Google服务器下载,你的服务器就可以大幅节约运算及网络流量资源

故此,将Google图表API作为网站的图表解决方案,是一个绝佳的选择。

这是Google官方提供的一个范例:

Google图表创建类 —— 高度封装!强力图表解决方案!

它的Url为:

http://chart.apis.google.com/chart?cht=p3&chd=t:60,40&chs=250x100&chl=Hello|World

你可以尝试修改Url中的各个参数,图表对应的图像就会发生变化。

这些参数在Google官方说明文档中都有详尽的说明,但即便如此,它们看起来也还是像天书一般,并且非常杂乱。

上面那个还仅仅是一个简单之至的图表,来看看文章末尾提供的范例所对应的Url:

http://chart.apis.google.com/chart?cht=lc&chs=1000x300&chtt=30天内日志记录量统计图&chco=BD6CE9FF,1865BBFF,0AA413FF,FF9E1FFF,FF565EFF&chm=B,BD6CE932,0,0,0|B,1865BB32,1,0,0|B,0AA41332,2,0,0|B,FF9E1F32,3,0,0|B,FF565E32,4,0,0&chdl=管理员|异常|系统|用户&chdlp=b&chd=t:0,12,0,180,103,0,71,0,0,2,0,0,0,0,0,47,0,0,0,127,0,11,0,0,0,0,0,0,0,118,41|0,0,111,22,2,0,3,0,27,2,23,19,9,18,30,18,0,6,16,3,0,8,0,0,4,0,1,0,0,21,3|0,4,77,80,26,0,7,0,50,18,49,42,33,74,77,56,0,32,83,38,0,18,0,0,46,8,24,0,4,97,48|0,1,4,9,1,0,3,0,4,1,1,4,2,3,12,9,0,7,7,2,0,1,0,0,5,8,23,0,1,3,2&chds=0,180&chxt=x,r,y&chxr=1,0,180|2,0,180&chxp=1,22.9677419354839,11.1612903225806,31.9677419354839,3.64516129032258&chxl=0:|6.14|6.15|6.16|6.17|6.18|6.19|6.20|6.21|6.22|6.23|6.24|6.25|6.26|6.27|6.28|6.29|6.30|7.1|7.2|7.3|7.4|7.5|7.6|7.7|7.8|7.9|7.10|7.11|7.12|7.13|7.14|1:|管理员均值|异常均值|系统均值|用户均值&chf=bg,s,FAFAFAFF|c,lg,90,EDFDFDFF,0,EDFDFD00,1

啊哈,是不是已经喷血了?

显然这样的图表不适合人工创建,而即使通过程序来创建,也非常麻烦:数据统计的逻辑本来就有够复杂了,再加上频繁地查看文档、测试……

有什么办法能让图表的创建变得轻松、简单吗?

高度封装的图表创建类

为实现这一目标,我决定将图表的创建操作封装起来,有了封装后的类库,就可以这样轻松的创建一个图表Url:

创建一个图表对象 > 为之添加各种所需参数 > 生成代码

以上面那个Google的三维饼图范例为例,我们通过下面的代码生成一个同样的图表:

[TestMethod()]

public void 生成代码Test2()

{

    var 图表 = new 三维饼图();

 

    图表.添加参数(new 图表尺寸 { 高度 = 100宽度 = 250 });

 

    var label = new 饼图和指数标签();

    label.标签列表.Add("Hello");

    label.标签列表.Add("World");

    图表.添加参数(label);

 

    var data = new 文本编码数据();

    data.数据列表.Add(new System.Collections.Generic.List<double>());

    data.数据列表[0].Add(60);

    data.数据列表[0].Add(40);

    图表.添加参数(data);

 

    var expected = "http://chart.apis.google.com/chart?cht=p3&chs=250x100&chl=Hello|World&chd=t:60,40";

    var actual = 图表.生成代码();

 

    Assert.AreEqual(expected, actual);

}

感觉如何?这样基本上就把整个创建流程语义化了,创建图表的时候再也不用频繁查看文档了吧!

此类库使用中文是出于三个原因:

其一就是我个人的写程序习惯,我觉得中文最便于自己理解,中文和英文放在一起非常显眼,并且中文在VisualStudio的智能感知列表中始终处于最下方,这样自定义的东西一下就能找到;

其二就是中文毕竟是我们的母语,大多数人一眼就能理解,省去翻译的麻烦;

其三就是其中的大部分命名直接引用或参考了Google的中文文档中的命名,这样大家在使用时能够更方便地对照文档。

类库解析

此类库中有两大基类:参数、图表

图表类就是各种类型的图表的基类,如饼图、三维饼图、折线图、条形图等。

参数即为图表的参数,如尺寸、数据、颜色、标签、标题等均继承于此类。

因为各种图表所能够支持的参数类型不尽相同,所以除了参数本身的封装类型之外,还定义了参数的支持接口,图表只有继承了这些支持接口,才能通过扩展方法“添加参数()”添加相应类型的参数:

Google图表创建类 —— 高度封装!强力图表解决方案!

扩展方法定义:

 Google图表创建类 —— 高度封装!强力图表解决方案!

上图中的“唯一参数标识”属性是用于避免参数重复添加的属性。

此外,参数还定义了一种依赖机制:

Google图表创建类 —— 高度封装!强力图表解决方案!

在生成代码时,如果仅有此参数,而没有其所需的某种依赖参数,则报告异常。

如:图表图例参数需依赖于图表颜色参数

生成图表范例

Google图表创建类 —— 高度封装!强力图表解决方案!

功能点:饼图 四色 标签 标题 条纹背景 整体不透明度控制

Google图表创建类 —— 高度封装!强力图表解决方案!

功能点:折线图 三色 图例 渐变背景 标题 轴标签定制

Google图表创建类 —— 高度封装!强力图表解决方案!

功能点:条形图 三色 纵向分布 图例 渐变背景 标题 轴标签定制

Asp.Net中,结合Entity Framework使用的应用范例

在页面中添加一个Image控件,然后在Page_Load中书写代码实现日志信息统计:

protected void Page_Load(object sender, EventArgs e)

{

    if (!IsPostBack)

    {

        var 图表 = new 折线图();

        图表.类型 = 折线图类型.均布折线图;

        图表.添加参数(new 图表尺寸 { 宽度 = 1000高度 = 300 });

        图表.添加参数(new 图表标题 { 标题 = "30天内日志记录量统计图" });

        图表.添加参数(new 实体填充 { 填充类型 = 实体填充类型.整体背景填充颜色 = Color.FromArgb(250250250) });

        var xt = new 线性渐变填充();

        图表.添加参数(xt);

        xt.角度 = 90;

        xt.填充类型 = 线性渐变填充类型.图表区域背景填充;

        xt.色标列表.Add(new 色标 位置 = 0颜色 = Color.FromArgb(237253253) });

        xt.色标列表.Add(new 色标 { 位置 = 1颜色 = Color.FromArgb(0237253253) });

        var color = new 图表颜色();

        图表.添加参数(color);

        color.颜色列表.AddRange(new Color[] { Color.FromArgb(189108233), Color.FromArgb(24101187), Color.FromArgb(10164,19), Color.FromArgb(25515831), Color.FromArgb(2558694), });

        var colorfill = new 区域填充();

        图表.添加参数(colorfill);

        colorfill.填充列表.Add(new 数据实体填充 { 颜色 = Color.FromArgb(50189108233), 目标数据组索引 = 0 });

        colorfill.填充列表.Add(new 数据实体填充 { 颜色 = Color.FromArgb(5024101187), 目标数据组索引 = 1 });

        colorfill.填充列表.Add(new 数据实体填充 { 颜色 = Color.FromArgb(501016419), 目标数据组索引 = 2 });

        colorfill.填充列表.Add(new 数据实体填充 颜色 = Color.FromArgb(5025515831), 目标数据组索引 = 3 });

        colorfill.填充列表.Add(new 数据实体填充 { 颜色 = Color.FromArgb(502558694), 目标数据组索引 = 4 });

        var tl = new 图表图例();

        图表.添加参数(tl);

        tl.位置 = 图表图例位置.;

        var td = new 带有数据换算的文本编码数据();

        图表.添加参数(td);

        td.换算标准.Add(new 范围限定());

        td.换算标准[0].最大值 = double.MinValue;

        td.换算标准[0].最小值 = double.MaxValue;

        var mtg = new 多轴标签();

        图表.添加参数(mtg);

        var dz = new 轴标签 { 类型 = 轴类型.底部 };

        var a = new 轴标签 { 类型 = 轴类型.右侧 };

        mtg.轴标签列表.Add(dz);

        mtg.轴标签列表.Add(a);

        using (var c = new DatabaseEntities())

        {

            var d = DateTime.Now.AddDays(-30);

            var s = c.日志.Select(f => new { f.触发时间, f.所属日志类型.名称 }).Where(f => f.触发时间 >= d).ToList().GroupBy(f =>f.名称);

            bool first = true;

            foreach (var f in s)

            {

                tl.图例名称列表.Add(f.Key);

                var dl = new List<double>();

                for (int i = -30; i <= 0; i++)

                {

                    var od = DateTime.Today.AddDays(i);

                    if (first)

                    {

                        dz.轴标签列表.Add(od.Month + "." + od.Day);

                    }

                    var cd = f.Count(v => v.触发时间.Date == od);

                    dl.Add(cd);

                    td.换算标准[0].最大值 = Math.Max(td.换算标准[0].最大值, cd);

                    td.换算标准[0].最小值 = Math.Min(td.换算标准[0].最小值, cd);

                }

                a.轴标签列表.Add(f.Key + "均值");

                a.轴标签位置列表.Add(dl.Average());

                td.数据列表.Add(dl);

                first = false;

            }

        }

        mtg.轴标签列表.Add(new 轴标签 { 类型 = 轴类型.左侧轴范围 = new 轴范围 { 起始值 = (int)td.换算标准[0].最小值终止值 =(int)td.换算标准[0].最大值 } });

        a.轴范围 = new 轴范围 { 起始值 = (int)td.换算标准[0].最小值终止值 = (int)td.换算标准[0].最大值 };

 

        Image1.ImageUrl = 图表.生成代码();

    }

}

生成的图表:

Google图表创建类 —— 高度封装!强力图表解决方案!

当前进度

目前还没有将所有图表及参数全部封装,但现有的功能已足以应付多数常规应用。

查看当前封装好的类示意图

源代码下载

另外,我也将提供类库的源代码,供大家自行扩展需要的功能:

下载类库源代码:

Google图表创建类 —— 高度封装!强力图表解决方案!

 

结语

我的设计还很不成熟,所以难免在此类库中存有一些设计缺陷,极力欢迎各位朋友指导、指正。

还有什么需求或想法,也欢迎在此留言述说。

本文转自斯克迪亚博客园博客,原文链接:http://www.cnblogs.com/SkyD/archive/2009/07/15/1523759.html,如需转载请自行联系原作者

上一篇:静态方法中不能new内部类的实例对象的总结


下一篇:jenkins动态参数插件Dynamic Parameter安装及简单使用