Search code examples
c#chartsmschart

Using PolygonAnnotation to draw within a chart


I'm trying to use PolygonAnnotation to draw a Polygon within a chart where I have four points that i would like to use as vertex.

Below my chart

enter image description here chart1

These Points are set at runtime in a Bubble Series:

System.Windows.Forms.DataVisualization.Charting.Series serieSA = chartCartesian.Series.FindByName("SeriesSafetyArea");

DataPoint dpA = new DataPoint(radarConfigured.SafetyArea.PointA.X,new Double[]{radarConfigured.SafetyArea.PointA.Y, -20});
DataPoint dpB = new DataPoint(radarConfigured.SafetyArea.PointB.X, new Double[]{radarConfigured.SafetyArea.PointB.Y, -20});
DataPoint dpC = new DataPoint(radarConfigured.SafetyArea.PointC.X, new Double[] { radarConfigured.SafetyArea.PointC.Y, -20 });
DataPoint dpD = new DataPoint(radarConfigured.SafetyArea.PointD.X, new Double[] { radarConfigured.SafetyArea.PointD.Y, -20 });
                dpA.Label = "A";
                dpB.Label = "B";
                dpC.Label = "C";
                dpD.Label = "D";
                serieSA.Points.Add(dpA);
                serieSA.Points.Add(dpB);
                serieSA.Points.Add(dpC);
                serieSA.Points.Add(dpD);

I would like to obtain a figure like a rectangle using these points. i've tried usign this code:

safetyAreaAnnotation = new PolygonAnnotation();
            safetyAreaAnnotation.ClipToChartArea = chartCartesian.ChartAreas[0].Name;
            //safetyAreaAnnotation.AnchorX = 10;
            //safetyAreaAnnotation.AnchorY = 20;
            PointF[] points = new PointF[4];
            points[0].X = (float)dpA.XValue;
            points[0].Y = (float)dpA.YValues[0] ;
            points[1].X = (float)dpB.XValue;
            points[1].Y = (float)dpB.YValues[0];
            points[2].X = (float)dpC.XValue;
            points[2].Y = (float)dpC.YValues[0];
            points[3].X = (float)dpD.XValue;
            points[3].Y = (float)dpD.YValues[0];
            byte[] type = new byte[4];
            type[0] = (byte)PathPointType.Start;
            type[1] = (byte)PathPointType.Line;
            type[2] = (byte)PathPointType.Line;
            type[3] = (byte)PathPointType.CloseSubpath;

            safetyAreaAnnotation.GraphicsPath=new System.Drawing.Drawing2D.GraphicsPath(points,type);  
           // //safetyAreaAnnotation.IsSizeAlwaysRelative = false;
           // //safetyAreaAnnotation.BackColor = Color.Red;
           safetyAreaAnnotation.AxisX = chartCartesian.ChartAreas[0].AxisX;
           safetyAreaAnnotation.AxisY = chartCartesian.ChartAreas[0].AxisY;
           safetyAreaAnnotation.AnchorDataPoint = serieSA.Points[0];
           // //safetyAreaAnnotation.AnchorX = 1;
           // //safetyAreaAnnotation.AnchorY = 20;
            chartCartesian.Annotations.Add(safetyAreaAnnotation);

But it doesn't work. Nothing is displayed in my chart. Maybe I should use something different to draw this polygon?

Update

That is the result after drawing a polygon:

enter image description here


Solution

  • 1 - Annotation

    Your Annotation doesn't show because you didn't set a size for it.

    From MSDN on PolyLines:

    Remarks

    A polyline must use coordinates relative to an annotation object, where (0,0) denotes the top-left coordinates and (100,100) denotes the bottom-right coordinates of the annotation.

    So the first thing you would need to do is the give the Annotation a Size:

    safetyAreaAnnotation.Width = 10;
    safetyAreaAnnotation.Height = 10;
    

    This makes it rather big, as the Size is given in percent of the ChartArea..

    For more see MSDN on Height etc..

    But even if you find a suitable size it is rather hard to set the polyline coordinates from DataPoint values to those relative to the Annotation area..

    Not recommended!


    2 - Drawing

    You can draw onto the Chart in the Pre- or PostPaint events:

        ChartArea ca = chartCartesian.ChartAreas[0];
        Axis ax = ca.AxisX;
        Axis ay = ca.AxisY;
    
        List<DataPoint> dp = new List<DataPoint>() { dpA, dpB, dpC, dpD };
        List<PointF> points = dp.Select(x=> new PointF(
            (float)ax.ValueToPixelPosition(x.XValue), 
            (float)ay.ValueToPixelPosition(x.YValues[0])
            )).ToList();
        using (SolidBrush brush = new SolidBrush(Color.FromArgb(64, Color.Gold)))
           e.ChartGraphics.Graphics.FillPolygon(brush, points.ToArray());
    

    Just make sure the code has access to the DataPoints.

    As you see this is rather simple: It makes use of the ValueToPixelPosition methods of the Axes.

    This is directly relating to the DataPoints, so it will automatically scale & move when resizing. I highly recommend drawing the area over using an the Annotation.

    enter image description hereenter image description here


    By the way: Your way to add a polygon to a GraphicsPath is overcomplicated. AddPolygon(PointList.ToArray()) would have have worked just as well. Only when you want a complex mix of rounded and pointed corners would you actually go into setting the Types array..