Search code examples
c#chartspositionconvertersdatapoint

Get Form.Left value of Point(X,Y) in ChartControl


I need the Left value (Or the Location on the screen) of a specific point in a Chart Control. Basiclly the 0,0 Point, because it changes when resizing the Form.

cheers


Solution

  • Assuming you mean the position of a DataPoint with XValue = 0 and YValue[0] = 0 you can use the XAxis function ValueToPixelPosition for this; here is an example, which assumes you have added a Label lbl to the chart's Controls and will keep that Label sitting at the position of the 3rd DataPoint:

    private void chart1_Resize(object sender, EventArgs e)
    {
        DataPoint dp = chart1.Series[0].Points[2];
        ChartArea ca = chart1.ChartAreas[0];
        Axis ax = ca.AxisX;
        Axis ay = ca.AxisY;
    
        int px = (int) ax.ValueToPixelPosition(dp.XValue);
        int py = (int) ay.ValueToPixelPosition(dp.YValues[0]);
    
        lbl.Location = new Point(px, py);
    }
    

    Do note that this function as well as the other conversion functions (PixelPositionToValue) will only work either in the Pre/PostPaint events or in mouse events. The Resize event also seems to work.

    Using them at other time, most notably before the chart is done with its layout, will either produce wrong or null values.

    enter image description here

    The px, py pixel values are relative to the Chart. To convert them to a Point relative to the Form you can use the usual conversion functions PointToScreen and PointToClient.


    Update:

    If you actually want the pixel coordinates of the top left of the ChartArea.InnerPlotPosition you can use these two functions:

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

    Use it maybe in the Resize event like this:

    ChartArea ca = chart1.ChartAreas[0];
    Rectangle ipr = Rectangle.Round(InnerPlotPositionClientRectangle(chart1, ca));
    lbl.Location =  ipr.Location;
    

    enter image description here

    You can easily offset it by a few pixels if you want now..