react-native-canvas
react-native-canvas copied to clipboard
Flickering during animation
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 slowsetTimeout
- 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
andcanvas.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>
);
}
}
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!
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?
Hey @zhiqiangx, sure you can! I'd be happy to review it.
Same issue calling drawImage
Any news ?
Came across the same flickering problem, any updates or helpful tips?
Currently, I don't have a solution for this except not awaiting when drawing the frame. If someone figures it out let me know!
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>
@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?
Same problem! It flickers quite heavily on iOS too.
+1 still on android 11
It's blinking a lot on Android too. T_T
Still flickering, but only on Android :(