原始碼推薦:一個使用C#繪製圖形引擎的Framework (轉)

worldblog發表於2007-12-02
原始碼推薦:一個使用C#繪製圖形引擎的Framework (轉)[@more@]

 


 Batman
 下面將推薦一個可以很方便的生成多種圖形格式的,使用了+技術的圖形
引擎程式碼。它的主要描述如下:
1.可以生成的圖形格式支援BMP
 EMF,GIF,Icon,JPEG,PNG,TIFF,WMF
2.在檔案ChartEngine.cs中為這個圖形引擎的大量關鍵程式碼
 StockPicker.檔案是一個使用該引擎繪圖的例子
3.要使用這個圖形引擎,需要把所有的程式碼檔案複製到你的的某個
運用目錄(注:不是普通目錄)中,然後在該目錄下建立一個bin目錄,
然後執行mk.bat
4.ImageGenerator_VB.asp檔案的頭使用了 %>來說明生成的是某種格式的圖形檔案
5.為了考慮,還可以在ImageGenerator_VB.asp中增加以下程式碼
,該程式碼可以將生成的圖形檔案快取起來
這樣如果網站訪問量大時,可以大大減輕伺服器的負擔

 好了,廢話少說,大家可以自己研究研究程式碼:
1.ChartEngine.cs檔案
using System.s;
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 Litle ;
 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 Solirush(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檔案






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


3.StockPicker.aspx檔案
<BR>&nbsp;void ChartBtn_Click(Object sender, EventArgs e) {<BR>&nbsp;chart.ImageUrl = "ImageGenerator_Vb.aspx?";<BR>&nbsp;chart.Visible = true;<BR>&nbsp;foreach(ListItem item in Stocks.Items) {<BR>&nbsp;if (item.ed == true) {<BR>&nbsp;chart.ImageUrl += "symbols=" + item.Value + "&";<BR>&nbsp;}<BR>&nbsp;}<BR>&nbsp;}<BR>


 


 
 

tt's Stock Picker


 
 MSFT
 Sun
 

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-987493/,如需轉載,請註明出處,否則將追究法律責任。

相關文章