New to Telerik UI for WinForms? Download free 30-day trial

How to Rotate the Labels for BarSeries

Environment

Product Version Product Author
2022.2.622 RadChartView for WinForms Desislava Yordanova

Description

The article aims to demonstrate a sample approach how to rotate the labels for the BarSeries. Consider the following example:


public RadForm1()
{
    InitializeComponent();
    this.radChartView1.LabelFormatting += RadChartView1_LabelFormatting;
    Telerik.WinControls.UI.BarSeries barSeries = new Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName");
    barSeries.ShowLabels = true;
    barSeries.DataPoints.Add(new CategoricalDataPoint(77, "Harley"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(28, "White"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(43, "Smith"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(11, "Jones"));
    barSeries.DataPoints.Add(new CategoricalDataPoint(18, "Marshall"));
    this.radChartView1.Series.Add(barSeries);
}

private void RadChartView1_LabelFormatting(object sender, ChartViewLabelFormattingEventArgs e)
{
    CategoricalDataPoint categoricalDataPoint = e.LabelElement.DataPoint as CategoricalDataPoint;
    e.LabelElement.Text = categoricalDataPoint.Category + " " + categoricalDataPoint.Value;
}


Sub New()
    InitializeComponent()

    AddHandler Me.RadChartView1.LabelFormatting, AddressOf RadChartView1_LabelFormatting
    Dim barSeries As New Telerik.WinControls.UI.BarSeries("Performance", "RepresentativeName")
    barSeries.ShowLabels = True
    barSeries.DataPoints.Add(New CategoricalDataPoint(77, "Harley"))
    barSeries.DataPoints.Add(New CategoricalDataPoint(28, "White"))
    barSeries.DataPoints.Add(New CategoricalDataPoint(43, "Smith"))
    barSeries.DataPoints.Add(New CategoricalDataPoint(11, "Jones"))
    barSeries.DataPoints.Add(New CategoricalDataPoint(18, "Marshall"))
    Me.RadChartView1.Series.Add(barSeries)


End Sub

Private Sub RadChartView1_LabelFormatting(sender As Object, e As ChartViewLabelFormattingEventArgs)
    Dim categoricalDataPoint As CategoricalDataPoint = TryCast(e.LabelElement.DataPoint, CategoricalDataPoint)
    e.LabelElement.Text = categoricalDataPoint.Category & " " & categoricalDataPoint.Value
End Sub

Default BarSeries' labels

rotate-labels-for-barseries 001

Solution

In order to rotate the labels for the bar elements, it is necessary to use a custom renderer and implement our own BarLabelElementDrawPart:

Make sure that you subscribe to the CreateRenderer event before populating the chart with data.


private void RadChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e)
{
    e.Renderer = new CustomCartesianRenderer(e.Area as CartesianArea);
}

public class CustomCartesianRenderer : CartesianRenderer
{
    public CustomCartesianRenderer(CartesianArea area)
        : base(area)
    {
    }
    protected override void InitializeSeriesLabels()
    {
        base.InitializeSeriesLabels();


        for (int i = 0; i <= this.DrawParts.Count - 1; i++)
        {
            BarLabelElementDrawPart labelPart = this.DrawParts[i] as BarLabelElementDrawPart;
            if (labelPart != null)
                this.DrawParts[i] = new CustomBarLabelElementDrawPart((BarSeries)labelPart.Element, this);
        }
    }
}

public class CustomBarLabelElementDrawPart : BarLabelElementDrawPart
{
    public CustomBarLabelElementDrawPart(BarSeries series, IChartRenderer renderer)
        : base(series, renderer)
    {
    }

    public override void Draw()
    {
        Graphics graphics = this.Renderer.Surface as Graphics;

        RadGdiGraphics radGraphics = new RadGdiGraphics(graphics);

        foreach (DataPointElement dataPointElement in this.Element.Children)
        {
            CategoricalDataPoint categoricalDataPoint = dataPointElement.DataPoint as CategoricalDataPoint;
            RadRect slot = categoricalDataPoint.LayoutSlot;
            RectangleF barBounds = new RectangleF(System.Convert.ToSingle((this.OffsetX + slot.X)), 
                System.Convert.ToSingle((this.OffsetY + slot.Y)), System.Convert.ToSingle(slot.Width), System.Convert.ToSingle(slot.Height));
            float realHeight = barBounds.Height * dataPointElement.HeightAspectRatio;
            barBounds.Y += barBounds.Height - realHeight;
            barBounds.Height = realHeight;
            barBounds = this.AdjustBarDataPointBounds(dataPointElement, barBounds);
            barBounds.Width = Math.Max(barBounds.Width, 1.0F);
            object state = radGraphics.SaveState();
            int horizontalTranslate = System.Convert.ToInt32((barBounds.X + barBounds.Width / (double)2));
            int verticalTranslate = System.Convert.ToInt32((barBounds.Y + barBounds.Height / (double)2));
            float angle = System.Convert.ToSingle(this.Element.LabelRotationAngle) % 360.0F;

            if (angle != 0)
            {
                radGraphics.TranslateTransform(horizontalTranslate, verticalTranslate);
                radGraphics.RotateTransform(angle);
                radGraphics.TranslateTransform(-horizontalTranslate, -verticalTranslate);
            }

            var labelText = categoricalDataPoint.Category + " " + categoricalDataPoint.Value;

            SizeF desiredSize = graphics.MeasureString(labelText, dataPointElement.Font);
            FillPrimitiveImpl fill = new FillPrimitiveImpl(dataPointElement, null);
            fill.PaintFill(radGraphics, 0, System.Drawing.Size.Empty, barBounds);
            BorderPrimitiveImpl border = new BorderPrimitiveImpl(dataPointElement, null);
            border.PaintBorder(radGraphics, 0, System.Drawing.Size.Empty, barBounds);
            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;

            RectangleF labelRect = new RectangleF(new PointF(barBounds.X + dataPointElement.Padding.Left + 
                (barBounds.Width - desiredSize.Width) / 2, barBounds.Y - desiredSize.Width), new SizeF(desiredSize.Width, desiredSize.Height));

            horizontalTranslate = System.Convert.ToInt32((labelRect.X + labelRect.Width / (double)2));
            verticalTranslate = System.Convert.ToInt32((labelRect.Y + labelRect.Height / (double)2));

            radGraphics.TranslateTransform(horizontalTranslate, verticalTranslate);
            radGraphics.RotateTransform(-90);
            radGraphics.TranslateTransform(-horizontalTranslate, -verticalTranslate);

            graphics.DrawString(labelText, dataPointElement.Font, Brushes.Black, labelRect, format);
            if (angle != 0)
                radGraphics.ResetTransform();

            radGraphics.RestoreState(state);
        }
    }

    private RectangleF AdjustBarDataPointBounds(DataPointElement point, RectangleF bounds)
    {
        RectangleF barBounds = bounds;

        if (point.BorderBoxStyle == BorderBoxStyle.SingleBorder || point.BorderBoxStyle == BorderBoxStyle.OuterInnerBorders)
        {
            barBounds.X += point.BorderWidth - System.Convert.ToInt32(((point.BorderWidth - 1.0F) / (double)2.0F));
            barBounds.Width -= point.BorderWidth;
            barBounds.Y += point.BorderWidth - System.Convert.ToInt32(((point.BorderWidth - 1.0F) / (double)2.0F));
            barBounds.Height -= point.BorderWidth;
        }
        else if (point.BorderBoxStyle == BorderBoxStyle.FourBorders)
        {
            barBounds.Y += 1;
            barBounds.Height -= 1;
            barBounds.X += 1;
            barBounds.Width -= 1;
        }

        if (((CartesianRenderer)this.Renderer).Area.Orientation == System.Windows.Forms.Orientation.Horizontal)
            barBounds.X -= 1;

        return barBounds;
    }
}


Private Sub RadChartView1_CreateRenderer(sender As Object, e As ChartViewCreateRendererEventArgs) Handles RadChartView1.CreateRenderer
    e.Renderer = New CustomCartesianRenderer(TryCast(e.Area, CartesianArea))

End Sub

Public Class CustomCartesianRenderer
    Inherits CartesianRenderer

    Public Sub New(ByVal area As CartesianArea)
        MyBase.New(area)
    End Sub
    Protected Overrides Sub InitializeSeriesLabels()
        MyBase.InitializeSeriesLabels()


        For i As Integer = 0 To Me.DrawParts.Count - 1
            Dim labelPart As BarLabelElementDrawPart = TryCast(Me.DrawParts(i), BarLabelElementDrawPart)
            If labelPart IsNot Nothing Then

                Me.DrawParts(i) = New CustomBarLabelElementDrawPart(CType(labelPart.Element, BarSeries), Me)
            End If
        Next
    End Sub
End Class

Public Class CustomBarLabelElementDrawPart
    Inherits BarLabelElementDrawPart

    Public Sub New(ByVal series As BarSeries, ByVal renderer As IChartRenderer)
        MyBase.New(series, renderer)
    End Sub

    Public Overrides Sub Draw()
        Dim graphics As Graphics = TryCast(Me.Renderer.Surface, Graphics)

        Dim radGraphics As RadGdiGraphics = New RadGdiGraphics(graphics)

        For Each dataPointElement As DataPointElement In Me.Element.Children
            Dim categoricalDataPoint As CategoricalDataPoint = TryCast(dataPointElement.DataPoint, CategoricalDataPoint) 
            Dim slot As RadRect = categoricalDataPoint.LayoutSlot
            Dim barBounds As RectangleF = New RectangleF(CSng((Me.OffsetX + slot.X)), CSng((Me.OffsetY + slot.Y)), CSng(slot.Width), CSng(slot.Height))
            Dim realHeight As Single = barBounds.Height * dataPointElement.HeightAspectRatio
            barBounds.Y += barBounds.Height - realHeight
            barBounds.Height = realHeight
            barBounds = Me.AdjustBarDataPointBounds(dataPointElement, barBounds)
            barBounds.Width = Math.Max(barBounds.Width, 1.0F)
            Dim state As Object = radGraphics.SaveState()
            Dim horizontalTranslate As Integer = CInt((barBounds.X + barBounds.Width / 2))
            Dim verticalTranslate As Integer = CInt((barBounds.Y + barBounds.Height / 2))
            Dim angle As Single = CSng(Me.Element.LabelRotationAngle) Mod 360.0F

            If angle <> 0 Then
                radGraphics.TranslateTransform(horizontalTranslate, verticalTranslate)
                radGraphics.RotateTransform(angle)
                radGraphics.TranslateTransform(-horizontalTranslate, -verticalTranslate)
            End If

            Dim labelText = categoricalDataPoint.Category & " " & categoricalDataPoint.Value

            Dim desiredSize As SizeF = graphics.MeasureString(labelText, dataPointElement.Font)
            Dim fill As FillPrimitiveImpl = New FillPrimitiveImpl(dataPointElement, Nothing)
            fill.PaintFill(radGraphics, 0, System.Drawing.Size.Empty, barBounds)
            Dim border As BorderPrimitiveImpl = New BorderPrimitiveImpl(dataPointElement, Nothing)
            border.PaintBorder(radGraphics, 0, System.Drawing.Size.Empty, barBounds) 
            Dim format As StringFormat = New StringFormat()
            format.Alignment = StringAlignment.Center

            Dim labelRect As New RectangleF(New PointF(barBounds.X + dataPointElement.Padding.Left + (barBounds.Width - desiredSize.Width) / 2,
                                                       barBounds.Y - desiredSize.Width),
                                            New SizeF(desiredSize.Width, desiredSize.Height))

            horizontalTranslate = CInt((labelRect.X + labelRect.Width / 2))
            verticalTranslate = CInt((labelRect.Y + labelRect.Height / 2))

            radGraphics.TranslateTransform(horizontalTranslate, verticalTranslate)
            radGraphics.RotateTransform(-90)
            radGraphics.TranslateTransform(-horizontalTranslate, -verticalTranslate)

            graphics.DrawString(labelText, dataPointElement.Font, Brushes.Black, labelRect, format) 
            If angle <> 0 Then
                radGraphics.ResetTransform()
            End If

            radGraphics.RestoreState(state)
        Next 
    End Sub

    Private Function AdjustBarDataPointBounds(ByVal point As DataPointElement, ByVal bounds As RectangleF) As RectangleF
        Dim barBounds As RectangleF = bounds

        If point.BorderBoxStyle = BorderBoxStyle.SingleBorder OrElse point.BorderBoxStyle = BorderBoxStyle.OuterInnerBorders Then
            barBounds.X += point.BorderWidth - CInt(((point.BorderWidth - 1.0F) / 2.0F))
            barBounds.Width -= point.BorderWidth
            barBounds.Y += point.BorderWidth - CInt(((point.BorderWidth - 1.0F) / 2.0F))
            barBounds.Height -= point.BorderWidth
        ElseIf point.BorderBoxStyle = BorderBoxStyle.FourBorders Then
            barBounds.Y += 1
            barBounds.Height -= 1
            barBounds.X += 1
            barBounds.Width -= 1
        End If

        If (CType(Me.Renderer, CartesianRenderer)).Area.Orientation = System.Windows.Forms.Orientation.Horizontal Then
            barBounds.X -= 1
        End If

        Return barBounds
    End Function 
End Class

Rotated BarSeries' labels

rotate-labels-for-barseries 002

See Also

In this article