Draw a ECG signal

Hello,
How to draw an ECG signal in a moving window ?
Thx,
Christophe

Tagged:

Posts

  • mattleibowmattleibow ZAXamarin Team Xamurai

    Hi Christophe,

    I am assuming you are talking about "electrocardiography"?

    In this case you probably want to draw a path, which you will construct using the data points (if any) or just random ups and downs. Then you can paint and request a repaint to keep a continuous update:

    public var DoPaint(object sender, SKPaintSurfaceEventArgs)
    {
        // draw ...
    
        // request repaint
        canvasView.InvalidateSurface();
    
        // or, if you don't have access to the view, just use sender
        ((SKCanvasView)sender).InvalidateSurface();
    }
    

    This will make the paint event similar to a game loop, which you can use to move the drawing by either using new points of the path, or translating the drawing matrix:

    canvas.Translate(-10, 0); // move the drawing 10 pixels to the left
    
  • cjacquelcjacquel FRMember ✭✭✭

    Hello,
    I would like to use the Translate instruction, but its not working :

    e.Surface.Canvas.Translate(-10, 0);
    After the drawPath.
    Could you help?
    Thx

  • mattleibowmattleibow ZAXamarin Team Xamurai

    The Translate was more of an example. What you will need to do is use it in a draw loop:

    int xOffset = 0;
    
    public var DoPaint(object sender, SKPaintSurfaceEventArgs e)
    {
        // move the canvas a bit
        e.Surface.Canvas.Translate(xOffset, 0);
    
        // tile the path / draw ...
    
        // prepare for next frame
        xOffset -= 10;
        if (xOffset < -canvasView.Width)
            xOffset = 0;
    
        // request repaint
        canvasView.InvalidateSurface();
    }
    

    Rather than just doing -= 10, you probably will want to calculate the delta time so that the animation is smooth and consistent.

  • cjacquelcjacquel FRMember ✭✭✭

    Its working but the advance si sometime jerky. Could you help ?

    Thx

  • mattleibowmattleibow ZAXamarin Team Xamurai

    Do you have something I could have a look at?

    It might be that you are doing too much on the UI thread... what is happening in the paint cycle? If at all possible, your project, or a simplified example would be very helpful.

  • cjacquelcjacquel FRMember ✭✭✭
    edited February 2017

    Hello,
    In the Xaml

      <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
        <views:SKCanvasView x:Name="myCanvas" PaintSurface="myPaintECG" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
      </StackLayout>
    

    In the Cs:

     Xamarin.Forms.Device.StartTimer(TimeSpan.FromMilliseconds(200), dispatcherTimer_Tick);
    

    To fill the Array every 200 ms. An Redraw.
    Then the draw function :

    void myPaintECG2(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
    {
        e.Surface.Canvas.Clear(new SKColor(255, 255, 255));
        SKMatrix firstTranslateM = SKMatrix.MakeTranslation(-10, 0);
        m_path.Transform(firstTranslateM);
    
        // Fill the Path
    ... 
        using (var paint = new SKPaint())
        {
              paint.IsAntialias = true;
              paint.Color = new SKColor(0x00, 0x00, 0xFF);
              paint.StrokeCap = SKStrokeCap.Round;
              paint.StrokeWidth = 2;
              paint.Style = SKPaintStyle.Stroke;
             e.Surface.Canvas.DrawPath(m_path, paint);
         };
    }
    

    Thx,

  • mattleibowmattleibow ZAXamarin Team Xamurai

    I think the issue was that your time was to high and the distance each tick too far. As a result, it was "jumpy". I tried this and it looked smooth:

    public partial class MainPage : ContentPage
    {
        private readonly SKPath path;
        private readonly SKPaint paint;
    
        private SKMatrix translation;
    
        public MainPage()
        {
            InitializeComponent();
    
            // create a path
            path = new SKPath();
            path.MoveTo(0, 60);
            path.LineTo(80, 140);
            path.MoveTo(80, 60);
            path.LineTo(0, 140);
    
            // create the paint
            paint = new SKPaint();
            paint.IsAntialias = true;
            paint.Color = new SKColor(0x00, 0x00, 0xFF);
            paint.StrokeCap = SKStrokeCap.Round;
            paint.StrokeWidth = 6;
            paint.Style = SKPaintStyle.Stroke;
    
            translation = SKMatrix.MakeIdentity();
        }
    
        protected override void OnAppearing()
        {
            base.OnAppearing();
    
            // start the animation
            Device.StartTimer(TimeSpan.FromMilliseconds(5), OnTimerTick);
        }
    
        private bool OnTimerTick()
        {
            translation.TransX += -2;
            if (translation.TransX < -path.Bounds.Width)
            {
                translation.TransX = canvasView.CanvasSize.Width + path.Bounds.Width;
            }
    
            canvasView.InvalidateSurface();
    
            return true;
        }
    
        private void OnPainting(object sender, SKPaintSurfaceEventArgs e)
        {
            var surface = e.Surface;
            var canvas = surface.Canvas;
    
            // clear the last drawing
            canvas.Clear(SKColors.White);
    
            // move the canvas on, instead of moving the path
            canvas.Concat(ref translation);
    
            // draw the path
            canvas.DrawPath(path, paint);
        }
    }
    
  • mattleibowmattleibow ZAXamarin Team Xamurai

    Also, if it is possible on your target devices, try using SKGLView for even better performance.

  • cjacquelcjacquel FRMember ✭✭✭

    Hello;
    I use Android; SKGLView is for IOS ?
    Thx

  • cjacquelcjacquel FRMember ✭✭✭
    edited February 2017

    Hello
    I use

       <views:SKGLView x:Name="myCanvas" PaintSurface="myPaint" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
    
            void myPaintECG2(SKPaintGLSurfaceEventArgs e)
            {
        ...
    
    

    But I have the Error :

    Xamarin.Forms.Xaml.XamlParseException: Position 8:39. Method myPaint does not have the correct signature

    Could you help ?
    Thx

  • mattleibowmattleibow ZAXamarin Team Xamurai

    @cjacquel You can use both SKCanvasView and SKGLView on iOS, Android and UWP.

    Your myPaint method must have the signature (I think you are missing the first arg, sender):

    void myPaint (object sender, SKPaintGLSurfaceEventArgs e)
    {
        // paint!
    }
    
  • ravidarji1290ravidarji1290 Member ✭✭

    Hi ,
    How to increase Height of ECG Signal in this sloution.

    public partial class MainPage : ContentPage
    {
    private readonly SKPath path;
    private readonly SKPaint paint;

    private SKMatrix translation;
    
    public MainPage()
    {
        InitializeComponent();
    
        // create a path
        path = new SKPath();
        path.MoveTo(0, 60);
        path.LineTo(80, 140);
        path.MoveTo(80, 60);
        path.LineTo(0, 140);
    
        // create the paint
        paint = new SKPaint();
        paint.IsAntialias = true;
        paint.Color = new SKColor(0x00, 0x00, 0xFF);
        paint.StrokeCap = SKStrokeCap.Round;
        paint.StrokeWidth = 6;
        paint.Style = SKPaintStyle.Stroke;
    
        translation = SKMatrix.MakeIdentity();
    }
    
    protected override void OnAppearing()
    {
        base.OnAppearing();
    
        // start the animation
        Device.StartTimer(TimeSpan.FromMilliseconds(5), OnTimerTick);
    }
    
    private bool OnTimerTick()
    {
        translation.TransX += -2;
        if (translation.TransX < -path.Bounds.Width)
        {
            translation.TransX = canvasView.CanvasSize.Width + path.Bounds.Width;
        }
    
        canvasView.InvalidateSurface();
    
        return true;
    }
    
    private void OnPainting(object sender, SKPaintSurfaceEventArgs e)
    {
        var surface = e.Surface;
        var canvas = surface.Canvas;
    
        // clear the last drawing
        canvas.Clear(SKColors.White);
    
        // move the canvas on, instead of moving the path
        canvas.Concat(ref translation);
    
        // draw the path
        canvas.DrawPath(path, paint);
    }
    

    }

Sign In or Register to comment.