c# 自绘双对数坐标曲线

it2023-01-07  128

工作需要实现一个双对数曲线图,没找到现成的插件,最后决定还是自己自绘一个,封装成插件算了。。。 最后的效果如下:

目录

封装控件的使用主要代码解析1.绘制坐标线段2.绘制x轴的对数坐标:3.绘制y轴的对数坐标:4.绘制曲线

源码链接: https://download.csdn.net/download/Yyuanyuxin/12979912

封装控件的使用

控件的属性设置如下为双对数曲线: 其他属性看说明即可,都在杂项里面比较简单。 ps:注意对数的话,不可设置最大最小值为0。 设置完成属性后,可直接输入数据(属性Datas)或者代码输入: 代码使用方式:

public void GetLine() { var ss = new List<PointF> { new PointF(33F, 5F), new PointF(0.2F, 100F), new PointF(65F, 34F), new PointF(10000, 10000) }; myDrawChart1.Datas = new List<MyDrawChartLine>() { new MyDrawChartLine(ss, default) }; } //绘制曲线 private void button1_Click(object sender, EventArgs e) { GetLine(); myDrawChart1.UpdateMenu(); } //随机添加曲线 private void button2_Click(object sender, EventArgs e) { Random ss = new Random(); var aaaa = new List<PointF> { new PointF((float)(ss.Next(1,44)), (float)(ss.Next(1, 34))), new PointF((float)(ss.Next(51, 676)), (float)(ss.Next(34, 3334))), new PointF((float)(ss.Next(1, 4344)), (float)(ss.Next(66, 1244))), new PointF((float)(ss.Next(33, 8888)), (float)(ss.Next(10, 10000))) }; myDrawChart1.AddLine(new MyDrawChartLine(aaaa, default)); } //清除所有曲线 private void button3_Click(object sender, EventArgs e) { myDrawChart1.Clear(); }

主要代码解析

1.绘制坐标线段

var g = _control.CreateGraphics();//获取画布 StartPoint = new PointF(VerticalMargin, height - HorizontalMargin);//VerticalMargin左右边距,HorizontalMargin垂直边距 //绘制X轴, MaxPointX = new PointF(width - VerticalMargin, height - HorizontalMargin); g.DrawLine(new Pen(Brushes.Black, 2), StartPoint, MaxPointX); //绘制Y轴 MaxPointY = new PointF(VerticalMargin, HorizontalMargin); g.DrawLine(new Pen(Brushes.Black, 2), MaxPointY, StartPoint);

2.绘制x轴的对数坐标:

float LenX = width - 2 * HorizontalMargin; var maxIndex = (float)Math.Log10(maxX); var minIndex = (float)Math.Log10(minX); int mainScaleCout = Math.Abs(Convert.ToInt32(maxIndex - minIndex)); for (int i = 0; i <= mainScaleCout; i++)//mainScaleCout等份Y轴 { var xValue = LenX * i / mainScaleCout + HorizontalMargin; PointF py1 = new PointF(xValue, height - HorizontalMargin + 5); PointF py2 = new PointF(xValue, height - HorizontalMargin); var inner = (float)Math.Pow(10, maxIndex - i); string sy = inner.ToString(); g.DrawLine(new Pen(Brushes.Black, 2), py1, py2);//绘制刻度线 g.DrawString(sy, new Font("宋体", 8f), Brushes.Black, new PointF(xValue - 3, height - HorizontalMargin / 1.1f));//绘制刻度值 if (i > 0)//子刻度线不均,分为10段 { float yLast = LenX / mainScaleCout * (i - 1) + VerticalMargin; var yValueMax = (float)Math.Log10(Math.Pow(10, maxIndex - i + 1)); var yValueMin = (float)Math.Log10(inner); for (int j = 1; j < 9; j++) { var value = (float)Math.Log10(inner + (inner * j)); float maxValue1 = yLast - (((yValueMax - value) / (yValueMax - yValueMin)) * (yLast - xValue)); PointF px11 = new PointF(maxValue1, height - HorizontalMargin); PointF px21 = new PointF(maxValue1, height - HorizontalMargin + 4); g.DrawLine(new Pen(Brushes.Black, 2), px11, px21); } } } //绘制y轴标题 Pen pen = new Pen(Color.Black, 1); g.DrawString(XName, new Font("宋体 ", 10f), Brushes.Black, new PointF(width - HorizontalMargin / 1.5f, height - HorizontalMargin / 1.5f));

3.绘制y轴的对数坐标:

和y轴原理类似

float LenY = height - 2 * VerticalMargin; var maxIndex = (float)Math.Log10(maxY); var minIndex = (float)Math.Log10(minY); int mainScaleCout = Math.Abs(Convert.ToInt32(maxIndex - minIndex)); for (int i = 0; i <= mainScaleCout; i++)//len等份Y轴 { var yValue = LenY / mainScaleCout * i + VerticalMargin; PointF px1 = new PointF(VerticalMargin, yValue); PointF px2 = new PointF(VerticalMargin - 5, yValue); float inner = (float)Math.Pow(10, maxIndex - i); string sx = inner.ToString(); g.DrawLine(new Pen(Brushes.Black, 2), px1, px2); StringFormat drawFormat = new StringFormat(); drawFormat.Alignment = StringAlignment.Far; drawFormat.LineAlignment = StringAlignment.Center; g.DrawString(sx, new Font("宋体", 8f), Brushes.Black, new PointF(VerticalMargin / 1.2f, LenY * i / mainScaleCout + VerticalMargin * 1.1f), drawFormat); if (i > 0) { float yLast = LenY / mainScaleCout * (i - 1) + VerticalMargin; var yValueMax = (float)Math.Log10(Math.Pow(10, maxIndex - i + 1)); var yValueMin = (float)Math.Log10(inner); var singleWidth = (yValue - yLast); for (int j = 1; j < 9; j++) { var value = (float)Math.Log10(inner + (inner * j)); float maxValue1 = yLast - (((yValueMax - value) / (yValueMax - yValueMin)) * (yLast - yValue)); PointF px11 = new PointF(VerticalMargin, maxValue1); PointF px21 = new PointF(VerticalMargin - 4, maxValue1); g.DrawLine(new Pen(Brushes.Black, 2), px11, px21); } } } Pen pen = new Pen(Color.Black, 1); g.DrawString(YName, new Font("宋体 ", 10f), Brushes.Black, new PointF(VerticalMargin / 3, VerticalMargin / 2f));

4.绘制曲线

先排序数据

if (lp == null) return null; for (int i = 0; i < lp.Count - 1; i++) { for (int j = 0; j < lp.Count - 1 - i; j++)// j开始等于0, { if (lp[j].X > lp[j + 1].X) { PointF temp = lp[j]; lp[j] = lp[j + 1]; lp[j + 1] = temp; } } } return lp;

转换数据点成为坐标点

List<PointF> listPointGraphics = new List<PointF>();//图上的点 foreach (PointF point in listPointData) { PointF p = new PointF(); float valueY = (float)Math.Log10(point.Y); float valueX = (float)Math.Log10(point.X); float valueMaxX = (float)Math.Log10(MaxXValue); float valueMinX = (float)Math.Log10(MinXValue); float valueMaxY = (float)Math.Log10(MaxYValue); float valueMinY = (float)Math.Log10(MinYValue); p.Y = MaxPointY.Y - (((valueMaxY - valueY) / (valueMaxY - valueMinY)) * (MaxPointY.Y - StartPoint.Y)); p.X = MaxPointX.X - (((valueMinX - valueX) / (valueMinX - valueMaxX)) * (MaxPointX.X - StartPoint.X)); listPointGraphics.Add(p); }

绘制曲线:

GraphicsPath gpArea = new GraphicsPath(); for (int i = 0; i < listPointGraphics.Count - 1; i++) { gpArea.AddLine(listPointGraphics[i], listPointGraphics[i + 1]); } g.DrawPath(new Pen(lineColor, lineWidth), gpArea); //边缘 gpArea.CloseFigure(); //是否封闭
最新回复(0)