Omkar Keluskar
Omkar Keluskar

Reputation: 29

Stop return from javascript function until SetTimeout executes

I am using a fabric.js to draw a binary tree/graph, I want to introduce a delay so that the sequence of drawing is visible. I used setTimeout method in my code but problem is all the nodes are getting delayed and drawn at the same time which I don't want. I want one node,then little delay then another node. Kindly help me.

Code:

delaytime=5000;

function add(x){
   console.log(x);
   canvas.add(x);
}



function addRoot(value){

    var value=String(value);
    var x=new fabric.Circle({ radius: radius,left:width/2,fill:'red',top:radius,originX: 'center', originY: 'center',fill:'red'});
    var text= new fabric.Text(value, {fontSize: 10, originX: 'center', originY: 'center',left:width/2,top:radius});

    setTimeout(function(){ add(x);},delaytime);
  setTimeout(function(){ add(text);},delaytime);



    return x;
}

In the code above the two setTimeout calls are getting executed at the same time but I want the program waits until it returns from first setTimeout call even if it is 5 seconds and then execute the next statement. Please give hints.

Async/await is also not working. Only first call getting drawn which is addRoot

Test.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test for fabric</title>

</head>
<body>

<canvas id="canvas" width="800" height="800" style="border:1px solid #000000">


</canvas>
<script src="fabric.js"></script>
    <script src="testfunctions.js">

    </script>
<script src="./testfunctions.js"></script>
<script>

    var canvas = new fabric.Canvas('canvas');
    var a10=addRoot(10);
    var a20=addNode(a10,20,225);
    var a40=addNode(a10,40,315);
    var a30=addNode(a20,30,270);

</script>

</body>
</html>

Code with async:

var canvas = new fabric.Canvas('canvas');
var height = parseInt(document.getElementById('canvas').getAttribute('height'));
var width = parseInt(document.getElementById('canvas').getAttribute('width'));
var distance = 200;
var radius = 20;
var linelimit = 180;
var delaytime = 1000;

 async function delay (time) {
  return new Promise(function (resolve) {
    setTimeout(resolve, time)
  })
}


async function addRoot (value) {
    var value = String(value);
    var x = new fabric.Circle({ radius: radius, left: width / 2, fill: 'red', top: radius, originX: 'center', originY: 'center', fill: 'red'});
    var text = new fabric.Text(value, {fontSize: 10, originX: 'center', originY: 'center', left: width / 2, top: radius});
    await delay(1000);
    canvas.add(x);
    canvas.add(text);
    return x
}

function addline (x1, y1, x2, y2) {
  console.log("In addline");
  var line = new fabric.Line([x1, y1, x2, y2], {stroke: 'black', originX: 'center', originY: 'center'});
  canvas.add(line)
}


 async function  addNode (node1, node2, angle) {
  var intialx = parseInt(node1.left);

  var initialy = parseInt(node1.top);

   console.log("addNode");

  if (angle > 0 && angle <= 90) {
    var pointx = Math.abs(Math.abs(Math.cos(angle * Math.PI / 180) * distance) + intialx);
    var pointy = Math.abs(Math.abs(Math.sin(angle * Math.PI / 180) * distance) - initialy);

    var initiallinex = Math.abs(Math.abs(Math.cos(angle * Math.PI / 180) * radius) + intialx);
    var initialliney = Math.abs(Math.abs(Math.sin(angle * Math.PI / 180) * radius) - initialy);
    var finallinex = Math.abs(Math.abs(Math.cos(angle * Math.PI / 180) * linelimit) + intialx);
    var finalliney = Math.abs(Math.abs(Math.sin(angle * Math.PI / 180) * linelimit) - initialy)
  }
  if (angle > 90 && angle <= 180) {
    var pointx = Math.abs(Math.cos(angle * Math.PI / 180) * distance + intialx);
    var pointy = Math.abs(Math.sin(angle * Math.PI / 180) * distance - initialy);

    var initiallinex = Math.abs(Math.cos(angle * Math.PI / 180) * radius + intialx);
    var initialliney = Math.abs(Math.sin(angle * Math.PI / 180) * radius - initialy);
    var finallinex = Math.abs(Math.cos(angle * Math.PI / 180) * linelimit + intialx);
    var finalliney = Math.abs(Math.sin(angle * Math.PI / 180) * linelimit - initialy)
  }
  if (angle > 180 && angle <= 270) {
    if (angle == 270) {
      var pointx = Math.abs(Math.cos(angle * Math.PI / 180) * distance + intialx);
      var pointy = Math.abs(Math.sin(angle * Math.PI / 180) * distance - initialy);
      var initiallinex = Math.abs(Math.cos(angle * Math.PI / 180) * radius + intialx);
      var initialliney = Math.abs(Math.sin(angle * Math.PI / 180) * radius - initialy);
      var finallinex = Math.abs(Math.cos(angle * Math.PI / 180) * linelimit + intialx);
      var finalliney = Math.abs(Math.sin(angle * Math.PI / 180) * linelimit - initialy)
    } else {
      var pointx = Math.abs(Math.cos(angle * Math.PI / 180) * distance + intialx);
      var pointy = Math.abs(Math.sin(angle * Math.PI / 180) * distance - initialy);
      var initiallinex = Math.abs(Math.cos(angle * Math.PI / 180) * radius + intialx);
      var initialliney = Math.abs(Math.sin(angle * Math.PI / 180) * radius - initialy);
      var finallinex = Math.abs(Math.cos(angle * Math.PI / 180) * linelimit + intialx);
      var finalliney = Math.abs(Math.sin(angle * Math.PI / 180) * linelimit - initialy)
    }
  } else {
    var pointx = Math.abs(Math.cos(angle * Math.PI / 180) * distance + intialx);
    var pointy = Math.abs(Math.sin(angle * Math.PI / 180) * distance - initialy);
    var initiallinex = Math.abs(Math.cos(angle * Math.PI / 180) * radius + intialx);
    var initialliney = Math.abs(Math.sin(angle * Math.PI / 180) * radius - initialy);
    var finallinex = Math.abs(Math.cos(angle * Math.PI / 180) * linelimit + intialx);
    var finalliney = Math.abs(Math.sin(angle * Math.PI / 180) * linelimit - initialy)
  }

  var x = new fabric.Circle({ radius: radius, originX: 'center', originY: 'center', fill: 'red', left: pointx, top: pointy});
  var value1 = String(node2);
  var text = new fabric.Text(value1, {fontSize: 10, originX: 'center', originY: 'center', left: pointx, top: pointy});
  await delay(1000);
  canvas.add(x);
  canvas.add(text);
  await delay(1000);
  console.log("Executed");
  addline(initiallinex, initialliney, finallinex, finalliney);
  return x;
}

Upvotes: 1

Views: 107

Answers (2)

Patrick Roberts
Patrick Roberts

Reputation: 51866

You can use ES2017 async / await:

function delay (time) {
  return new Promise(function (resolve) {
    setTimeout(resolve, time)
  })
}

let delaytime = 1000

async function addRoot (value) {
  console.log('do stuff')
  // var value=String(value);
  // var x=new fabric.Circle({ radius: radius,left:width/2,fill:'red',top:radius,originX: 'center', originY: 'center',fill:'red'});
  // var text= new fabric.Text(value, {fontSize: 10, originX: 'center', originY: 'center',left:width/2,top:radius});
  await delay(delaytime)
  console.log('add x')
  // add(x);
  await delay(delaytime)
  console.log('add text')
  // add(text);
  return { value: value }
  // return x;
}

// usage
addRoot('some value').then(function (returnedValue) {
  console.log(returnedValue)
})

Notice the delay in the timestamps next to each console.log() output in the demo.

Update

In order to properly use this code with minimal change to yours, change the following snippet:

var canvas = new fabric.Canvas('canvas');
var a10=addRoot(10);
var a20=addNode(a10,20,225);
var a40=addNode(a10,40,315);
var a30=addNode(a20,30,270);

to this:

// to support await operator
(async function () {
  // do not declare another canvas, you've already done so in other block
  var a10 = await addRoot(10)
  var a20 = await addNode(a10, 20, 225)
  var a40 = await addNode(a10, 40, 315)
  var a30 = await addNode(a20, 30, 270)
})()

Upvotes: 1

Rex Hsu
Rex Hsu

Reputation: 494

There are two ways to achieve what you want to do

(1) add additional delaytime at the last setTimeout

setTimeout(function() {

  add(x);
}, delaytime);

setTimeout(function() {

  add(text);
}, delaytime * 2);

(2) Place the last setTimeout inside the first setTimeout

setTimeout(function() {

  add(x);
  setTimeout(function() {

    add(text);
  }, delaytime);
}, delaytime);

Upvotes: 0

Related Questions