我正在尝试创建一个应用程序,该应用程序将在一个表单上包含四个折线图。当用户将鼠标拖动到这些图表上时,应该有一条垂直线穿过每个图表,并且将显示每个图表的当前值。有什么方法可以在 C#/.NET 和 WinForms 中完成此操作吗?
这是我想要实现的目标的示例:
最佳答案
我建议将您的数据放入一个 MSChart 控件中,并带有四个独立的ChartAreas。
为此,您需要设置它们的位置,因为默认布局为 2x2。
然后添加一个VerticalLineAnnotation
并使其可移动。
在其移动事件中,您触发图表的 Paint
事件,您可以在其中计算必要的数据,即要显示的值以及显示它们的位置。
这是一个例子:
Paint
事件的编码如下:
private void chart_Paint(object sender, PaintEventArgs e)
{
double xv = VL.X; // get x-value of annotation
for (int i = 0; i < chart.ChartAreas.Count; i++)
{
ChartArea ca = chart.ChartAreas[i];
Series s = chart.Series[i];
int px = (int )ca.AxisX.ValueToPixelPosition(xv);
var dp = s.Points.Where(x => x.XValue >= xv).FirstOrDefault();
if (dp != null)
{
int py = (int )ca.AxisY.ValueToPixelPosition(s.Points[0].YValues[0]) - 20;
e.Graphics.DrawString(dp.YValues[0].ToString("0.00"),
Font, Brushes.Black, px, py);
}
}
}
请注意使用两个轴函数在图表中的两个(三个)坐标系之间进行转换:我们从数据值开始,然后转到像素。第三个系统是百分比,我们将在下面设置图表区域时遇到。
另请注意,为了简单起见,我假设每个 ChartArea 有一个系列;所以我可以使用相同的索引。您还可以通过使用正确的 ChartArea.Name 字段 (*) 搜索系列来找到相应的系列。
随意设置不同的 y 位置,当然还有字体、格式等。
为了使其生效,我们对这两个事件进行编码:
private void chart_AnnotationPositionChanging(object sender,
AnnotationPositionChangingEventArgs e)
{
chart.Invalidate();
}
private void chart_AnnotationPositionChanged(object sender, EventArgs e)
{
chart.Invalidate();
}
包括测试数据创建在内的图表设置有点长......:
首先我们为注释声明一个类级别变量。当然,我们也可以从 chart.Annotations
集合中获取它......:
VerticalLineAnnotation VL = null;
private void setupbutton_Click(object sender, EventArgs e)
{
chart.ChartAreas.Clear();
chart.Series.Clear();
for (int i = 0; i < 4; i++)
{
ChartArea ca = chart.ChartAreas.Add("CA" + (i+1));
ca.Position = new ElementPosition(0, i*23 + 5, 90, 25);
Series s = chart.Series.Add("S" + (i+1));
s.ChartType = SeriesChartType.Line;
s.MarkerStyle = MarkerStyle.Circle; // make the points stand out
s.MarkerSize = 3;
s.ChartArea = ca.Name; // where each series belongs (*)
for (int j = 0; j < 50; j++) // a few test data
{
s.Points.AddXY(j, Math.Sin((( (j + 1) *(i + 1) ) / 55f) * 10f));
}
}
VL = new VerticalLineAnnotation(); // the annotation
VL.AllowMoving = true; // make it interactive
VL.AnchorDataPoint = chart.Series[0].Points[0]; // start at the 1st point
VL.LineColor = Color.Red;
VL.IsInfinitive = true; // let it go all over the chart
chart.Annotations.Add(VL);
}
如果您仔细观看动画,您会看到值跳跃;那是因为我只有50分。如果您想显示插值,您可以通过查找其他相邻点并进行一些简单的数学运算来实现。但在很多情况下,这是无稽之谈。
请注意,我在设置 ChartArea.Position
时使用了一些“魔法”数字。它位于图表的百分比中,我在顶部和底部以及右侧的图例
留了一点余量。
关于c# - 跨多个折线图的垂直线,并在 Winforms 中显示每个图表的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49872756/