Reputation: 61
I am learning JavaScript, coming from eight years of Python experience, and as an exercise I made a Mandelbrot renderer that generates the fractal and uses putImageData
to update the canvas from left to right one single-pixel column at a time.
I found that with this approach the visible image in the browser only updates when the full-screen calculation is complete (rather than seeing it appear gradually from left to right as I wanted). I understand that it is the expected behaviour, so I decided to add the "scan-line" animation by using requestAnimationFrame
. (something like seen here: Christian Stigen Larsen renderer)
My expectation is that lighter calculations should render faster (as the next frame is available sooner) and higher-iteration calculations should render slower. What I found with my implementation is that the scan-line is consistently slow.
I have isolated this issue from anything to do with my Mandelbrot calculations, as this behaviour also happens for the minimal case below. I am running this on Chrome 83 and see the canvas populate very slowly at a constant rate (approx 30 pixels per second) from left to right.
Is my implementation of rAF incorrect or are my expectations wrong? The renderer I linked to uses setTimeout()
to animate, but I read that it is a widely discouraged practice these days.
How should I implement a left-to-right scan update of my canvas at the highest available frame-rate (I am not worried about limiting it at the moment)?
EDIT: For clarity, the code below draws a single thin rectangle at every frame request by rAF, and takes exactly the same amount of time to paint the full canvas as a 100-iteration Mandelbrot render.
This suggest to me that the slowness of it is not due to amount of calculations taking place between frames.
const canvas = document.querySelector('.myCanvas');
const width = window.innerWidth;
const height = window.innerHeight;
const ctx = canvas.getContext('2d');
function anim(timestamp, i) {
if (i < width) {
ctx.fillRect(i, 0, 1, height);
window.requestAnimationFrame(function(timestamp) {
anim(timestamp, i + 1);
})
}
}
ctx.fillStyle = 'rgb(0,0,0)';
window.requestAnimationFrame(function(timestamp) {
anim(timestamp, 0);
});
<!DOCTYPE html>
<html lang="en">
<head>
<canvas class="myCanvas">
<p>Add suitable fallback here.</p>
</canvas>
<script src="slow%20rAF.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
<meta charset="UTF-8">
<title>Mandelbrot</title>
</head>
<body>
</body>
</html>
Upvotes: 0
Views: 249
Reputation: 7399
There is no 'faster' requestAnimationFrame.
Generally the answer to this is to separate calcuations from rendering. Ideally the calculations happen off of the main thread and rendering is handled on the main thread. Even without threading you should be able to find a way to do the calculations outside of the RAF, and just have the RAF render the pixels.
Upvotes: 2