Blog

Styling Annotations

In our blog post Introducing Annotations, we looked into the different ways of creating and deleting annotations from the chart and how we can interact with them. In this blog post, we will take a closer look at how we can style annotations. Annotations are only available in the premium version of Visiblox charts.

Annotation Elements

Each annotation consists of an AnnotationElement and a MovingElement. The AnnotationElement is what we see when we are not interacting with the annotation - the normal element - whereas the MovingElement is an extra element rendered on top of the AnnotationElement when we are interacting with the annotation (dragging/editing/clicking etc). For example, the MovingElement of the LineAnnotation is a much thicker, semi-transparent line which makes clicking the annotation easier. In most of the predefined annotations, the AnnotationElement and the MovingElement have the same shape but a different style. Some examples are displayed below:


normal & interacting line annotation

normal & interacting text annotation

normal & interacting callout text annotation

Element Styles

Both the AnnotationElement and the MovingElement have different styles applied to them depending on the state in which the annotation is in. The possible states are: normal (no interaction), selected, highlighted/moving and creationand the element styles are:

  • AnnotationElementStyle: the style applied to the AnnotationElement when the annotation is at the normal state.
  • AnnotationElementSelectedStyle: the style applied to the AnnotationElement when the annotation is selected.
  • AnnotationElementCreationStyle: the style applied to the AnnotationElement when the annotation is being created. This style is only useful when creating annotations using the AnnotationBehaviour, not when the annotations are added programmatically.
  • MovingElementStyle: the style applied to the MovingElement when the annotation is highlighted or moving.
  • MovingElementCollapsedStyle: the style applied to the MovingElement when no interaction takes place or when the annotation is in either the normal, selected and creation state. Typically, it will either be collapsed or invisible.

Applying Custom Styles

Now that we've taken a bit of a closer look at the elements and their styles, we will look into the different ways we can apply a custom style. We can either create a custom style for one of the element styles discussed above or create a complete annotation style - provide a custom style for all of the element styles. The custom style creation can either be done from code or from xaml. If you want your custom style to be applied to all the annotations of the same type, you can create an implicit style. In the following sections we will explore each of the options separately, but first let's look at how we select the target type of each style.

Selecting the TargetType

As we already mentioned, the AnnotationElement is the visual element normally displayed and the MovingElement is usually the same type of element displayed on top of the AnnotationElement. The more complex annotations, like the CalloutTextAnnotation, have a different TargetType for the AnnotationElement and the MovingElement. Here is a list for all the predefined annotations:

  • Line, HorizontalLine, HorizontalLineWithValue, VerticalLine, VerticalLineWithValue: the TargetType for all the element styles is Line.
  • Rectangle, Ellipse: the TargetType is Shape.
  • EventAnnotation: the TargetType is EventAnnotationControl. The EventAnnotationControl consists of a Line and a Border that contains a TextBlock.
  • TextAnnotation: the TargetType for the AnnotationElement is TextAnnotationControl and for the MovingElement is TextAnnotationHighlightElement. The TextAnnotationControl consists of a TextBox and the TextAnnotationHighlightElement represents the rectangle outlining the TextBox. In order to change it's style, you need to set the property TextRectangleStyle where the TargetType should be Path.
  • CalloutTextAnnotation: the TargetType for the AnnotationElement is CalloutTextAnnotationControl and for the MovingElement is CalloutTextAnnotationHighlightElement. The CalloutTextAnnotationControl is a TextAnnotationControl with a Line and a Point. The Line connects the TextBox with the Point. In order to style the Line, you need to set the LineStyle of the CalloutTextAnnotationControl where the TargetType is Line and in order to style the Point, you need to set the PointStyle where the TargetType is Shape (by default it's an ellipse but you can change that by providing your own template). The CalloutTextAnnotationHighlightElement is a TextAnnotationHighlightElement with a Line that can be styled by setting the LineStyle property.

Custom Element Styles

Creating a custom style for one of the element styles is the easiest and fastest way to change the styling of a specific state of an annotation. For example, let's create a custom style for the normal state of a RectangleAnnotation from code:

Setting styles from code
Style normal = new Style(typeof(Shape));
normal.Setters.Add(new Setter(Shape.FillProperty, new SolidColorBrush(Colors.LightGray)));
normal.Setters.Add(new Setter(Shape.StrokeProperty, new SolidColorBrush(Colors.DarkGray)));
normal.Setters.Add(new Setter(Shape.StrokeThicknessProperty, 1));

And assign it to a RectangleAnnotation:

RectangleAnnotation rect = new RectangleAnnotation(point1, point2);
rect.IsInteractionEnabled = true;
rect.AnnotationElementStyle = normal;

The annotation now uses the default styles for the selected and highlight/moving states, and the custom style for the normal state. Let's create a custom style for the other states as well and assign them to the corresponding styles:

Style selected = new Style(typeof(Shape));
selected.Setters.Add(new Setter(Shape.StrokeThicknessProperty, 3));
selected.Setters.Add(new Setter(Shape.FillProperty, new SolidColorBrush(Colors.Blue)));

Style moving = new Style(typeof(Shape));
moving.Setters.Add(new Setter(Shape.StrokeProperty, new SolidColorBrush(Colors.Yellow)));
moving.Setters.Add(new Setter(Shape.StrokeThicknessProperty, 12));
moving.Setters.Add(new Setter(Shape.FillProperty, new SolidColorBrush(Colors.Transparent)));

Style movingCollapsed = new Style(typeof(Shape));
movingCollapsed.Setters.Add(new Setter(Shape.VisibilityProperty, Visibility.Collapsed));

rect.AnnotationElementSelectedStyle = selected;
rect.MovingElementStyle = moving;
rect.MovingElementCollapsedStyle = movingCollapsed;
Setting styles from XAML

Alternatively, you can set the same styles from XAML. In the following example we will be styling a LineAnnotation from XAML. First, we need to define the custom styles in our Resources:

<Style TargetType="Line" x:Key="CustomLineAnnotationElementStyle">
    <Setter Property="StrokeThickness" Value="2"/>            
    <Setter Property="Stroke" Value="Magenta" />
</Style>
 
<Style TargetType="Line" x:Key="CustomLineAnnotationElementSelectedStyle">
    <Setter Property="StrokeThickness" Value="2"/>
    <Setter Property="Stroke" Value="Red" />
</Style>
 
<Style TargetType="Line" x:Key="CustomLineAnnotationMovingElementStyle">
    <Setter Property="StrokeThickness" Value="12"/>
    <Setter Property="Stroke" Value="Orange" />
    <Setter Property="Opacity" Value="0.3" />
    <Setter Property="StrokeStartLineCap" Value="Round"/>
    <Setter Property="StrokeEndLineCap" Value="Round"/>            
</Style>
 
<Style TargetType="Line" x:Key="CustomLineAnnotationMovingElementCollapsedStyle">
    <Setter Property="Stroke" Value="Transparent" />
</Style>

Then, we need to set them from code to the various element styles of a LineAnnotation:

LineAnnotation line = new LineAnnotation(point1, point2);
line.IsInteractionEnabled = true;

line.AnnotationElementStyle = Resources["CustomLineAnnotationElementStyle"] as Style;
line.AnnotationElementSelectedStyle = Resources["CustomLineAnnotationElementSelectedStyle"] as Style;
line.MovingElementStyle = Resources["CustomLineAnnotationMovingElementStyle"] as Style;
line.MovingElementCollapsedStyle = Resources["CustomLineAnnotationMovingElementCollapsedStyle"] as Style;

Custom Annotation Style

Setting each element style separately is useful when we want to use the default annotation styles but change only the normal state style, for example. If we want to override all the default element styles, then we can create an annotation style and assign it to it's Style property. So, for the RectangleAnnotation example described above, we would not need to set all the individual styles separately but wrap them all in one style:

//We don't need to it separately
//rect.AnnotationElementStyle = normal;
//rect.AnnotationElementSelectedStyle = selected;
//rect.MovingElementStyle = moving;
//rect.MovingElementCollapsedStyle = movingCollapsed;

Style s = new Style(typeof(RectangleAnnotation));
s.Setters.Add(new Setter(RectangleAnnotation.AnnotationElementStyleProperty, normal));
s.Setters.Add(new Setter(RectangleAnnotation.AnnotationElementSelectedStyleProperty, selected));
s.Setters.Add(new Setter(RectangleAnnotation.MovingElementStyleProperty, moving));
s.Setters.Add(new Setter(RectangleAnnotation.MovingElementCollapsedStyleProperty, movingCollapsed));

rect.Style = s; 

And for the LineAnnotation example, we would need to add to the Resources one more style:

<Style TargetType="charts:LineAnnotation" x:Key="CustomLineAnnotationStyle">
    <Setter Property="AnnotationElementStyle" Value="{StaticResource CustomLineAnnotationElementStyle}" />
    <Setter Property="AnnotationElementSelectedStyle" Value="{StaticResource CustomLineAnnotationElementSelectedStyle}" />
    <Setter Property="MovingElementStyle" Value="{StaticResource CustomLineAnnotationMovingElementStyle}" />
    <Setter Property="MovingElementCollapsedStyle" Value="{StaticResource CustomLineAnnotationMovingElementCollapsedStyle}" />
</Style>

And then set only one style from code:

line.Style = Resources["CustomLineAnnotationStyle"] as Style;

IMPORTANT: Setting a custom style to the annotation will override all the element styles so you need to define them all or you run the risk of your annotation not showing anything in the states that have not been defined. Also, you will notice that in both examples, the MovingElementCollapsedStyle is either collapsed or invisible.

Implicit Annotation Style

Setting the styles from code behind makes the code look quite messy, and I guess that it is most commonly used when we just want to provide one custom element style. Defining the styles in XAML and applying them to the annotation's Style property is a cleaner way of providing our own styles but we still have to apply them to each annotation separately. But what happens if we want to apply a custom style to all the annotations of the same type?

The answer to that is to use implicit styles. An implicit style is a style defined in XAML as a Resource, but it does not have a Resource key and so it is applied to all the elements of the specified TargetType. So, in the LineAnnotation example, if we don't provide a Key all the LineAnnotations will have the custom style:

<Style TargetType="charts:LineAnnotation">
    <Setter Property="AnnotationElementStyle" Value="{StaticResource CustomLineAnnotationElementStyle}" />
    <Setter Property="AnnotationElementSelectedStyle" Value="{StaticResource CustomLineAnnotationElementSelectedStyle}" />
    <Setter Property="MovingElementStyle" Value="{StaticResource CustomLineAnnotationMovingElementStyle}" />
    <Setter Property="MovingElementCollapsedStyle" Value="{StaticResource CustomLineAnnotationMovingElementCollapsedStyle}" />
</Style>

From version 2.1 of the premium edition of Visiblox charts, we include the default xaml files which contain the styles and templates applied to all the elements of Visiblox charts. The generic.DefaultTheme.xaml file contains all the annotation styles applied by default (implicit styles).

Example

In the following example, you can see the above code in action. Specifically, you can create RectangleAnnotations with the default style and custom style applied, as well as LineAnnotations where the implicit style is applied. The source code of the example can be downloaded here and you will need to add a reference to the premium Visiblox charts library in order to compile it.

Conclusion

In this blog post we explored the different ways of styling annotations, either from code or from XAML. Specifically, we looked at the annotation elements (the elements that make up each annotation), the styles provided for each of them and the impact each of these styles has in the different states that an annotation can be in.

Comments

The TargetType of the VerticalLine is wrong, it has to be Canvas, not Line or you will get an InvalidOperationException.
 
Posted by Ignacio Soler
Hi Ignacio, Whilst the Annotations provided do extend Canvas, if you want to style them correctly you need to style the AnnotationElement and MovingElement instead, which have the TargetTypes described above. Styles should be assigned to properties on the Annotation (e.g. AnnotationElementStyle etc.) rather than applied in any other way. Regards, Partha
 
Posted by Partha Lal

Post a comment