工作需要实现一个双对数曲线图,没找到现成的插件,最后决定还是自己自绘一个,封装成插件算了。。。 最后的效果如下:
源码链接: 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(); }和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));先排序数据
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(); //是否封闭