Jump to content

For Loop with 2 Timeouts inside


writer1

Recommended Posts

Hi,

 

I have beginner skills using JavaScript in HTML5 projects. I use an eLearning software package (Opus) which can generate lessons that use JavaScript to animate objects in exercises.

 

I am trying to animate a circle object and have it scale larger and scale smaller to look like breathing. Since the scaling larger and smaller needs to follow a pattern, I am trying to build a script. So far, if I place a circle object (Vector8) in the center, my script will make the circle expand once, but no contraction cycle, no looping. Here's my script. I am hoping someone can help and suggest how to get the circle object to loop so that it repeatedly gets bigger, then smaller.

 

The goal is to have one breath in, wait 500 ms, then one breath out that takes 2X the time of the in breath, then wait 500 ms, then another breath in, etc. in a repeating cycle.

calcBreathing()function calcBreathing(){      _DWPub.bar1=10   _DWPub.bar2=60/_DWPub.bar1   _DWPub.loop=0   for (_DWPub.loop = 0;_DWPub.loop<_DWPub.bar1;_DWPub.loop++)      {      window.setTimeout(function() {Page1.Vector8.Scale(0.5, 0.5, _DWPub.bar2 * 0.3)}, 500)      window.setTimeout(function() {Page1.Vector8.Scale(0.5, 0.5, _DWPub.bar2 * 0.3)}, 500)      if (_DWPub.loop < _DWPub.bar2) {                    _DWPub.loop++;}}}             

Thank you for your help.

Edited by writer1
Link to comment
Share on other sites

That code seems strange. You have a for loop where you first say the loop should run 10 times (in the actual for statement), then each time through the loop you schedule the same code to run twice after 500 milliseconds, then you increase the loop counter again for the first 5 times through the loop, so it's not actually running 10 times. I don't understand the point of most of that code.Let's assume it only take 1 millisecond to run through that for loop each time (it actually takes much less). The first time through you're going to schedule those 2 pieces of identical code to run after 500 ms. Then, the next time through the loop, you do the exact same thing. The end result is going to be those 2 pieces of code running after 500 ms, 501 ms, 502 ms, etc. So, starting after 500 ms, it's going to keep running those pieces of code as fast as the original for loop ran. It's not going to space them out 500 ms apart or anything like that.Is one of those lines supposed to make the scale larger and the other smaller? Right now they're both doing the same thing, and they're both going to run at the same time.

Link to comment
Share on other sites

Apologies for not being clearer, and all of those mistakes in the script.

 

The eLearning software that I am working with uses its own script, which is a variation of ECMA262 JavaScript, an older standard. This script can not be used for an HTML5 type export. So, I am trying to rewrite the old script for this exercise into new JavaScript. Not easy for a beginner like me.

 

What I need to do in the (stress-reducing) exercise is show the student a circle object that, using scaling, looks like breathing: it would expand and contract. They can use it to pace their own breathing. The cycle for expand/contract would be a specific number of breaths per minute: so maybe starting with 10 breaths per minute. Each breath is one expand/contract cycle. Contract component timing is 2X expand component (optimally, we exhale slower than we inhale, about half as fast). A breath pacing exercise may start at 10 breaths per minute (or 12, some other number), then after one minute, go to 9 breaths per minute, then each minute --1, until 6 breaths per minute is reached and 6 is practiced for one minute. The break the loop and stop.

 

I hope this is a little clearer. But feel free to ask more questions, clarifications.

Link to comment
Share on other sites

My first thought is a sine wave, but that's going to be the same speed in the positive and negative directions:https://www.google.com/search?client=opera&q=sine+curve&sourceid=opera&ie=UTF-8&oe=UTF-8#q=sine+waveThe math would be really easy with a sine wave function, but that's probably not what you want. If you need different speeds then you could do it with either 2 functions, or just 1 where you pass the parameters for the animation you're doing. Once one animation ends then you wait some amount of time before starting the next one, so the animation to expand would run and finish and schedule the animation to contract for half a second later or whatever the delay between them is.Basically, in Javascript animation is done a step at a time. If you're only animating the scale of it then that's fine. Say the scale starts at 1.00, and you first want to scale it up to 1.25 over 1 second, then the next animation scales back to 1.00 over 2 seconds. In order to do the animation you need to decide how many steps you want, which is like the frame rate of a movie. Modern browsers can use the requestAnimationFrame functionality to do animation, but the older way is to use setTimeout or setInterval to change it by a little each time.So, if you're going from 1.00 to 1.25 over 1 second, and you want to do 25 frames per second, then each step is 40 milliseconds (1000 milliseconds divided by 25 frames per second). So, you have 25 steps, and you're going from 1.00 to 1.25. So you're changing by .25 over 25 steps, so each step you're changing by .01 (.25 / 25). So you'll have a function that runs every 40 milliseconds to add .01 to the scale, until the scale reaches 1.25, then it stops. Then it would schedule the next function to run to decrease the scale. If you want to decrease it back to 1.00 over 2 seconds, then you change it by .005 each step instead of .01.So, you could use 2 functions to do that, or 1 function where you pass things like the ending scale, step, delay, etc. Either one would work. The function would do its animation for that step and then schedule itself to run again, e.g.:

function do_animation(end_scale, step, delay) {  // get the current scale  // if the current scale is not the end scale, then add step to the current scale  // if the animation is not finished then run the function again  setTimeout(function() { do_animation(end_scale, step, delay); }, delay);  // if the animation is finished, then schedule the opposite function to run   if (end_scale == 1) {    setTimeout(function() { do_animation(1.25, step * 2, delay); }, 1000);  }  else {    setTimeout(function() { do_animation(1.00, step / 2, delay); }, 1000);  }}
You could kick that off by just running the function to start the first animation:
do_animation(1.25, .01, 40);
  • Like 1
Link to comment
Share on other sites

Thank you for this explanation, so I can learn.

 

If I am understanding correctly, then the driver in this model would be the start and end scale size. I'm not sure this can be used, since the start and end is driven by time, cycle duration, not scale amount. Here is an explanation about the timing needed:

 

If the exercise starts at 10 BPM (breaths per minute), then I would want to have the circle expand/contract 10 cycles (twice as long within each cycle for the contraction than for the expansion to correctly mirror "good" breathing). After that one minute at 10 BPM, it would decrease to 9 BPM, for one minute, and the 9 cycles would each change their duration to fit into that one minute (again retaining the proportion of 1:2 for inhale/expand and exhale/contract). That way, through 8 BPM, 7 BPM, 6 BPM, then it would remain at 6 BPM for whatever total length of time the user selects for the entire exercise. They can practice for 10 minutes for example (that would leave 5 more cycles at 6 BPM after stepping down to and completing one minute of 6 BPM). So, timing varies depending on which BPM minute the animation is currently in.

 

Seems challenging. Maybe can't be done as an HTML5 JS animation?

 

Devoted Member: I'm using Opus Professional as a software package. While it can use JS and export as HTML5, it's core function files use their own unique naming conventions to identify objects and variables. So "Page1.Vector8.Scale(a,b,c)" refers to the circle object named Vector8 on the main page which is to be scaled, and the scale parameters are JS parameters. So, (0.5, 0.5, _DWPub.bar2 * 0.3) would scale the height and width by a factor of 50% (1 = 100%, 1.5 = 150%), with the duration as BPM/60 * .3 each inhale cycle component, and (should be) -0.5, -0.5, _DWPub.bar2 * 0.6 for each exhale cycle component. The naming and unique scripting are not mine, but a feature of the software package (see link above).

 

HTH

Edited by writer1
Link to comment
Share on other sites

Seems challenging. Maybe can't be done as an HTML5 JS animation?

Of course it can, it's just math to work out the step and delay and things like that in each animation. That's all animation is really, a series of small changes done quickly. If you can work out the math to get the right step and delay for each BPM value then you can plug those numbers in and it will work.For a given BPM value, for example, you need to figure out how long a single breath takes, and from that you work down to get the animation timing so that the breath takes that long.

So, (0.5, 0.5, _DWPub.bar2 * 0.3) would scale the height and width by a factor of 50% (1 = 100%, 1.5 = 150%), with the duration as BPM/60 * .3 each inhale cycle component,

If that scale method includes a duration parameter then it will do the animation for you, so all you need to figure out is the duration for a single breath given a certain BPM.
Link to comment
Share on other sites

Hi,

 

Thank you for the encouragement. I think where I am stuck is in the adding of 2 timeouts (one for the inhale part of the breath cycle and one for the exhale part of the breath cycle) inside a loop.

 

The breath duration can be one of the scaling parameters in each function: for inhale = _DWPub.bar2 * 0.3, for exhale = _DWPub.bar2 * 0.6. The scaling parameter for inhale (H, W) is .5, .5, for exhale is -.5, -.5. Problem is that there should be a 500 ms delay between inhale and exhale or exhale and inhale.

 

So need to loop: inhale, delay(timeout?), exhale, delay (timeout?) as long as the loop counter (++) is less than the bar1 variable (BPM), then break the loop, go to a new iteration of the loop with a new bar1 (BPM) which a separate function would be decrementing (--) after one minute (another delay/timeout but for a different function than the scaling function: a separate BPM counter function which runs down until 6 BPM, then stays at 6 BPM for exercise duration). Whew!

 

But where I'm stuck is those first 2 functions, inhale, exhale as timeouts (to proivide the 500 ms delay in between) inside of a loop. My loop (see first posting above) isn't changing/incrementing. Gets stuck running only once.

 

So, still trying to figure it out. Any suggestions appreciated.

Link to comment
Share on other sites

I don't like using a loop for things like that, do you have any documentation for that scale function? If it supports a callback, that would be the way to go, tell it to run a function after the animation finishes and then you can chain them.

Link to comment
Share on other sites

Hi,

 

It appears that Opus (the eLearning app that I'm using) can use this scaling function:

Scale( Horizontal, Vertical, Time, Wait )// so Vector8.Scale(.5,.5,_DWPub.bar2 * 0.3,) would scale the circle to 150% horizontal and vertical (height and width) over a time duraction based on breaths per minute (BPM)/60* .3 (inhale),// with Wait defaulting to true (so the next line of script will not run until this scaling is completed). After a 500 ms delay, it would run the exhale scaling which would scale the circle back// in twice the duraction as the inhale. Then another 500 ms delay and back to inhale. 

I'm not familiar with the term "callback" but looking it up online, I think Opus can do callbacks in JS.

 

Just not sure what the total function for the breathing inhale/exhale cycle would look like?

Link to comment
Share on other sites

It would be similar to the do_animate function I showed above, where the last few lines decide what to do for the next animation.I guess you can use that fourth parameter set to true to make the animation synchronous, although it's still kind of a kludgy way to do repeated animation. You can't just use an infinite loop to keep doing the animation because you have the delay between animations.If you don't have the option of using a callback then the best you can do is try to do something similar:

setTimeout(function() { Scale( 1.5, 1.5, 1000 ) }, 500); // first inhalesetTimeout(function() { Scale( 1, 1, 2000 ) }, 2000); // first exhalesetTimeout(function() { Scale( 1.5, 1.5, 1000 ) }, 2500); // second inhalesetTimeout(function() { Scale( 1, 1, 2000 ) }, 4000); // second exhale...
Pay attention to the last parameter, it sets the first inhale to run in 500 milliseconds, then the first exhale to run after 2000 milliseconds (which should be 500ms after the first one finishes), then 2500, 4000, etc. So it queues everything up at once. You could generalize that and build a for loop if you want everything to run a certain number of times. Without the delay between animations, or if you could use callbacks, then it would be less confusing.
  • Like 1
Link to comment
Share on other sites

Thank you for this. I can use it to experiment with different options. Since there are a finite number of cycles as well as a finite number of minutes for the exercise, I may end up with the "long way" suggested by your above script. Once "hard-coded" in, it may be my best option.

 

May have more questions as I try to go forward.

 

Again, thank you.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...