Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 9 of 9
  1. #1
    Regular Coder
    Join Date
    Mar 2005
    Posts
    115
    Thanks
    3
    Thanked 0 Times in 0 Posts

    nested timeouts - how to implement?

    I'm running into issues while trying to make some simple code to loop through and display different combinations of 3 colours.
    I want to show 3 boxes on screen and then loop through/increment each possible combination of colours.

    For simplicity's sake I'm trying to go from black to white in each box like this:

    (box1rgb/box2rgb/box3rgb)

    step 1: 000 000 000
    step 2: 000 000 111
    step 3: 000 000 222
    .
    .
    .
    step 256: 000 000 255255255
    step 257: 000 111 000
    step 258: 000 111 111
    step 259: 000 111 222
    .
    .
    .
    step 512: 000 111 255255255
    step 513: 000 222 000
    step 514: 000 222 111
    .
    etc.

    Yes, I know the thing will take a long time to complete!

    The colour is being set by the statement
    document.getElementById("box#").style.backgroundColor = "rgb(" + p1 + "," + p1 + "," + p1 + ")"; where p1 is the incrementing variable.

    Firstly I tried to do it using nested "for" loops.
    Code:
      for (p3=0;p3<=255;p3++) {
    
        document.getElementById("box03").style.backgroundColor  = "rgb(" + p3 + "," + p3 + "," + p3 + ")";
      
        for (p2=0;p2<=255;p2++) {
    
          document.getElementById("box02").style.backgroundColor  = "rgb(" + p2 + "," + p2 + "," + p2 + ")";
        
          for (p1=0;p1<=255;p1++) {
          
            document.getElementById("box01").style.backgroundColor  = "rgb(" + p1 + "," + p1 + "," + p1 + ")";
    		
          }
        }
      }
    But of course the code executes far too rapidly for each combination to be seen. It all chewed up lots of CPU and nothing was smooth.

    To slow the process, I tried a single recursive loop using a timeout statement:
    Code:
    function loopandshow() {
      document.getElementById("box01").style.backgroundColor  = "rgb(" + currentcolour + "," + currentcolour + "," + currentcolour + ")";
      currentcolour += 1;
      if (currentcolour <= 255) window.setTimeout("loopandshow();", 20);
    }
    This worked smoothly for a single box but I couldn't work out how to nest this format 3 levels deep and have each level increment only when the deeper level had completed the cycle.

    Any advice would be gratefully appreciated.

    Thanks in advance.

  • #2
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,521
    Thanks
    3
    Thanked 507 Times in 494 Posts
    may help

    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    
    <head>
      <title></title>
    <style type="text/css">
    /*<![CDATA[*/
    .message {
      width:100px;height:100px;background-Color:#FFCC66;
    }
    
    /*]]>*/
    </style>
    <script type="text/javascript">
    // AnimateII (08-October-2010)
    // by Vic Phillips http://www.vicsjavascripts.org.uk
    
    // To progressively change the
    // left, top, width, height, color, background-Color, Opacity, border-Width, border-Color, clip
    // style of an element over a specified period of time.
    
    // **** Application Notes
    
    // **** The HTML Code
    //
    // when moving an element the inline or class rule style position of the element should be assigned as
    // 'position:relative;' or 'position:absolute;'
    // If not assigned the style position of the element will be assigned as 'position:relative;' by the script.
    //
    // The element would normally be assigned a unique ID name.
    //
    
    // **** Initialising the Script.
    //
    // The script is initialised by assigning an instance of the script to a variable.
    // e.g A = new zxcAnimateII('left','id1')
    // where:
    //  A           = a global variable                                                               (variable)
    //  parameter 0 = the mode(see Note 1).                                                           (string)
    //  parameter 1 = the unique ID name or element object.                                           (string or element object)
    //  parameter 2 = the initial value.                                                              (digits, default = 0)
    //
    
    // **** Executing the Effect
    //
    // The effect is executed by an event call to function 'A.animate(10,800 ,5000,[10,800]);'
    // where:
    //  A           = the global referencing the script instance.                                 (variable)
    //  parameter 0 = the start value.                                                            (digits, for opacity minimum 0, maximum 100)
    //  parameter 1 = the finish value.                                                           (digits, for opacity minimum 0, maximum 100)
    //  parameter 2 =  period of time between the start and finish of the effect in milliseconds. (digits or defaults to previous or 0(on first call) milliSeconds)
    //  parameter 3 = (optional) the type of progression, 'sin', 'cos' or 'liner'.                (string, default = 'liner')
    //                 'sin' progression starts fast and ends slow.
    //                 'cos' progression starts slow and ends fast.
    
    // **** Notes
    //
    //  Note 1:  Examples modes: 'left', 'top', 'width', 'height', 'opacity', clip, 'color', 'background-Color'.
    //
    //  Note 2:  The default units(excepting opacity) are 'px'.
    //           For hyphenated modes, the first character after the hyphen must be upper case, all others lower case.
    //
    //  Note 3:  To animate colors('color' or 'background-Color') the start and finish values may be.
    //           HEX('#FF0000') or RGB('rgb(255,0,0)'), abbreviated HEX or named colors are not allowed.
    //
    //  Note 4:  To animate 'clip' the start and finish values may be
    //            arrays of the top, right, bottom and left values([0,100,20,0])
    //           or the standard clip format 'rect(0px,100px,20px,0px)'.
    //
    //  Note 5:  It may be required to access the current value of the effect.
    //           An array storing the current, start and finish values of the element effect may be accessed
    //           from the element effect.data as fields 0, 1 and 2 respectively && each field is an array.
    //           For color each field is an array storing the R, G, B values.
    //           The current effect value is recorded in A.data[0].
    //
    //  Note 6:  A function may be called on completion of the effect by assigning the function
    //           to the animator instance property .Complete.
    //           e.g. [instance].Complete=function(){ alert(this.data[0]); };
    //
    
    
    // **** Functional Code(2.61K) - NO NEED to Change
    
    
    function zxcAnimateII(mde,obj,srt){
     this.obj=(typeof(obj)=='string')?document.getElementById(obj):obj;
     this.mde=mde.replace(/[-#]/g,'');
     this.data=[srt?this.convert(srt,this.mde):0];
     this.to=null;
    }
    
    zxcAnimateII.prototype={
    
     animate:function(srt,fin,ms,c){
      this.std=!(this.mde.indexOf('olor')>0||this.mde=='clip'||this.mde=='opacity');
      srt=this.convert(srt,this.mde);
      fin=this.convert(fin,this.mde);
      this.pos=true;
      for (var z0=0;z0<srt.length;z0++){
       if (srt[z0]<0||fin[z0]<0){
        this.pos=false;
       }
      }
      c=c||'';
      this.c=c.charAt(0).toLowerCase();
      this.mS=ms||2000;
      clearTimeout(this.to);
      this.srttime=new Date().getTime();
      this.inc=Math.PI/(2*this.mS);
      this.data=[[],srt,fin];
      this.cng();
     },
    
     cng:function(){
      var ms=new Date().getTime()-this.srttime;
      for (var z0=0;z0<this.data[2].length;z0++){
       this.data[0][z0]=Math.floor(this.c=='s'?(this.data[2][z0]-this.data[1][z0])*Math.sin(this.inc*ms)+this.data[1][z0]:this.c=='c'?(this.data[2][0])-(this.data[2][z0]-this.data[1][z0])*Math.cos(this.inc*ms):(this.data[2][z0]-this.data[1][z0])/this.mS*ms+this.data[1][z0]);
       if (this.pos&&this.data[0][z0]<0){
        this.data[0][z0]=0;
       }
      }
      this.cngstyle();
      if (ms<this.mS){
       this.to=setTimeout(function(oop){ return function(){oop.cng(); } }(this), 10);
      }
      else {
       this.data[0]=this.data[2];
       this.cngstyle(this.data[0]);
       if (this.Complete){
        this.Complete(this);
       }
      }
     },
    
     cngstyle:function(){
      var v=this.data[0];
      if (this.std){
       this.obj.style[this.mde]=v[0]+'px';
      }
      else if (this.mde.indexOf('olor')>0){
       this.obj.style[this.mde]='rgb('+v[0]+','+v[1]+','+v[2]+')';
      }
      else if (this.mde=='clip'){
       this.obj.style[this.mde]='rect('+v[0]+'px,'+v[1]+'px,'+v[2]+'px,'+v[3]+'px)';
      }
      else if (this.mde=='opacity'){
       zxcOpacity(this.obj,v[0]);
      }
     },
    
     convert:function(col,mde){
      if (typeof(col)=='object'){
       return col;
      }
      else if (mde=='clip'){
       col=col.replace(/[rect()px]/g,'').split(',');
       return [col[0]*1,col[1]*1,col[2]*1,col[3]*1];
      }
      else if (!col.toString().match('#')){
       return [parseInt(col)];
      }
      else {
       col=parseInt(col.substring(1,3),16)+','+parseInt(col.substring(3,5),16)+','+parseInt(col.substring(5,7),16);
       col=col.replace(/[rgb()\s]/g,'').split(',');
       return [parseInt(col[0]),parseInt(col[1]),parseInt(col[2])];
      }
     }
    }
    
    function zxcOpacity(obj,opc){
     if (opc<0||opc>100) return;
     obj.style.filter='alpha(opacity='+opc+')';
     obj.style.opacity=obj.style.MozOpacity=obj.style.WebkitOpacity=obj.style.KhtmlOpacity=opc/100-.001;
    }
    
    </script>
    </head>
    
    <body>
    <div class="message" id="tst" ></div>
    
    <script type="text/javascript">
    /*<![CDATA[*/
    
    var box=new zxcAnimateII('background-Color','tst')
    
    box.animate('#FFCC66','#FFFFCC',1000);
    /*]]>*/
    </script>
    </body>
    
    </html>
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • Users who have thanked vwphillips for this post:

    pavinder (11-30-2010)

  • #3
    Regular Coder
    Join Date
    Mar 2005
    Posts
    115
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by vwphillips View Post
    may help

    Code:
    .
    .
    .
    box.animate('#FFCC66','#FFFFCC',1000);
    /*]]>*/
    </script>
    </body>
    
    </html>
    Thanks for the code sample Vic - a really elegant effect, gratefully received.
    I've tried sequencing some animations and the effect is quite stunning.

    I wonder if this method could enable the "nesting" of timeout functions I'm aiming for or whether it's limit is sequential timeout functions?

    Thanks in advance.

  • #4
    Regular Coder
    Join Date
    Mar 2005
    Posts
    115
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Just to elaborate on what I need to achieve, the problem with timeouts is although I can create a delay until the cycle on one level has finished before executing code to change the layer above it (as Vic's code does), this isn't enough.

    Vic's example allows me to execute an entire cycle of change one one level after another level has finished. For my project each level of loop has to increment just a single step after the layer below it completes a cycle.

    So I think I need some hybrid between nested for loops and timeouts (if such a beast exists).

  • #5
    New to the CF scene
    Join Date
    Nov 2010
    Posts
    2
    Thanks
    0
    Thanked 0 Times in 0 Posts
    you guys have done great job!

  • #6
    Regular Coder
    Join Date
    Mar 2005
    Posts
    115
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by Moodyxh View Post
    you guys have done great job!
    I think Vic has, I'm just asking for help!

  • #7
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,521
    Thanks
    3
    Thanked 507 Times in 494 Posts
    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    
    <head>
      <title></title>
    <style type="text/css">
    /*<![CDATA[*/
    .message {
      width:100px;height:100px;background-Color:#FFCC66;
    }
    
    /*]]>*/
    </style>
    <script type="text/javascript">
    // AnimateII (08-October-2010)
    // by Vic Phillips http://www.vicsjavascripts.org.uk
    
    // To progressively change the
    // left, top, width, height, color, background-Color, Opacity, border-Width, border-Color, clip
    // style of an element over a specified period of time.
    
    // **** Application Notes
    
    // **** The HTML Code
    //
    // when moving an element the inline or class rule style position of the element should be assigned as
    // 'position:relative;' or 'position:absolute;'
    // If not assigned the style position of the element will be assigned as 'position:relative;' by the script.
    //
    // The element would normally be assigned a unique ID name.
    //
    
    // **** Initialising the Script.
    //
    // The script is initialised by assigning an instance of the script to a variable.
    // e.g A = new zxcAnimateII('left','id1')
    // where:
    //  A           = a global variable                                                               (variable)
    //  parameter 0 = the mode(see Note 1).                                                           (string)
    //  parameter 1 = the unique ID name or element object.                                           (string or element object)
    //  parameter 2 = the initial value.                                                              (digits, default = 0)
    //
    
    // **** Executing the Effect
    //
    // The effect is executed by an event call to function 'A.animate(10,800 ,5000,[10,800]);'
    // where:
    //  A           = the global referencing the script instance.                                 (variable)
    //  parameter 0 = the start value.                                                            (digits, for opacity minimum 0, maximum 100)
    //  parameter 1 = the finish value.                                                           (digits, for opacity minimum 0, maximum 100)
    //  parameter 2 =  period of time between the start and finish of the effect in milliseconds. (digits or defaults to previous or 0(on first call) milliSeconds)
    //  parameter 3 = (optional) the type of progression, 'sin', 'cos' or 'liner'.                (string, default = 'liner')
    //                 'sin' progression starts fast and ends slow.
    //                 'cos' progression starts slow and ends fast.
    
    // **** Notes
    //
    //  Note 1:  Examples modes: 'left', 'top', 'width', 'height', 'opacity', clip, 'color', 'background-Color'.
    //
    //  Note 2:  The default units(excepting opacity) are 'px'.
    //           For hyphenated modes, the first character after the hyphen must be upper case, all others lower case.
    //
    //  Note 3:  To animate colors('color' or 'background-Color') the start and finish values may be.
    //           HEX('#FF0000') or RGB('rgb(255,0,0)'), abbreviated HEX or named colors are not allowed.
    //
    //  Note 4:  To animate 'clip' the start and finish values may be
    //            arrays of the top, right, bottom and left values([0,100,20,0])
    //           or the standard clip format 'rect(0px,100px,20px,0px)'.
    //
    //  Note 5:  It may be required to access the current value of the effect.
    //           An array storing the current, start and finish values of the element effect may be accessed
    //           from the element effect.data as fields 0, 1 and 2 respectively && each field is an array.
    //           For color each field is an array storing the R, G, B values.
    //           The current effect value is recorded in A.data[0].
    //
    //  Note 6:  A function may be called on completion of the effect by assigning the function
    //           to the animator instance property .Complete.
    //           e.g. [instance].Complete=function(){ alert(this.data[0]); };
    //
    
    
    // **** Functional Code(2.61K) - NO NEED to Change
    
    
    function zxcAnimateII(mde,obj,srt){
     this.obj=(typeof(obj)=='string')?document.getElementById(obj):obj;
     this.mde=mde.replace(/[-#]/g,'');
     this.data=[srt?this.convert(srt,this.mde):0];
     this.to=null;
    }
    
    zxcAnimateII.prototype={
    
     animate:function(srt,fin,ms,c){
      this.std=!(this.mde.indexOf('olor')>0||this.mde=='clip'||this.mde=='opacity');
      srt=this.convert(srt,this.mde);
      fin=this.convert(fin,this.mde);
      this.pos=true;
      for (var z0=0;z0<srt.length;z0++){
       if (srt[z0]<0||fin[z0]<0){
        this.pos=false;
       }
      }
      c=c||'';
      this.c=c.charAt(0).toLowerCase();
      this.mS=ms||2000;
      clearTimeout(this.to);
      this.srttime=new Date().getTime();
      this.inc=Math.PI/(2*this.mS);
      this.data=[[],srt,fin];
      this.cng();
     },
    
     cng:function(){
      var ms=new Date().getTime()-this.srttime;
      for (var z0=0;z0<this.data[2].length;z0++){
       this.data[0][z0]=Math.floor(this.c=='s'?(this.data[2][z0]-this.data[1][z0])*Math.sin(this.inc*ms)+this.data[1][z0]:this.c=='c'?(this.data[2][0])-(this.data[2][z0]-this.data[1][z0])*Math.cos(this.inc*ms):(this.data[2][z0]-this.data[1][z0])/this.mS*ms+this.data[1][z0]);
       if (this.pos&&this.data[0][z0]<0){
        this.data[0][z0]=0;
       }
      }
      this.cngstyle();
      if (ms<this.mS){
       this.to=setTimeout(function(oop){ return function(){oop.cng(); } }(this), 10);
      }
      else {
       this.data[0]=this.data[2];
       this.cngstyle(this.data[0]);
       if (this.Complete){
        this.Complete(this);
       }
      }
     },
    
     cngstyle:function(){
      var v=this.data[0];
      if (this.std){
       this.obj.style[this.mde]=v[0]+'px';
      }
      else if (this.mde.indexOf('olor')>0){
       this.obj.style[this.mde]='rgb('+v[0]+','+v[1]+','+v[2]+')';
      }
      else if (this.mde=='clip'){
       this.obj.style[this.mde]='rect('+v[0]+'px,'+v[1]+'px,'+v[2]+'px,'+v[3]+'px)';
      }
      else if (this.mde=='opacity'){
       zxcOpacity(this.obj,v[0]);
      }
     },
    
     convert:function(col,mde){
      if (typeof(col)=='object'){
       return col;
      }
      else if (mde=='clip'){
       col=col.replace(/[rect()px]/g,'').split(',');
       return [col[0]*1,col[1]*1,col[2]*1,col[3]*1];
      }
      else if (!col.toString().match('#')){
       return [parseInt(col)];
      }
      else {
       col=parseInt(col.substring(1,3),16)+','+parseInt(col.substring(3,5),16)+','+parseInt(col.substring(5,7),16);
       col=col.replace(/[rgb()\s]/g,'').split(',');
       return [parseInt(col[0]),parseInt(col[1]),parseInt(col[2])];
      }
     }
    }
    
    function zxcOpacity(obj,opc){
     if (opc<0||opc>100) return;
     obj.style.filter='alpha(opacity='+opc+')';
     obj.style.opacity=obj.style.MozOpacity=obj.style.WebkitOpacity=obj.style.KhtmlOpacity=opc/100-.001;
    }
    
    </script>
    </head>
    
    <body>
    <div class="message" id="tst0" ></div>
    <div class="message" id="tst1" ></div>
    <div class="message" id="tst2" ></div>
    
    <script type="text/javascript">
    /*<![CDATA[*/
    
    var box0=new zxcAnimateII('background-Color','tst0');
    var box1=new zxcAnimateII('background-Color','tst1');
    box1.Complete=function(){
     box0.animate('#FFCC66','#FFFFCC',1000);
    }
    var box2=new zxcAnimateII('background-Color','tst2');
    box2.Complete=function(){
     box1.animate('#FFCC66','#FFFFCC',1000);
    }
    box2.animate('#FFCC66','#FFFFCC',1000);
    /*]]>*/
    </script>
    </body>
    
    </html>
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • #8
    Regular Coder
    Join Date
    Mar 2005
    Posts
    115
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Sorry, Vic, maybe I didn't explain quite clearly enough - I don't need the 3 boxes to change sequentially. I need them to change in a similar way to a digital counter.

    That is, once the bottom box has completed a full cycle of change from black to white (for the sake of example let's say it takes 128 steps), then the middle box will increment by just 1 step. Once the bottom box has completed its second full 128-step cycle, the middle box will increment another single step.

    In this way it will take 128 black-->white cycles of the bottom box until the middle box completes a single cycle.
    And at this point the top box will increment the first step of its 128-step cycle.

    So over time, for each cycle of the top box the middle box will cycle 128 times and the bottom box will complete 128x128=16,384 cycles.

    It's this conditionality which has me thinking in terms of nested loops, but if I use the zxcAnimateII() function within another function within another function then how can the code know how to just increment a single step and how to suspend processing until the box underneath it has completed a full cycle?

    Of course I could set the period of time of the function to increasingly high powers of the innermost loop, but very soon (as I add a few more boxes) the numbers exceed the allowable maximum.

  • #9
    Regular Coder
    Join Date
    Mar 2005
    Posts
    115
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Received a suggestion from elsewhere which helps incredibly and should be all I need to continue from here.

    I've copied it below in case anyone else is interested.

    Thanks again Vic for your comments and advice, much appreciated, and I can see some very interesting ways the script you shared might help in future online artworks.

    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title>loopandShow</title>
    <style type="text/css">
    #box1, #box2, #box3 {
      float: left; margin: 20px;
      width: 200px; height : 200px;
      background: black;
    }
    </style>
    </head>
    <body>
    <div id = 'box1'></div>
    <div id = 'box2'></div>
    <div id = 'box3'></div>
    <script type="text/javascript">
    // From: http://www.webdeveloper.com/forum/showthread.php?t=239101
    
    function loopandShow(els){
      // define local variables
      var elNodesStyles = [];
      var timer = null;
      var elColor = [];
    
      // Store nodes in an array.
      // Therefore avoiding having to search the DOM repeatedly in colourInc.
      for (var i = 0, len = els.length; i < len; i+=1){
        elNodesStyles.push(document.getElementById(els[i]).style);
        elColor.push(0);
      }
    
      var colourInc = function(){
        // if we've reached 255 in 3rd box, clear the timer and return
        if (elColor[2] > 255) { // optional setting all box colors to 255 here, if desired
          clearInterval(timer); timer = null; return;
        }    
        // loop through our nodes, and set property
        elNodesStyles[0].background = "rgb(" + elColor[0] + "," + elColor[0] + "," + elColor[0] + ")";
        elNodesStyles[1].background = "rgb(" + elColor[1] + "," + elColor[1] + "," + elColor[1] + ")";
        elNodesStyles[2].background = "rgb(" + elColor[2] + "," + elColor[2] + "," + elColor[2] + ")";
    // adjust speed of changes with different increment assignments below
        elColor[0]+=8;;
        if (elColor[0] > 255) { elColor[1]+=16; elColor[0] = 0; }
        if (elColor[1] > 255) { elColor[2]+=32; elColor[1] = 0; }
      };  
      
      timer = setInterval(colourInc, 5);
    }
    
    // an array of elements
    var elems = ['box1', 'box2', 'box3'];
    loopandShow(elems);
    
    </script>
    </body>


  •  

    Tags for this Thread

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •