13

Is there a simple way to retrieve the X/Y coordinates of ANY point in the chart Area (relative to that chart Axis of course)?

As of now, I just managed to retrieve coordinates when the mouse is on a Series (not outside)

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);
    }
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Mehdi LAMRANI
  • 11,289
  • 14
  • 88
  • 130

7 Answers7

11

Anyway, as always with MS Chart Controls, there is no easy way to do things,
but a funky workaround to get things done. I am sadly getting used to it...

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
}
Mehdi LAMRANI
  • 11,289
  • 14
  • 88
  • 130
  • 1
    I have just tried this: pX works ok, but pY remains constant (=1) (while both e.X and e.Y change). Also it adds a full-chart crosshair which can be undesirable in some particular cases. – Ivan Mar 02 '14 at 05:22
10

This works for my purposes and doesn't side effect the cursor.

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);
}
Quinn
  • 101
  • 1
  • 2
6

I tried your answer, but it didn't work for me. It ended up putting the cursor in one spot and never moving. I believe this is because I use decimal/double values along both axes, and the cursor is being rounded to the nearest integer.

After several attempts, I was able to work out a method for determining where the cursor is inside the chart. The hard part was figuring out that all the "positions" for the chart elements are actually percentage values (from 0 to 100).

As per
http://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.elementposition.aspx:
"Defines the position of the chart element in relative coordinates, which range from (0,0) to (100,100)."

I hope you don't mind, I am posting this answer here just for posterity, in case anyone else comes across this problem, and your method also does not work for them. Its not pretty or elegant in any way, but so far it works for me.

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);
}
csauve
  • 5,904
  • 9
  • 40
  • 50
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);
    }
}
Kim Ki Won
  • 1,795
  • 1
  • 22
  • 22
1

This works

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

And this works

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
    A little more explanation is always good to make your answer more valuable ;) – ForceMagic Oct 20 '12 at 02:08
  • The first one does not work for me. The e.X value was zero and the chartlocation was 28 thereby giving a negative number for x (which caused an exception) when I tried to locate an annotation there. – CramerTV Nov 22 '13 at 22:51
0

This is what I got, I think many of us are along the same lines but with different interpretations of what it is you're looking for.

This will give you the coordinates at any location in the plotting area. I found the HitTest gives a clean and simple solution, but there are a few checks to make, whether the cursor is on a data point, a gridline, or in the plotting area (which seem to take precedence in that order). I assume you'll be interested in the coordinate regardless of which of those objects the mouse is over.

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();
}
APCrowder
  • 41
  • 8
0

VB.net version, with zoom correction:

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