asp.net中用VML动态的画出数据分析图表详解
JemBai http://www.cnblogs.com/JemBai/

在开发系统的时候有许多数据分析需要用图形的方式来表现出,这样更直观又清淅。如果我们使用高级去动态
生成统计图表的话不但编写起来非常困难,而且实用性不是很好,从美观的角度上讲也是很设计的。然而Microsoft公司提供了一个专们的矢量画图语言,这就是VML.

  如果要用VML去画静态页面的话那是比较好看也好操作,但实用性不是很高。但要是画出来的图所表示的数据
是从数据库里面读取下来的可以动态表示要统计的内容的话,那实用性就不言而喻了。

    最近我们也要做一个数据统计图表,我想如果能把VML画图做成一个控件那该多很,做自定义控件(本人才疏学浅)我不怎么会做,但我们公司有个.NET很牛 的人,我经常看到他重写.net里自带的控件使这些控件变得更好用,于是我也产生一种想法,看能不能把VML也嵌套进去.结果做的还是有点起色.下面跟大 家分享一下.
我是把VML图表用Lable控件显示出来的,给Lable类添加了一些自定义属性.(在下面的代码里面有的属性还没有用到用与以后扩展)

页面代码如下
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DrawTest.aspx.cs" Inherits="DrawTest" %>

    xmlns="http://www.w3.org/1999/xhtml">

    Page
   



   
       


           

                                    IsDrawVML="True" BgDistance="10" EnableViewState="False" ZhuWidth="20" YItemWidth="40"
                    CssClass="changeBg" BorderColor="White" BorderWidth="0px" LineColor="#4CAFFE"
                    XSign="(年份)" YSign="(万/单位)" XPosition="50" IsZhuOrBing="Zhu" Redii="80">

           

       

   

这里面的.标签里的” xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"

”和. v":*{ behavior: url(#default#VML) }

o":*{ behavior: url(#default#VML) }

是必不可少的.

下面是CS代码部分
private int xposition;
        private int yposition;
        private int xwidth;
        private int yheight;
        private bool isdrawVML;
        private int bgdistance;//背景距离(斜线之间的垂直距离)
        private int zhuWidth;
        private string lineColor;
        private int yItemWidth;
        private string xSign;//X轴标记
        private string ySign;//Y轴标记
        private List datasource;
        private IszhuOrBing isZhuOrBing;
        private int radii;//画饼图要用的半径

        public IszhuOrBing IsZhuOrBing
        {
            get { return isZhuOrBing; }
            set { isZhuOrBing = value; }
        }
        #region 属性的定义
 
        ///


        /// 画饼图的半径
        ///

        public int Redii
        {
            get { return radii; }
            set { radii = value; }
        }
        ///
        /// X轴的位置
        ///

        public int XPosition
        {
            get { return xposition; }
            set { xposition = value; }
        }

        ///


        /// Y轴位置
        ///

        public int YPosition
        {
            get { return yposition; }
            set { yposition = value; }
        }
        //
        ///
        /// X轴宽度
        ///

        public int XWidth
        {
            get { return xwidth; }
            set { xwidth = value; }
        }
        //
        ///
        /// Y轴高度
        ///

        public int YHeight
        {
            get { return yheight; }
            set { yheight = value; }
        }
        ///
        /// 是否是画VML图
        ///

        public bool IsDrawVML
        {
            get { return isdrawVML; }
            set { isdrawVML = value; }
        }
        ///
        /// 背景距离(斜线之间的垂直距离)
        ///

        public int BgDistance
        {
            get
            {
                return bgdistance;
            }
            set
            {
                if (value <= 0)
                    bgdistance = 10;
                else
                    bgdistance = value;
            }
        }

        ///


        /// 柱子的宽度
        ///

        public int ZhuWidth
        {
            get { return zhuWidth; }
            set { zhuWidth = value; }
        }

        ///


        /// 柱子的颜色
        ///

        public string LineColor
        {
            get { return lineColor; }
            set { lineColor = value; }
        }
 
        ///
        /// Y轴方向的间距
        ///

        public int YItemWidth
        {
            get { return yItemWidth; }
            set { yItemWidth = value; }
        }
        ///
        /// X轴标识
        ///

        public string XSign
        {
            get { return xSign; }
            set { xSign = value; }
        }
        ///
        /// Y轴标识
        ///

        public string YSign
        {
            get { return ySign; }
            set { ySign = value; }
        }
        ///
        /// 数据源(柱子高度)
        ///

        public List DataSource
        {
            get { return datasource; }
            set { datasource = value; }
        }

        #endregion
判断是画柱图还是饼图.
   //画VML图
        StringBuilder sbText = new StringBuilder();
        string strHeight = "";
        string strTop = "";

        public void DrawVml()
        {

            if (isdrawVML == true)
            {//
                if (isZhuOrBing== IszhuOrBing.Bing)
                {
                    DrawBingImage();
                }
                else if (isZhuOrBing == IszhuOrBing.Zhu)
                {
                    DrawZhuImage();
                }
            }
        }   
***IsZhuOrBing是一个自定义的枚举类型.

    //柱子一升的脚本
        private string RegisterScript()
        {
            string m_strScript = " ";
            return m_strScript;
        }
上面的那段代码是要向客户端注册的JS脚本用于,画柱图时渐长效果的.
开始画VML图
//画柱图.
  public void DrawZhuImage()
        {
                 base.Text = "";
                //画Div
                //sbText.Append("

");
                sbText.Append("
");
                //base.Style.Value = "left:" + xposition + ";position:relative; top:" + yposition + "; width:" + (xwidth+20) + "; height:" + (20+yheight) + ";'";
                //画X轴
                sbText.Append(""
                    + "
" + xSign + "");
                //画X轴方向的线条
                int HaveData = ComputeX(xwidth);
                //if (HaveData == 0)
                //{
                //    sbText.Append("
");
                //    base.Text = sbText.ToString(0, sbText.Length);
                //    return;
                //}
                //画Y轴
                sbText.Append("" + ySign + "");
                //画Y轴方向的线条
                ComputeY(yheight);

                //画DIV结束标记
                sbText.Append("

");
                //画隐形文本框
                  sbText.Append("");
                    sbText.Append("");
                    //给Lable控件的Text赋值
                base.Text = sbText.ToString(0, sbText.Length);
                Page.RegisterStartupScript("zhuup", RegisterScript());
        }
        //
        private int ComputeX(int XWidth)
        {  //柱子颜色数组
            string[,] ZColor = new string[6, 2];
            ZColor[0, 0] = "#666699"; ZColor[0, 1] = "#d9d9e5";
            ZColor[1, 0] = "#00ff00"; ZColor[1, 1] = "#d1ffd1";
            ZColor[2, 0] = "#ff0000"; ZColor[2, 1] = "#ffbbbb";
            ZColor[3, 0] = "#ff9900"; ZColor[3, 1] = "#ffe3bb";
            ZColor[4, 0] = "#33cccc"; ZColor[4, 1] = "#cff4f3";
            ZColor[5, 0] = "#993300"; ZColor[5, 1] = "#ffc7ab";
           
            XWidth -= 10;//箭头下面的长度
           
            int ColorIndex = 0;
            double height = 0;
            int Zhuposition = 0;
            int Count = this.DataSource==null?XWidth:this.DataSource.Count;
            int num=1;
            //Count = 0;
            //if (Count == 0)
            //{
            //    sbText.Append("
暂无数据
");
            //    return 0;
            //}
            int UnitLength = XWidth / Count;//计算单位长度
            foreach (VmlDataSource var in this.datasource)
            {
                //画X轴下标
                sbText.Append(""
                    + "" + var.Key + "");

                height = var.value;
                Zhuposition = ((num - 1) * UnitLength + UnitLength / 2) - (zhuWidth / 2);

                if (ColorIndex >= ZColor.Length / 2)
                {
                    ColorIndex = 0;
                }
                //sbText.Append(""
                     + ""
                     + "
"
                     + "");
                strHeight += height + ",";
                strTop += (yheight - height) + ",";
                ColorIndex++;
                num++;
            }
            return 1;
        }
        //
        private void ComputeY(int YHeight)
        {
            YHeight -= 10;//箭头下面的长度
            if (yItemWidth > 0)
            {
                int Units = YHeight / yItemWidth;//计算单位长度
                for (int i = 0; i <= Units; i++)
                {
                    int areaLenght = yheight - (i * yItemWidth);
                    sbText.Append(""
                                 + ""
                                 + "
" + i * yItemWidth + ""
                                 + "");
                }
                //画Y轴平行的线
                sbText.Append("");
            }
        }
        #endregion
        #region 画饼图
        private void DrawBingImage()
        {
            base.Text = "";
            //定义颜色
            string[] Colors = new string[6];
            Colors[0] = "#666699";
            Colors[1] = "#00ff00";
            Colors[2] = "#ff0000";
            Colors[3] = "#ff9900";
            Colors[4] = "#33cccc";
            Colors[5] = "#993300";
            //开始标记
            //sbText.Append("

");
            //
            double TotalCount = 0;
            foreach (VmlDataSource vd in datasource)
            {
                TotalCount += vd.value;
            }
            //计算单位数字的角度
            double UnitAngle = 360 / TotalCount;
            //存储画下弧度的起点
            double TempUnitArc=0.00;
            //存储前面已有的角度
            double TempUnitAngle=0.00;
            int i = 0;
            string ColorInfo = "";
            sbText.Append("
");
            sbText.Append("
");
            sbText.Append("");
            foreach (VmlDataSource vd in datasource)
            {

                //计算弧度
                double UnitArc = (vd.value * UnitAngle + TempUnitAngle) * Math.PI / 180;
                //计算开始和结束位置
                double sx = Math.Round(Math.Cos(TempUnitArc) * radii);//Math.Sign(
                double sy = Math.Round(Math.Sin(TempUnitArc) * radii);
                double ex = Math.Round(Math.Cos(UnitArc) * radii);
                //double aa = Math.Sin(UnitArc) * radii;
                //double bb = Math.Round(Math.Sin(UnitArc) * radii,4);
                double ey = Math.Round(Math.Sin(UnitArc) * radii);
                //所占百份比
                double rate = Math.Round(vd.value * 100 / TotalCount, 2);
                //开始画图
                sbText.Append("                sbText.Append(" path='m0,0 l" + sx + "," + sy + " ar-" + radii + ",-" + radii + "," + radii + "," + radii + "," + ex + "," + ey + "," + sx + "," + sy + " l0,0 x e'");
                sbText.Append("title='名称:" + vd.key + ""r数量:" + vd.value + ""r所占比例:" + rate + "%'>
");
                //给临时变量赋值
                TempUnitAngle += vd.value * UnitAngle;
                TempUnitArc = UnitArc;
                //显示颜色说明框
                ColorInfo += "

"
                    + "  " + vd.key + ":" + vd.value + "  (" + rate + "%)
"
                    ;
                //如果颜色遍历完了,还有数据要显示那就重新再一次遍历。占:" + (Math.Round(vd.value * 100 / TotalCount, 2)) + "%
                i = (i >= Colors.Length ? 0 : ++i);
            }
            sbText.Append("
");
            sbText.Append("
");
            //sbText.Append("
");
            //总数
            sbText.Append("
总数据:"+TotalCount+"
");
            sbText.Append(ColorInfo);
            sbText.Append("
");
            this.Text = sbText.ToString();
        }
        #endregion
        ///
        /// 控件加载时画图
        ///

        ///
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e); // Page.RegisterStartupScript("HelloWord", "");
             DrawVml();
            //Page.RegisterStartupScript("", "");
        }
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            Page.RegisterStartupScript("", "");
        }
    }
*注意里面的数据源类型和枚举在下面定义.
  ///
    /// 画图时用的数据源
    ///

    public class VmlDataSource
    {
        public VmlDataSource()
        {

        }

        public string key;
        public double value;
        ///


        /// 键值
        ///

        public string Key
        {
            get { return key; }
            set { key = value; }
        }
        public double Value
        {
            get
            {
                if (this.value.GetType() != Type.GetType("System.Int32"))
                    return 0;
                else
                    return this.value;
            }
            set
            {
                this.value = value;
            }
        }

    }
    ///


    /// 枚举画图的类型
    ///

    public enum IszhuOrBing
    {
        //
        Zhu=0,
        //
        Bing=1
    }
}
整个过程就是这样了,不过这只是个粗略的过程里面还很多的BUG没有解觉掉.画数据统计的图表完成了.
效果图如下.

 

 

 

 

 

 

 

 

 

 

CIO之家 www.ciozj.com 公众号:imciow
关联的文档
也许您喜欢