Dundas Chart for Windows Forms
Annotations
See Also Send comments on this topic.
Using Dundas Chart > Enterprise Edition Features > Annotations



Glossary Item Box

Overview

Enterprise Only Feature.

Annotations are commonly used to comment, or elaborate on, chart elements like data points. However, annotations can also be used to draw custom shapes, and are far easier to work with than one of the paint-related events like PrePaint or PostPaint, or using GDI+ drawing routines. This topic discusses annotations, and gives you techniques, and code samples to help you work with them.

 

Annotation Types and Descriptions

 

Annotation Description Points to Note
Line

A line, which has optional start and end caps.

For arrow annotations consider using the Arrow type instead, which allows for greater control over the arrow.

  • Width and height, which can be negative, control the angle and length of line and should be set.
  • Has Right and Bottom properties, which can be used at run-time only, instead of Width and Height properties (this is available to all annotations).
  • Has Anchor method, which can be used at run-time to anchor line to two data points (this is available to all annotations).

Vertical Line

A vertical line.

  • Height controls length of line, and can be a negative value.

Horizontal Line

A horizontal line.

  • Width controls length of line, and can be a negative value.

Text

Text annotation.

  • Cannot have a border. For text with a border use another annotation (e.g. Rectangle, Ellipse, etc.).
  • A text annotation could replace various labels (e.g. data point label).
Rectangle A rectangle, with optional text.
  • Can be used to show text with a rectangular border.
Ellipse An ellipse, with optional text.
  • Can be used to show text with an elliptical border.
Arrow An arrow.
  • Has more control over the arrow (e.g. size) compared to a Line annotation.
Border3D Annotation that has a 3D border skin, with optional text.
  • Good for medium to large-sized annotations (with small annotations, the skin may not leave room for the text).
Callout Callout, with optional text.
  • Numerous styles available (e.g. cloud, rectangle, etc.).
Polyline Polyline, which consists of multiple lines. 
  • The multiple lines, and their positions, are controlled by the Path property.
  • FreeDrawPlacement  property allows for free-form drawing.
  • Coordinates of the path points are relative to the bounding rectangle of the polyline, and not to the entire chart image.
Polygon Polygon, which consists of multiple lines that form a closed figure.
  • The multiple lines, and their positions, are controlled by the PathPoints property, which consists of points that control the line paths.
  • FreeDrawPlacement  property allows for free-form drawing.
  • Coordinates of the path points are relative to the bounding rectangle of the polyline, and not to the entire chart image.
Group Group itself is an annotation, so it has all common annotation properties.
  • Annotations property is a collection property that stores other annotations.
Image Displays an image as an annotation.
  • Image can be tiled, scaled, or unscaled.

 

Coordinate System

By default, annotations are positioned using relative coordinates, with "0,0" representing the top-left corner, and "100,100" being the bottom-right corner of the chart image. It is also possible to switch from this relative coordinate system to a system that uses axis values. With an axis coordinate system, X and Y, which represent the position of the top-left corner of an annotation, are set using X axis and Y axis values, instead of a value that ranges from 0-100.

 

There are several ways to use axis values when specifying the position and size of an annotation, including the following:

  1. By explicitly setting the AxisX, AxisY or both of these annotation properties to a ChartArea object's AxisX, and AxisY properties.
  2. By anchoring the annotation to a data point using the AnchorDataPoint property. In this case its positioning is automatically calculated.

 

Other Considerations

 

Positioning and Sizing

All annotations have X and Y property, that determines:

 

The  X and Y property can be explicitly set using either axis values or relative coordinates (see Coordinate System section above). Alternatively, X and Y can have a value of Not Set (programmatically represented by Double.NaN), in which case, if the annotation is anchored, then these values are automatically calculated.

 

Note
In regards to positioning annotations, remember that line-type annotations require special consideration.

 

Annotations can be positioned in a number of ways, including:

  1. Anchoring them to a data point using the  AnchorDataPoint property
  2. Anchoring them to a point within the chart image, which can be set using the AnchorX and AnchorY properties. The X and Y property should not be set because normally they are automatically calculated.
  3. Explicitly positioning them using either axis values or coordinates that are relative to the entire chart image (see Coordinate System section above).

 

The following are some points to note in regards to working with annotations:

  • The  AnchorAlignment property determines the alignment of an annotation's bounding rectangle.
  • An annotation can be offset by using the AnchorOffsetX and AnchorOffsetY properties.

  • The size of an annotation is controlled by the Width and Height properties. Annotations with text (AnnotationRectangle, etc.) can have their Width and Height properties not set (represented by Double.NaN), in which case their size is automatically scaled to fit their text.

  • Polyline and Polygon Annotations: The coordinates of the data point's paths, that are stored in the PathPoint collection, are relative to the bounding rectangle of the polyline or polygon, not to the entire chart image. When relative coordinates are used "0,0" is the position of the top-left corner of the polyline bounding rectangle, and "100,100" is the position of the bottom-right corner of the polyline.

     

    Note
    The PathPoints property is only available at design-time. To set the path at run-time use the Path property.

     

  • Group annotations: The coordinates of the child annotations that are stored in the Annotations collection property are relative to the bounding rectangle of the group, and not to the entire chart. 
  • Annotations that display text will be sized automatically if their width and height have not been set (they have their default value of Double.NaN). This size set is the minimal size necessary to display the text.
  • If the  ClipToChartArea property is set to an existing chart area, then only the portion of an annotation that falls within that chart area will be drawn.

 

Anchoring an Annotation

When an annotation is anchored, it is "glued" to the point onto which it is anchored, and this anchor point can be positioned either inside or outside of the annotation. The user may move the annotation at runtime, to move the anchor point in this manner, the end-user selects the point using the left mouse button, and moves the anchor point by dragging the mouse. This functionality is controlled by the AllowAnchorMoving property. If the position of an annotation is explicitly set (using code, or at run-time by the end-user) then the annotation will no longer be glued to its anchor point. This occurs because the position properties no longer have a value of "Not set" (i.e. Double.NaN).

When an annotation object is anchored to a series' data point, special keywords can be used in the annotation's Text, and Tooltip, properties to access data point data like X and Y values, labels, and others. Refer to the following table for a listing of all available keywords:

 

Keyword  Replaced By 
#VALX

X value of data point.

#VAL, #VALY, #VALY2, #VALY3, ...

Y values of the data point.

#SER

Series name.

#LABEL

Data point label.

#INDEX Data point index.
#PERCENT Percentage of the data point Y value.
#TOTAL Total of all Y values in the series.
#LEGENDTEXT Legend text.

 

The keywords shown above act as variables that can be used to represent chart data in a flexible and changing way.

The AnchorX and AnchorY properties have precedence over the AnchorDataPoint property.

 

Note
Three-point break, Kagi, Renko, and Point Figure charts do not support data point anchors.

 

End-User Interaction

You can allow your end-user to interact with annotations, or even create new annotations by providing the necessary functionality to do so. This functionality come via a set of methods and properties, that can be set to make your chart annotations fully interactive.

The following is a list of properties that all annotations possess:

  • Tooltip property that allows for the display of tooltips.
  • The AllowResizing property determines whether or not an annotation can be resized using its GUI resize handles. In other words, it is still possible to resize the annotation programmatically, or in the case of polylines and polygons, by using the path point handles.
  • The AllowTextEditing property controls whether or not end-users can edit an annotation's text at run-time.

 

Please note the following items concerning text editing:

  • Text editing is only allowed if AllowTextEditing property is set to true.

  • If the end-user presses the ESC key, this will end the text edit operation without saving any changes.

  • If the end-user presses the Enter key within a single line text, this will end the editing session. If multiline text is supported, then it will insert a carriage return/new line into the text string. To end the editing session for an annotation with multiline text, the end-user must click outside of the annotation.

  • Annotations are event driven objects, and as such, provide you with the opportunity to use event handlers in your code.

 

Working With Annotations

Grouping

An annotation group is similar to other annotations in that it has appearance properties, a bounding rectangle, position and size properties, etc. The major difference is that an annotation group has an  Annotations collection property, that is used to store its child annotation objects.

 

The purpose of annotation groups is two-fold:

  • You can group your annotations so they can be moved as a single entity.
  • Common appearance properties can be applied to all grouped annotations at once.

 

The appearance properties of an annotation group are not applied to the group's bounding rectangle, rather, they are applied to its child annotations. However, child annotation appearance properties do have precedence over the group appearance properties.

The position of a child annotation is always relative to the group's location, and not relative to the entire chart image. "0,0" represents the position of the top-left corner of the group, and "100,100" is the position of the bottom-right corner of the group.

 

Certain properties of child annotations will not have any effect, and therefore should not be set.

The following properties have no effect when set in a child annotation:

  • SizeAlwaysRelative: Has no effect since size is always relative to group annotation.
  • AnchorDataPoint, AnchorAlignment, AnchorX, AnchorY, AnchorOffsetX, AnchorOffsetY.

 

SmartLabels™

SmartLabels™ are labels that reposition themselves to prevent collision with other labels, thereby improving their readability.

To use SmartLabels™ with annotations perform the following:

  • Anchor the annotation to either a data point using AnchorDataPoint, or to a fixed point within the chart using the AnchorX and AnchorY properties.

 

Note
The annotation must be anchored in order to use SmartLabels™.

 

  • Make sure that the position of the annotation is not explicitly set. At design-time make sure the X and Y properties have a value of "Not set". At run-time the X and Y properties can be set to Double.NaN.
  • If you do not want any other label to collide with your annotations, then those labels must also have their SmartLabel™ properties enabled. 

 

3D Considerations

  • Annotations displayed in 3D charts do not have any control over their depth.
  • Annotations that are anchored to a data point will have the same depth as the data point they are anchored to. In all other cases annotations are displayed on the front surface of the 3D chart area.
  • Annotations that are anchored to the 3D Pie chart will not display correctly.

 

Creating Annotations

Creating Annotations at Run-Time

Annotations can be created at run-time in one of two ways, either:

  1. Programmatically, using either the Annotations.Add method, or one of the Annotations.AddPolyline, Annotations.AddLine, or other methods.

 

Creating Annotations Programmatically

The Add method requires that the annotation object be initialized before it is used, however, the AddLine, and AddRectangle methods have parameters that are used in the object's constructor to initialize it.

Example

This example demonstrates how to add annotations using the generic Add method.

Visual Basic Copy Code
Imports Dundas.Charting.WinControl
 ... 
 
' Create new polyline annotation, and specify its name. 
Dim myPolyline As PolylineAnnotation = New PolylineAnnotation 
myPolyline.Name = "myPolyline" 

' Create array of points. 
Dim Points(3) As Point 
Points(0) = New Point(6, 6) 
Points(1) = New Point(3, 5) 
Points(2) = New Point(1, 1) 

' Set axis properties, so that position (set by Point object coordinates set above) 
' uses axis coordinates. 
myPolyline.AxisX = chart1.ChartAreas(0).AxisX 
myPolyline.AxisY = chart1.ChartAreas(0).AxisY 

' Add array of Point objects to polyline's Path property (defines path).
myPolyline.Path.AddLines(Points) 

' Add initialized Polyline object to Annotations collection. 
Chart1.Annotations.Add(myPolyline) 

' Redraw Chart.
Chart1.Invalidate()

C# Copy Code
using Dundas.Charting.WinControl; 
  ... 
// Create new polyline annotation, and specify its name. 
Dundas.Charting.WinControl.PolylineAnnotation myPolyline = new PolylineAnnotation(); 
myPolyline.Name = "myPolyline"; 

// Create array of points. 
Point[] Points = new Point[3]; 
Points[0] = new Point(6,6); 
Points[1] = new Point(3,5); 
Points[2] = new Point(1,1); 

// Set axis properties, so that position (set by Point object coordinates set above) 
// uses axis coordinates.
myPolyline.AxisX = chart1.ChartAreas[0].AxisX; 
myPolyline.AxisY = chart1.ChartAreas[0].AxisY; 

// Add array of Point objects to polyline's Path property (defines path). 
myPolyline.Path.AddLines(Points); 

// Add initialized Polyline object to Annotations collection. 
chart1.Annotations.Add(myPolyline);

// Redraw chart. 
chart1.Invalidate();

 

Example

This example demonstrates how to add a Polyline annotation to the Chart.

Visual Basic Copy Code
Imports Dundas.Charting.WinControl 
Imports System.Drawing.Drawing2D
 ... 
 
'Create array of Point structures. 
Dim Points(3) As Point 
Points(0) = New Point(6, 6) 
Points(1) = New Point(3, 5) 
Points(2) = New Point(1, 1) 

' Create GraphicsPath object, add points. 
Dim myGraphicsPath As GraphicsPath = New GraphicsPath 
myGraphicsPath.AddLines(Points) 

' Add polyline annotation.
Chart1.Annotations.AddPolyline("myPolyline", myGraphicsPath) 

' Have annotation use axis coordinates. 
Chart1.Annotations("myPolyline").AxisX = Chart1.ChartAreas(0).AxisX 
Chart1.Annotations("myPolyline").AxisY = Chart1.ChartAreas(0).AxisY 

' Force repainting of chart.
Chart1.Invalidate()

C# Copy Code
using Dundas.Charting.WinControl; 
using System.Drawing.Drawing2D; 
   ... 
   
//Create array of Point structures. 
Point[] myPoints = new Point[3]; 
myPoints[0]= new Point(6,6); 
myPoints[1] = new Point(3,5);
myPoints[2] = new Point(1,1);

// Create GraphicsPath object, add points. 
GraphicsPath myGraphicsPath = new GraphicsPath(); 
myGraphicsPath.AddLines(myPoints); 

// Add polyline annotation.
chart1.Annotations.AddPolyline("myPolyline",myGraphicsPath); 

// Have annotation use axis coordinates. 
chart1.Annotations["myPolyline"].AxisX = chart1.ChartAreas[0].AxisX; 
chart1.Annotations["myPolyline"].AxisY = chart1.ChartAreas[0].AxisY; 

// Force repainting of chart.
chart1.Invalidate();

 

Working With Z-Order

By default, annotations are drawn on top of data points, markers, and other chart elements. The z-order determines which items are displayed upper-most in the image drawn. To change the z-order of an annotation, the annotation needs to be custom painted in the PrePaint event, which repeatedly fires for the ChartPicture object, Series, and ChartArea objects. The element that fired the event is the found in the sender parameter of the PrePaint event handler, therefore you can check to see that this is the element that you want to work with, before executing code on it.

 

Note
Annotations that are drawn using the PrePaint event handler are not added to the Annotations collection. Instead they are painted behind the relevant chart element.

 

To change the z-order of your Series, you must also use the PrePaint event. Since this event fires just before a chart element is drawn, it provides us with an opportunity to draw an annotation behind a chart element. We must be certain that the event was fired by the element that we want to work (e.g. a data point, and therefore the data series that the point belongs to), therefore we must check to see who the sender object of the event was. If it is the element that we are looking for, then we can create an annotation object, and proceed to draw it on our chart. To do this, we only need one annotation object, we just re-initialize it and use it to do our drawing.

Example

This example demonstrates how to use the PrePaint event to draw annotations behind a series named "Series3". Since the PrePaint event is raised more than once for the series, we use a boolean named bExecuted to make sure that our drawing code executes once, and only once. Also, a boolean named bDrawBehindPoints is set to true in a button's Click event, which we also check before code execution.

Visual Basic Copy Code
Imports Dundas.Charting.WinControl
  ... 
  
' Boolean that is used to make sure code in PrePaint event only executes once. 
Dim bExecuted As Boolean = False 

' Boolean set by button click event. 
Dim bDrawBehindPoints As Boolean = False 
  ...
  
Private Sub Chart1_PrePaint(ByVal sender As Object, ByVal e As Dundas.Charting.WinControl.ChartPaintEventArgs) 
Handles Chart1.PrePaint 
' Check to see if event is being raised for a Series object. 
If TypeOf sender Is Dundas.Charting.WinControl.Series 
 Then 
 ' Check to see if the Series has a name of "Series3". Notice we use a boolean named bExecuted to make sure 
 ' this code executes once and only once (event is raised more than once for Series3). Also, bDrawBehindPoints 
 ' is set to true in a button's Click event. 

 If bDrawBehindPoints And sender.Name = "Series3" And bExecuted = False Then 
  ' use one Annotation object, just keep repainting it with new location and text. 
  Dim myRectAnnotation As RectangleAnnotation = New Dundas.Charting.WinControl.RectangleAnnotation 

  ' Use axis coordinates.
  myRectAnnotation.AxisX = Chart1.ChartAreas(0).AxisX 
  myRectAnnotation.AxisY = Chart1.ChartAreas(0).AxisY 

  ' Draw one annotation per data point in series. We set the X and Y properties to position the 
  ' annotation, set the text to the Y value of the cooresponding data point, and then paint it. 
  Dim i As Int16 For i= 0 To Chart1.Series("Series3").Points.Count - 1 
  myRectAnnotation.X = i + 1 
  myRectAnnotation.Y = Chart1.Series("Series3").Points(i).YValues(0) + 1
  myRectAnnotation.Text = "Value: " + Chart1.Series("Series3").Points(i).YValues(0).ToString
  myRectAnnotation.Paint(Chart1, e.ChartGraphics) Next bExecuted = True 
 End If
End If 
End Sub 
  ... 
' Reset boolean, so that annotation will be drawn if chart is repainted. 
Private Sub Chart1_PostPaint(ByVal sender As Object, ByVal e As Dundas.Charting.WinControl.ChartPaintEventArgs) 
Handles Chart1.PostPaint
  bExecuted = False 
End Sub

C# Copy Code
using Dundas.Charting.WinControl;
 ... 
 
// Boolean set by button click event.
private bool bDrawBehindPoints = false; 

// Boolean that is used to make sure code in PrePaint event only executes once. 
private bool bExecuted = false; 
 ...

private void chart1_PrePaint(object sender, Dundas.Charting.WinControl.ChartPaintEventArgs e) 
{
  // Check to see if event is being raised for a Series object. 
  if(sender is Dundas.Charting.WinControl.Series) 
  { 
    // Check to see if the Series has a name of "Series3". Notice we use a boolean named bExecuted to make sure 
    // this code executes once and only once (event is raised more than once for Series3). Also, bDrawBehindPoints 
    // is set to true in a button's Click event. 

    if(bDrawBehindPoints && ((Dundas.Charting.WinControl.Series)sender).Name == "Series3" 
      && bExecuted == false) 
      { 
        // use one Annotation object, just keep repainting it with new location and text.
        Dundas.Charting.WinControl.RectangleAnnotation myRectAnnotation = 
                new Dundas.Charting.WinControl.RectangleAnnotation(); 

        // Use axis coordinates.
        myRectAnnotation.AxisX = chart1.ChartAreas[1].AxisX; 
        myRectAnnotation.AxisY = chart1.ChartAreas[1].AxisY; 

        // Draw one annotation per data point in series. We set the X and Y properties to position the 
        // annotation, set the text to the Y value of the cooresponding data point, and then paint it.
        for(int i = 0; i < chart1.Series[2].Points.Count;i++) 
        { 
          // Series is indexed (X values all set to zero), so use indices, not X values of data points 
          myRectAnnotation.X = i + 1;

          // Set height of annotation. 
          myRectAnnotation.Y = chart1.Series[2].Points[i].YValues[0] + 1;
          myRectAnnotation.Text = "Value: " + chart1.Series[2].Points[i].YValues[0];
          myRectAnnotation.Paint(chart1,e.ChartGraphics); 
        } 
        bExecuted = true; 
      }       
    } 
  }
   ... 
// Reset boolean, so that annotation will be drawn if chart is repainted. 
private void chart1_PostPaint(object sender, Dundas.Charting.WinControl.ChartPaintEventArgs e) 
{
  if(sender is ChartPicture)
  { 
    bExecuted = false; 
  }
}

See Also

©2009. All Rights Reserved.