一个使用C#绘制图形引擎的Framework

2010-08-28 10:49:35来源:西部e网作者:

下面将推荐一个可以很方便的生成多种图形格式的,使用了ASP+技术的图形
引擎代码。它的主要描述如下:
1.可以生成的图形文件格式支持BMP
  EMF,GIF,Icon,JPEG,PNG,TIFF,WMF
2.在文件ChartEngine.cs中为这个图形引擎的大量关键代码
  StockPicker.aspx文件是一个使用该引擎绘图的例子
3.要使用这个图形引擎,需要把所有的代码文件复制到你的web的某个
运用目录(注:不是普通目录)中,然后在该目录下建立一个bin目录,
然后运行mk.bat
4.ImageGenerator_VB.asp文件的头使用了<%@ Page ContentType="image/jpeg"
  %>来说明生成的是某种格式的图形文件
5.为了服务器性能考虑,还可以在ImageGenerator_VB.asp中增加以下代码
<%@ OutputCache Duration="60" %>,该代码可以将生成的图形文件缓存起来
这样如果网站访问量大时,可以大大减轻服务器的负担

    好了,废话少说,大家可以自己研究研究代码:
1.ChartEngine.cs文件
using System.WinForms;
using System.Collections;
using System.Collections.Bases;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.ComponentModel;
using System;
using System.IO;

namespace ChartGenerator  {
    //Core Line Data structure
    public struct LineData {
        public float[] LineValues  ;
        public string LineTitle ;
        public string LineSymbol ;
    }
    //Line Data plus display style information
    public class ChartLine {
        private Color lineColor ;
        private LineData lineData ;
        private DashStyle lineStyle ;
        private int lineWidth  ;
        //Constructors
        public ChartLine() :base() {}
        public ChartLine(LineData lineData) :base() {
            this.lineData = lineData;
        }

        //Properties
        public Color Color {
            get { return lineColor ; }
            set { lineColor = value ; }
        }

        public DashStyle LineStyle {
            get { return lineStyle ; }
            set { lineStyle = value ; }
        }
       
        public string Symbol {
            get { return lineData.LineSymbol ; }
            set { lineData.LineSymbol = value ; }
        }

        public string Title {
            get { return lineData.LineTitle ; }
            set { lineData.LineTitle = value ; }
        }

        public float[] Values {
            get { return lineData.LineValues ; }
            set { lineData.LineValues = value ; }
        }

        public int Width {
            get { return lineWidth ; }
            set { lineWidth = value ; }
        }

        //Methods
        public void SetLineData(LineData lineData) {
            this.lineData = lineData;
        }
    }

    //Chart Data structure
    public class ChartData {

        private float yTickSize;
        private float yMax;
        private float yMin;
        private string[] xAxisTitles ;
        private ChartLineList lines = new ChartLineList();
        private Color gridColor=Color.Blue;
        private bool showHGridLines=true;
        private bool showVGridLines=true;

        //Properties
        public float YTickSize {
            get { return yTickSize ; }
            set { yTickSize = value ; }
        }

        public float YMax {
            get { return yMax ; }
            set { yMax = value ; }
        }

        public float YMin {
            get { return yMin ; }
            set { yMin = value ; }
        }

        public string[] XAxisTitles {
            get { return xAxisTitles ; }
            set { xAxisTitles = value ; }
        }

        public ChartLineList Lines {
            get { return lines ; }
            set { lines = value ; }
        }

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

        public bool ShowHGridLines {
            get { return showHGridLines ; }
            set { showHGridLines = value ; }
        }

        public bool ShowVGridLines {
            get { return showVGridLines ; }
            set { showVGridLines = value ; }
        }

        //Collection of Chart Lines
        public class ChartLineList : TypedCollectionBase {
           public ChartLine this[int index] {
               get {
                   return (ChartLine)(List[index]);
               }
               set {
                   List[index] = value;
               }
           }

            public int Add(ChartLine value) {
               return List.Add(value);
            }

            public void Insert(int index, ChartLine value) {
               List.Insert(index, value);
            }

            public int IndexOf(ChartLine value) {
               return List.IndexOf(value);
            }

            public bool Contains(ChartLine value) {
               return List.Contains(value);
            }

            public void Remove(ChartLine value) {
               List.Remove(value);
            }

            public void CopyTo(ChartLine[] array, int index) {
               List.CopyTo(array, index);
            }
       }   
    }

    //Charting Engine - draws a chart based on the given ChartData
    public class ChartEngine {
        private ChartData chartData ;
        private float left;
        private float right;
        private float top;
        private float bottom;
        private float tickCount;
        private float yCount;  
        private float hspacing;
        private float vspacing;
        private Graphics g;
        private Rectangle r;
        private Color backColor;
        private Color foreColor;
        private Font baseFont;
        private Font legendFont;
        private RectangleF legendRect;

        public ChartEngine() {

        }                          

 

        public Bitmap DrawChart(int width, int height, ChartData chartData) {

 

           Bitmap newBitmap = new Bitmap(width,height,PixelFormat.Format32bppARGB);

           Graphics g = Graphics.FromImage(newBitmap);

       

           Rectangle r = new Rectangle(0, 0, width, height);

           Color myForeColor = Color.Black;

           Color myBackColor = Color.White;

           Font myFont = new Font("Arial", 10);

 

           this.DrawChart(g, r, myBackColor, myForeColor, myFont, chartData);

 

           return newBitmap;

        }

 

        public void DrawChart(Graphics g, Rectangle r, Color backColor,

Color foreColor, Font baseFont, ChartData chartData) {

 

            this.chartData = chartData;

            this.g = g;

            this.r = r;

            this.backColor = backColor;

            this.foreColor = foreColor;

            this.baseFont = baseFont;

            this.legendFont = new Font(baseFont.FontFamily,

(baseFont.Size * 2/3), baseFont.Style | FontStyle.Bold);

 

 

            g.SmoothingMode = SmoothingMode.AntiAlias;

 

            CalculateChartDimensions();

           

            DrawBackground();

            InternalDrawChart() ;

        }

 

        private void CalculateChartDimensions() {

 

            right = r.Width - 5;

            top = 5 * baseFont.Size ;

            bottom = r.Height - baseFont.Size * 2;

 

            tickCount = chartData.YMin ;

            yCount = (chartData.YMax-chartData.YMin) / chartData.YTickSize ;

            hspacing = (bottom-top) / yCount;

            vspacing = (right) / chartData.XAxisTitles.Length;

 

            //Left depends on width of text - for simplicities sake assume that largest yvalue is the biggest

            //Take into account the first X Axis title

            float maxYTextSize = g.MeasureString(chartData.YMax.ToString(), baseFont).Width;

            float firstXTitle = g.MeasureString(chartData.XAxisTitles[0], baseFont).Width;

 

            left = (maxYTextSize > firstXTitle) ? maxYTextSize : firstXTitle ;

            left = r.X + left + 5 ;

 

            //Calculate size of legend box

 

            float maxLegendWidth = 0 ;

            float maxLegendHeight = 0 ;

 

            //Work out size of biggest legend

            foreach (ChartLine cl in chartData.Lines) {

                float currentWidth = g.MeasureString(cl.Title, legendFont).Width;

                float currentHeight = g.MeasureString(cl.Title, legendFont).Height;

                maxLegendWidth = (maxLegendWidth > currentWidth) ? maxLegendWidth : currentWidth ;

                maxLegendHeight = (maxLegendHeight > currentHeight) ? maxLegendHeight : currentHeight ;

            }

 

            legendRect = new RectangleF(r.X+2, r.Y+2, maxLegendWidth + 25 + 5, ((maxLegendHeight+2)*chartData.Lines.Count) + 3) ;

        }

 

        private void DrawBackground() {

            LinearGradientBrush b = new LinearGradientBrush(r, Color.SteelBlue, backColor,LinearGradientMode.Horizontal);

            g.FillRectangle(b, r);

            b.Dispose();

        }

 

        private void InternalDrawChart() {

 

            DrawGrid() ;

 

            foreach (ChartLine cl in chartData.Lines) {

                DrawLine(cl);

            }

 

            DrawLegend() ;

 

            //Draw time on chart

            string timeString = DateTime.ToString(DateTime.Now) ;

            SizeF textsize = g.MeasureString(timeString,baseFont);

            g.DrawString(timeString, baseFont, new SolidBrush(foreColor), r.Width - textsize.Width - 5, textsize.Height * 2 / 3) ;

        }                      

 

        private  void DrawGrid() {

 

            Pen gridPen = new Pen(chartData.GridColor) ;

 

            //Vertical - include tick desc's

            if (chartData.ShowVGridLines) {

                for (int i = 0 ; (vspacing * i) < right; i++) {

                    float x = left + (vspacing *i);          

                    string desc = chartData.XAxisTitles[i];

                    g.DrawLine(gridPen, x,top,x,bottom +(baseFont.Size*1/3));

                    SizeF textsize = g.MeasureString(desc,baseFont);

                    g.DrawString(desc, baseFont, new SolidBrush(chartData.GridColor), x-(textsize.Width/2), bottom + (baseFont.Size*2/3)) ;

                }

            }

 

            //Horizontal

            if (chartData.ShowHGridLines) {

                for (float i = bottom ; i > top; i-=hspacing) {

                    string desc = tickCount.ToString();

                    tickCount+=chartData.YTickSize;

                    g.DrawLine(gridPen, right, i, left-3, i);

                    SizeF textsize = g.MeasureString(desc,baseFont);

                    g.DrawString(desc, baseFont, new SolidBrush(chartData.GridColor), left-textsize.Width - 3, i - (textsize.Height/2)) ;

                }

            }

        }

 

        private void DrawLine(ChartLine chartLine) {

 

            Pen linePen = new Pen(chartLine.Color);

            linePen.StartCap = LineCap.Round;

            linePen.EndCap = LineCap.Round;

            linePen.Width = chartLine.Width ;

            linePen.DashStyle = chartLine.LineStyle;

 

            PointF[] Values = new PointF[chartLine.Values.Length];

            float scale = hspacing / chartData.YTickSize ;

 

            for (int i = 0 ; i < chartLine.Values.Length; i++) {

                float x = left + vspacing * i;          

                Values[i] = new PointF(x, bottom-chartLine.Values[i]*scale);

            }

 

            g.DrawLines(linePen, Values);

        }

 

        private void DrawLegend() {

 

            //Draw Legend Box

            ControlPaint.DrawBorder(g, (Rectangle)legendRect, SystemColors.WindowFrame, ButtonBorderStyle.Solid);

            LinearGradientBrush b = new LinearGradientBrush(legendRect, backColor, Color.SteelBlue, LinearGradientMode.Horizontal);

            r.Inflate(-1, -1);

            g.FillRectangle(b, legendRect);

            b.Dispose();

 

            float startY = 5;

 

            foreach (ChartLine cl in chartData.Lines) {

                Pen p = new Pen(cl.Color) ;

                p.Width = p.Width*4;

                SizeF textsize = g.MeasureString(cl.Title, legendFont);

                float lineY = startY + textsize.Height / 2 ;

                g.DrawLine(p, r.X + 7, lineY, r.X + 25, lineY);

                g.DrawString(cl.Title, legendFont, new SolidBrush(foreColor), r.X + 30, startY);

                startY += (textsize.Height+2);

            }

        }

    }

}

2.ImageGenerator_Vb.aspx文件

<%@ Page Language="VB" ContentType="image/jpeg" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Drawing2D" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="ChartGenerator" %>
<script language="VB" runat=server>
    Function GetStockDetails(Symbol as String) as ChartLine
        Dim myChartLine as new ChartLine
        if (symbol = "msft") then
            Dim StockValues() as Single = { 60, 110, 120, 180, 185, 190, 240, 290 }
            myChartLine.Width = 5
            myChartLine.Color = Color.White
            myChartLine.LineStyle = DashStyle.Solid
            myChartLine.Title = "Microsoft Corp. (MSFT)"
            myChartLine.Symbol = "MSFT"
            myChartLine.Values = StockValues
            return myChartLine
        elseif (symbol = "sun") then
           Dim StockValues() as Single = { 180, 155, 125, 60, 25, 15, 10, 3 }
            myChartLine.Width = 5
            myChartLine.Color = Color.Red
            myChartLine.LineStyle = DashStyle.Dot
            myChartLine.Title = "Sun Corp. (Sun)"
            myChartLine.Symbol = "Sun"
            myChartLine.Values = StockValues
            return myChartLine
        end if
        return nothing
    End Function
    Sub Page_Load(Sender as Object, E as EventArgs)
        ' Generate Chart Data For Image....
        Dim XAxes() as String = { "9:00AM", "9:30AM", "10:00AM", "11:00AM", "12:00AM", "1:00PM", "1:30PM" }
        Dim MyChartData as New ChartData
        MyChartData.YTickSize = 20
        MyChartData.YMax = 250
        MyChartData.YMin = 0
        MyChartData.XAxisTitles = XAxes
        Dim Symbols() as String = Request.QueryString.GetValues("symbols")
        if (Not Symbols Is Nothing) then
           for i=0 to Symbols.Length-1
              Dim stockValue as ChartLine = GetStockDetails(symbols(i).ToLower)
              if (stockValue <> noting) then
                 myChartData.Lines.Add(stockValue)
              end if
           Next
        end if
        ' Create In-Memory BitMap of JPEG
        Dim MyChartEngine as New ChartEngine
        Dim StockBitMap as BitMap = MyChartEngine.DrawChart(600, 400, myChartData)
        ' Render BitMap Stream Back To Client
        StockBitMap.Save(Response.OutputStream, ImageFormat.JPEG)
     End Sub
</script>

3.StockPicker.aspx文件
<script language="C#" runat=server>
   void ChartBtn_Click(Object sender, EventArgs e) {
      chart.ImageUrl = "ImageGenerator_Vb.aspx?";
      chart.Visible = true;
      foreach(ListItem item in Stocks.Items) {
         if (item.Selected == true) {
            chart.ImageUrl += "symbols=" + item.Value + "&";
         }
      }
   }
</script>
<html>
   <body>
      <form runat=server>
         <h1>Scott's Stock Picker</h1>
         <asp:checkboxlist id="Stocks" runat=server>
             <asp:listitem>MSFT</asp:listitem>
             <asp:listitem>Sun</asp:listitem>
         </asp:checkboxlist>
         <asp:button text="Chart Your Selected Stocks" OnClick="ChartBtn_Click" runat=server/>
         <hr>
         <asp:Image id="chart" ImageUrl="" Visible=false runat=server/>
      </form>
   </body>
</html>

4.mk.bat文件
csc /t:library /debug+ /out:bin\chartgen.dll ChartEngine.cs /r:System.Web.dll /r:System.Winforms.dll /r:System.Drawing.dll /r:System.dll

关键词:C#

赞助商链接: