C#实现坐标轴及其上的点。

来源:互联网 发布:java web项目开发书籍 编辑:程序博客网 时间:2024/05/02 00:54

公司在用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));
            }