公司在用DevExpress包,为了实现一个类似坐标的图表,发现用DevExpress比较困难,首先,其X、Y轴的大小是自动的,如何设置成固定值,必须在“设计时”,而“运行时”无法更改。搞了很长一段时间都没实现,无奈之下,自己画一个。实现起来还是挺难的,首先对坐标值的计算,允许小于1和特别大的值,这时就需要计算X;轴或Y轴应该分几个大的刻度,每个刻度代表多少像素。而且,这一个大刻度又对应多少确切的数值。坐标的四周允许有空白,这时又给计算坐标带来些麻烦,最终研究了半天,搞定了。如下代码:
//必须传递的参数
float xMax = 200f; float yMax = 100f;//x轴最大值,y轴最大值
int picWidth = 410, picHeight = 410;//图片大小
float[][] dots = new float[3][];
dots[0] = new float[] { 100, 100 };
dots[1] = new float[] { 150, 200 };
dots[2] = new float[] { 200, 200 };
Pen penAxis = Pens.Blue;//坐标轴
Pen penSlant = Pens.Green;//45度斜线
Color colorDot = Color.Red;//点
//配置参数
int top = 10, right = 10, left = 40, bottom = 40;//定义边缘空白
int xBigLength = 6, yBigLength = 6;//大刻度线的长度
int xSmallCount = 5, ySmallCount = 5;//一个大刻度内的小刻度个数
int xSmallLength = 3, ySmallLength = 3;//小刻度线长度
int xArrowLength = 10, yArrowLength = 10;//坐标轴箭头占用的最少坐标长度
int arrowLineLength = 3;//箭头线的长度
int dotRadius = 2;//点的半径
#region 初始化相应的类
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(picWidth, picHeight, PixelFormat.Format32bppArgb);
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap);
graphics.FillRectangle(Brushes.Transparent, 0, 0, picWidth, picHeight);
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
#endregion
#region 计算所需的值
int xUsableLength = picWidth - left - right - xArrowLength, yUsableLength = picHeight - top - bottom - yArrowLength;
int xBigCount = 10, yBigCount = 10;//大刻度个数
double xRate = 1, yRate = 1;//一个大刻度的比率,即一个大刻度的实际数值
int xDigitLen;
if (xMax < 1)
{
xDigitLen = (((int)(1 / xMax)).ToString()).Length;
xRate = 1 / Math.Pow(10, xDigitLen);
xBigCount = (int)(xMax * Math.Pow(10, xDigitLen)) + 1;
}
else
{
xDigitLen = (((int)xMax).ToString()).Length;//整数位数
xRate = Math.Pow(10, (xDigitLen - 1));//比率:1、10、100、1000...
xBigCount = (int)(xMax / xRate) + 1;
}
int yDigitLen;
if (yMax < 1)
{
yDigitLen = (((int)(1 / yMax)).ToString()).Length;
yRate = 1 / Math.Pow(10, yDigitLen);
yBigCount = (int)(yMax * Math.Pow(10, yDigitLen)) + 1;
}
else
{
yDigitLen = (((int)yMax).ToString()).Length;//整数位数
yRate = Math.Pow(10, (yDigitLen - 1));//比率:1、10、100、1000...
yBigCount = (int)(yMax / yRate) + 1;
}
int xBigScaleLen = (xUsableLength / (xBigCount * xSmallCount)) * xSmallCount;//x轴方向一个大刻度代表的像素数
int yBigScaleLen = (yUsableLength / (yBigCount * ySmallCount)) * ySmallCount;//y轴方向一个大刻度代表的像素数
int xSmallScaleLen = xBigScaleLen / xSmallCount;//x轴方向一个小刻度代表的像素数
int ySmallScaleLen = yBigScaleLen / ySmallCount;//y轴方向一个小刻度代表的像素数
#endregion
#region 划轴、箭头、斜线
//X轴
graphics.DrawLine(penAxis, new Point(left, picHeight - bottom), new Point(picWidth - right, picHeight - bottom));
//x轴箭头
graphics.DrawLine(penAxis, new Point(picWidth - right, picHeight - bottom), new Point(picWidth - right - arrowLineLength, picHeight - bottom - arrowLineLength));
graphics.DrawLine(penAxis, new Point(picWidth - right, picHeight - bottom), new Point(picWidth - right - arrowLineLength, picHeight - bottom + arrowLineLength));
//Y轴
graphics.DrawLine(penAxis, new Point(left, picHeight - bottom), new Point(left, top));
//y轴箭头
graphics.DrawLine(penAxis, new Point(left, top), new Point(left - arrowLineLength, top + arrowLineLength));
graphics.DrawLine(penAxis, new Point(left, top), new Point(left + arrowLineLength, top + arrowLineLength));
//45%线
graphics.DrawLine(penSlant, new Point(left, picHeight - bottom), new Point(picWidth - right, top));
#endregion
#region 画大刻度、小刻度
Font font = new Font("宋体", 9f, new FontStyle());
for (int i = 0; i <= xBigCount; i++)
{
//X轴大刻度
graphics.DrawLine(penAxis, new Point(left + xBigScaleLen * i, picHeight - bottom), new Point(left + xBigScaleLen * i, picHeight - bottom + xBigLength));
//X轴标数
string str = (i * xRate).ToString();
Size textSize = TextRenderer.MeasureText(str, font);
graphics.DrawString(str, font, new SolidBrush(Color.Blue),
new PointF(left + xBigScaleLen * i - textSize.Width / 2, picHeight - bottom + textSize.Height));
}
for (int i = 0; i <= yBigCount; i++)
{
//Y轴大刻度
graphics.DrawLine(penAxis, new Point(left, picHeight - bottom - yBigScaleLen * i), new Point(left - yBigLength, picHeight - bottom - yBigScaleLen * i));
//Y轴标数
string str = (i * yRate).ToString();
Size textSize = TextRenderer.MeasureText(str, font);
graphics.DrawString(str, font, new SolidBrush(Color.Blue),
new PointF(left - textSize.Width - 10, picHeight - bottom - yBigScaleLen * i - textSize.Height / 2));
}
for (int i = 0; i < xBigCount * xSmallCount; i++)
{
//X轴小刻度
graphics.DrawLine(penAxis, new Point(left + xSmallScaleLen * i, picHeight - bottom), new Point(left + xSmallScaleLen * i, picHeight - bottom + xSmallLength));
}
for (int i = 0; i < yBigCount * ySmallCount; i++)
{
//Y轴小刻度
graphics.DrawLine(penAxis, new Point(left, picHeight - bottom - ySmallScaleLen * i), new Point(left - ySmallLength, picHeight - bottom - ySmallScaleLen * i));
}
#endregion
//画点
SolidBrush dotBrush = new SolidBrush(colorDot);
foreach (float[] dot in dots)
{
int x = left + (int)(xBigScaleLen * dot[0] / xRate);
int y = picHeight - bottom - (int)(yBigScaleLen * dot[1] / yRate);
graphics.FillEllipse(dotBrush, new Rectangle(x - dotRadius, y - dotRadius, 2 * dotRadius, 2 * dotRadius));
}