1

My task is to draw a graph in chart control using mouse and retrieve the (X,Y) points from the Graph.

I tried of drawing a graph with mouse. Here is the normal Graph looks like.enter image description here After drawing with mouse, it looks like : enter image description here The code which i used to draw graph is :

    private void Form1_Load(object sender, EventArgs e)
    {
    chart1.ChartAreas[0].AxisX.Minimum =0170101;
    chart1.ChartAreas[0].AxisX.Maximum =0175951;
    chart1.ChartAreas[0].AxisY.Minimum=0780101;
    chart1.ChartAreas[0].AxisY.Maximum=0785951;
    double range = chart1.ChartAreas[0].AxisX.Maximum - chart1.ChartAreas[0].AxisX.Minimum;
        chart1.ChartAreas[0].AxisX.Interval = range / 5;

        range = chart1.ChartAreas[0].AxisY.Maximum - chart1.ChartAreas[0].AxisY.Minimum;
        chart1.ChartAreas[0].AxisY.Interval = range / 5;
    }
    private void chart1_MouseMove(object sender, MouseEventArgs e)
    {
        if (!(FirstPoint == null))
        {
            Graphics g = chart1.CreateGraphics();
            Pen ErasePen = new Pen(Color.Transparent);
            g.DrawLine(ErasePen, FirstPoint, TempPoint);
            TempPoint = new Point(e.X, e.Y);
            this.Refresh();
        }
    }
    private void chart1_MouseDown_1(object sender, MouseEventArgs e)
    {
        FirstPoint = new Point(e.X, e.Y);
        TempPoint = new Point(e.X, e.Y);
    }

    private void chart1_MouseUp_1(object sender, MouseEventArgs e)
    {
        LineEndPoints Line = new LineEndPoints
        {
            StartPoint = FirstPoint,
            endPont = new Point(e.X, e.Y)
        };
        LinesList.Add(Line);
        // FirstPoint = null;
        this.Refresh();
    }

    private void chart1_Paint_1(object sender, PaintEventArgs e)
    {
        foreach (LineEndPoints line in LinesList)
        {
            e.Graphics.DrawLine(Pens.Green, line.StartPoint, line.endPont);
        }
        if (!(FirstPoint == null))
        {
            e.Graphics.DrawLine(Pens.Red, FirstPoint, TempPoint);
        }
    }

When I used to draw a graph it is moving away from the max and min values of the chart control. Now what I need to know is: 1) My graph should not move away from the X and Y axis points of the chart control. 2) I need to know the X,Y points of the graph which is drawn with respect to chart axis but not with form axis.

I use C# VS 2010 Win-forms.

TaW
  • 53,122
  • 8
  • 69
  • 111
Gopi
  • 236
  • 2
  • 6
  • 20
  • If you are supposed to a) use a chart control and b) later retrieve the points are you sure you should actually draw on the graph's surface? I would guess you are expected to add points to a series in the chart. also you will need to be clear about the way the mouse should be used: by clicking or by dragging on the chart? – TaW Apr 27 '15 at 17:32
  • @TaW Ya I know how to draw a graph by using series of points into series and then adding that series to the graph. But my task is to draw a graph with mouse move. I was unable to take the points into series, which is drawn on the chart. That's my problem of retrieving the points X,Y with respect to chart. – Gopi Apr 27 '15 at 17:40
  • 1
    It is tricky. Since you are drawing in the chart's Paint event, conversion methods will work, according to [MSDN](https://msdn.microsoft.com/en-us/library/system.windows.forms.datavisualization.charting.axis.pixelpositiontovalue%28v=vs.110%29.aspx) – TaW Apr 27 '15 at 18:11
  • @TaW Ya thanks. I am working on it. Meanwhile if possible can you give me some example for this type conversion please. – Gopi Apr 27 '15 at 18:22
  • See the updated example in my answer! – TaW Apr 27 '15 at 20:03

1 Answers1

1

Chart uses a different coordinate system for its content than its Control surface, ie the mouse loacation; there are conversion functions but they come with a caveat: They are only guaranteed to work in the Paint events..

Here is an example that translates the pixel points to chart point values. You can see the two graphics overlaying very nicely: The DataPoints are connected in blue lines and the pixel points by dotted red lines..:

enter image description here

    public Form1()
    {
        InitializeComponent();
        chart1.Series[0].ChartType = SeriesChartType.Line;
        chart1.ChartAreas[0].AxisX.Minimum = 0;
        chart1.ChartAreas[0].AxisX.Maximum = 500;
        chart1.ChartAreas[0].AxisY.Minimum = 0;
        chart1.ChartAreas[0].AxisY.Maximum = 500;
    }

    List<Point> points = new List<Point>();

    private void chart1_MouseClick(object sender, MouseEventArgs e)
    {
        points.Add(e.Location);
        chart1.Invalidate();
    }

    private void chart1_Paint(object sender, PaintEventArgs e)
    {
        chart1.Series[0].Points.Clear();
        foreach(Point pt in points)
        {
            double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(pt.X);
            double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(pt.Y);
            chart1.Series[0].Points.AddXY(dx, dy);
        }
        if (points.Count > 1)
            using (Pen pen = new Pen(Color.Red, 2.5f))
               e.Graphics.DrawLines(pen, points.ToArray());
    }

Note that this will always clear the DataPoints and recreate them from the pixel points list, according to the current chart layout using the PixelPositionToValue method. The layout will always change when things like label sizes, other scaling, other minimum/maximum values etc change.

Maybe you really want to work the other way round, that is change the clicked points using the ValueToPixelPosition.

Here is the modified example that keeps the DataPoints and recalculates the pixel points:

    List<Point> points = new List<Point>();
    Point lastPoint = Point.Empty;

    private void chart1_MouseClick(object sender, MouseEventArgs e)
    {
        lastPoint = e.Location;
        chart1.Invalidate();
    }

    private void chart1_Paint(object sender, PaintEventArgs e)
    {
        // if we have a new point, convert to DataPoint and add to Series.Points:
        if (lastPoint != Point.Empty)
        {
            double dx = chart1.ChartAreas[0].AxisX.PixelPositionToValue(lastPoint.X);
            double dy = chart1.ChartAreas[0].AxisY.PixelPositionToValue(lastPoint.Y);
            chart1.Series[0].Points.AddXY(dx, dy);
        }
        lastPoint = Point.Empty;
        // now recalculate all pixel points:
        points.Clear();
        foreach (DataPoint pt in chart1.Series[0].Points)
        {
            double x = chart1.ChartAreas[0].AxisX.ValueToPixelPosition(pt.XValue);
            double y = chart1.ChartAreas[0].AxisY.ValueToPixelPosition(pt.YValues[0]);
            points.Add(new Point((int)x, (int)y));
        }

        if (points.Count > 1)
            using (Pen pen = new Pen(Color.Red, 2.5f))
            {
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                e.Graphics.DrawLines(pen, points.ToArray());
            }
    }

This makes a lot more sense, since the DataPoints are always bound to the chart's scaling, so they are the 'real thing'. When you resize the Chart the DataPoints and the Graphic they make up are scaled as usual and the drawn pixel points follow perfectly:

enter image description hereenter image description here

(When you resize the first version you can see how nothing is being scaled up or down and only the chart's grid lines change..)

Note that I set up a few things to start with, so that not every point I add enforces too many layout changes. Also note that sometimes there still occurs a feedback loop when the new points change e.g. the label sizes, which enforces a layout change and the paint loop.. To fix this you should probably control the labels' formats!

Also note that both conversion methods only work (correctly) in the Paint event(s), probably because only then the current layout is being settled.

TaW
  • 53,122
  • 8
  • 69
  • 111
  • Thanks, I'll go through this and get back to you. Hope this works. – Gopi Apr 28 '15 at 02:18
  • It works in some way, the problem is when i maximize the window graph is changing from its previous position. Anyway Thanks – Gopi Apr 28 '15 at 13:46
  • Which version do you use? The second one shouldn't do that. – TaW Apr 28 '15 at 14:13
  • Oh ya sorry forget to mention that, first code changes, but the second one is pretty good. – Gopi Apr 28 '15 at 15:21
  • Hey, when i execute the second code, graph is same like the 2nd one which i mentioned in my question. Please check it out. It is making us to draw outside the chart control. – Gopi Apr 28 '15 at 17:03
  • Be sure to get the order of events right: 1) right after the mouseclick (or up or down) you need to store the point and then call invalidate to trigger paint. there you can add this (one) point, translated, to the series-points. 2) in the paint you need to recreate the complete pixel-point list each time because the layout may have changed! - As you can see in the images, when done right, the pixel-points and the datapoint are sitting perfectly on each other! – TaW Apr 28 '15 at 17:11
  • I inly used the MosueClick to add a Point. If you need to use the mousemove event (for what? better placement of the point?) then you will have to make sure to not add the temporary points to the DataPoint collection until mouseUp! Maybe a flag will help or checking the mousebutton... - If your problems don't go away, you can update the question with the current version of your code.. – TaW Apr 28 '15 at 17:15
  • Graph is perfectly plotting and I am getting X,Y values of chart correctly. What i mean to say is, just see the 2nd graph in my question. We are drawing the graph in the "yellow" part of the chart also. But I should not want like that. I should draw only on the black screen, with mouse we should not draw on yellow screen. Hope you understand my problem. – Gopi Apr 28 '15 at 17:22
  • Not sure I do understand. Do you mean your lines get drawn someplace else than where you clicked on or do you mean you don't want the user to be able to click to outside the paintarea? – TaW Apr 28 '15 at 17:24
  • ok then I'll try myself with what I have. Thanks for your suggestions. – Gopi Apr 28 '15 at 17:31