react-native-canvas icon indicating copy to clipboard operation
react-native-canvas copied to clipboard

Flickering during animation

Open andySigler opened this issue 5 years ago • 12 comments

I am testing out react-native-canvas to use for an animation. However, I am unable to draw a simple animation without a flickering. It looks as if the canvas is rendering to the display halfway through the drawing functions, but that's just a guess.

Here is a video showing my test. The left view is in the browser, and the right view is with react-native-canvas in a simulator (btw it behaves the same when ran on device). You will notice the animation works just fine when ran in a browser.

I have tried a few combinations of changes to see what would remove the flickering, but none have removed the flickering:

  • using requestAnimationFrame and also a slow setTimeout
  • removing any calls to fillRect that would erase the entire canvas
  • only erasing (drawing over) the spaces on the canvas that have updated
  • removing references to canvas.width and canvas.height inside draw functions
  • commenting and uncommenting different parts of the code/drawing functions

And my code is below:

import React, { Component } from 'react';
import { View, Dimensions } from 'react-native';

import Canvas from 'react-native-canvas';


function drawCircle(context, color, x, y) {
  context.strokeStyle = color;
  context.lineWidth = 5; // hard-coded width
  context.beginPath();
  context.arc(x, y, 30, 0, Math.PI * 2, false);  // hard-coded radius
  context.closePath();
  context.stroke();
}


function updateBouncingCircleCoords(canvas, pos, step) {
  pos.x += step.x;
  if (pos.x < 0 || pos.x > canvas.width) {
    step.x *= -1;
    pos.x += step.x;
  }
  pos.y += step.y;
  if (pos.y < 0 || pos.y > canvas.height) {
    step.y *= -1;
    pos.y += step.y;
  }
  return [pos, step]
}


function drawLoop(canvas, context, pos, step) {
  [pos, step] = updateBouncingCircleCoords(canvas, pos, step);
  context.save();
  context.fillStyle = 'gray';
  context.fillRect(0, 0, canvas.width, canvas.height);
  drawCircle(context, 'blue', pos.x, pos.y);
  drawCircle(context, 'red', canvas.width / 2, canvas.height / 2);
  context.restore();
  requestAnimationFrame(() => drawLoop(canvas, context, pos, step));
}


export default class HelloWorldApp extends Component {

  initCanvas(c) {
    const canvas = c
    const thisWindow = Dimensions.get('window');
    canvas.width = thisWindow.width;
    canvas.height = thisWindow.height;
    const pos = {x: 0, y: 0};
    const step = {x: 5, y: 5};
    pos.x = canvas.width / 2;
    pos.y = canvas.height / 2;
    context = canvas.getContext('2d');
    requestAnimationFrame(() => drawLoop(canvas, context, pos, step));
  }

  render() {
    return (
      <View>
        <Canvas ref={this.initCanvas}/>
      </View>
    );
  }
}

andySigler avatar Oct 28 '19 20:10 andySigler

Hey, thank you for trying React Native Canvas and reporting this issue so well. I am not quite sure what is causing the flickering but it will require some debugging effort I can not fit into my schedule at the moment. Leads for solution and PRs are welcome though!

iddan avatar Oct 29 '19 08:10 iddan

Hi, @iddan ,I think the problem is caused by React Native Canvas takes too much time in WebView message, and I want to create a function which will allows any Canvas updates in an event loop to be batched together in CanvasRenderingContext2D.js .Can I submit a PR?

zhiqiangx avatar Dec 10 '19 09:12 zhiqiangx

Hey @zhiqiangx, sure you can! I'd be happy to review it.

iddan avatar Dec 10 '19 09:12 iddan

Same issue calling drawImage

Any news ?

ajouve avatar Jan 07 '20 18:01 ajouve

Came across the same flickering problem, any updates or helpful tips?

Shudog avatar Feb 19 '20 01:02 Shudog

Currently, I don't have a solution for this except not awaiting when drawing the frame. If someone figures it out let me know!

iddan avatar Feb 19 '20 11:02 iddan

I've found a dirty solution for this on Anderoid. This was an App killer until I discovered a solution.

I added a second canvas (with fixed props so it shouldn't redraw) to get 2 canvases side by side at the same height. I noticed that only the left canvas flickers!

So the fix is to add a dummy canvas with minimal width. Flicker is now completely gone, at least at the low frame rates I'm using. Code below. LtyLabel, and LtyLabelAxes contain a react-native-canvas.

          <View style={{flex: 80, flexDirection: 'row'}}>
            <View style={{flexDirection: 'row', backgroundColor: '#020202', flex: 1, margin: 0}}>
              <LtyLabelAxes style={{flex: 1}} graphSeparation = {8/(48+48)}
                minPres = {0} maxPres = {1} minFlow = {0} maxFlow = {1}
              />
            </View>
            <View style={{flexDirection: 'row', backgroundColor: '#020202', flex: 10, margin: 0}}>
              <LtyLabelAxes style={{flex: 1}} graphSeparation = {8/(48+48)}
                minPres = {this.minPres} maxPres = {this.maxPres} minFlow = {this.minFlow} maxFlow = {this.maxFlow}
              />
            </View>
            <View style={{flexDirection: 'row', backgroundColor: '#020202', flex: 390, margin: 0}}>
              <LtyLabel style={{flex: 1}} newData={this.state.newData} graphSeparation = {8/(48+48)}
                force={this.state.forceUpdate} arraySize={this.arraySize}
                minPres = {this.minPres} maxPres = {this.maxPres} minFlow = {this.minFlow} maxFlow = {this.maxFlow}
              />
            </View>
          </View>

briangmitie avatar May 08 '20 15:05 briangmitie

@iddan First of all, thank you very much for this library, my app wouldn't be possible without it! However, I have now run into the same problem discussed here: clearing the canvas and redrawing causes extreme flickering, at least on Android (I cannot test this on iOS, unfortunately.) Have you made any progress on this?

@zhiqiangx Did you ever get this working witht he solution you described above?

matthiasferch avatar Feb 20 '21 18:02 matthiasferch

Same problem! It flickers quite heavily on iOS too.

Nesh108 avatar Jun 22 '21 15:06 Nesh108

+1 still on android 11

joonas-yoon avatar Nov 13 '21 13:11 joonas-yoon

It's blinking a lot on Android too. T_T

hangju21a avatar Jan 27 '22 08:01 hangju21a

Still flickering, but only on Android :(

dblas-softserve avatar Dec 20 '22 06:12 dblas-softserve