Reputation: 1384
I am using p5.js to create growing tree in html5 convas.
I want to generate following tree smoothly instead of at once.
function setup(){
createCanvas(600,600);
noLoop();
}
function draw(){
background(255);
strokeWeight(10);
translate(width/2,height-20);
branch(0);
}
function branch(depth){
if (depth < 10) {
line(0,0,0,-height/10); // draw a line going up
{
translate(0,-height/10); // move the space upwards
rotate(random(-0.05,0.05)); // random wiggle
if (random(1.0) < 0.6){ // branching
rotate(0.3); // rotate to the right
scale(0.8); // scale down
push(); // now save the transform state
branch(depth + 1); // start a new branch!
pop(); // go back to saved state
rotate(-0.6); // rotate back to the left
push(); // save state
branch(depth + 1); // start a second new branch
pop(); // back to saved state
}
else { // no branch - continue at the same depth
branch(depth);
}
}
}
}
function mouseReleased(){
redraw();
}
html, body {
margin: 0;
padding: 0;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
<!DOCTYPE html><html><head>
</head>
<body>
<script src="sketch.js"></script>
</body></html>
I am using setTimeout function to delay each recursive branch to grow the tree smoothly.
But getting following unexpected shape
function setup(){
createCanvas(600,600);
noLoop();
}
function draw(){
background(255);
strokeWeight(10);
translate(width/2,height-20);
branch(0);
}
function branch(depth){
setTimeout(function() {
if (depth < 10) {
line(0,0,0,-height/10); // draw a line going up
{
translate(0,-height/10); // move the space upwards
rotate(random(-0.05,0.05)); // random wiggle
if (random(1.0) < 0.6){ // branching
rotate(0.3); // rotate to the right
scale(0.8); // scale down
push(); // now save the transform state
branch(depth + 1); // start a new branch!
pop(); // go back to saved state
rotate(-0.6); // rotate back to the left
push(); // save state
branch(depth + 1); // start a second new branch
pop(); // back to saved state
}
else { // no branch - continue at the same depth
branch(depth);
}
}
}
}, 500);
}
function mouseReleased(){
redraw();
}
html, body {
margin: 0;
padding: 0;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
<!DOCTYPE html><html><head>
</head>
<body>
<script src="sketch.js"></script>
</body></html>
Please give any solution to grow the tree smoothly (instead of at once).
Upvotes: 1
Views: 303
Reputation: 350272
You can use async
and await
for this.
Define a utility function the returns a promise that resolves after a given delay:
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
Make your branch
function async
(just prepend it with that keyword).
Add await
before each of the three recursive calls you make. For example:
await branch(depth+1);
Add a new line to introduce the delay:
if (depth < 10) {
await delay(10); // "sleep" for 10 milliseconds.
// ...
The result:
function setup(){
createCanvas(600,600);
noLoop();
}
function draw(){
background(255);
strokeWeight(10);
translate(width/2,height-20);
branch(0);
}
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
async function branch(depth){
if (depth < 10) {
await delay(10);
line(0,0,0,-height/10); // draw a line going up
{
translate(0,-height/10); // move the space upwards
rotate(random(-0.05,0.05)); // random wiggle
if (random(1.0) < 0.6){ // branching
rotate(0.3); // rotate to the right
scale(0.8); // scale down
push(); // now save the transform state
await branch(depth + 1); // start a new branch!
pop(); // go back to saved state
rotate(-0.6); // rotate back to the left
push(); // save state
await branch(depth + 1); // start a second new branch
pop(); // back to saved state
}
else { // no branch - continue at the same depth
await branch(depth);
}
}
}
}
function mouseReleased(){
redraw();
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
Note that the mouseReleased
function may get called while there is still an asychronous chain of drawing ongoing. This will lead to an unexpected mix of drawing taking place.
You can avoid this, by temporarily "disabling" that function with a guard, as follows:
Define a global variable busy = false
;
Manage that variable at the start/end of the drawing, by changing the function draw
to:
function draw(){
if (busy) return; // guard against concurrent drawing activity
busy = true; // set guard
background(255);
strokeWeight(10);
translate(width/2,height-20);
branch(0).then(() => busy = false); // clear guard asynchronously
}
function setup(){
createCanvas(600,600);
noLoop();
}
let busy = false;
function draw(){
if (busy) return; // guard against concurrent drawing activity
busy = true; // set guard
background(255);
strokeWeight(10);
translate(width/2,height-20);
branch(0).then(() => busy = false); // clear guard asynchronously
}
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
async function branch(depth){
if (depth < 10) {
await delay(10);
line(0,0,0,-height/10); // draw a line going up
{
translate(0,-height/10); // move the space upwards
rotate(random(-0.05,0.05)); // random wiggle
if (random(1.0) < 0.6){ // branching
rotate(0.3); // rotate to the right
scale(0.8); // scale down
push(); // now save the transform state
await branch(depth + 1); // start a new branch!
pop(); // go back to saved state
rotate(-0.6); // rotate back to the left
push(); // save state
await branch(depth + 1); // start a second new branch
pop(); // back to saved state
}
else { // no branch - continue at the same depth
await branch(depth);
}
}
}
}
function mouseReleased(){
redraw();
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
Upvotes: 3