How To Create Delay In Fractal Drawing Recursive Function
Solution 1:
The attempt with setTimeout
delays the first call, then spawns two recursive calls for its subtrees that have the same timeout, leading to them walking over each other, and so on down.
All recursive calls need to wait for the entire left subtree to complete drawing before moving on to the right one, which also needs to complete before the call can resolve and let the parent proceed to its next operation (right subtree or resolving). You can't have two different call frames messing with the same canvas stack at the same time.
I'd use promises to do this; this lets you manage the ordering of setTimeout
s and set the desired delay with a sleep
function, basically a promisified setTimeout
.
constsleep = ms => newPromise(
resolve =>setTimeout(resolve, ms)
);
const cx = document.querySelector("canvas").getContext("2d");
asyncfunctionbranch(length, angle, scale) {
cx.fillRect(0, 0, 1, length);
if (length < 8) {
return;
}
awaitsleep(50); // delay in ms, good to make into a parameter
cx.save();
cx.translate(0, length);
cx.rotate(-angle);
awaitbranch(length * scale, angle, scale);
cx.rotate(2 * angle);
awaitbranch(length * scale, angle, scale);
cx.restore();
}
cx.translate(300, 0);
branch(60, 0.5, 0.8);
<canvaswidth="600"height="300"></canvas>
For comparison, here's how you could do it without promises using a callback that each child fires to signal to its parent that it's done, so the parent knows when to draw the next subtree or resolve:
const cx = document.querySelector("canvas").getContext("2d");
functionbranch(length, angle, scale, done) {
cx.fillRect(0, 0, 1, length);
if (length < 8) {
done && done();
return;
}
setTimeout(() => {
cx.save();
cx.translate(0, length);
cx.rotate(-angle);
branch(length * scale, angle, scale, () => {
cx.rotate(2 * angle);
branch(length * scale, angle, scale, () => {
cx.restore();
done && done();
});
});
}, 50);
}
cx.translate(300, 0);
branch(60, 0.5, 0.8);
<canvaswidth="600"height="300"></canvas>
Since you're doing an animation on canvas, you might consider using requestAnimationFrame
to loop through a generator function that draws each frame. RAF offers better-quality animations than setTimeout
.
const cx = document.querySelector("canvas").getContext("2d");
function *branch(length, angle, scale) {
cx.fillRect(0, 0, 1, length);
if (length < 8) {
return;
}
yield;
cx.save();
cx.translate(0, length);
cx.rotate(-angle);
yield *branch(length * scale, angle, scale);
cx.rotate(2 * angle);
yield *branch(length * scale, angle, scale);
cx.restore();
}
cx.translate(300, 0);
const branchGen = branch(60, 0.5, 0.8);
const speedMs = 50;
let lastTime = 0;
let done = false;
(functiondrawFrame(time) {
!done && requestAnimationFrame(drawFrame);
if (time && lastTime === 0) {
lastTime = time;
}
elseif (lastTime > 0 && time >= lastTime + speedMs) {
({done} = branchGen.next());
lastTime += speedMs;
}
})();
<canvaswidth="600"height="300"></canvas>
Post a Comment for "How To Create Delay In Fractal Drawing Recursive Function"