C#GDI + 自定义绘制曲线图表控件 DataChart
这里只说明在计算刻度和曲线绘制的时候 只提供思路, 只是做了下简单的计算, 不喜勿喷 还望见谅, 高手直接飘过吧. 这个要做好, 还是需要研究研究算法的, 比如刻度随着控件的大小发生改变的时候计算不同的值, 根据刻度范围来计算刻度以及刻度值等, 这里没有研究, 制作简单的绘制, 让其知道自定义曲线控件的画法, 对于新手来讲应该是有一些帮助的. 有时间我把研究过后的算法加上做一个通用可靠一点的控件分享.
例子如下图所示
首先百度一张图片, 就按照它的样子来绘制
该图片链接地址
DataChart 控件制作
在绘制曲线控件之前首先得 C#GDI+ 绘制线段 (实线或虚线), 矩形, 字符串, 圆, 椭圆
1. 添加一个用户控件
2. 重写 OnPaint 方法
- protected override void OnPaint(PaintEventArgs e)
- {
- base.OnPaint(e);
- Graphics graphics = e.Graphics;
- // 绘制代码部分...
- }
3. 绘制绘图区域
- #region 绘图区域
- int plotBorder = 0;
- if (this.plotBorderWith % 2 == 0)
- plotBorder = this.plotBorderWith / 2;
- else
- plotBorder = this.plotBorderWith / 2 + 1;
- int plotWidth = this.Width - this.Padding.Left - this.Padding.Right - this.plotBorderWith;
- int plotHeitht = this.Height - this.Padding.Top - this.Padding.Bottom - this.plotBorderWith;
- Rectangle plotArea = new Rectangle(
- this.Padding.Left + plotBorder,
- this.Padding.Top + plotBorder,
- plotWidth,
- plotHeitht);
- using (SolidBrush brush = new SolidBrush(this.plotBackColor))
- {
- graphics.FillRectangle(brush, plotArea);
- }
- #endregion
- View Code
4. 绘制曲线区域
- #region 绘制曲线区域
- int borderwith = 0;
- if (this.gridBorderWith % 2 == 0)
- borderwith = this.gridBorderWith / 2;
- else
- borderwith = this.gridBorderWith / 2;
- int gridWith = this.Width - this.Padding.Left - this.Padding.Right - this.FontHeight - this.FontHeight - this.gridBorderWith - 2 * this.plotBorderWith;
- int gridHeight = this.Height - this.FontHeight - 2 * this.FontHeight - this.gridBorderWith;
- Rectangle rectangle = new Rectangle(
- this.Padding.Left + this.FontHeight + this.FontHeight + this.plotBorderWith + this.gridBorderWith / 2,
- this.Padding.Top + this.FontHeight,
- gridWith,
- gridHeight);
- using (SolidBrush solidGridBrush = new SolidBrush(this.gridBackColor))
- {
- graphics.FillRectangle(solidGridBrush, rectangle);
- }
- using (Pen penGrid = new Pen(this.gridBorderColor, this.gridBorderWith))
- {
- graphics.DrawRectangle(penGrid, rectangle);
- }
- #endregion
- View Code
5. 绘制文本区域
- #region 绘制文本区域
- SizeF szfTitle;
- SizeF szfyLabel;
- SizeF szfxLabel;
- szfTitle = graphics.MeasureString(this.title, this.Font);
- szfyLabel = graphics.MeasureString(this.yLabel, this.Font);
- szfxLabel = graphics.MeasureString(this.xLabel, this.Font);
- // 绘制标题
- if (this.title != null)
- {
- int strLeft = rectangle.X + rectangle.Width / 2 - (int)szfTitle.Width / 2;
- int strHeight = this.Padding.Top + this.plotBorderWith;
- graphics.DrawString(this.title, this.Font, Brushes.Black, strLeft, strHeight);
- }
- // 绘制垂直方向文本
- if (this.yLabel != null)
- {
- graphics.TranslateTransform(0, this.Height); // 坐标平移
- graphics.RotateTransform(-90); // 坐标旋转
- int strLeft = 0;
- if (this.xLabel != "")
- strLeft = this.Padding.Bottom + this.gridBorderWith + 2 * (int)szfxLabel.Height + rectangle.Height / 2 - (int)szfyLabel.Width / 2;
- else
- strLeft = this.Padding.Bottom + this.gridBorderWith + (int)szfxLabel.Height + rectangle.Height / 2 - (int)szfyLabel.Width / 2;
- int strHeight = 0;
- graphics.DrawString(this.yLabel, this.Font, Brushes.Black, strLeft, strHeight);
- graphics.RotateTransform(90);
- graphics.TranslateTransform(0, -this.Height);
- }
- // 绘制水平方向文本
- if (this.xLabel != null)
- {
- int strLeft = rectangle.X + rectangle.Width / 2 - (int)szfxLabel.Width / 2;
- int strHeight = rectangle.Y + rectangle.Height + (int)szfxLabel.Height;
- graphics.DrawString(this.xLabel, this.Font, Brushes.Black, strLeft, strHeight);
- }
- #endregion
- View Code
6. 绘制坐标轴
这里提供思路, 没有仔细去计算,
- #region x 轴
- double scale = (this.xMax - this.xMin) / rectangle.Width;
- int number = 10; // 将 x 轴分为 10 份实际根据控件的大小来做分配, 这里简单举例 10 份为例
- double perPixel = rectangle.Width / number; // 每一份的占用的像素宽度
- double value = 100; // 间隔值 这里只是写测试例子直接写死了, 按照使用来讲不能这么干有时间了, 这是个算法问题, 重新补上
- int position = 0;
- double positionValue = this.xMin;
- using (Pen pen = new Pen(this.gridLineColor, 1))
- {
- for (int i = 0; i < number; i++)
- {
- pen.DashStyle = DashStyle.Solid;
- //x 轴刻度
- graphics.DrawLine(pen,
- rectangle.X + position,
- rectangle.Y + rectangle.Height,
- rectangle.X + position,
- rectangle.Y + rectangle.Height - 8);
- string scaleValue = positionValue.ToString("F0");
- SizeF szfValue = graphics.MeasureString(scaleValue, this.Font);
- int strX = rectangle.X + position - (int)szfValue.Width / 2;
- int strY = rectangle.Y + rectangle.Height;
- //x 轴刻度值
- graphics.DrawString(scaleValue, this.Font, Brushes.Black, strX, strY);
- positionValue += value;
- position += (int)perPixel;
- }
- }
- #endregion
- #region y 轴
- double scaley = (this.yMax - this.yMin) / this.Width;
- int numbery = 6;
- double perPixelY = rectangle.Height / numbery;
- double valueYinterval = 10;
- int positiony = 0;
- double positionValueY = this.yMin;
- using (Pen pen = new Pen(this.gridLineColor, 1))
- {
- for (int i = 0; i <= numbery; i++)
- {
- pen.DashStyle = DashStyle.Solid;
- //y 轴刻度
- graphics.DrawLine(pen,
- rectangle.X,
- rectangle.Y + rectangle.Height - positiony,
- rectangle.X + 8,
- rectangle.Y + rectangle.Height - positiony);
- string scaleValueY = positionValueY.ToString("F0");
- SizeF szfValue = graphics.MeasureString(scaleValueY, this.Font);
- int strX = rectangle.X - (int)szfValue.Width;
- int strY = rectangle.Y + rectangle.Height - positiony - (int)szfValue.Height/2;
- //x 轴刻度值
- graphics.DrawString(scaleValueY, this.Font, Brushes.Black, strX, strY);
- positionValueY += valueYinterval;
- positiony += (int)perPixelY;
- }
- }
- #endregion
- View Code
7. 绘制曲线
这里绘制曲线只提供思路, 没有仔细研究算法
- #region 绘制曲线
- if (x == null || y == null) return;
- float scaleX = (float)(rectangle.Width / (this.xMax - this.xMin));
- float scaleY = (float)(rectangle.Height / (this.yMax - this.yMin));
- PointF[] points = new PointF[x.Length];
- for (int i = 0; i < this.x.Length; i++)
- {
- points[i] = new PointF(
- (float)((this.x[i] - this.xMin) * scaleX + rectangle.X),
- rectangle.Y + rectangle.Height - (float)((this.y[i] - this.yMin) * scaleY));
- }
- using (Pen pen = new Pen(this.curveColor))
- {
- graphics.DrawLines(pen, points);
- }
- #endregion
- View Code
8. 效果展示
9. 程序源代码下载
源代码工程文件下载
来源: http://www.bubuko.com/infodetail-2869319.html