CartesianGridLineAnnotation with vertical label

5 posts, 1 answers
  1. Holger
    Holger avatar
    33 posts
    Member since:
    Jan 2015

    Posted 31 Mar Link to this post

         Hi, is there a way to control the orientation of Labels in CartesianGridLineAnnotation?

    To avoid overlapping I would like to have a vertical label on a vertical line, which looks to me like better visual design.

    But I haven't found any properties to Control simple things like orientation.

  2. Dess | Tech Support Engineer, Sr.
    Admin
    Dess | Tech Support Engineer, Sr.  avatar
    3280 posts

    Posted 02 Apr Link to this post

    Hello, Holger,   

    You can control how the label of the CartesianGridLineAnnotation is oriented by using a custom CartesianGridLineAnnotationDrawPart. You can find below a sample code snippet demonstrating how to achieve the illustrated behavior:

    public RadForm1()
    {
        InitializeComponent();
     
        this.radChartView1.CreateRenderer += radChartView1_CreateRenderer;
     
        ScatterLineSeries scatterSeries = new ScatterLineSeries();
        scatterSeries.DataPoints.Add(new ScatterDataPoint(15, 19));
        scatterSeries.DataPoints.Add(new ScatterDataPoint(18, 10));
        scatterSeries.DataPoints.Add(new ScatterDataPoint(13, 15));
        scatterSeries.DataPoints.Add(new ScatterDataPoint(10, 8));
        scatterSeries.DataPoints.Add(new ScatterDataPoint(5, 2));
        scatterSeries.PointSize = new SizeF(8, 8);
        this.radChartView1.Series.Add(scatterSeries);
        ScatterLineSeries scatterSeries2 = new ScatterLineSeries();
        scatterSeries2.DataPoints.Add(new ScatterDataPoint(2, 24));
        scatterSeries2.DataPoints.Add(new ScatterDataPoint(7, 12));
        scatterSeries2.DataPoints.Add(new ScatterDataPoint(15, 10));
        scatterSeries2.DataPoints.Add(new ScatterDataPoint(18, 22));
        scatterSeries2.DataPoints.Add(new ScatterDataPoint(20, 20));
        scatterSeries2.Shape = new RoundRectShape(1);
        scatterSeries2.PointSize = new SizeF(8, 8);
        this.radChartView1.Series.Add(scatterSeries2);
         
        CartesianGridLineAnnotation annotation1 = new CartesianGridLineAnnotation();
        annotation1.Axis = this.radChartView1.Axes[0] as CartesianAxis;
        annotation1.Value = 5.8;
        annotation1.Label = "Some text";
         
        annotation1.BorderColor = Color.Red;
        annotation1.BorderDashStyle = DashStyle.Solid;
        annotation1.BorderWidth = 1;
        this.radChartView1.Annotations.Add(annotation1);
    }
     
    private void radChartView1_CreateRenderer(object sender, ChartViewCreateRendererEventArgs e)
    {
        e.Renderer = new CustomRenderer(e.Area as CartesianArea);
    }
     
    public class CustomRenderer : CartesianRenderer
    {
        public CustomRenderer(CartesianArea area) : base(area)
        {
        }
     
        protected override void InitializeAnnotations(AnnotationDrawMode drawMode)
        {
            for (int i = 0; i < this.Area.Annotations.Count; i++)
            {
                if (this.Area.Annotations[i] is CartesianGridLineAnnotation)
                {
                    this.DrawParts.Add(new CustomCartesianGridLineAnnotationDrawPart(this.Area.Annotations[i] as CartesianGridLineAnnotation, this));
                }
            }
        }
    }
     
    public class CustomCartesianGridLineAnnotationDrawPart : CartesianGridLineAnnotationDrawPart
    {
        public CustomCartesianGridLineAnnotationDrawPart(CartesianGridLineAnnotation element, CartesianRenderer renderer) : base(element, renderer)
        {
        }
     
        public override void Draw()
        {
            FieldInfo fi = typeof(CartesianGridLineAnnotation).GetField("model", BindingFlags.Instance | BindingFlags.NonPublic);
            ChartAnnotationModel model = fi.GetValue(this.Element) as ChartAnnotationModel;
            RectangleF rect = ChartRenderer.ToRectangleF(model.LayoutSlot);
            rect.Offset(this.ViewportOffsetX, this.ViewportOffsetY);
     
            Graphics graphics = this.Renderer.Surface as Graphics;
            RadGdiGraphics radGraphics = new RadGdiGraphics(graphics);
     
            Rectangle clipRect = ChartRenderer.ToRectangle(this.Element.View.GetArea<CartesianArea>().AreaModel.PlotArea.LayoutSlot);
            clipRect.Offset((int)this.ViewportOffsetX, (int)this.ViewportOffsetY);
            graphics.SetClip(clipRect);
     
            GraphicsPath path = new GraphicsPath();
            path.AddLine(rect.Location, new PointF(rect.Right, rect.Bottom));
     
            BorderPrimitiveImpl border = new BorderPrimitiveImpl(this.Element, null);
            border.PaintBorder(radGraphics, null, path, rect);
     
            rect.Size = graphics.MeasureString(this.Element.Label, this.Element.Font);
            rect.Offset(this.Element.PositonOffset.Width + 1, this.Element.PositonOffset.Height + 1);
     
            TextParams tp = new TextParams();
            tp.textOrientation = Orientation.Vertical;
            tp.font = this.Element.Font;
            tp.foreColor = this.Element.ForeColor;
            tp.paintingRectangle = new RectangleF(rect.X, rect.Y, rect.Height, rect.Width);
            tp.text = this.Element.Label;
      
            FillPrimitiveImpl fill = new FillPrimitiveImpl(this.Element, null);
            fill.PaintFill(radGraphics, null, rect);
     
            radGraphics.DrawString(tp, new SizeF(rect.Height, rect.Width));
        }
    }


    I hope this information helps. If you need any further assistance please don't hesitate to contact me. 


    Regards,
    Dess | Tech Support Engineer, Sr.
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  3. Holger
    Holger avatar
    33 posts
    Member since:
    Jan 2015

    Posted 04 Apr in reply to Dess | Tech Support Engineer, Sr. Link to this post

    well, thank you.
    I understand the idea and the concept, but it doesn't work, and I'm wondered why it worked on your side.

    The order of execution is kind of wrong.
    In the line radChartView1.Series.Add(scatterSeries2);
    the CreateRenderer event is already invoked, it tries to measures some label or so, 

    there are about 20 levels of function calls on the call-stack all internal Telerik code.

    At this point in time, the annotations arent' created, but the InitializeAnnotation is also called immediatly in the constructor of the Renderer.

    It tried to add the series later, but this doesn't work, since the axis is not created, before the serious is added.

    I have a barseries, instead of a scatter, but I guess this will not make the difference.
    However, there is a problem with the order of commands and events.

    Probably the Drawpart has to be added at another place (another time).

    something like radchartview.Area.Renderer exists, but is not public accessible.

  4. Answer
    Dess | Tech Support Engineer, Sr.
    Admin
    Dess | Tech Support Engineer, Sr.  avatar
    3280 posts

    Posted 04 Apr Link to this post

    Hello, Holger,    

    It is necessary to subscribe to the CreateRenderer event before populating RadChartView. Thus, we will ensure that the custom rendering for the annotation and its label will be performed. I have attached my sample project for your reference. Could you please give it a try on your end and see how it works? 

    Should you have further questions please let me know.

     Regards,
    Dess | Tech Support Engineer, Sr.
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  5. Holger
    Holger avatar
    33 posts
    Member since:
    Jan 2015

    Posted 04 Apr Link to this post

    Well I found it.

    This "InitializeAnnotations" is called 4 times.

    The first 2 times there are no existing annotations, I had a crash, while your kind of stated "if an annotation exists than ..."

    But since the method is called twice with annotations, there are 2 drawparts created for the same element (also in your sample).

    It doesn't seem to disturb the layout logic, it's just probably not the perfect way as DrawParts should be used.

    I would expect, adding multiple Drawparts for the same Element causes exceptions; well it didn't.

     

    However, your support compensates the leak of documentation.

    Just by reading documentation you never get the approch of accessing private Properties via Reflection and stuff like this.

     

Back to Top