ASP.NET图形化的曲线图类

chart.cs

using System;
using System.Drawing;

namespace Report
{
    
/// <summary>
    
/// Chart 的摘要说明。
    
/// ==================================================================================================
    
/// 
    
///    ClassName  :Report.Chart  
    
///    Intro      :
    
///    Example    :  
    
///    Ver        :0.2
    
///     
    
///    Author     :ttyp  
    
///    Email      :ttyp@21cn.com  
    
///    Date       :2007-7-30
    
/// ==================================================================================================
    
/// </summary>
    public class Chart
    {
        
public Chart(){}

        
private string    _data    = "";
        
private int        _width    = 100;
        
private int        _height    = 100;
        
private int        _padding= 8;
        
private Color    _grid_color        = Color.FromArgb(0x93,0xbe,0xe2);
        
private Color    _border_color    = Color.FromArgb(0x93,0xbe,0xe2);
        
private Font    _font            = new Font("Arial",8);

        
public Font Font
        {
            
get { return _font;}
            
set { _font = value;}
        }

        
public Color BorderColor
        {
            
get { return _border_color;}
            
set { _border_color = value;}
        }

        
public Color GridColor
        {
            
get { return _grid_color;}
            
set { _grid_color = value;}
        }

        
public int Padding
        {
            
get { return _padding;}
            
set { _padding = Math.Max(0,value);}
        }

        
public int Width
        {
            
get { return _width;}
            
set { _width = Math.Max(0,value);}
        }

        
public int Height
        {
            
get { return _height;}
            
set { _height = Math.Max(0,value);}
        }

        
public string Data
        {
            
get { return _data;}
            
set { _data = value;}
        }

        
public void Render()
        {
            
int width        = this.Width;
            
int height        = this.Height;
            
int padding        = this.Padding;    
    
            
            System.Drawing.Bitmap image 
= new System.Drawing.Bitmap(width,height);    
            
            Graphics g 
= Graphics.FromImage(image);

            
//清空图片背景色
            g.Clear(Color.White);

            
//虚线画笔
            Pen dot                = new Pen(this.GridColor);
            dot.DashStyle    
= System.Drawing.Drawing2D.DashStyle.Dot;

            
//实线画笔
            Pen solid            = new Pen(this.BorderColor);

            
//文字字体
            Font font            = this.Font;        
            
try
            {                

                
//冗余,去除最后的数据分割标记,防止空数据
                if(this.Data.EndsWith(";"))
                {
                    
this.Data = this.Data.Substring(0,this.Data.Length-1);
                }

                
string[] info = this.Data.Split(';');        //数据信息

                
if(info.Length>=2)
                {
                

                    
string[] lines = info[0].Split(',');    //图例
                    string[] units = info[1].Split(',');    //单位和标题格式,a,b,c,d  a 纵坐标单位 b 纵坐标格式 N 数字 D 时间 后面是具体格式,c 横坐标单位 d 横坐标格式(同b)

                    
//曲线颜色表
                    Color[] color    = new Color[]{Color.Blue,Color.Green,Color.Red,Color.Gray,Color.Black,Color.Magenta,Color.Cyan,Color.Yellow,Color.DeepPink,Color.BurlyWood,Color.DarkRed,Color.Gold};


                    
//图例文字的大小
                    SizeF sFont            = GetMaxSize(lines,g,font);

                    
//获得刻度文字高度
                    int textHeight        = (int)(sFont.Height*3/2);

                    
//曲线点的个数
                    int points            = info.Length-2;

                    
//得到曲线点数组集合
                    string[,] curve = new string[info.Length-2,lines.Length+1];
                    
for(int i=0;i<points;i++)
                    {
                        
string[] l = info[i+2].Split(',');
                        
int len = l.Length;
                                                
                        
for(int j=0;j<=lines.Length;j++)
                        {
                            
if(j<len)
                            {                        
                                curve[i,j] 
= l[j];
                            }
                            
else
                            {
                                curve[i,j] 
= "N";            //非数据,不画线
                            }
                        }                
                    }        
        
                    
//获得最大,最小值
                    double maxY,minY,maxX,minX;

                    GetMaxMin(curve,
out maxY,out minY,out maxX,out minX);
                    
//冗余最大最小值
                    if(maxY==minY)
                    {
                        
if(maxY==0)
                        {
                            maxY 
= 10;
                            minY 
= -10;
                        }
                        
else
                        {
                            
if(maxY>0)
                            {
                                maxY 
= maxY*2;
                                minY 
= 0;
                            }
                            
else
                            {
                                maxY 
= 0;
                                minY 
= maxY*2;
                            }
                        }
                    }

                    
if(maxX==minX)
                    {
                        
if(maxX==0)
                        {
                            maxX 
= 10;
                            minX 
= -10;
                        }
                        
else
                        {
                            
if(maxX>0)
                            {
                                maxX 
= maxX*2;
                                minY 
= 0;
                            }
                            
else
                            {
                                maxX 
= 0;
                                minX 
= maxX*2;
                            }
                        }
                    }

                    
//获取坐标框的上下左右
                    float left        = (padding*2+sFont.Height+2 + sFont.Width + padding+GetMaxSize(units[1],g,font).Width+padding);
                    
float bottom    = height-padding-textHeight;
                    
float top        = padding;
                    
float right        = width -padding;

                    
//获取曲线框的宽度和高度(比坐标框略小)
                    float yWidth = bottom-top-GetMaxSize(units[0],g,font).Height*3/2-padding;
                    
float xWidth = right-left-GetMaxSize(units[3],g,font).Width/2 - sFont.Width -padding;


                    
//---------------------------------------------------------------------------------

                    
//获取最大行
                    int maxrow    = (int)(yWidth/(sFont.Height/2*3));
                    maxrow    
= Math.Max(maxrow,1);

                    
//获取Y步进值
                    float stepYv = (float)((maxY-minY)/(maxrow));

                    
if(units[1].Length>1)
                    {
                        
//整数分割,调整最大行和最大最小值
                        if(units[1].Substring(0,1).ToLower()=="d")
                        {
                            maxY    
= Math.Ceiling(maxY);
                            minY    
= Math.Floor(minY);
                            stepYv    
= (float)Math.Ceiling((maxY-minY)/maxrow);
                            maxrow    
= (int)((maxY-minY)/stepYv);                            
                        }    
                    }

                    
float stepy        = (float)((yWidth/(maxY-minY))*stepYv);

                
                    
//---------------------------------------------------------------------------------


                    
//得到最大的网格列(最多10列)
                    int maxcol    = points;
                    maxcol        
= Math.Min(points,maxcol);
                    maxcol        
= Math.Max(maxcol,1);

                    
//获取X步进值
                    float stepXv = (float)((maxX-minX)/(maxcol));

                    
if(units[3].Length>1)
                    {
                        
//整数分割,调整最大和最小值,以及步进
                        if(units[3].Substring(0,1).ToLower()=="d")
                        {
                            maxX    
= Math.Ceiling(maxX);
                            minX    
= Math.Floor(minX);
                            stepXv    
= (float)Math.Ceiling((maxX-minX)/maxcol);
                            maxcol    
= (int)((maxX-minX)/stepXv);
                        }                
                    }

                    
//获得最大显示列数
                    int dispcol = (int)((xWidth)/(GetMaxSize(units[3].Substring(1),g,font).Width+padding));
                    dispcol 
= Math.Max(dispcol,1);

                    
//如果最大显示列小于最大列,则应该缩减
                    if(dispcol<maxcol)
                    {
                        stepXv    
= (float)Math.Ceiling((maxX-minX)/dispcol);
                        maxcol    
= (int)((maxX-minX)/stepXv);
                    }


                    
float stepx = (float)((xWidth/(maxX-minX))*stepXv);


                    
//获得最大的曲线数目
                    int maxline    = color.Length;            
                    maxline        
= Math.Min(maxline,lines.Length);


                    
//画图例边框
                    g.DrawRectangle(solid, padding, (height-((sFont.Height+5)*maxline+2*padding))/2,padding*2+sFont.Height+2 + sFont.Width, (sFont.Height+5)*maxline+2*padding);

                    
//画图例
                    for(int i=0;i<maxline;i++)
                    {
                        SolidBrush fb 
= new SolidBrush(color[i]);
                        SolidBrush bl 
= new SolidBrush(Color.Black);
                        
//画图例方框
                        g.FillRectangle(fb,padding*2, (height-((sFont.Height+5)*maxline+2*padding))/2+(sFont.Height+5)*i+padding,sFont.Height, sFont.Height);
                        
//画图例文字
                        g.DrawString(lines[i], font, bl, padding*2+sFont.Height+2,(height-((sFont.Height+5)*maxline+2*padding))/2+(sFont.Height+5)*i+padding);

                    }                


                    
//画坐标
                    g.DrawLine(solid,left,top,left,bottom);        //Y
                    g.DrawLine(solid,left,bottom,right,bottom);    //X

                    
//画坐标箭头
                    g.DrawLine(solid,left,top,left-padding/3,top+padding/2);            //Y箭头
                    g.DrawLine(solid,left,top,left+padding/3,top+padding/2);

                    g.DrawLine(solid,right,bottom,right
-padding/2,bottom-padding/3);    //X箭头
                    g.DrawLine(solid,right,bottom,right-padding/2,bottom+padding/3);


                
                    
//画X刻度
                    for(int i=0;i<=maxcol;i++)
                    {
                        SolidBrush bl 
= new SolidBrush(Color.Black);
                        
if(i>0)
                        {
                            g.DrawLine(dot,left
+i*stepx,top+padding,left+i*stepx,bottom);    
                        }

                        
string text = "";

                        
switch(units[3].Substring(0,1).ToString())
                        {
                            
case "N":
                                text 
= (minX+stepXv*i).ToString(units[3].Substring(1));
                                
break;
                            
case "D":
                                text 
= DateTime.FromOADate((int)(minX+stepXv*i)).ToString(units[3].Substring(1));                                
                                
break;
                        }        

                        SizeF xf 
= GetMaxSize(text,g,font);
                    
                        g.DrawString(text, font, bl, left
+i*stepx-xf.Width/2,bottom+xf.Height/2);                

                        
if(i==0)
                        {
                            g.DrawString(units[
2], font, bl, right-GetMaxSize(units[2],g,font).Width,bottom);                    
                        }

                        
if(points<=1)
                        {
                            
break;
                        }
                    }

                    
//画Y刻度
                    for(int i=0;i<=maxrow;i++)
                    {
                        SolidBrush bl 
= new SolidBrush(Color.Black);

                        
if(i>0)
                        {
                            g.DrawLine(dot,left,bottom
-i*stepy,right-padding,bottom-i*stepy);    
                        }


                        
string text = "";

                        
switch(units[1].Substring(0,1).ToString())
                        {
                            
case "N":
                                text 
=  (minY+i*stepYv).ToString(units[1].Substring(1));
                                
break;
                            
case "D":
                                text 
= DateTime.FromOADate(int.Parse(curve[i,0])).ToString(units[1].Substring(1));                                
                                
break;
                        }        

                        SizeF xf 
= GetMaxSize(text,g,font);
                    
                        g.DrawString(text, font, bl, left
-xf.Width,bottom-stepy*i-xf.Height/2);                

                        
if(i==0)
                        {
                            g.DrawString(units[
0], font, bl, left-GetMaxSize(units[0],g,font).Width-3,top);                    
                        }
                    }

                    
//画图片的边框线
                    g.DrawRectangle(solid, 00, image.Width - 1, image.Height - 1);

                    
float[] px = new float[maxline];
                    
float[] py = new float[maxline];

                    
bool[]    ps = new bool[maxline];

                    
//画曲线
                    for(int j=0;j<points;j++)
                    {
                        
float v  = float.Parse(curve[j,0]);
                        
float cx = (float)(left+(xWidth)*(v-minX)/(maxX-minX));

                        
for(int i=0;i<maxline;i++)
                        {            
                            
try
                            {
                                
float w  = float.Parse(curve[j,i+1]);
                                
float cy = (float)(bottom - (yWidth)*(w-minY)/(maxY-minY));

                                
if(ps[i])
                                {
                                    Pen cp 
= new Pen(color[i]);
                                    g.DrawLine(cp,px[i],py[i],cx,cy);
                                }

                                px[i] 
= cx;
                                py[i] 
= cy;
                                ps[i] 
= true;

                                
if(points==1)
                                {
                                    image.SetPixel((
int)cx,(int)cy,color[i]);
                                }
                            }
                            
catch
                            {
                                ps[i] 
= false;
                            }
                        }
                    }
                }
                
else
                {
                    
string msg = "no data";
                    g.DrawString(msg,font,
new SolidBrush(Color.Black), (width - GetMaxSize(msg,g,font).Width)/2,(height-GetMaxSize(msg,g,font).Height)/2);
                }

                System.Web.HttpContext.Current.Response.ClearContent();
                System.Web.HttpContext.Current.Response.ContentType
="image/Gif";

                image.Save(System.Web.HttpContext.Current.Response.OutputStream,System.Drawing.Imaging.ImageFormat.Gif);

            }
            
finally
            {
                g.Dispose();
                image.Dispose();
            }
        }

        
private SizeF GetMaxSize(string[] s,Graphics g,Font f)
        {
            
string max = "";

            
for(int i=0;i<s.Length;i++)
            {
                
if(s[i].Length>max.Length)
                {
                    max 
= s[i];
                }
            }

            
return g.MeasureString(max,f);
        }

        
private SizeF GetMaxSize(string s,Graphics g,Font f)
        {
            
return g.MeasureString(s,f);
        }

        
private void GetMaxMin(string[,] data,out double maxY,out double minY,out double maxX,out double minX)
        {
            
int row = 0;
            
int col = 0;

            
double m =double.MinValue,n=double.MaxValue;
            
double p =double.MinValue,q=double.MaxValue;

            row 
= data.GetLength(0);
            col 
= data.GetLength(1);

            
for(int i=0;i<row;i++)
            {
                
for(int j=0;j<col;j++)
                {
                    
double v = 0;
                    
                    
try
                    {
                        v 
= double.Parse(data[i,j]);
                    
                        
if(j>0)
                        {
                            
if(v>m)
                            {
                                m 
= v;
                            }
                            
if(v<n)
                            {
                                n 
= v;
                            }
                        }
                        
else
                        {
                            
if(v>p)
                            {
                                p 
= v;
                            }
                            
if(v<q)
                            {
                                q 
= v;
                            }
                        }
                    }
                    
catch{}
                }
            }

            maxY 
= m;
            minY 
= n;

            maxX 
= p;
            minX 
= q;
        }
    }
}

使用方法

demo.cs
        private void Page_Load(object sender, System.EventArgs e)
        {

            
string data = "Total,T1,T2,T3,T4;(kwh),N0.0,(day),Dyyyy-MM-dd;";

            
int days = 50;
            DateTime start 
= DateTime.Now.AddDays(-1*days);

            System.Random random 
= new Random();

            System.Text.StringBuilder sb 
= new System.Text.StringBuilder();

            sb.Append(data);

            
string[] b = new string[days];

            
for(int i=0;i<days;i++)
            {
                
string[] a = new string[6];

                a[
0= ((int)DateTime.Now.AddDays(-1*i).ToOADate()).ToString();

                
for(int j=1;j<6;j++)
                {
                    System.Threading.Thread.Sleep(
1);

                    a[j] 
= random.Next(100).ToString();

                }

                b[i] 
=string.Join(",",a);
            }

            sb.Append(
string.Join(";",b));

            data 
= sb.ToString();

            Report.Chart chart 
= new Report.Chart();

            chart.Data        
= data;
            chart.Width        
= 800;
            chart.Height    
= 200;
            chart.Padding    
= 8;
            chart.Font 
= new System.Drawing.Font("楷体2312",8);

            chart.Render();

        }

demo


posted @ 2007-07-20 13:47  ttyp  阅读(3173)  评论(2编辑  收藏  举报