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

时间:2016-07-19 08:58:09

标签: c#

我有一个包含多个系列的极坐标图表。我希望有一个功能可以点击任何系列中的一个数据点并执行某些操作。我尝试使用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

1 个答案:

答案 0 :(得分:0)

以下是解决问题的两种方法;没有人可以实际点击连接线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);
}