asp.net中用VML动态的画出数据分析图表详解【转】

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

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

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

我是把VML图表用Lable控件显示出来的,Lable类添加了一些自定义属性.(在下面的代码里面有的属性还没有用到用与以后扩展)

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

< html  xmlns:v ="urn:schemas-microsoft-com:vml"  xmlns:o ="urn:schemas-microsoft-com:office:office"
    xmlns
="http://www.w3.org/1999/xhtml" >
< head  id ="Head1"  runat ="server" >
    
< title > Page </ title >
    
< style  type ="text/css" >
v":*
{  behavior :  url(#default#VML)  }
o":*
{  behavior :  url(#default#VML)  }
.changeBg
{ FILTER :  progid:DXImageTransform.Microsoft.Gradient(gradientType=0,startColorStr=#FFFFFF,endColorStr=#9DCDFA) ;
}
.shadwDiv
{  width : 600px ;  height : 500px ;  text-align : center ;  filter  :  progid:DXImageTransform.Microsoft.DropShadow ( enabled=true  , color=#000 , offX=10 , offY=10 , positive=true )  ;  }
</ style >

</ head >
< body >
    
< form  id ="form1"  runat ="server" >
        
< div  class ="shadwDiv"  >
            
< div  style ="padding-top: 30px; border: solid 2px #BBBBBB; background-color: #EFEFEF;
                width: 600px; height: 500px;"
>
                
< asp:VmlLabel  ID ="labTest3"  runat ="server"  XWidth ="400"  YHeight ="400"  YPosition ="50"
                    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" ></ asp:VmlLabel >
            
</ div >
        
</ div >
    
</ form >
</ body >
</ html >

这里面的.<html>标签里的” 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 < VmlDataSource >  datasource;
        
private  IszhuOrBing isZhuOrBing;
        
private  int  radii; // 画饼图要用的半径

        
public  IszhuOrBing IsZhuOrBing
        {
            
get  {  return  isZhuOrBing; }
            
set  { isZhuOrBing  =  value; }
        }
        
#region  属性的定义
  
        
///  <summary>
        
///  画饼图的半径
        
///  </summary>
         public  int  Redii
        {
            
get  {  return  radii; }
            
set  { radii  =  value; }
        }
        
///  <summary>
        
///  X轴的位置
        
///  </summary>
         public  int  XPosition
        {
            
get  {  return  xposition; }
            
set  { xposition  =  value; }
        }

        
///  <summary>
        
///  Y轴位置
        
///  </summary>
         public  int  YPosition
        {
            
get  {  return  yposition; }
            
set  { yposition  =  value; }
        }
        
//
         ///  <summary>
        
///  X轴宽度
        
///  </summary>
         public  int  XWidth
        {
            
get  {  return  xwidth; }
            
set  { xwidth  =  value; }
        }
        
//
         ///  <summary>
        
///  Y轴高度
        
///  </summary>
         public  int  YHeight
        {
            
get  {  return  yheight; }
            
set  { yheight  =  value; }
        }
        
///  <summary>
        
///  是否是画VML图
        
///  </summary>
         public  bool  IsDrawVML
        {
            
get  {  return  isdrawVML; }
            
set  { isdrawVML  =  value; }
        }
        
///  <summary>
        
///  背景距离(斜线之间的垂直距离)
        
///  </summary>
         public  int  BgDistance
        {
            
get
            {
                
return  bgdistance;
            }
            
set
            {
                
if  (value  <=  0 )
                    bgdistance 
=  10 ;
                
else
                    bgdistance 
=  value;
            }
        }

        
///  <summary>
        
///  柱子的宽度
        
///  </summary>
         public  int  ZhuWidth
        {
            
get  {  return  zhuWidth; }
            
set  { zhuWidth  =  value; }
        }

        
///  <summary>
        
///  柱子的颜色
        
///  </summary>
         public  string  LineColor
        {
            
get  {  return  lineColor; }
            
set  { lineColor  =  value; }
        }
 
        
///  <summary>
        
///  Y轴方向的间距
        
///  </summary>
         public  int  YItemWidth
        {
            
get  {  return  yItemWidth; }
            
set  { yItemWidth  =  value; }
        }
        
///  <summary>
        
///  X轴标识
        
///  </summary>
         public  string  XSign
        {
            
get  {  return  xSign; }
            
set  { xSign  =  value; }
        }
        
///  <summary>
        
///  Y轴标识
        
///  </summary>
         public  string  YSign
        {
            
get  {  return  ySign; }
            
set  { ySign  =  value; }
        }
        
///  <summary>
        
///  数据源(柱子高度)
        
///  </summary>
         public  List < VmlDataSource >  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  =  "  <script language='javascript' type='text/javascript'> "
                    
+ " var gao=0; "
                    
+ " var ProcID=0; "
                    
+ " var ProcName=null; "
                    
+ " var i=0; "
                    
+ " var HeightContent=document.getElementById('heightDataSource').value; "
                    
+ " var arrHeight=new Array(); "
                    
+ " var arrTop=new Array(); "
                    
+ " arrHeight=HeightContent.split(','); "
                    
+ " var showBar=null; "
                    
+ " function AllPlay() "
                    
+ " { "
                    
+ "     i++; "
                        
                    
+ "     gao=0; "
                    
+ "    var procBarID='DataZhu'+i; " // ;    
                     + "     Play(procBarID);     "
                    
+ " } "
                    
+ " function Play(procBarID) "
                    
+ " {     "
                    
+ "   var procBar=document.getElementById(procBarID); "
                    
+ "   if(procBar!=null) "
                    
+ "   { "
                      
+ "       ProcName=procBar; "
                        
+ "     PlaySub(); "
                        
+ " } "
                    
+ " } "
                    
+ " function PlaySub() "
                    
+ " { "
                      
+ "       var procBar=ProcName; "
                        
+ "     showBar=document.getElementById('ShowData'+i); "
                          
+ "   showBar.style.display='block'; "
                            
+ " gao++; "
                            
+ " var ygao=parseInt(procBar.style.height); "
                            
+ " var ytop=parseInt(procBar.style.top); "
                            
+ " if(ygao<arrHeight[i-1]) "
                            
+ " {     "
                             
+ "    procBar.style.top=ytop-gao; "
                              
+ "   procBar.style.height=ygao+gao; "
                               
+ "  showBar.style.top=ytop-gao-25; "
                                
+ " setTimeout(PlaySub,20); "
                            
+ " } "
                            
+ " else "
                            
+ " "
                              
+ "   AllPlay(); "
                            
+ " } "
                    
+ " } "
                    
+ " </script> " ;
            
return  m_strScript;
        }
上面的那段代码是要向客户端注册的JS脚本用于,画柱图时渐长效果的.
开始画VML图
// 画柱图.
   public  void  DrawZhuImage()
        {
                 
base .Text  =  "" ;
                
// 画Div
                
// sbText.Append("<div style=' border:solid 1px red;width:" + (xwidth+10) + "; height:" + (yheight+10) + ";;filter : progid:DXImageTransform.Microsoft.DropShadow ( enabled=true  , color=#66333333 , offX=4 , offY=4 , positive=true );'>");
                sbText.Append( " <div id='PicDiv'  style='left:0;position:relative; top:0; width: "  +  xwidth  +  " ; height: "  +  yheight  +  " ;text-align:left;'> " );
                
// base.Style.Value = "left:" + xposition + ";position:relative; top:" + yposition + "; width:" + (xwidth+20) + "; height:" + (20+yheight) + ";'";
                
// 画X轴
                sbText.Append( " <v:line id='Xzhou' from='0, "  +  yheight  +  " ' to=' "  +  xwidth  +  " , "  +  yheight  +  " '> "
                    
+  " <v:stroke  EndArrow='Classic'/></v:line><v:TextBox style='position:absolute; width:100px;top: "  +  (yheight  +  10 +  " ;left: "  +  (xwidth)  +  " '> "  +  xSign  +  " </v:TextBox> " );
                
// 画X轴方向的线条
                 int  HaveData  =  ComputeX(xwidth);
                
// if (HaveData == 0)
                
// {
                
//     sbText.Append("</div>");
                
//     base.Text = sbText.ToString(0, sbText.Length);
                
//     return;
                
// }
                
// 画Y轴
                sbText.Append( " <v:line id='Yzhou' from='0, "  +  yheight  +  " ' to='0,0'><v:stroke  EndArrow='Classic'/><v:TextBox style=' width:100px;padding-left:10px;'> "  +  ySign  +  " </v:TextBox></v:line> " );
                
// 画Y轴方向的线条
                ComputeY(yheight);

                
// 画DIV结束标记
                sbText.Append( " </div> " );
                
// 画隐形文本框
                  sbText.Append( " <input type='hidden' value=' "  +  strHeight.Substring( 0 , strHeight.Length  -  1 +  " ' name='heightDataSource' id='heightDataSource'/> " );
                    sbText.Append(
" <input type='hidden' value=' "  +  strTop.Substring( 0 , strTop.Length  -  1 +  " ' name='topDataSource' id='topDataSource'/> " );
                    
// 给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("<div style='font-size:14px;color:red;'>暂无数据</div>");
            
//     return 0;
            
// }
             int  UnitLength  =  XWidth  /  Count; // 计算单位长度
             foreach  (VmlDataSource var  in  this .datasource)
            {
                
// 画X轴下标
                sbText.Append( " <v:line  from=' "  +  num  *  UnitLength  +  " , "  +  yheight  +  " ' to=' "  +  num  *  UnitLength  +  " , "  +  (yheight  +  bgdistance)  +  " '> "
                    
+  " </v:line><v:shape style='left: "  +  (num  *  UnitLength  - 50 +  " ;top: "  +  yheight  +  " ;'><v:textbox> "  +  var.Key  +  " </v:textbox></v:shape> " );

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

                
if  (ColorIndex  >=  ZColor.Length  /  2 )
                {
                    ColorIndex 
=  0 ;
                }
                
// sbText.Append("<v:rect id='DataZhu"+num+"' style='z-index:1; position:absolute; top:" + (yheight - height) + ";"
                  sbText.Append( " <v:rect id='DataZhu " + num + " ' style='z-index:1; position:absolute; top: "  +  yheight  +  " ; "
                     
+  " left: "  +  Zhuposition  +  " ;width: "  +  zhuWidth  +  " ;height:0;' fillcolor=' "  +  ZColor[ColorIndex,  0 +  " '> "
                     
+  " <v:fill color2=' "  +  ZColor[ColorIndex,  1 +  " ' rotate='t' type='gradient'/> "
                     
+  " <v:extrusion v:ext='view' backdepth=' "  +  ( 2  *  bgdistance)  +  " ' color=' "  +  ZColor[ColorIndex,  0 +  " ' brightness='0.2' on='t'/></v:rect> "
                     
+  " <v:TextBox id='ShowData " + num + " ' style='position:absolute;display:none;z-index:2;top: "  +  (yheight  -  20 +  " ; left: "  +  Zhuposition  +  " '> "  +  height  +  " </v:TextBox> " );
                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(
" <v:line from='0, "  +  areaLenght  +  " ' to=' "  +  bgdistance  +  " , "  +  (areaLenght  -  bgdistance)  +  " ' color=' "  +  lineColor  +  " '><v:stroke color=' "  +  lineColor  +  " '/></v:line> "
                                 
+  " <v:line from='0, "  +  areaLenght  +  " ' to='-10, "  +  areaLenght  +  " '> "
                                 
+  " </v:line><v:shape style='top: "  +  (areaLenght - 10 +  " ;left:-50;'><v:TextBox> "  +  i  *  yItemWidth  +  " </v:TextBox></v:shape> "
                                 
+  " <v:line from=' "  +  bgdistance  +  " , "  +  (areaLenght  -  bgdistance)  +  " ' to=' "  +  xwidth  +  " , "  +  (areaLenght  -  bgdistance)  +  " '><v:stroke color=' "  +  lineColor  +  " '/></v:line> " );
                }
                
// 画Y轴平行的线
                sbText.Append( " <v:line id='YzhouPX' from=' "  +  bgdistance  +  " , "  +  (yheight  -  bgdistance)  +  " ' to=' "  +  bgdistance  +  " , "  +  ((yheight  -  (Units  *  yItemWidth))  -  bgdistance)  +  " '><v:stroke color=' "  +  lineColor  +  " '/></v:line> " );
            }
        }
        
#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("<div id='pic' style='position:absolute;'>");
            
//
             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(
" <div id='PicDiv'  style='left:0;position:relative; top:0; width: "  +  xwidth  +  " ; height: "  +  yheight  +  " ;text-align:left; font-size:12px; border:solid 1px red;'> " );
            sbText.Append(
" <div style='left: "  +  (radii + xposition)  +  " ;position:relative; top: "  +  (radii + yposition)  +  " ;'> " );
            sbText.Append(
" <v:TextBox id='msgShow' inset='5pt,5pt,5pt,5pt' style='width: "  +  Colors[i]  +  " ;position:absolute;z-index:2;display:none;background-color:red; font-size:12px;'></v:TextBox> " );
            
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( " <v:shape ID='ccc' style='position:absolute;width:200px; height:200px;'coordsize='200,200' fillcolor='# "  +  Colors[i]  +  " ' filled='t' strokecolor='#FFFFFF' " );
                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  +  " %'></v:shape> " );
                
// 给临时变量赋值
                TempUnitAngle  +=  vd.value  *  UnitAngle;
                TempUnitArc 
=  UnitArc;
                
// 显示颜色说明框
                ColorInfo  +=  " <div style='position:relative;padding-top:3px;padding-bottom:3px;' title='所占比例: "  +  rate  +  " %' onMouseOver='this.style.border=" " solid 1px #D38F61" " ' onMouseOut='this.style.border=" " none" " '> "
                    
+  "   <v:rect style='position:relative;width:20px;height:20px;' fillcolor=' "  +  Colors[i]  +  " '/> "  +  vd.key  +  " "  +  vd.value  +  "   ( "  +  rate  +  " %)</div> "
                    ;
                
// 如果颜色遍历完了,还有数据要显示那就重新再一次遍历。占:" + (Math.Round(vd.value * 100 / TotalCount, 2)) + "%
                i  =  (i  >=  Colors.Length  ?  0  :  ++ i);
            }
            sbText.Append(
" </div> " );
            sbText.Append(
" <div style='border:solid 1px #000;padding:10px;margin-right:10px;position:relative;left: "  +  ( 2  *  radii  +  20  +  xposition)  +  " px;top:10px;width: "  +  (xwidth  -  ( 2  *  radii  +  40  +  xposition))  +  " ;'> " );
            
// sbText.Append("<div style='padding-left:10px;width:" + (xwidth - (2 * radii +30+ xposition)) +";height:auto;'>");
            
// 总数
            sbText.Append( " <div style='background-color:#000;color:#fff;'>总数据: " + TotalCount + " </div> " );
            sbText.Append(ColorInfo);
            sbText.Append(
" </div></div> " );
            
this .Text  =  sbText.ToString();
        }
        
#endregion
        
///  <summary>
        
///  控件加载时画图
        
///  </summary>
        
///  <param name="e"></param>
         protected  override  void  OnLoad(EventArgs e)
        {
            
base .OnLoad(e);  //  Page.RegisterStartupScript("HelloWord", "<script>alert('BBB');</script>");
             DrawVml();
            
// Page.RegisterStartupScript("", "<script>alert('aaa');</script>");
        }
        
protected  override  void  OnPreRender(EventArgs e)
        {
            
base .OnPreRender(e);
            Page.RegisterStartupScript(
"" " <script>AllPlay();</script> " );
        }
    }
* 注意里面的数据源类型和枚举在下面定义.
  
///  <summary>
    
///  画图时用的数据源
    
///  </summary>
     public  class  VmlDataSource
    {
        
public  VmlDataSource()
        {

        }

        
public  string  key;
        
public  double  value;
        
///  <summary>
        
///  键值
        
///  </summary>
         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;
            }
        }

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

饼图为:

转载于:https://www.cnblogs.com/JemBai/archive/2008/08/19/1271368.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值