在图表控件上显示鼠标坐标轴坐标

13

是否有一种简单的方法可以检索图表区域中任何点的X/Y坐标(相对于该图表轴线)?

目前,我只能在鼠标停留在系列上时检索坐标(而不是在外部)。

private void chart_GetToolTipText(object sender, ToolTipEventArgs e)
{
    if (e.HitTestResult.Series != null)
    {
        e.Text = e.HitTestResult.Series.Points[e.HitTestResult.PointIndex].YValues[0] + " \n " + DateTime.FromOADate(e.HitTestResult.Series.Points[e.HitTestResult.PointIndex].XValue);
    }
}
7个回答

11

无论如何,对于MS图表控件来说,要做事情并没有简单的方法,但有一种奇特的解决方法可以完成任务。我很遗憾已经习惯了这种情况...

private void chart1_MouseWhatever(object sender, MouseEventArgs e)
{
    chartArea1.CursorX.SetCursorPixelPosition(new Point(e.X, e.Y), true);
    chartArea1.CursorY.SetCursorPixelPosition(new Point(e.X, e.Y), true);

    double pX = chartArea1.CursorX.Position; //X Axis Coordinate of your mouse cursor
    double pY = chartArea1.CursorY.Position; //Y Axis Coordinate of your mouse cursor
}

1
我刚试了一下:pX正常工作,但pY保持不变(=1)(而e.X和e.Y都会改变)。此外,它添加了一个完整的图表十字线,在某些特定情况下可能不太理想。 - Ivan

10

这对我的目的有效,并且不会影响游标。

private Tuple<double,double> GetAxisValuesFromMouse(int x, int y)
{
    var chartArea = _chart.ChartAreas[0];
    var xValue = chartArea.AxisX.PixelPositionToValue(x);
    var yValue = chartArea.AxisY.PixelPositionToValue(y);
    return new Tuple<double, double>(xValue, yValue);
}

6
我尝试了你的答案,但它对我没有起作用。最终光标停留在一个位置并且没有移动。我认为这是因为我沿着两个轴使用十进制/双精度值,而光标被四舍五入到最近的整数。
经过多次尝试,我成功地找出了一种确定图表内光标位置的方法。难点在于弄清楚所有图表元素的“位置”实际上都是百分比值(从0到100)。
根据
http://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.elementposition.aspx
“定义图表元素在相对坐标系中的位置,其范围从(0,0)到(100,100)。”

希望你不介意,我在这里发布这个答案,以备后人参考,以防他们也遇到这个问题,你的方法对他们也不起作用。虽然它不太漂亮或优雅,但至少对我目前来说是有效的。

private struct PointD
{
  public double X;
  public double Y;
  public PointD(double X, double Y)
  {
    this.X = X;
    this.Y = Y;
  }
}

private void chart1_MouseMove(object sender, MouseEventArgs e)
{
  var pos = LocationInChart(e.X, e.Y);
  lblCoords.Text = string.Format("({0}, {1}) ... ({2}, {3})", e.X, e.Y, pos.X, pos.Y);
}

private PointD LocationInChart(double xMouse, double yMouse)
{
  var ca = chart1.ChartAreas[0];

  //Position inside the control, from 0 to 100
  var relPosInControl = new PointD
  (
    ((double)xMouse / (double)execDetailsChart.Width) * 100,
    ((double)yMouse / (double)execDetailsChart.Height) * 100
  );

  //Verify we are inside the Chart Area
  if (relPosInControl.X < ca.Position.X || relPosInControl.X > ca.Position.Right
  || relPosInControl.Y < ca.Position.Y || relPosInControl.Y > ca.Position.Bottom) return new PointD(double.NaN, double.NaN);

  //Position inside the Chart Area, from 0 to 100
  var relPosInChartArea = new PointD
  (
    ((relPosInControl.X - ca.Position.X) / ca.Position.Width) * 100,
    ((relPosInControl.Y - ca.Position.Y) / ca.Position.Height) * 100
  );

  //Verify we are inside the Plot Area
  if (relPosInChartArea.X < ca.InnerPlotPosition.X || relPosInChartArea.X > ca.InnerPlotPosition.Right
  || relPosInChartArea.Y < ca.InnerPlotPosition.Y || relPosInChartArea.Y > ca.InnerPlotPosition.Bottom) return new PointD(double.NaN, double.NaN);

  //Position inside the Plot Area, 0 to 1
  var relPosInPlotArea = new PointD
  (
    ((relPosInChartArea.X - ca.InnerPlotPosition.X) / ca.InnerPlotPosition.Width),
    ((relPosInChartArea.Y - ca.InnerPlotPosition.Y) / ca.InnerPlotPosition.Height)
  );

  var X = relPosInPlotArea.X * (ca.AxisX.Maximum - ca.AxisX.Minimum) + ca.AxisX.Minimum;
  var Y = (1 - relPosInPlotArea.Y) * (ca.AxisY.Maximum - ca.AxisY.Minimum) + ca.AxisY.Minimum;

  return new PointD(X, Y);
}

2
private void OnChartMouseMove(object sender, MouseEventArgs e)
{
    var sourceChart = sender as Chart;
    HitTestResult result = sourceChart.HitTest(e.X, e.Y);
    ChartArea chartAreas = sourceChart.ChartAreas[0];

    if (result.ChartElementType == ChartElementType.DataPoint)  
    {
        chartAreas.CursorX.Position = chartAreas.AxisX.PixelPositionToValue(e.X);
        chartAreas.CursorY.Position = chartAreas.AxisY.PixelPositionToValue(e.Y);
    }
}

可以工作,甚至是Y轴!谢谢 - Yura G

1

这个有效

private void chart1_MouseWhatever(object sender, MouseEventArgs e)
{   
    Point chartLocationOnForm = chart1.FindForm().PointToClient(chart1.Parent.PointToScreen(chart1.Location));     

    double x = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X - chartLocationOnForm.X);    
    double y = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Y - chartLocationOnForm.Y);
}

这个可以正常工作

private void chart1_MouseWhatever(object sender, MouseEventArgs e)
{ 
    Point chartLocationOnForm = chart1.FindForm().PointToClient(chart1.Parent.PointToScreen(chart1.Location));                

    chart1.ChartAreas[0].CursorX.SetCursorPixelPosition(new PointF(e.X - chartLocationOnForm.X, e.Y - chartLocationOnForm.Y), true);
    chart1.ChartAreas[0].CursorY.SetCursorPixelPosition(new PointF(e.X - chartLocationOnForm.X, e.Y - chartLocationOnForm.Y), true);

    double x = chart1.ChartAreas[0].CursorX.Position;
    double y = chart1.ChartAreas[0].CursorY.Position;
}

2
更详细的解释总是有益的,可以使您的答案更有价值 ;) - ForceMagic
第一个对我不起作用。e.X的值为零,chartlocation为28,因此在我尝试在那里定位注释时,x为负数(导致异常)。 - CramerTV

0

这是我得到的,我想我们很多人都在相同的思路上,但对你要寻找的东西有不同的解释。

这将为您提供绘图区域中任何位置的坐标。我发现HitTest提供了一个干净简单的解决方案,但需要进行一些检查,例如光标是否位于数据点、网格线或绘图区域(在此顺序中似乎优先)。我假设您将对该坐标感兴趣,而不管鼠标悬停在哪个对象上。

private void chart_GetToolTipText(object sender, ToolTipEventArgs e)
{
    // If the mouse isn't on the plotting area, a datapoint, or gridline then exit
    HitTestResult htr = chart.HitTest(e.X, e.Y);
    if (htr.ChartElementType != ChartElementType.PlottingArea && htr.ChartElementType != ChartElementType.DataPoint && htr.ChartElementType != ChartElementType.Gridlines)
        return;

    ChartArea ca = chart.ChartAreas[0]; // Assuming you only have 1 chart area on the chart

    double xCoord = ca.AxisX.PixelPositionToValue(e.X);
    double yCoord = ca.AxisY.PixelPositionToValue(e.Y);

    e.Text = "X = " + Math.Round(xCoord, 2).ToString() + "\nY = " + Math.Round(yCoord, 2).ToString();
}

0

VB.net版本,带有缩放校正:

Private Function LocationInChart(xMouse, yMouse) As PointF
    Dim ca = Chart1.ChartAreas(0)

    'Position inside the control, from 0 to 100
    Dim relPosInControl = New PointF((xMouse / Chart1.Width) * 100, (yMouse / Chart1.Height) * 100)

    'Verify we are inside the Chart Area
    If (relPosInControl.X < ca.Position.X Or relPosInControl.X > ca.Position.Right Or relPosInControl.Y < ca.Position.Y Or relPosInControl.Y > ca.Position.Bottom) Then Return New PointF(Double.NaN, Double.NaN)

    'Position inside the Chart Area, from 0 to 100
    Dim relPosInChartArea = New PointF(((relPosInControl.X - ca.Position.X) / ca.Position.Width) * 100, ((relPosInControl.Y - ca.Position.Y) / ca.Position.Height) * 100)

    'Verify we are inside the Plot Area
    If (relPosInChartArea.X < ca.InnerPlotPosition.X Or relPosInChartArea.X > ca.InnerPlotPosition.Right Or relPosInChartArea.Y < ca.InnerPlotPosition.Y Or relPosInChartArea.Y > ca.InnerPlotPosition.Bottom) Then Return New PointF(Double.NaN, Double.NaN)

    'Position inside the Plot Area, 0 to 1
    Dim relPosInPlotArea = New PointF(((relPosInChartArea.X - ca.InnerPlotPosition.X) / ca.InnerPlotPosition.Width), ((relPosInChartArea.Y - ca.InnerPlotPosition.Y) / ca.InnerPlotPosition.Height))

    Dim X = relPosInPlotArea.X * (ca.AxisX.Maximum - ca.AxisX.Minimum) + ca.AxisX.Minimum
    Dim Y = (1 - relPosInPlotArea.Y) * (ca.AxisY.Maximum - ca.AxisY.Minimum) + ca.AxisY.Minimum

    ' zoomo korekcija
    Dim zoomx = (ca.AxisX.ScaleView.ViewMaximum - ca.AxisX.ScaleView.ViewMinimum) / (ca.AxisX.Maximum - ca.AxisX.Minimum)
    Dim zoomy = (ca.AxisY.ScaleView.ViewMaximum - ca.AxisY.ScaleView.ViewMinimum) / (ca.AxisY.Maximum - ca.AxisY.Minimum)
    Dim xx = ca.AxisX.ScaleView.ViewMinimum + X * zoomx
    Dim yy = ca.AxisY.ScaleView.ViewMinimum + Y * zoomy

    Return New PointF(xx, yy)
End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接