Search code examples
c#winformsannotationsmschart

how to align polyline annotation with respect to graph point in ms chart


I had added Polyline annotation to graph control. But it is not aligned properly in given datapoint in Addline() method.

        PolylineAnnotation annotation = new PolylineAnnotation();
        annotation.AxisX = chart1.ChartAreas[0].AxisX;
        annotation.AxisY = chart1.ChartAreas[0].AxisY;
        annotation.AnchorX = 0;
        annotation.AnchorY = 0;
        annotation.Height = 30;
        annotation.Width = -30;
        annotation.LineWidth = 3;
        annotation.StartCap = LineAnchorCapStyle.None;
        annotation.EndCap = LineAnchorCapStyle.None;
        annotation.Alignment = ContentAlignment.BottomLeft;
        annotation.AnchorAlignment = ContentAlignment.BottomRight;
        annotation.AnchorDataPoint = new DataPoint(this.chart1.Series[0]);

        annotation.AllowAnchorMoving = true;
        annotation.AllowMoving = true;
        annotation.AllowPathEditing = true;
        annotation.AllowResizing = true;
        annotation.AllowSelecting = true;

        annotation.GraphicsPath.AddLine(10, 20, 30, 30);
        chart1.Annotations.Add(annotation);

enter image description here


Solution

  • Annotations are complex and anchoring them is too.

    It starts rather simple: To anchor an Annotation you need to set its AnchorDataPoint to an existing DataPoint.

    This line does nothing like that:

    annotation.AnchorDataPoint = new DataPoint(this.chart1.Series[0]);
    

    as the newly created DataPoint is empty. Its has been added and it has values of (0d, 0d), but you probably want to keep the Annotation aligned to a real DataPoint, maybe like this..:

    annotation.AnchorDataPoint = chart1.Series[0].Points[someIndex];
    

    But there is more: There actually are two ways to anchor an Annotation:

    • Anchor it to a DataPoint or
    • Anchor it with fixed AnchorX and AnchorY values.

    (And then you can set them to fixed X & Y values, too.)

    Your code actually does both! But: anchoring the coordinates takes precedence over anchoring to a DataPoint.

    This is nice as you can combine them and first anchor to a DataPoint and then anchor one of the coordinates to a fixed value: say, x-value stays with the point but the y-value is maybe always at 0..

    Also note that you are adding only one line to your polyline and you don't start it at (0,0) but at (10,20) which may be quite some way off the anchor..

    And then there is the issue of size and alignment of the polyline itself!

    It has a size which MSDN claims is given in pixels. This is nonsense. Instead it is given in value units of the two respective Axes. You can see this when you resize the Chart the Annotation will resize as well; see the screenshot!

    Now for the GraphicsPath and its points: Those are given in percent of the Size of the Annotation. To get a feeling for this add a test annotation path that encloses the whole area:

     annotation.GraphicsPath.AddRectangle(new Rectangle(0, 0, 100, 100));
    

    Here is a screenshot of what we have got:

    enter image description here

    As you can see the most logical alignment is TopLeft and after translating the line to (0,0) it would stick right into the point.

    Note that I have added a 2nd Series to make the anchor data point stand out.. - Also note that while the Annotation size is a square (10,10) is is stretched horizontally along with the whole chart.

    This is the full code I used:

    PolylineAnnotation annotation = new PolylineAnnotation();
    annotation.AxisX = chart1.ChartAreas[0].AxisX;
    annotation.AxisY = chart1.ChartAreas[0].AxisY;
    
    annotation.Height = 10;
    annotation.Width = 10;
    annotation.LineWidth = 3;
    annotation.StartCap = LineAnchorCapStyle.None;
    annotation.EndCap = LineAnchorCapStyle.None;
    annotation.Alignment = ContentAlignment.TopLeft;
    annotation.AnchorAlignment = ContentAlignment.TopLeft;
    
    annotation.X = annotation.Y = annotation.AnchorX = annotation.AnchorY = double.NaN;
    
    DataPoint dp = chart1.Series[0].Points[33];
    annotation.AnchorDataPoint = dp;
    chart1.Series[1].Points.AddXY(dp.XValue, dp.YValues[0]);  // my red points series
    
    annotation.AllowAnchorMoving = true;
    annotation.AllowMoving = true;
    annotation.AllowPathEditing = true;
    annotation.AllowResizing = true;
    annotation.AllowSelecting = true;
    
    annotation.GraphicsPath.AddLine(10, 20, 30, 30);
    Rectangle r = new Rectangle(0, 0, 100, 100);
    annotation.GraphicsPath.AddRectangle(r);
    
    chart1.Annotations.Add(annotation);
    

    Also note that just to make sure no wrong anchors are active I have reset the X/Y and the AnchorX/Y values by setting them to double.NaN! This is not really needed here, as those are the defaults anyway..

    Here btw is another post on the topic!