极谱图中具有多个系列的hittest [英] hittest in polar chart with multiple series

查看:69
本文介绍了极谱图中具有多个系列的hittest的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有多个系列的极坐标图.我想要一种功能来单击任何系列中的数据点之一并执行某些操作.我尝试使用HitTest,并且只能在一个系列中使用.问题是当我在具有多个序列的图表中使用时,有时当我单击数据点时,它返回一个不同的点.请帮忙.

这是我使用的代码段.

  HitTestResult结果= chart1.HitTest(e.X,e.Y,ChartElementType.DataPoint);如果(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(对象发送者,MouseEventArgs e){HitTestResult结果= chart1.HitTest(e.X,e.Y,ChartElementType.DataPoint);如果(result.ChartElementType == ChartElementType.DataPoint){dpCurrent = result.Series.Points [result.PointIndex];if(距离(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(对象发送者,MouseEventArgs e){HitTestResult hit = chart1.HitTest(e.X,e.Y);如果(hit.ChartElementType == ChartElementType.DataPoint){dpCurrent = hit.Series.Points [hit.PointIndex];dpCurrent.MarkerSize = largeMarkerSize;}别的{如果(dpCurrent!= null)dpCurrent.MarkerSize = normalMarkerSize;dpCurrent = null;} 

不幸的是,即使您仅打了连接的线 HitTest 仍然会触发DataPoint-hit,无论您制作它们的细度或颜色如何.

..输入解决方案二:

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

现在,在处理匹配之前,您需要进行额外的检查,也许是这样的:

  if(distance(PolarValueToPixelPosition(dpCurrent,chart1,hit.ChartArea),e.Location)< = markerRadius)...//执行点击内容 

这是坐标转换函数:

  PointF PolarValueToPixelPosition(DataPoint dp,统计图,ChartArea ca){RectangleF ipp = InnerPlotPositionClientRectangle(chart,ca);双交叉= ca.AxisX.Crossing!= double.NaN?ca.AxisX.Crossing:0;//对于RangeChart更改90 zo 135!float phi =(float)(360f/大约AxisX.Maximum/180f * Math.PI *(dp.XValue-90 + crossing));float yMax =(float)ca.AxisY.Maximum;float yMin =(float)ca.AxisY.Minimum;浮点半径= ipp.Width/2f;float len =(float)(dp.YValues [0]-yMin)/(yMax-yMin);PointF C =新的PointF(ipp.X + ipp.Width/2f,ipp.Y + ipp.Height/2f);float xx =(float)(Math.Cos(phi)*半径* len);float yy =(float)(Math.Sin(phi)*半径* len);返回新的PointF(C.X + xx,C.Y + yy);} 

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

 浮动距离(PointF pt1,PointF pt2){浮点数d =(float)Math.Sqrt((pt1.X-pt2.X)*(pt1.X-pt2.X)+(pt1.Y-pt2.Y)*(pt1.Y-pt2.Y));返回d;} 

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

  RectangleF ChartAreaClientRectangle(图表,ChartArea CA){RectangleF CAR = CA.Position.ToRectangleF();浮动pw = chart.ClientSize.Width/100f;浮动ph = chart.ClientSize.Height/100f;返回新的RectangleF(pw * CAR.X,ph * CAR.Y,pw * CAR.Width,ph * CAR.Height);}RectangleF InnerPlotPositionClientRectangle(图表图表,ChartArea CA){RectangleF IPP = CA.InnerPlotPosition.ToRectangleF();RectangleF CArp = ChartAreaClientRectangle(chart,CA);浮点pw = CArp.Width/100f;浮点ph = CArp.Height/100f;返回新的RectangleF(CArp.X + pw * IPP.X,CArp.Y + ph * IPP.Y,pw * IPP.Width,ph * IPP.Height);} 

I have a polar chart with multiple series. I want to have a functionality to click on one of the datapoints in any series and perform something. I tried to use the HitTest and it works on a single series. The problem is when I used in on a chart with multiple series and sometimes when I click on a datapoint, it returns a different point. Please help.

This is the snippet that I used.

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;
}

update:

Thanks you so much for bearing with me. Anyway, this is the code incorporating what you suggested.

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;
        }
    }

However, I noticed that the value of "phi" in the PolarValueToPixelPosition is always returning NaN

解决方案

Here are two ways to solve the problem; none can actually make the HitTest ignore clicking on the connecting lines.

But they should be fine, espacially when you implement them both.

The first provides feedback to the user so he can see in advance which point the mouse is over and he is about to click:

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;
    }

Unfortunately the HitTest will still trigger a DataPoint-hit even if you only hit the connecting lines, no matter how thin you make them or what color they have..

..enter solution two:

One can write a custom HitTest by calculating the pixel-coordinates of the DataPoints; this is not as simple as calling the Axis.ValueToPixelPosition methods as it involves some modest amount of math..:

Now before processing the hit you would do an additional check, maybe like this:

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

Here is the coordinate transformation function:

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);
}

It makes use of a simple distance function..:

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;
}

Also of two other useful functions to calculate the pixel size of the InnerPlotPosition, which I have used in quite a few answers now..:

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);
}

这篇关于极谱图中具有多个系列的hittest的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆