坐标变换 class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Drawing;
namespace Utility
{
public class CAxis
{
protected float m_Scale;
protected float m_Offset;
public CAxis()
{
m_ShowLabel = true;
}
protected float m_LogicMax;
public float LogicMax
{
get { return m_LogicMax; }
set { m_LogicMax = value; }
}
protected bool m_ShowLabel = true;
[DefaultValue(true)]
public bool ShowLabel
{
get { return m_ShowLabel; }
set { m_ShowLabel = value; }
}
protected string m_AxisUnit;
[DefaultValue(null)]
public string AxisUnit
{
get { return m_AxisUnit; }
set { m_AxisUnit = value; }
}
protected string m_FormatString = "F1";
[DefaultValue("F1")]
public string FormatString
{
get { return m_FormatString; }
set { m_FormatString = value; }
}
protected float m_LogicMin;
public float LogicMin
{
get { return m_LogicMin; }
set { m_LogicMin = value; }
}
protected bool m_Vertical;
public bool Vertical
{
get { return m_Vertical; }
set { m_Vertical = value; }
}
protected Point m_Location;
public Point Location
{
get { return m_Location; }
set { m_Location = value; }
}
protected int m_Length;
public int Length
{
get { return m_Length; }
set { m_Length = value; }
}
protected int m_Step = 30;
[DefaultValue(30)]
public int Step
{
get { return m_Step; }
set { m_Step = value; }
}
protected float m_MinimumLogicStep = 0.0f;
public float MinimumLogicStep
{
get { return m_MinimumLogicStep; }
set { m_MinimumLogicStep = value; }
}
public float LogicScale
{
get { return m_Scale; }
}
public int ToPhycical(float size)
{
return (int) (m_Scale *size + m_Offset);
}
public float GetLogicStep()
{
float logicSize = m_LogicMax - m_LogicMin;
m_Scale = m_Length / logicSize;
m_Offset = -m_Length * m_LogicMin / logicSize;
double x = Math.Log10(logicSize * m_Step / m_Length);
int int_part = (x >= 0) ? (int)(x+0.1f) : (int)(x-0.1f) - 1;
double x2 = Math.Pow(10, (double) x - int_part);
double x3 = Math.Pow(10, (double) int_part);
int x4 = (int)(x2+0.1f);
int y1 = 20;
if (x4 < 10) y1 = 10;
if (x4 < 5) y1 = 5;
if (x4 < 2) y1 = 2;
if (x4 < 1) y1 = 1;
float dy = (float) (y1 * x3);
return dy < m_MinimumLogicStep ? m_MinimumLogicStep : dy;
}
public void DrawGrid(Graphics g, Pen pen, Font font, int length, bool showLabel)
{
int p;
string s;
float logicSize = m_LogicMax - m_LogicMin;
float dy = GetLogicStep();
if (m_Vertical) {
for (double y = m_LogicMin; y <= m_LogicMax; y += dy) {
y = (float) ((int) (y / dy + (y >= 0 ? 0.01f : -0.01f)) * dy);
if (y >= m_LogicMin) {
p = m_Location.Y - (int) (m_Scale * y + m_Offset);
if (y == 0.0f) {
g.DrawLine(Pens.Silver, m_Location.X, p, m_Location.X + length, p);
s = "0";
}
else {
g.DrawLine(pen, m_Location.X, p, m_Location.X + length, p);
s = y.ToString(m_FormatString);
}
if (m_ShowLabel && showLabel) {
SizeF sf = g.MeasureString(s, font);
g.DrawString(s, font, Brushes.Black, m_Location.X - sf.Width - 4, p - sf.Height / 2);
}
}
}
if (m_AxisUnit != null && m_AxisUnit.Length > 0) {
g.DrawString(m_AxisUnit, font, Brushes.Black, m_Location.X + 1, m_Location.Y - m_Length + 1);
}
}
else {
for (float y = m_LogicMin; y <= m_LogicMax; y += dy) {
y = (float) ((int) (y / dy + (y >= 0 ? 0.01f : -0.01f)) * dy);
if (y >= m_LogicMin) {
p = m_Location.X + (int) (m_Scale * y + m_Offset);
if (y == 0.0f) {
g.DrawLine(Pens.Silver, p, m_Location.Y, p, m_Location.Y - length);
s = "0";
}
else {
g.DrawLine(pen, p, m_Location.Y, p, m_Location.Y - length);
s = y.ToString(m_FormatString);
}
if (m_ShowLabel && showLabel) {
SizeF sf = g.MeasureString(s, font);
g.DrawString(s, font, Brushes.Black, p - sf.Width / 2, m_Location.Y + sf.Height / 2 - 2);
}
}
}
if (m_AxisUnit != null && m_AxisUnit.Length > 0) {
SizeF sf = g.MeasureString(m_AxisUnit, font);
g.DrawString(m_AxisUnit, font, Brushes.Black, m_Location.X + m_Length - sf.Width - 1, m_Location.Y - sf.Height - 1);
}
}
}
}
}
Chart Control:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
namespace Utility
{
public partial class ChartControl : UserControl
{
protected bool m_bRebuilt = false;
protected bool m_bSizeChanged = true;
protected CMemoryGraph m_Graph;
protected CMemoryGraph m_ChartGraph;
protected Point m_StartPoint;
protected Pen m_AxisPen;
protected Point m_DragPoint;
protected bool m_bBeginDrag = false;
protected SolidBrush m_PlotBackgroundBrush;
public PaintEventHandler OnDrawChart;
public PaintEventHandler OnBeforeDrawChart;
public PaintEventHandler OnAfterDrawChart;
public ChartControl()
{
InitializeComponent();
m_Graph = new CMemoryGraph();
m_XAxis = new CAxis();
m_YAxis = new CAxis();
m_PlotRectangle = new Rectangle();
m_StartPoint = new Point();
m_XAxis.Vertical = false;
m_YAxis.Vertical = true;
m_LeftTopMargin = new Point(56, 10);
m_RightBottomMargin = new Point(16, 40);
m_Graph.Location = new Point(0, 0);
m_AxisPen = new Pen(Color.LightGray);
m_AxisPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
m_PlotBackgroundBrush = new SolidBrush(Color.White);
// m_BackgroundColor = this.BackColor;
}
#region Properties
protected bool m_bYAxisFollowXAxis = false;
[DefaultValue(false)]
public bool YAxisFollowXAxis
{
get { return m_bYAxisFollowXAxis; }
set { m_bYAxisFollowXAxis = value; }
}
public CMemoryGraph MemoryGraph
{
get { return m_Graph; }
}
protected CAxis m_XAxis;
public CAxis XAxis
{
get { return m_XAxis; }
set { m_XAxis = value; }
}
protected CAxis m_YAxis;
public CAxis YAxis
{
get { return m_YAxis; }
set { m_YAxis = value; }
}
protected Point m_LeftTopMargin;
[DefaultValue(typeof(System.Drawing.Point), "56,10")]
public Point LeftTopMargin
{
get { return m_LeftTopMargin; }
set { m_LeftTopMargin = value; }
}
protected Point m_RightBottomMargin;
[DefaultValue(typeof(System.Drawing.Point), "16,40")]
public Point RightBottomMargin
{
get { return m_RightBottomMargin; }
set { m_RightBottomMargin = value; }
}
protected float m_XLogicMax;
public float XLogicMax
{
get { return m_XLogicMax; }
set { m_XLogicMax = value; }
}
protected float m_XLogicMin;
[DefaultValue(0f)]
public float XLogicMin
{
get { return m_XLogicMin; }
set { m_XLogicMin = value; }
}
protected float m_YLogicMax;
public float YLogicMax
{
get { return m_YLogicMax; }
set { m_YLogicMax = value; }
}
protected float m_YLogicMin;
[DefaultValue(0f)]
public float YLogicMin
{
get { return m_YLogicMin; }
set { m_YLogicMin = value; }
}
protected string m_YTitle;
[DefaultValue(null)]
public string YTitle
{
get { return m_YTitle; }
set { m_YTitle = value; }
}
protected string m_XTitle;
[DefaultValue(null)]
public string XTitle
{
get { return m_XTitle; }
set { m_XTitle = value; }
}
protected int m_YTitleLeftMargin = 8;
[DefaultValue(8)]
public int YTitleLeftMargin
{
get { return m_YTitleLeftMargin; }
set { m_YTitleLeftMargin = value; }
}
protected int m_XTitleBottomMargin = 6;
[DefaultValue(6)]
public int XTitleBottomMargin
{
get { return m_XTitleBottomMargin; }
set { m_XTitleBottomMargin = value; }
}
protected PointF[] m_PlotPoints = null;
[DefaultValue(null)]
public PointF[] PlotPoints
{
get { return m_PlotPoints; }
set { m_PlotPoints = value; }
}
protected Color m_PlotColor = Color.Blue;
[DefaultValue(typeof(Color), "Blue")]
public Color PlotColor
{
get { return m_PlotPen.Color; }
set { m_PlotPen.Color = value; }
}
[DefaultValue(typeof(Color), "White")]
public Color PlotBackgroundColor
{
get { return m_PlotBackgroundBrush.Color; }
set { m_PlotBackgroundBrush.Color = value; }
}
[DefaultValue(1)]
public int PlotPenWidth
{
get { return (int) m_PlotPen.Width; }
set { m_PlotPen.Width = value; }
}
protected bool m_PlotTypeIsBar;
[DefaultValue(false)]
public bool PlotTypeIsBar
{
get { return m_PlotTypeIsBar; }
set { m_PlotTypeIsBar = value; }
}
protected Pen m_PlotPen = new Pen(Color.Blue, 1);
public Pen PlotPen
{
get { return m_PlotPen; }
}
protected Rectangle m_PlotRectangle;
public Rectangle PlotRectangle
{
get { return m_PlotRectangle; }
}
public int LogicToX(float x)
{
return m_XAxis.ToPhycical(x);
}
protected PointF m_MaxLogicLimit;
public PointF MaxLogicLimit
{
// get { return m_MaxLogicLimit; }
set { m_MaxLogicLimit = value; }
}
protected PointF m_MinLogicLimit;
public PointF MinLogicLimit
{
// get { return m_MinLogicLimit; }
set { m_MinLogicLimit = value; }
}
#endregion
protected SolidBrush m_FontBrush;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
m_FontBrush = new SolidBrush(this.ForeColor);
}
protected override void OnPaint(PaintEventArgs e)
{
if (m_bRebuilt) {
Graphics g;
if (m_bSizeChanged) {
m_PlotRectangle = new Rectangle(m_LeftTopMargin.X, m_LeftTopMargin.Y,
this.Size.Width - m_LeftTopMargin.X - m_RightBottomMargin.X,
this.Size.Height - m_LeftTopMargin.Y - m_RightBottomMargin.Y);
g = m_Graph.CreateMemoryGraphics(this.ClientSize);
m_bSizeChanged = false;
}
else {
g = m_Graph.MemoryGraphics;
g.ResetClip();
g.ResetTransform();
}
m_Graph.EraseBackground(this.BackColor);
if (m_PlotBackgroundBrush.Color != this.BackColor) {
g.FillRectangle(m_PlotBackgroundBrush, m_PlotRectangle);
}
m_XAxis.Location = new Point(m_LeftTopMargin.X, this.Size.Height - m_RightBottomMargin.Y);
m_XAxis.Length = m_PlotRectangle.Size.Width;
m_XAxis.LogicMax = m_XLogicMax;
m_XAxis.LogicMin = m_XLogicMin;
m_XAxis.DrawGrid(g, m_AxisPen, this.Font, m_PlotRectangle.Size.Height, true);
m_YAxis.Location = new Point(m_LeftTopMargin.X, this.Size.Height - m_RightBottomMargin.Y);
m_YAxis.Length = m_PlotRectangle.Size.Height;
if (m_bYAxisFollowXAxis) {
m_YLogicMax = m_YLogicMin + (m_XLogicMax - m_XLogicMin) * m_YAxis.Length / m_XAxis.Length;
}
m_YAxis.LogicMin = m_YLogicMin;
m_YAxis.LogicMax = m_YLogicMax;
m_YAxis.DrawGrid(g, m_AxisPen, this.Font, m_PlotRectangle.Size.Width, true);
if (m_XTitle != null && m_XTitle.Length > 0) {
SizeF sf = g.MeasureString(m_XTitle, SystemFonts.DefaultFont);
g.DrawString(m_XTitle, SystemFonts.DefaultFont, m_FontBrush, (this.Size.Width - sf.Width) / 2, this.Size.Height - sf.Height - m_XTitleBottomMargin);
}
if (m_YTitle != null && m_YTitle.Length > 0) {
SizeF sf = g.MeasureString(m_YTitle, SystemFonts.DefaultFont);
g.TranslateTransform(m_YTitleLeftMargin, m_YAxis.Location.Y - (m_YAxis.Length - sf.Width) / 2);
g.RotateTransform(270.0f);
g.DrawString(m_YTitle, SystemFonts.DefaultFont, m_FontBrush, 0, 0);
g.ResetTransform();
}
g.DrawRectangle(Pens.Black, m_LeftTopMargin.X-1, m_LeftTopMargin.Y-1, m_XAxis.Length+2, m_YAxis.Length+2);
if (OnBeforeDrawChart != null)
OnBeforeDrawChart(this, e);
g.SetClip(m_PlotRectangle);
g.TranslateTransform(m_LeftTopMargin.X, m_LeftTopMargin.Y);
if (OnDrawChart != null)
OnDrawChart(this, e);
m_bRebuilt = false;
}
m_Graph.PaintToScreen(e.Graphics);
e.Graphics.SetClip(m_PlotRectangle);
if (OnAfterDrawChart != null) {
e.Graphics.TranslateTransform(m_LeftTopMargin.X, m_LeftTopMargin.Y);
OnAfterDrawChart(this, e);
}
}
public void UpdateChart()
{
Graphics g = m_Graph.MemoryGraphics;
g.ResetTransform();
g.FillRectangle(Brushes.White, m_PlotRectangle);
m_XAxis.DrawGrid(g, m_AxisPen, this.Font, m_PlotRectangle.Size.Height, false);
m_YAxis.DrawGrid(g, m_AxisPen, this.Font, m_PlotRectangle.Size.Width, false);
g.DrawRectangle(Pens.Black, m_LeftTopMargin.X - 1, m_LeftTopMargin.Y - 1, m_XAxis.Length + 2, m_YAxis.Length + 2);
if (OnBeforeDrawChart != null)
OnBeforeDrawChart(this, null);
g.SetClip(m_PlotRectangle);
g.TranslateTransform(m_LeftTopMargin.X, m_LeftTopMargin.Y);
if (OnDrawChart != null)
OnDrawChart(this, null);
this.Invalidate();
}
public void PlotLines(Graphics g)
{
if (m_PlotPoints != null && m_PlotPoints.Length > 0) {
if (m_PlotTypeIsBar) {
for (int i = 0; i < m_PlotPoints.Length; i++) {
DrawLine(m_PlotPen, m_PlotPoints[i].X, 0, m_PlotPoints[i].X, m_PlotPoints[i].Y);
}
}
else {
SetLogicStartPoint(m_PlotPoints[0]);
for (int i = 1; i < m_PlotPoints.Length; i++) {
DrawLineTo(m_PlotPen, m_PlotPoints[i]);
}
}
}
}
public int LogicToY(float y)
{
return m_YAxis.Length - m_YAxis.ToPhycical(y);
}
public void SetLogicStartPoint(float x, float y)
{
m_StartPoint.X = m_XAxis.ToPhycical(x);
m_StartPoint.Y = m_YAxis.Length - m_YAxis.ToPhycical(y);
}
public void SetLogicStartPoint(PointF point)
{
m_StartPoint.X = m_XAxis.ToPhycical(point.X);
m_StartPoint.Y = m_YAxis.Length - m_YAxis.ToPhycical(point.Y);
}
public void DrawLine(Pen pen, float x1, float y1, float x2, float y2)
{
m_Graph.MemoryGraphics.DrawLine(pen, LogicToX(x1), LogicToY(y1), LogicToX(x2), LogicToY(y2));
}
public void DrawLine(Pen pen, PointF point1, PointF point2)
{
m_Graph.MemoryGraphics.DrawLine(pen, LogicToX(point1.X), LogicToY(point1.Y), LogicToX(point2.X), LogicToY(point2.Y));
}
public void DrawLineTo(Pen pen, float x, float y)
{
int x1 = LogicToX(x);
int y1 = LogicToY(y);
m_Graph.MemoryGraphics.DrawLine(pen, m_StartPoint.X, m_StartPoint.Y, x1, y1);
m_StartPoint.X = x1;
m_StartPoint.Y = y1;
}
public void DrawLineTo(Pen pen, PointF point)
{
int x1 = LogicToX(point.X);
int y1 = LogicToY(point.Y);
m_Graph.MemoryGraphics.DrawLine(pen, m_StartPoint.X, m_StartPoint.Y, x1, y1);
m_StartPoint.X = x1;
m_StartPoint.Y = y1;
}
public void DrawCircle(Pen pen, float originX, float originY, float radius)
{
int x1 = LogicToX(originX - radius);
int y1 = LogicToY(originY + radius);
int x2 = LogicToX(originX + radius);
int y2 = LogicToY(originY - radius);
m_Graph.MemoryGraphics.DrawEllipse(pen, x1, y2, x2 - x1, y1 - y2);
}
//*********************************************************************************//
public void DrawLine(Graphics g, Pen pen, float x1, float y1, float x2, float y2)
{
g.DrawLine(pen, LogicToX(x1), LogicToY(y1), LogicToX(x2), LogicToY(y2));
}
public void DrawLine(Graphics g, Pen pen, PointF point1, PointF point2)
{
g.DrawLine(pen, LogicToX(point1.X), LogicToY(point1.Y), LogicToX(point2.X), LogicToY(point2.Y));
}
public void DrawLineTo(Graphics g, Pen pen, float x, float y)
{
int x1 = LogicToX(x);
int y1 = LogicToY(y);
g.DrawLine(pen, m_StartPoint.X, m_StartPoint.Y, x1, y1);
m_StartPoint.X = x1;
m_StartPoint.Y = y1;
}
public void DrawLineTo(Graphics g, Pen pen, PointF point)
{
int x1 = LogicToX(point.X);
int y1 = LogicToY(point.Y);
g.DrawLine(pen, m_StartPoint.X, m_StartPoint.Y, x1, y1);
m_StartPoint.X = x1;
m_StartPoint.Y = y1;
}
public void DrawCircle(Graphics g, Pen pen, float originX, float originY, float radius)
{
int x1 = LogicToX(originX - radius);
int y1 = LogicToY(originY + radius);
int x2 = LogicToX(originX + radius);
int y2 = LogicToY(originY - radius);
g.DrawEllipse(pen, x1, y2, x2 - x1, y1 - y2);
}
//*********************************************************************************//
protected override void OnResize(EventArgs e)
{
m_bSizeChanged = true;
base.OnResize(e);
Refresh();
}
public override void Refresh()
{
m_bRebuilt = true;
base.Refresh();
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
//*********************************************************************************//
public void MoveUpDown(float ratio)
{
float fx = (XLogicMax - XLogicMin) * ratio;
if (fx > 0 && m_XLogicMax < m_MaxLogicLimit.X) {
if ((m_XLogicMax + fx) > m_MaxLogicLimit.X)
fx = m_MaxLogicLimit.X - m_XLogicMax;
m_XLogicMax += fx;
m_XLogicMin += fx;
Refresh();
}
else if (fx < 0 && m_XLogicMin > m_MinLogicLimit.X) {
if ((m_XLogicMin + fx) < m_MinLogicLimit.X)
fx = m_MinLogicLimit.X - m_XLogicMin;
m_XLogicMax += fx;
m_XLogicMin += fx;
Refresh();
}
}
public void MoveLeftRigh(float ratio)
{
float fy = (YLogicMax - YLogicMin) * ratio;
if (fy > 0 && m_YLogicMax < m_MaxLogicLimit.Y) {
if ((m_YLogicMax + fy) > m_MaxLogicLimit.Y)
fy = m_MaxLogicLimit.Y - m_YLogicMax;
m_YLogicMax += fy;
m_YLogicMin += fy;
Refresh();
}
else if (fy < 0 && m_YLogicMin > m_MinLogicLimit.Y) {
if ((m_YLogicMin + fy) < m_MinLogicLimit.Y)
fy = m_MinLogicLimit.Y - m_YLogicMin;
m_YLogicMax += fy;
m_YLogicMin += fy;
Refresh();
}
}
public void ZoomIn(float ratio, float limitX, float limitY)
{
float dx = XLogicMax - XLogicMin;
float dy = YLogicMax - YLogicMin;
float rx = dx * ratio;
float ry = dy * ratio;
if (dx > limitX && dy > limitY) {
XLogicMax -= rx;
XLogicMin += rx;
YLogicMax -= ry;
YLogicMin += ry;
this.Refresh();
}
}
public void ZoomOut(float ratio)
{
float dx = XLogicMax - XLogicMin;
float dy = YLogicMax - YLogicMin;
float rx = dx * ratio;
float ry = dy * ratio;
float x1 = XLogicMax + rx;
float x2 = XLogicMin - rx;
float y1 = YLogicMax + ry;
float y2 = YLogicMin - ry;
if ( dx < (m_MaxLogicLimit.X - m_MinLogicLimit.X) ||
dy < (m_MaxLogicLimit.Y - m_MinLogicLimit.Y)) {
XLogicMax = x1;
XLogicMin = x2;
YLogicMax = y1;
YLogicMin = y2;
this.Refresh();
}
}
//*********************************************************************************//
protected override void OnMouseDown(MouseEventArgs e)
{
if (!AllowDrop) return;
if (e.Button == MouseButtons.Left) {
m_DragPoint = new Point(e.X, e.Y);
if (m_PlotRectangle.Contains(m_DragPoint)) {
m_bBeginDrag = true;
this.Cursor = Cursors.Hand;
base.OnMouseDown(e);
}
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (!AllowDrop) return;
if (e.Button == MouseButtons.Left && m_bBeginDrag) {
if (m_PlotRectangle.Contains(e.X, e.Y)) {
int x = -e.X + m_DragPoint.X;
int y = e.Y - m_DragPoint.Y;
float fx = x / m_XAxis.LogicScale;
float fy = y / m_YAxis.LogicScale;
if (fx > 0 && m_XLogicMax < m_MaxLogicLimit.X) {
if ((m_XLogicMax + fx) > m_MaxLogicLimit.X)
fx = m_MaxLogicLimit.X -m_XLogicMax;
m_XLogicMax += fx;
m_XLogicMin += fx;
m_bRebuilt = true;
}
else if (fx < 0 && m_XLogicMin > m_MinLogicLimit.X) {
if ((m_XLogicMin + fx) < m_MinLogicLimit.X)
fx = m_MinLogicLimit.X - m_XLogicMin;
m_XLogicMax += fx;
m_XLogicMin += fx;
m_bRebuilt = true;
}
if (fy > 0 && m_YLogicMax < m_MaxLogicLimit.Y) {
if ((m_YLogicMax + fy) > m_MaxLogicLimit.Y)
fy = m_MaxLogicLimit.Y - m_YLogicMax;
m_YLogicMax += fy;
m_YLogicMin += fy;
m_bRebuilt = true;
}
else if (fy < 0 && m_YLogicMin > m_MinLogicLimit.Y) {
if ((m_YLogicMin + fy) < m_MinLogicLimit.Y)
fy = m_MinLogicLimit.Y - m_YLogicMin;
m_YLogicMax += fy;
m_YLogicMin += fy;
m_bRebuilt = true;
}
this.Cursor = Cursors.Default;
base.OnMouseUp(e);
base.Refresh();
}
}
m_bBeginDrag = false;
}
}
}