在多个系列的极坐标图中最热门

本文关键字:最热 热门 极坐标 个系列 | 更新日期: 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);
}