Quick Start Guide > Tutorials (Xamarin.iOS) > Tutorial 07 - Working with Annotations
Tutorial 07 - Working with Annotations

In the prior tutorials we have familiarized with a great and powerful SciChart functionality. In this one we are going to play around with one more cool thing SciChart supports - Annotations!

We are going to build on our previous Tutorial 06 - Adding RealTime Updates to add annotations to a chart in a realtime context.
But, let's take a look at how can we add simple annotation like Line, Box or Text.

Adding simple annotations

Source code for this tutorial can be found at our Xamarin Examples Github Repository under Tutorials.iOS

Let's add simple Text annotation with "Hello SciChart world" text. To do that, we only need to create instance of TextAnnotation and attach to the scichart surface instance:

Adding Text annotation
Copy Code
var textAnnotation = new SCITextAnnotation();
textAnnotation.XAxisId = "xAxis";
textAnnotation.YAxisId = "yAxis";
textAnnotation.CoordinateMode = SCIAnnotationCoordinateMode.Relative;
textAnnotation.X1Value = 0.7;
textAnnotation.Y1Value = 0.5;
textAnnotation.Text = "Hello SciChart world";
textAnnotation.Style.TextStyle.FontSize = 18;
textAnnotation.Style.TextColor = UIColor.White;
textAnnotation.Style.BackgroundColor = UIColor.Clear;
_surface.Annotations = new SCIAnnotationCollection(new[] { textAnnotation});

Adding custom annotation

Before we will start to work on creating CustomAnnotations, let's check we are on the same page. The source code of our ViewController class should look like as follow:

ViewController class
Copy Code
using System;
using UIKit;
using SciChart.iOS.Charting;
using Foundation;
namespace AddingAnnotations
{
    public partial class ViewController : UIViewController
    {
        private SCIChartSurface _surface;
        private XyDataSeries<Double, Double> _lineDataSeries;
        private XyDataSeries<Double, Double> _scatterDataSeries;

        private SCIFastLineRenderableSeries _lineRenderableSeries;
        private SCIXyScatterRenderableSeries _scatterRenderableSeries;
        // timer, used for updating data
        private NSTimer _timer;
        // phase variable used for data slipping
        private double _phase = 0.0;
        // instance variable for counting the data points in data series
        private int _i = 0;
        public ViewController(IntPtr handle) : base(handle)
        {
        }
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            // Perform any additional setup after loading the view, typically from a nib.
            _surface = new SCIChartSurface();
            _surface.TranslatesAutoresizingMaskIntoConstraints = true;
            _surface.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
            _surface.Frame = this.View.Bounds;
            this.View.AddSubview(_surface);
            _surface.XAxes.Add(new SCINumericAxis() { GrowBy = new SCIDoubleRange(0.1, 0.1) });
            _surface.YAxes.Add(new SCINumericAxis() { GrowBy = new SCIDoubleRange(0.1, 0.1) });
            CreateDataSeries();
            CreateRenderableSeries();
            AddModifiers();
        }
        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);
            if (_timer == null)
            {
                _timer = NSTimer.CreateRepeatingScheduledTimer(0.01, (timer) =>
                {
                    _i++;
                    _lineDataSeries.Append(_i, Math.Sin(_i * 0.1 + _phase));
                    _scatterDataSeries.Append(_i, Math.Cos(_i * 0.1 + _phase));
                    _phase += 0.01;
                    _surface.ZoomExtents();
                });
            }
        }
        public override void ViewWillDisappear(bool animated)
        {
            base.ViewWillDisappear(animated);
            _timer.Invalidate();
            _timer = null;
        }
        void CreateDataSeries()
        {
            // Init line data series
            _lineDataSeries = new XyDataSeries<Double, Double>();
            // Setting fifo capacity, once new data values will be added, the old one will be removed
            _lineDataSeries.FifoCapacity = 500;
            // Naming data series, so its name will be shown in LegendModifier
            _lineDataSeries.SeriesName = "LineSeries";
            for (var i = 0; i < 500; i++)
            {
                _lineDataSeries.Append(i, Math.Sin(i * 0.1));
            }
            // Init scatter data series
            _scatterDataSeries = new XyDataSeries<Double, Double>();
            // Setting fifo capacity, once new data values will be added, the old one will be removed
            _scatterDataSeries.FifoCapacity = 500;
            // Naming data series, so its name will be shown in LegendModifier
            _scatterDataSeries.SeriesName = "ScatterSeries";
            for (var i = 0; i < 500; i++)
            {
                _scatterDataSeries.Append(i, Math.Cos(i * 0.1));
            }
            _i = _lineDataSeries.Count;
        }
        void CreateRenderableSeries()
        {
            _lineRenderableSeries = new SCIFastLineRenderableSeries();
            _lineRenderableSeries.DataSeries = _lineDataSeries;
            _scatterRenderableSeries = new SCIXyScatterRenderableSeries();
            _scatterRenderableSeries.DataSeries = _scatterDataSeries;
            _surface.RenderableSeries.Add(_lineRenderableSeries);
            _surface.RenderableSeries.Add(_scatterRenderableSeries);
        }
        void AddModifiers()
        {
            var xAxisDragmodifier = new SCIXAxisDragModifier();
            xAxisDragmodifier.DragMode = SCIAxisDragMode.Pan;
            xAxisDragmodifier.ClipModeX = SCIClipMode.None;
            var yAxisDragmodifier = new SCIYAxisDragModifier();
            yAxisDragmodifier.DragMode = SCIAxisDragMode.Pan;
            var extendZoomModifier = new SCIZoomExtentsModifier();
            var pinchZoomModifier = new SCIPinchZoomModifier();
            // Adding Rollover and Legend modifiers
            var rolloverModifier = new SCIRolloverModifier();
            var legendCollectionModifier = new SCILegendModifier();
            var groupModifier = new SCIChartModifierCollection();
            groupModifier.Add(xAxisDragmodifier);
            groupModifier.Add(yAxisDragmodifier);
            groupModifier.Add(pinchZoomModifier);
            groupModifier.Add(extendZoomModifier);
            groupModifier.Add(rolloverModifier);
            groupModifier.Add(legendCollectionModifier);
            _surface.ChartModifiers = groupModifier;
        }
        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
            // Release any cached data, images, etc that aren't in use.
        }
    }
}

And the application should work just like this:

Next: Adding the Custom Annotations to the Chart

The SciChart framework you are currantly using already has a CustomAnnotation class. This allows you to use any class inherited from UIVIew and add it to the chart. For example, let's say, we would like to have a custom "text" annotation with "Y" text and place it on every X=100 position. In this case what we need is to declare the UILabel instance and set it to the SCICustomAnnotation's contentView property, just like in the following code:

ViewController class
Copy Code
using System;
using UIKit;
using SciChart.iOS.Charting;
using Foundation;
namespace AddingAnnotations
{
    public partial class ViewController : UIViewController
    {
        private SCIChartSurface _surface;
        private XyDataSeries<Double, Double> _lineDataSeries;
        private XyDataSeries<Double, Double> _scatterDataSeries;

        private SCIFastLineRenderableSeries _lineRenderableSeries;
        private SCIXyScatterRenderableSeries _scatterRenderableSeries;
        // timer, used for updating data
        private NSTimer _timer;
        // phase variable used for data slipping
        private double _phase = 0.0;
        // instance variable for counting the data points in data series
        private int _i = 0;
        // Used to store annotations
        private SCIAnnotationCollection _annotationCollection = new SCIAnnotationCollection();
        public ViewController(IntPtr handle) : base(handle)
        {
        }
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            // Perform any additional setup after loading the view, typically from a nib.
            _surface = new SCIChartSurface();
            _surface.TranslatesAutoresizingMaskIntoConstraints = true;
            _surface.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
            _surface.Frame = this.View.Bounds;
            this.View.AddSubview(_surface);
            _surface.XAxes.Add(new SCINumericAxis() { GrowBy = new SCIDoubleRange(0.1, 0.1) });
            _surface.YAxes.Add(new SCINumericAxis() { GrowBy = new SCIDoubleRange(0.1, 0.1) });
            CreateDataSeries();
            CreateRenderableSeries();
            AddModifiers();
            _surface.Annotations = _annotationCollection;
        }
        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);
            if (_timer == null)
            {
                _timer = NSTimer.CreateRepeatingScheduledTimer(0.01, (timer) =>
                {
                    _i++;
                    _lineDataSeries.Append(_i, Math.Sin(_i * 0.1 + _phase));
                    _scatterDataSeries.Append(_i, Math.Cos(_i * 0.1 + _phase));
                    _phase += 0.01;
                    //if (_i % 100 == 0)
                    //{
                    //    var customAnnotation = new SCICustomAnnotation();
                    //    var customAnnotationContentView = new UILabel(frame: CGRect.init(x: 0, y: 0, width: 10, height: 10));
                    //    customAnnotationContentView.text = "Y";
                    //    customAnnotationContentView.backgroundColor = UIColor.lightGray;

                    //    customAnnotation.contentView = customAnnotationContentView;
                    //    customAnnotation.x1 = SCIGeneric(i);
                    //    customAnnotation.y1 = SCIGeneric(0.5);
                    //    customAnnotation.coordinateMode = .relativeY;
                    //    // adding new custom annotation into the annotationGroup property
                    //    _annotationCollection.addItem(customAnnotation);
                    //    // removing annotations that are out of visible range
                    //    let customAn = _annotationCollection.item(at: 0) as!SCICustomAnnotation;
                    //    if (customAn.x1 < Double(i) - totalCapacity)
                    //    {
                    //        // since the contentView is UIView element - we have to call removeFromSuperView method to remove it from screen
                    //        customAn.contentView.removeFromSuperview();
                    //        annotationGroup.removeItem(customAn)
                    //    }
                    //}
                    _surface.ZoomExtents();
                });
            }
        }
        public override void ViewWillDisappear(bool animated)
        {
            base.ViewWillDisappear(animated);
            _timer.Invalidate();
            _timer = null;
        }
        void CreateDataSeries()
        {
            // Init line data series
            _lineDataSeries = new XyDataSeries<Double, Double>();
            // Setting fifo capacity, once new data values will be added, the old one will be removed
            _lineDataSeries.FifoCapacity = 500;
            // Naming data series, so its name will be shown in LegendModifier
            _lineDataSeries.SeriesName = "LineSeries";
            for (var i = 0; i < 500; i++)
            {
                _lineDataSeries.Append(i, Math.Sin(i * 0.1));
            }
            // Init scatter data series
            _scatterDataSeries = new XyDataSeries<Double, Double>();
            // Setting fifo capacity, once new data values will be added, the old one will be removed
            _scatterDataSeries.FifoCapacity = 500;
            // Naming data series, so its name will be shown in LegendModifier
            _scatterDataSeries.SeriesName = "ScatterSeries";
            for (var i = 0; i < 500; i++)
            {
                _scatterDataSeries.Append(i, Math.Cos(i * 0.1));
            }
            _i = _lineDataSeries.Count;
        }
        void CreateRenderableSeries()
        {
            _lineRenderableSeries = new SCIFastLineRenderableSeries();
            _lineRenderableSeries.DataSeries = _lineDataSeries;
            _scatterRenderableSeries = new SCIXyScatterRenderableSeries();
            _scatterRenderableSeries.DataSeries = _scatterDataSeries;
            _surface.RenderableSeries.Add(_lineRenderableSeries);
            _surface.RenderableSeries.Add(_scatterRenderableSeries);
        }
        void AddModifiers()
        {
            var xAxisDragmodifier = new SCIXAxisDragModifier();
            xAxisDragmodifier.DragMode = SCIAxisDragMode.Pan;
            xAxisDragmodifier.ClipModeX = SCIClipMode.None;
            var yAxisDragmodifier = new SCIYAxisDragModifier();
            yAxisDragmodifier.DragMode = SCIAxisDragMode.Pan;
            var extendZoomModifier = new SCIZoomExtentsModifier();
            var pinchZoomModifier = new SCIPinchZoomModifier();
            // Adding Rollover and Legend modifiers
            var rolloverModifier = new SCIRolloverModifier();
            var legendCollectionModifier = new SCILegendModifier();
            var groupModifier = new SCIChartModifierCollection();
            groupModifier.Add(xAxisDragmodifier);
            groupModifier.Add(yAxisDragmodifier);
            groupModifier.Add(pinchZoomModifier);
            groupModifier.Add(extendZoomModifier);
            groupModifier.Add(rolloverModifier);
            groupModifier.Add(legendCollectionModifier);
            _surface.ChartModifiers = groupModifier;
        }
        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
            // Release any cached data, images, etc that aren't in use.
        }
    }
}

As a result we should now see an application with following behavior:

See Also