本文摘选自《Practical C# Charts and Graphics》,有兴趣的朋友可以到网上下载电子书。
今天主要贴出一些如何实现K线图(蜡烛图)的代码,废话不多说,直接看下面。
1.外面文件读取类(TextFileReader.cs):
View Code
using System;
using System.Text;
using System.Collections.Specialized;
using System.Collections;
using System.Windows.Forms;
using System.IO;
namespace Example4_9
{
class TextFileReader
{
public string[,] ReadTextFile(string fileName)
{
if (File.Exists(fileName))
{
string[,] sArray = ReadFile(fileName);
return sArray;
}
else
{
return null;
}
}
private string[,] ReadFile(string fileName)
{
try
{
StringCollection sc = new StringCollection();
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.ReadWrite);
StreamReader sr = new StreamReader(fs);
// Read file into a string collection
int noBytesRead = 0;
string oneLine;
while ((oneLine = sr.ReadLine()) != null)
{
noBytesRead += oneLine.Length;
sc.Add(oneLine);
}
sr.Close();
string[] sArray = new string[sc.Count];
sc.CopyTo(sArray, 0);
char[] cSplitter = { ' ', ',', ':', '\t' };
string[] sArray1 = sArray[0].Split(cSplitter);
string[,] sArray2 = new string[sArray1.Length, sc.Count];
for (int i = 0; i < sc.Count; i++)
{
sArray1 = sArray[sc.Count - 1 - i].Split(cSplitter);
for (int j = 0; j < sArray1.Length; j++)
{
sArray2[j, i] = sArray1[j];
}
}
return sArray2;
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error Saving File.");
return null;
}
}
}
}
2.股票数据(DataSeries.cs)
View Code
using System;
using System.Drawing;
namespace Example4_9
{
public class DataSeries
{
private string[,] dataString;
private LineStyle lineStyle;
private string seriesName = "";
public DataSeries()
{
lineStyle = new LineStyle();
}
public LineStyle LineStyle
{
get { return lineStyle; }
set { lineStyle = value; }
}
public string[,] DataString
{
get { return dataString; }
set { dataString = value; }
}
public string SeriesName
{
get { return seriesName; }
set { seriesName = value; }
}
}
}
3.数据集合(DataCollection.cs)
View Code
using System;
using System.Collections;
using System.Drawing;
namespace Example4_9
{
public class DataCollection
{
private Form1 form1;
private ArrayList dataSeriesList;
private int dataSeriesIndex = 0;
private StockChartTypeEnum stockChartType =
StockChartTypeEnum.HiLoOpenClose;
public DataCollection(Form1 fm1)
{
dataSeriesList = new ArrayList();
form1 = fm1;
}
public StockChartTypeEnum StockChartType
{
get { return stockChartType; }
set { stockChartType = value; }
}
public enum StockChartTypeEnum
{
HiLo = 0,
HiLoOpenClose = 1,
Candle = 2
}
public ArrayList DataSeriesList
{
get { return dataSeriesList; }
set { dataSeriesList = value; }
}
public int DataSeriesIndex
{
get { return dataSeriesIndex; }
set { dataSeriesIndex = value; }
}
public void Add(DataSeries ds)
{
dataSeriesList.Add(ds);
if (ds.SeriesName == "")
{
ds.SeriesName = "DataSeries" + dataSeriesList.Count.ToString();
}
}
public void Insert(int dataSeriesIndex, DataSeries ds)
{
dataSeriesList.Insert(dataSeriesIndex, ds);
if (ds.SeriesName == "")
{
dataSeriesIndex = dataSeriesIndex + 1;
ds.SeriesName = "DataSeries" + dataSeriesIndex.ToString();
}
}
public void Remove(string dataSeriesName)
{
if (dataSeriesList != null)
{
for (int i = 0; i < dataSeriesList.Count; i++)
{
DataSeries ds = (DataSeries)dataSeriesList[i];
if (ds.SeriesName == dataSeriesName)
{
dataSeriesList.RemoveAt(i);
}
}
}
}
public void RemoveAll()
{
dataSeriesList.Clear();
}
public void AddStockChart(Graphics g, ChartStyle cs)
{
foreach (DataSeries ds in DataSeriesList)
{
Pen aPen = new Pen(ds.LineStyle.LineColor, ds.LineStyle.Thickness);
aPen.DashStyle = ds.LineStyle.Pattern;
SolidBrush aBrush = new SolidBrush(ds.LineStyle.LineColor);
SolidBrush whiteBrush = new SolidBrush(Color.White);
float barLength = form1.PlotPanel.Width / (5*ds.DataString.GetLength(1));
for (int i = 0; i < ds.DataString.GetLength(1); i++)
{
float[] stockdata = new float[4];
for (int j = 0; j < stockdata.Length; j++)
{
stockdata[j] = Convert.ToSingle(ds.DataString[j+1,i]);
}
PointF ptHigh = cs.Point2D(new PointF(i, stockdata[1]));
PointF ptLow = cs.Point2D(new PointF(i, stockdata[2]));
PointF ptOpen = cs.Point2D(new PointF(i, stockdata[0]));
PointF ptCLose = cs.Point2D(new PointF(i, stockdata[3]));
PointF ptOpen1 = new PointF(ptOpen.X - barLength, ptOpen.Y);
PointF ptClose1 = new PointF(ptCLose.X + barLength, ptCLose.Y);
PointF ptOpen2 = new PointF(ptOpen.X + barLength, ptOpen.Y);
PointF ptClose2 = new PointF(ptCLose.X - barLength, ptCLose.Y);
// Draw Hi-Lo stock chart:
if (StockChartType == StockChartTypeEnum.HiLo)
{
g.DrawLine(aPen, ptHigh, ptLow);
}
// Draw Hi-Li-Open-Close chart:
else if (StockChartType == StockChartTypeEnum.HiLoOpenClose)
{
g.DrawLine(aPen, ptHigh, ptLow);
g.DrawLine(aPen,ptOpen, ptOpen1);
g.DrawLine(aPen, ptCLose, ptClose1);
}
// Draw candle chart:
else if (stockChartType == StockChartTypeEnum.Candle)
{
PointF[] pts = new PointF[4];
pts[0] = ptOpen1;
pts[1] = ptOpen2;
pts[2] = ptClose1;
pts[3] = ptClose2;
g.DrawLine(aPen, ptHigh, ptLow);
if (stockdata[0] > stockdata[3])
{
g.FillPolygon(aBrush,pts);
}
else if (stockdata[0] < stockdata[3])
{
g.FillPolygon(whiteBrush, pts);
}
g.DrawPolygon(aPen, pts);
}
}
aPen.Dispose();
aBrush.Dispose();
whiteBrush.Dispose();
}
}
}
}
4.股票图形类别(ChartType.cs)
View Code
using System;
using System.Collections.Generic;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace Example4_9
{
public class ChartStyle
{
private Form1 form1;
private Rectangle chartArea;
private Color chartBackColor;
private Color chartBorderColor;
private Color plotBackColor = Color.White;
private Color plotBorderColor = Color.Black;
private DashStyle gridPattern = DashStyle.Solid;
private Color gridColor = Color.LightGray;
private float gridLineThickness = 1.0f;
private bool isXGrid = false;
private bool isYGrid = false;
private string xLabel = "X Axis";
private string yLabel = "Y Axis";
private string sTitle = "Title";
private Font labelFont = new Font("Arial", 10, FontStyle.Regular);
private Color labelFontColor = Color.Black;
private Font titleFont = new Font("Arial", 12, FontStyle.Regular);
private Color titleFontColor = Color.Black;
private float xLimMin = 0f;
private float xLimMax = 10f;
private float yLimMin = 0f;
private float yLimMax = 10f;
private float xTick = 1f;
private float yTick = 2f;
private Font tickFont;
private Color tickFontColor = Color.Black;
private float xtickOffset = 0f;
private float ytickOffset = 0f;
private BarTypeEnum barType = BarTypeEnum.Vertical;
public ChartStyle(Form1 fm1)
{
form1 = fm1;
chartArea = form1.ClientRectangle;
chartBackColor = fm1.BackColor;
chartBorderColor = fm1.BackColor;
tickFont = form1.Font;
}
public BarTypeEnum BarType
{
get { return barType; }
set { barType = value; }
}
public enum BarTypeEnum
{
Vertical = 0,
Horizontal = 1,
VerticalStack = 2,
HorizontalStack = 3,
VerticalOverlay = 4,
HorizontalOverlay = 5
}
public Font TickFont
{
get { return tickFont; }
set { tickFont = value; }
}
public Color TickFontColor
{
get { return tickFontColor; }
set { tickFontColor = value; }
}
public Color ChartBackColor
{
get { return chartBackColor; }
set { chartBackColor = value; }
}
public float XTickOffset
{
get { return xtickOffset; }
set { xtickOffset = value; }
}
public float YTickOffset
{
get { return ytickOffset; }
set { ytickOffset = value; }
}
public Color ChartBorderColor
{
get { return chartBorderColor; }
set { chartBorderColor = value; }
}
public Color PlotBackColor
{
get { return plotBackColor; }
set { plotBackColor = value; }
}
public Color PlotBorderColor
{
get { return plotBorderColor; }
set { plotBorderColor = value; }
}
public Rectangle ChartArea
{
get { return chartArea; }
set { chartArea = value; }
}
public bool IsXGrid
{
get { return isXGrid; }
set { isXGrid = value; }
}
public bool IsYGrid
{
get { return isYGrid; }
set { isYGrid = value; }
}
public string Title
{
get { return sTitle; }
set { sTitle = value; }
}
public string XLabel
{
get { return xLabel; }
set { xLabel = value; }
}
public string YLabel
{
get { return yLabel; }
set { yLabel = value; }
}
public Font LabelFont
{
get { return labelFont; }
set { labelFont = value; }
}
public Color LabelFontColor
{
get { return labelFontColor; }
set { labelFontColor = value; }
}
public Font TitleFont
{
get { return titleFont; }
set { titleFont = value; }
}
public Color TitleFontColor
{
get { return titleFontColor; }
set { titleFontColor = value; }
}
public float XLimMax
{
get { return xLimMax; }
set { xLimMax = value; }
}
public float XLimMin
{
get { return xLimMin; }
set { xLimMin = value; }
}
public float YLimMax
{
get { return yLimMax; }
set { yLimMax = value; }
}
public float YLimMin
{
get { return yLimMin; }
set { yLimMin = value; }
}
public float XTick
{
get { return xTick; }
set { xTick = value; }
}
public float YTick
{
get { return yTick; }
set { yTick = value; }
}
virtual public DashStyle GridPattern
{
get { return gridPattern; }
set { gridPattern = value; }
}
public float GridThickness
{
get { return gridLineThickness; }
set { gridLineThickness = value; }
}
virtual public Color GridColor
{
get { return gridColor; }
set { gridColor = value; }
}
public void PlotPanelStyle(Graphics g)
{
Pen aPen = new Pen(ChartBorderColor, 1f);
SolidBrush aBrush = new SolidBrush(ChartBackColor);
SizeF tickFontSize = g.MeasureString("A", TickFont);
// Create vertical gridlines:
float fX, fY, xm, ym;
aPen = new Pen(GridColor, 1f);
aPen.DashStyle = GridPattern;
xm = XLimMin + XTickOffset;
if (BarType == BarTypeEnum.Vertical ||
BarType == BarTypeEnum.VerticalOverlay ||
BarType == BarTypeEnum.VerticalStack)
{
xm = XTickOffset + XLimMin;
}
// Create vertical gridelines:
if (IsYGrid == true)
{
for (fX = xm; fX < XLimMax; fX += XTick)
{
g.DrawLine(aPen, Point2D(new PointF(fX, YLimMin)),
Point2D(new PointF(fX, YLimMax)));
}
}
// Create the x-axis tick marks:
for (fX = xm; fX < XLimMax; fX += XTick)
{
PointF yAxisPoint = Point2D(new PointF(fX, YLimMin));
g.DrawLine(Pens.Black, yAxisPoint, new PointF(yAxisPoint.X,
yAxisPoint.Y - 8f));
}
// Create horizontal gridlines:
aPen = new Pen(GridColor, 1f);
aPen.DashStyle = GridPattern;
ym = YLimMin + YTickOffset;
if (BarType == BarTypeEnum.Horizontal ||
BarType == BarTypeEnum.HorizontalOverlay ||
BarType == BarTypeEnum.HorizontalStack)
{
ym = YTickOffset + YLimMin + YTick / 2;
}
if (IsXGrid == true)
{
for (fY = ym; fY < YLimMax; fY += YTick)
{
g.DrawLine(aPen, Point2D(new PointF(XLimMin, fY)),
Point2D(new PointF(XLimMax, fY)));
}
}
// Create the y-axis tick marks:
for (fY = ym; fY < YLimMax; fY += YTick)
{
PointF xAxisPoint = Point2D(new PointF(XLimMin, fY));
g.DrawLine(Pens.Black, xAxisPoint,
new PointF(xAxisPoint.X + 5f, xAxisPoint.Y));
}
aPen.Dispose();
aBrush.Dispose();
}
public void SetChartArea(Graphics g)
{
SetPlotPanel(g);
// Draw chart area:
Pen aPen = new Pen(ChartBorderColor, 1f);
SolidBrush aBrush = new SolidBrush(ChartBackColor);
SizeF tickFontSize = g.MeasureString("A", TickFont);
g.FillRectangle(aBrush, ChartArea);
g.DrawRectangle(aPen, ChartArea);
// Create the x-axis tick labels:
aBrush = new SolidBrush(TickFontColor);
float xm = XLimMin + XTickOffset;
float xticklabel = 0f;
if (BarType == BarTypeEnum.Vertical ||
BarType == BarTypeEnum.VerticalOverlay ||
BarType == BarTypeEnum.VerticalStack)
{
xm = XTickOffset + XLimMin;
xticklabel = 0;
}
for (float fX = xm; fX <= XLimMax; fX += XTick)
{
PointF yAxisPoint = Point2D(new PointF(fX, YLimMin));
StringFormat sFormat = new StringFormat();
sFormat.Alignment = StringAlignment.Center;
g.DrawString((fX + xticklabel).ToString(), TickFont, aBrush,
new PointF(form1.PlotPanel.Left + yAxisPoint.X,
form1.PlotPanel.Top + yAxisPoint.Y + 4f), sFormat);
}
// Create the y-axis tick labels:
float ym = YLimMin + YTickOffset;
float yticklabel = 0f;
if (BarType == BarTypeEnum.Horizontal ||
BarType == BarTypeEnum.HorizontalOverlay ||
BarType == BarTypeEnum.HorizontalStack)
{
ym = YTickOffset + YLimMin + YTick / 2;
yticklabel = YTick / 2;
}
for (float fY = ym; fY <= YLimMax; fY += YTick)
{
PointF xAxisPoint = Point2D(new PointF(XLimMin, fY));
StringFormat sFormat = new StringFormat();
sFormat.Alignment = StringAlignment.Far;
g.DrawString((fY + yticklabel).ToString(), TickFont, aBrush,
new PointF(form1.PlotPanel.Left + xAxisPoint.X - 3f,
form1.PlotPanel.Top + xAxisPoint.Y
- tickFontSize.Height / 2), sFormat);
}
AddLabels(g);
}
private void SetPlotPanel(Graphics g)
{
// Set form1.PlotPanel:
float xOffset = ChartArea.Width / 30.0f;
float yOffset = ChartArea.Height / 30.0f;
SizeF labelFontSize = g.MeasureString("A", LabelFont);
SizeF titleFontSize = g.MeasureString("A", TitleFont);
if (Title.ToUpper() == "NO TITLE")
{
titleFontSize.Width = 8f;
titleFontSize.Height = 8f;
}
float xSpacing = xOffset / 3.0f;
float ySpacing = yOffset / 3.0f;
SizeF tickFontSize = g.MeasureString("A", TickFont);
float tickSpacing = 2f;
SizeF yTickSize = g.MeasureString(YLimMin.ToString(), TickFont);
for (float yTick = YLimMin + YTickOffset; yTick <= YLimMax; yTick += YTick)
{
SizeF tempSize = g.MeasureString(yTick.ToString(), TickFont);
if (yTickSize.Width < tempSize.Width)
{
yTickSize = tempSize;
}
}
float leftMargin = xOffset + labelFontSize.Width +
xSpacing + yTickSize.Width + tickSpacing;
float rightMargin = xOffset;
float topMargin = yOffset + titleFontSize.Height + ySpacing;
float bottomMargin = yOffset + labelFontSize.Height +
ySpacing + tickSpacing + tickFontSize.Height;
// Define the plot panel size:
int[] panelsize = new int[4];
form1.PlotPanel.Left = ChartArea.X + (int)leftMargin;
form1.PlotPanel.Top = ChartArea.Y + (int)topMargin;
form1.PlotPanel.Width = ChartArea.Width - (int)leftMargin - 2 * (int)rightMargin;
form1.PlotPanel.Height = ChartArea.Height - (int)topMargin - (int)bottomMargin;
form1.PlotPanel.BackColor = plotBackColor;
}
private void AddLabels(Graphics g)
{
float xOffset = ChartArea.Width / 30.0f;
float yOffset = ChartArea.Height / 30.0f;
SizeF labelFontSize = g.MeasureString("A", LabelFont);
SizeF titleFontSize = g.MeasureString("A", TitleFont);
// Add horizontal axis label:
SolidBrush aBrush = new SolidBrush(LabelFontColor);
SizeF stringSize = g.MeasureString(XLabel, LabelFont);
g.DrawString(XLabel, LabelFont, aBrush,
new Point(form1.PlotPanel.Left + form1.PlotPanel.Width / 2 -
(int)stringSize.Width / 2, ChartArea.Bottom -
(int)yOffset - (int)labelFontSize.Height));
// Add y-axis label:
StringFormat sFormat = new StringFormat();
sFormat.Alignment = StringAlignment.Center;
stringSize = g.MeasureString(YLabel, LabelFont);
// Save the state of the current Graphics object
GraphicsState gState = g.Save();
g.TranslateTransform(ChartArea.X + xOffset, ChartArea.Y
+ yOffset + titleFontSize.Height
+ yOffset / 3 + form1.PlotPanel.Height / 2);
g.RotateTransform(-90);
g.DrawString(YLabel, LabelFont, aBrush, 0, 0, sFormat);
// Restore it:
g.Restore(gState);
// Add title:
aBrush = new SolidBrush(TitleFontColor);
stringSize = g.MeasureString(Title, TitleFont);
if (Title.ToUpper() != "NO TITLE")
{
g.DrawString(Title, TitleFont, aBrush,
new Point(form1.PlotPanel.Left + form1.PlotPanel.Width / 2 -
(int)stringSize.Width / 2, ChartArea.Top + (int)yOffset));
}
aBrush.Dispose();
}
public PointF Point2D(PointF pt)
{
PointF aPoint = new PointF();
aPoint.X = (pt.X - XLimMin) *
form1.PlotPanel.Width / (XLimMax - XLimMin);
aPoint.Y = form1.PlotPanel.Height -(pt.Y - YLimMin) *
form1.PlotPanel.Height / (YLimMax - YLimMin);
return aPoint;
}
}
}
5.改善后画线类(LineStyle.cs)
View Code
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
namespace Example4_9
{
public class LineStyle
{
private DashStyle linePattern = DashStyle.Solid;
private Color lineColor = Color.Black;
private float LineThickness = 1.0f;
private PlotLinesMethodEnum pltLineMethod = PlotLinesMethodEnum.Lines;
private bool isVisible = true;
public LineStyle()
{
}
public bool IsVisible
{
get { return isVisible; }
set { isVisible = value; }
}
public PlotLinesMethodEnum PlotMethod
{
get { return pltLineMethod; }
set { pltLineMethod = value; }
}
virtual public DashStyle Pattern
{
get { return linePattern; }
set { linePattern = value; }
}
public float Thickness
{
get { return LineThickness; }
set { LineThickness = value; }
}
virtual public Color LineColor
{
get { return lineColor; }
set { lineColor = value; }
}
public enum PlotLinesMethodEnum
{
Lines = 0,
Splines = 1
}
}
}
6.Form1中相关代码
View Code
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Example4_9
{
public partial class Form1 : Form
{
private ChartStyle cs;
private DataCollection dc;
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.BackColor = Color.White;
// Subscribing to a paint eventhandler to drawingPanel:
PlotPanel.Paint +=
new PaintEventHandler(PlotPanelPaint);
cs = new ChartStyle(this);
dc = new DataCollection(this);
// Specify chart style parameters:
cs.Title = "Chart of GE Stock";
cs.XTickOffset = 1;
cs.XLimMin = -1f;
cs.XLimMax = 20f;
cs.YLimMin = 32f;
cs.YLimMax = 36f;
cs.XTick = 2f;
cs.YTick = 0.5f;
dc.StockChartType = DataCollection.StockChartTypeEnum.HiLoOpenClose;
}
private void AddData()
{
dc.DataSeriesList.Clear();
TextFileReader tfr = new TextFileReader();
DataSeries ds = new DataSeries();
// Add GE stock data from a text data file:
ds = new DataSeries();
ds.DataString = tfr.ReadTextFile("GE.txt");
ds.LineStyle.LineColor = Color.DarkBlue;
dc.Add(ds);
}
private void PlotPanelPaint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
AddData();
cs.PlotPanelStyle(g);
dc.AddStockChart(g, cs);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
cs.ChartArea = this.ClientRectangle;
cs.SetChartArea(g);
}
}
}
改变股票图表样式,修改dc.StockChartType属性即可,如: dc.StockChartType = DataCollection.StockChartTypeEnum.HiLoOpenClose;
数据文件如下:
5-May-06 34.94 35.22 34.87 35.16
4-May-06 34.5 34.94 34.48 34.8
3-May-06 34.22 34.67 34.19 34.4
2-May-06 34.39 34.59 34.1 34.48
1-May-06 34.64 34.72 34.32 34.39
28-Apr-06 34.49 34.78 34.35 34.59
27-Apr-06 33.9 34.68 33.89 34.43
26-Apr-06 34.07 34.44 33.88 34.13
25-Apr-06 34 34.06 33.8 33.97
24-Apr-06 33.81 34 33.8 33.93
21-Apr-06 34.25 34.32 33.68 33.97
20-Apr-06 33.8 34.18 33.63 34.12
19-Apr-06 33.95 33.97 33.5 33.89
18-Apr-06 33.52 33.97 33.21 33.87
17-Apr-06 33.76 33.76 33.07 33.29
13-Apr-06 34.19 34.36 33.61 33.89
12-Apr-06 34.3 34.53 34.17 34.46
11-Apr-06 33.92 34.07 33.63 34.05
10-Apr-06 34.06 34.08 33.8 33.92
7-Apr-06 34.55 34.75 34.01 34.03
最终样式如下:
转载于:https://www.cnblogs.com/jiewong/archive/2012/12/06/stock.html