在多个系列的极坐标图中最热门
本文关键字:最热 热门 极坐标 个系列 | 更新日期: 2023-09-27 17:57:32
我有一个包含多个系列的极坐标图。我想要一个功能来点击任何系列中的一个数据点并执行一些操作。我试着使用HitTest,它只适用于一个系列。问题是,当我在一个有多个系列的图表上使用时,有时当我点击一个数据点时,它会返回一个不同的点。请帮忙。
这是我使用的片段。
HitTestResult result = chart1.HitTest(e.X, e.Y, 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(e.X, e.Y, 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(e.X, e.Y);
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命中,即使您只命中连接的行,无论它们有多薄或颜色如何。。
。。输入解决方案二:
可以通过计算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(C.X + xx, C.Y + 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);
}