How to create delay in fractal drawing recursive function(如何在分形图递归函数中创建延迟)
问题描述
我正在使用Eloquent JavaScript中遇到的一个分形图递归函数。
我想为每个分支的绘制设置延迟-以便在我修补此函数及其参数时可视化分支/递归调用的流。
我在下面的代码中使用setTimeout
的方法似乎不起作用,我不知道原因。
我希望cx.fillRect(...)
为每个延迟绘制一个分支;而不是堆叠在队列中,因为setTimeout
之外没有其他代码可等待。
在下面,我首先包括了正在工作的分形图html/js代码,没有尝试包括延迟。第二段代码是我试图包含setTimeout
延迟。
我使用setTimeout
的非工作尝试:
数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假">
<canvas width="600" height="300"></canvas>
<script>
let cx = document.querySelector("canvas").getContext("2d");
function branch(length, angle, scale) {
setTimeout(() => {
cx.fillRect(0, 0, 1, length);
if (length < 8) return;
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();
}, 80);
}
cx.translate(300, 0);
branch(60, 0.5, 0.8);
</script>
无延迟工作代码:
数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假"><canvas width="600" height="300"></canvas>
<script>
let cx = document.querySelector("canvas").getContext("2d");
function branch(length, angle, scale) {
cx.fillRect(0, 0, 1, length);
if (length < 8) return;
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();
}
cx.translate(300, 0);
branch(60, 0.5, 0.8);
</script>
推荐答案
尝试setTimeout
会延迟第一次调用,然后为其子树生成两个具有相同超时的递归调用,导致它们相互遍历,以此类推。
所有递归调用都需要等待整个左子树完成绘制,然后才能移到右子树,这也需要在调用可以解析之前完成,并让父级继续下一个操作(右子树或解析)。不能让两个不同的调用帧同时处理同一画布堆栈。
我会使用Promise来实现这一点;这允许您管理setTimeout
的顺序,并使用sleep
函数设置所需的延迟,基本上是简化的setTimeout
。
const sleep = ms => new Promise(
resolve => setTimeout(resolve, ms)
);
const cx = document.querySelector("canvas").getContext("2d");
async function branch(length, angle, scale) {
cx.fillRect(0, 0, 1, length);
if (length < 8) {
return;
}
await sleep(50); // delay in ms, good to make into a parameter
cx.save();
cx.translate(0, length);
cx.rotate(-angle);
await branch(length * scale, angle, scale);
cx.rotate(2 * angle);
await branch(length * scale, angle, scale);
cx.restore();
}
cx.translate(300, 0);
branch(60, 0.5, 0.8);
<canvas width="600" height="300"></canvas>
为了进行比较,下面介绍了如何在没有承诺的情况下使用回调来完成此操作,每个子级都会触发该回调,以通知其父级已完成操作,这样父级就知道何时绘制下一个子树或解析:
数据-lang="js"数据-隐藏="真"数据-控制台="真"数据-巴贝尔="假">const cx = document.querySelector("canvas").getContext("2d");
function branch(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);
<canvas width="600" height="300"></canvas>
因为您是在画布上制作动画,所以可以考虑使用requestAnimationFrame
循环访问绘制每个帧的生成器函数。RAF提供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;
(function drawFrame(time) {
!done && requestAnimationFrame(drawFrame);
if (time && lastTime === 0) {
lastTime = time;
}
else if (lastTime > 0 && time >= lastTime + speedMs) {
({done} = branchGen.next());
lastTime += speedMs;
}
})();
<canvas width="600" height="300"></canvas>
这篇关于如何在分形图递归函数中创建延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在分形图递归函数中创建延迟
基础教程推荐
- 在 JS 中获取客户端时区(不是 GMT 偏移量) 2022-01-01
- 在for循环中使用setTimeout 2022-01-01
- 角度Apollo设置WatchQuery结果为可用变量 2022-01-01
- 悬停时滑动输入并停留几秒钟 2022-01-01
- Karma-Jasmine:如何正确监视 Modal? 2022-01-01
- 响应更改 div 大小保持纵横比 2022-01-01
- 动态更新多个选择框 2022-01-01
- 我什么时候应该在导入时使用方括号 2022-01-01
- 有没有办法使用OpenLayers更改OpenStreetMap中某些要素 2022-09-06
- 当用户滚动离开时如何暂停 youtube 嵌入 2022-01-01