在多个系列的极坐标图表中测试

我有一个有多个系列的极坐标图表。 我希望有一个function可以点击任何系列中的一个数据点并执行某些操作。 我尝试使用HitTest,它适用于单个系列。 问题是当我在具有多个系列的图表上使用时,有时当我点击数据点时,它会返回不同的点。 请帮忙。

这是我使用的片段。

HitTestResult result = chart1.HitTest(eX, eY, ChartElementType.DataPoint); if (result.ChartElementType == ChartElementType.DataPoint) { var xVal = result.Series.Points[result.PointIndex].XValue; var yVal = result.Series.Points[result.PointIndex].YValues; result.Series.Points[result.PointIndex].MarkerColor = Color.Black; } 

更新:

非常感谢你对我的支持。 无论如何,这是包含您建议的代码。

 DataPoint dpCurrent = null; int normalMarkerSize = 10; int largeMarkerSize = 15; private void chart1_MouseClick(object sender, MouseEventArgs e) { HitTestResult result = chart1.HitTest(eX, eY, ChartElementType.DataPoint); if (result.ChartElementType == ChartElementType.DataPoint) { dpCurrent = result.Series.Points[result.PointIndex]; if (distance(PolarValueToPixelPosition(dpCurrent, chart1, result.ChartArea), e.Location) <= 5) result.Series.Points[result.PointIndex].MarkerColor = Color.Black; } } 

但是,我注意到PolarValueToPixelPosition中“phi”的值总是返回NaN

以下是解决问题的两种方法; 没有人可以让HitTest 忽略点击连接线。

但它们应该没问题,特别是当你同时实施它们时。

第一个向用户提供反馈 ,以便他可以提前看到鼠标在哪个点,他将要点击:

 DataPoint dpCurrent = null; int normalMarkerSize = 8; int largeMarkerSize = 12; private void chart1_MouseMove(object sender, MouseEventArgs e) { HitTestResult hit = chart1.HitTest(eX, eY); if (hit.ChartElementType == ChartElementType.DataPoint) { dpCurrent = hit.Series.Points[hit.PointIndex]; dpCurrent.MarkerSize = largeMarkerSize; } else { if (dpCurrent != null) dpCurrent.MarkerSize = normalMarkerSize; dpCurrent = null; } 

不幸的是,即使你只打了连接线HitTest仍会触发DataPoint命中,无论你制作多么薄或它们有什么颜色。

..enter解决方案二:

可以通过计算DataPoints的像素坐标来编写自定义HitTest ; 这不像调用Axis.ValueToPixelPosition方法那么简单,因为它涉及一些适量的数学..:

现在在处理命中之前你会做一个额外的检查,可能是这样的:

  if (distance(PolarValueToPixelPosition(dpCurrent, chart1, hit.ChartArea), e.Location) <= markerRadius) ...//do the hit stuff 

这是坐标转换函数:

 PointF PolarValueToPixelPosition(DataPoint dp, Chart chart, ChartArea ca) { RectangleF ipp = InnerPlotPositionClientRectangle(chart, ca); double crossing = ca.AxisX.Crossing != double.NaN ? ca.AxisX.Crossing : 0; // for RangeChart change 90 zo 135 ! float phi = (float)(360f / ca.AxisX.Maximum / 180f * Math.PI * (dp.XValue - 90 + crossing ) ); float yMax = (float)ca.AxisY.Maximum; float yMin = (float)ca.AxisY.Minimum; float radius = ipp.Width / 2f; float len = (float)(dp.YValues[0] - yMin) / (yMax - yMin); PointF C = new PointF(ipp.X + ipp.Width / 2f, ipp.Y + ipp.Height / 2f); float xx = (float)(Math.Cos(phi) * radius * len); float yy = (float)(Math.Sin(phi) * radius * len); return new PointF(CX + xx, CY + yy); } 

它利用了一个简单的距离函数..:

 float distance(PointF pt1, PointF pt2) { float d = (float)Math.Sqrt((pt1.X - pt2.X) * (pt1.X - pt2.X) + (pt1.Y - pt2.Y) * (pt1.Y - pt2.Y)); return d; } 

还有另外两个有用的函数来计算InnerPlotPosition的像素大小,我现在已经在很多答案中使用了..:

 RectangleF ChartAreaClientRectangle(Chart chart, ChartArea CA) { RectangleF CAR = CA.Position.ToRectangleF(); float pw = chart.ClientSize.Width / 100f; float ph = chart.ClientSize.Height / 100f; return new RectangleF(pw * CAR.X, ph * CAR.Y, pw * CAR.Width, ph * CAR.Height); } RectangleF InnerPlotPositionClientRectangle(Chart chart, ChartArea CA) { RectangleF IPP = CA.InnerPlotPosition.ToRectangleF(); RectangleF CArp = ChartAreaClientRectangle(chart, CA); float pw = CArp.Width / 100f; float ph = CArp.Height / 100f; return new RectangleF(CArp.X + pw * IPP.X, CArp.Y + ph * IPP.Y, pw * IPP.Width, ph * IPP.Height); }