home *** CD-ROM | disk | FTP | other *** search
/ com!online 2002 May / comcd0502.iso / homepage / special / javascript / 01_01 / nova / javascript / animate2.js
Encoding:
JavaScript  |  2000-05-22  |  16.9 KB  |  572 lines

  1. /*******************************************************************
  2. *
  3. * File    : animate.js
  4. *
  5. * Created : 2000/05/16
  6. *
  7. * Author  : Roy Whittle  (Roy@Whittle.com) www.Roy.Whittle.com
  8. *
  9. * Purpose : To create animated rollovers
  10. *
  11. * History
  12. * Date         Version        Description
  13. *
  14. * 2000-05-16    2.0        I have been doing JavaScript for over 8 months
  15. *                    and have decided to start this project from
  16. *                    scratch using what I have learned.
  17. *                    Knowing now what is required for animated rollovers
  18. *                    I have re-done the state transition diagram to
  19. *                    come up with a more robust design.
  20. ***********************************************************************/
  21. /*** Create some global variables ***/
  22. var AnimationRunning = false; /*** Global state of animation ***/
  23. var FrameInterval    = 30;   /*** Time between frames in milliseconds   ***/
  24.  
  25. var AniImage = new Array();
  26. var AniFrame = new Array();
  27.  
  28. var BaseHref="images/";
  29. var Sep     = "/";
  30. var Timer   = null;
  31.  
  32. /***********************************************************
  33. * Function   : ImageError
  34. *
  35. * Parameters : 
  36. *              
  37. * Description : If the image being loaded does not exist then
  38. *               this function will report an error giving the
  39. *               full URL of the image we are trying to load.
  40. *              
  41. ***********************************************************/
  42. function ImageError()
  43. {
  44.     alert("animate.js has detected an error\nImage not found\n" + this.src);
  45. }
  46. /***********************************************************
  47. * Function   : CreateAnimationFrames
  48. *
  49. * Parameters : aniName - the name of the animation.
  50. *              n       - number of frames in animation
  51. *              ext     - the type of image (".GIF", ".JPG")
  52. *              
  53. * Description : Creates an object that can hold the current
  54. *               images for the animation.
  55. *               There must be 1 ".ext" file for every frame
  56. *               of animation  and they must reside in a 
  57. *               the directory "images/name/x.ext". 
  58. *               E.g.
  59. *                 "images/email/0.gif"
  60. *                 "images/email/1.gif"
  61. *                 ....
  62. *                 "images/email/x.gif" //where x=(n-1);
  63. ***********************************************************/
  64. function CreateAnimationFrames(aniName, n, ext)
  65. {
  66.     this.num_frames = n;
  67.     for(var i=0 ; i<n ; i++)
  68.     {
  69.         this[i]=new Image();
  70.         this[i].src = BaseHref + aniName + Sep + i + ext;
  71.  
  72.         this[i].onerror=ImageError;
  73.     }
  74. }
  75. /***********************************************************
  76. * Function   : CreateAnimatedImage
  77. *
  78. * Parameters : imgNname - the name of the image.
  79. *              aniName  - the name of the animation effect
  80. *                         to use with this image
  81. *              
  82. * Description : Creates an object that can hold the current
  83. *               state of the animation for a particular image
  84. * NOTE: imgName must match an image defined in the document
  85. *      BODY (e.g. <IMG SRC="xxx.ext" NAME="imgName">)
  86. ***********************************************************/
  87. function CreateAnimatedImage(imgName, aniName)
  88. {
  89.     if(document.images)
  90.     {
  91.         this.img_name   = imgName;
  92.         this.ani_name   = aniName;
  93.         this.next_on    = null;
  94.         this.next_off   = null;
  95.         this.index      = 0;
  96.         this.target_frame= 0;
  97.         this.state      = "CLOSED";
  98.         this.img        = null;
  99.     }
  100.     
  101. }
  102.  
  103. /*****************************************************************
  104. * Function    : getImage
  105. *
  106. * Parameters : n - the name of the image to find
  107. *           d - the (window/layer) document
  108. *
  109. * Description : In ie - just get the doucument.image.
  110. *            In NS, if there are layers we recursively
  111. *            search them for the image.
  112. *
  113. *****************************************************************/
  114. function getImage(n, d) 
  115. {
  116.     var img = d.images[n];
  117.     if(!img && d.layers)  
  118.         for(var i=0 ; !img && i<d.layers.length ; i++) 
  119.             img=getImage(n,d.layers[i].document); 
  120.     return img;
  121. }
  122.  
  123. /*****************************************************************
  124. * Function    : startAnimation
  125. *
  126. * Description : Set a timeout which will call the animate routine
  127. *               and start the animation running
  128. *****************************************************************/
  129. function startAnimation()
  130. {
  131.     if(!AnimationRunning)
  132.         Animate();
  133. }
  134. /*******************************************************************
  135. *
  136. * Function    : Animate
  137. *
  138. * Description : Each animation object has a state.
  139. *               The states normally go as follows
  140. *                   CLOSED->OPENING->OPEN
  141. *                   OPEN->CLOSING->CLOSED.
  142. *               When a turn_on() event is received, an image in the
  143. *               CLOSED state is switched to the OPENING state until OPEN
  144. *               is reached. When the turn_off() event is received an image
  145. *               in the OPEN state is switched to the CLOSING state until
  146. *               the CLOSED state is reached. 
  147. *
  148. *               The special cases are what happens when we get turn_off() when
  149. *               in the middle of opening. In this case the path is :-
  150. *               CLOSED->OPENING->OPEN_CLOSE->CLOSING->CLOSED.
  151. *               in this way the image will fully "open" before it starts 
  152. *               closing. This can be changed by always setting the state
  153. *               to "CLOSING" when the turn_off() event is received.
  154. *
  155. *               If the button is "CLOSING" and the turn_on() event is
  156. *               received and the new open animation is null or the same
  157. *               then the state is set back to "OPENING and the
  158. *               button will start opening again immediately.
  159. *                 Otherwise the state is set to CLOSE_OPEN so the image
  160. *               will get to the CLOSED state and start opening with the
  161. *               new animation.
  162. *
  163. *******************************************************************/
  164. function Animate()
  165. {    
  166.     AnimationRunning = false; /*** Are there more frames that need displaying? ***/
  167.  
  168.     for(var i in AniImage)
  169.     {
  170.         var b=AniImage[i];
  171.         var a=AniFrame[b.ani_name];
  172.  
  173.         if(b.state == "OPENING")
  174.         {
  175.             /*** Increment the frame index - display the next frame ***/
  176.             /*** when fully open, set state to "OPEN"               ***/
  177.             if(++b.index < a.num_frames)
  178.             {
  179.                 b.img.src=a[b.index].src;
  180.                 AnimationRunning = true;
  181.             }
  182.             else
  183.             {
  184.                 b.index=a.num_frames-1;
  185.                 b.state = "OPEN";
  186.             }
  187.         }
  188.         else if(b.state == "OPEN_CLOSE")
  189.         {
  190.             /*** Increment the frame index - display the next frame ***/
  191.             /*** when fully open, set state to "CLOSING"            ***/
  192.             if(++b.index < a.num_frames)
  193.             {
  194.                 b.img.src=a[b.index].src;
  195.             }
  196.             else
  197.             {
  198.                 if(b.next_off)
  199.                 {
  200.                     b.ani_name=b.next_off;
  201.                     a=AniFrame[b.ani_name];
  202.                     b.next_off=null;
  203.                 }
  204.                 b.index=a.num_frames-1;
  205.                 b.state = "CLOSING";
  206.             }
  207.             AnimationRunning = true;
  208.         }
  209.         else if(b.state == "CLOSING")
  210.         {
  211.             /*** Decrement the frame index - display the next frame ***/
  212.             /*** when fully closed, set state to "CLOSED"           ***/
  213.             if(--b.index >= 0)
  214.             {
  215.                 b.img.src=a[b.index].src;
  216.                 AnimationRunning = true;
  217.             }
  218.             else
  219.             {
  220.                 b.index=0;
  221.                 b.state = "CLOSED";
  222.             }
  223.         }
  224.         else if(b.state == "CLOSE_OPEN")
  225.         {
  226.             /*** Decrement the frame index - display the next frame ***/
  227.             /*** when fully closed, set state to "OPENING"           ***/
  228.             if(--b.index >= 0)
  229.             {
  230.                 b.img.src=a[b.index].src;
  231.             }
  232.             else
  233.             {
  234.                 b.index=0;
  235.                 b.ani_name=b.next_on;
  236.                 b.state = "OPENING";
  237.             }
  238.             AnimationRunning = true;
  239.         }
  240.         else if(b.state == "ROTATE_UP")
  241.         {
  242.             /*** Increment the frame index - display the next frame ***/
  243.             /*** when target reached, set state to "CLOSED"        ***/
  244.             if(b.index != b.target_frame)
  245.             {
  246.                 if(++b.index == a.num_frames)
  247.                     b.index = 0;
  248.                 b.img.src=a[b.index].src;
  249.                 AnimationRunning = true;
  250.             }
  251.             else
  252.                 b.state = "CLOSED";
  253.         }
  254.         else if(b.state == "ROTATE_DOWN")
  255.         {
  256.             /*** Decrement the frame index - display the next frame ***/
  257.             /*** when target reached, set state to "CLOSED"        ***/
  258.             if(b.index != b.target_frame)
  259.             {
  260.                 if(--b.index < 0)
  261.                     b.index = a.num_frames-1;
  262.                 b.img.src=a[b.index].src;
  263.                 AnimationRunning = true;
  264.             }
  265.             else
  266.                 b.state = "CLOSED";
  267.         }
  268.     }
  269.     /*** Check to see if we need to animate any more frames. ***/
  270.     if(AnimationRunning)
  271.     {
  272.         if(!Timer)
  273.             Timer=setInterval("Animate()",FrameInterval);
  274.     }
  275.     else
  276.     {
  277.         clearInterval(Timer);
  278.         Timer=null;
  279.     }
  280. }
  281. /***********************************************************
  282. * Function   : ErrorCheck
  283. *
  284. * Parameters : funcName - the name of the function that called this one
  285. *              imgName  - The name of the image being animated
  286. *              aniName  - (optional) the animation being used.
  287. *              
  288. * Description : This function checks that all the required
  289. *               objects that make up animated RollOvers
  290. *               have been defined. It will report any errors
  291. *               detected. This function will also search for
  292. *            the corresponding document image by calling getImage().
  293. *              
  294. ***********************************************************/
  295. function ErrorCheck(funcName, imgName, aniName)
  296. {
  297.     var err_str="";
  298.  
  299.     if(AniImage[imgName]==null)
  300.         err_str += "Error    : AnimatedImage \"" + imgName + "\" not defined\n";
  301.     else
  302.     {
  303.         var b=AniImage[imgName];
  304.         if(b.img == null)
  305.             b.img=getImage(imgName, document);
  306.  
  307.         if(b.img==null)
  308.             err_str += "Error    : Document <IMG NAME=\"" + imgName + "\"> not defined\n";
  309.  
  310.         /*** Check the AnimationFrames(b.ani_name, n, ext) has been defined ***/
  311.         if(AniFrame[b.ani_name]==null)
  312.             err_str += "Error    : AnimationFrames \"" + b.ani_name + "\" not defined\n";
  313.  
  314.     }
  315.  
  316.     if(aniName)
  317.         /*** Check the AnimationFrames(aniName, n, ext) has been defined ***/
  318.         if(AniFrame[aniName]==null)
  319.             err_str += "Error    : AnimationFrames \"" + aniName + "\" not defined\n";
  320.  
  321.     if(err_str)
  322.     {
  323.         var extra = aniName ? ("\",\"" + aniName + "\")") : ("\")");
  324.         alert("animate.js has detected an error\n       --------------------------------\n"
  325.             + err_str
  326.             + "Function    : " + funcName + "(\"" + imgName + extra);
  327.     
  328.         return true;
  329.     }
  330.  
  331.     return false;
  332. }
  333. /************* OBJECT CONSTRUCTORS ******************************/
  334. /***********************************************************
  335. * Function   : AnimatedImage
  336. *
  337. * Parameters : imgName - the name of the image.
  338. *              aniName - the name of the animation effect
  339. *                     to use with this image
  340. *              
  341. * Description : Creates an object to hold the current state of
  342. *            the animation and stores it in the AniImage array.
  343. ***********************************************************/
  344. function AnimatedImage(imgName, aniName)
  345. {
  346.     AniImage[ imgName ] = new CreateAnimatedImage( imgName, aniName);
  347.  
  348.     if(AniFrame[aniName]==null)
  349.         alert("animate.js has detected a possible error\n       --------------------------------\n"
  350.             + "Error    : AnimationFrames \"" + aniName + "\" not defined\n"
  351.             + "Function    : AnimatedImage(\"" + imgName + "\",\"" + aniName + "\")");
  352.  
  353. }
  354. /***********************************************************
  355. * Function   : AnimationFrames
  356. *
  357. * Parameters : aniName - the name of the animation effect
  358. *              n    - number of frames in animation
  359. *              ext  - the type of image (".GIF", ".JPG")
  360. *              
  361. * Description : Creates an object to hold all the frames
  362. *               for an animation and stores it in the AniFrames array.
  363. ***********************************************************/
  364. function AnimationFrames(aniName, n, ext)
  365. {
  366.     /*** Only download this animation if we don't already have it ***/
  367.     if(AniFrame[aniName] == null)
  368.         AniFrame[ aniName ]= new CreateAnimationFrames(aniName, n, ext);
  369.     else
  370. //        alert(aniName + " already defined");
  371.         ;
  372. }
  373. /***********************************************************
  374. * Function   : AnimatedGif AnimatedJpg
  375. *
  376. * Parameters : name - the name of the image.
  377. *              n    - number of frames in animation
  378. *              
  379. * Description : These are a couple of helper functions to
  380. *               help create simple animations.
  381. *
  382. ***********************************************************/
  383. function AnimatedGif(name, n)
  384. {
  385.     AnimationFrames(name, n, ".gif");
  386.     AnimatedImage( name, name);
  387. }
  388. function AnimatedJpg(name, n)
  389. {
  390.     AnimationFrames(name, n, ".jpg");
  391.     AnimatedImage( name, name);
  392. }
  393. /*************** ANIMATION METHODS **************************************/
  394. /*****************************************************************
  395. *
  396. * Function   : turn_on
  397. *
  398. * Parameters : ingName - string containing the name of the
  399. *                        image to start animating.
  400. *           aniName - optional, animation to use to open.
  401. *
  402. * Description: Checks that the imgName is in a valid state to
  403. *              start "OPENING". If it is it sets the state to
  404. *              "OPENING" and calls startAnimation.             
  405. *
  406. *****************************************************************/
  407. function turn_on(imgName, aniName)
  408. {
  409.     if(!ErrorCheck("turn_on", imgName, aniName))
  410.     {
  411.         var b=AniImage[ imgName ];
  412.  
  413.         if(b.state == "CLOSED" )
  414.         {
  415.             b.state = "OPENING";
  416.             if(aniName)
  417.                 b.ani_name=aniName;
  418.             startAnimation();
  419.         }
  420.         else if ( b.state == "OPEN_CLOSE"
  421.             ||  b.state == "CLOSING" 
  422.             ||  b.state == "CLOSE_OPEN") 
  423.         {
  424.             if(!aniName || b.ani_name==aniName)
  425.                 b.state = "OPENING";
  426.             else
  427.             {
  428.                 b.next_on=aniName;
  429.                 b.state = "CLOSE_OPEN";
  430.             }
  431.         }
  432.         /*** Special effect, can only happen in forced situations ***/
  433.         /*** Hopefully this is described in the manual ***/
  434.         else if( b.state == "OPENING"
  435.             || b.state == "OPEN")
  436.         {
  437.             if(aniName && b.ani_name != aniName)
  438.             {
  439.                 b.ani_name=aniName;
  440.                 b.index=0;
  441.                 b.state="OPENING";
  442.                 startAnimation();
  443.             }
  444.         }
  445.     }
  446. }
  447. /*****************************************************************
  448. *
  449. * Function   : turn_off
  450. *
  451. * Parameters : imgName - string containing the name of the
  452. *                        image to start reverse animating.
  453. *
  454. * Description: Checks that the imgName is in a valid state to
  455. *              start "CLOSING". If it is it sets the state to
  456. *              "CLOSING" and calls startAnimation.             
  457. *
  458. *****************************************************************/
  459. function turn_off(imgName, aniName)
  460. {
  461.     if(!ErrorCheck("turn_off", imgName, aniName))
  462.     {
  463.         var b=AniImage[ imgName ];
  464.  
  465.         if( b.state == "OPEN")        
  466.         {
  467.             if(aniName)
  468.             {
  469.                 b.ani_name=aniName;
  470.                 b.index=AniFrame[aniName].num_frames-1;
  471.             }
  472.             b.state = "CLOSING";
  473.             startAnimation();
  474.         }
  475.         else if(b.state == "CLOSE_OPEN")
  476.         {
  477.             b.next_off=null;
  478.             b.state="CLOSING"
  479.         }
  480.         else if( b.state == "OPENING" )
  481.         {
  482.             b.next_off = aniName;
  483.             b.state = "OPEN_CLOSE";
  484.         }
  485.     }
  486. }
  487. /******************************* LOOPING ANIMATION METHODS ****************/
  488. /*****************************************************************
  489. *
  490. * Function   : animate_to
  491. *
  492. * Parameters : imgName - string containing the name of the
  493. *                        image to start animating.
  494. *              frameNo - the target frame
  495. *
  496. * Description: Determines the shortest animation path to the
  497. *           target frame. sets the state and calls startAnimation.             
  498. *
  499. *****************************************************************/
  500. function animate_to(frameNo, imgName)
  501. {
  502.     if(!ErrorCheck("animate_to", imgName) )
  503.     {
  504.         var b = AniImage[ imgName  ];
  505.         var a = AniFrame[ b.ani_name];
  506.         var s = frameNo - b.index;
  507.  
  508.         b.target_frame = frameNo;
  509.  
  510.         if(Math.abs(s) > (a.num_frames/2))
  511.         {
  512.             if(s < 0)
  513.                 b.state = "ROTATE_UP";
  514.             else
  515.                 b.state = "ROTATE_DOWN";
  516.         }
  517.         else
  518.         {
  519.             if(s > 0)
  520.                 b.state = "ROTATE_UP";
  521.             else
  522.                 b.state = "ROTATE_DOWN";
  523.         }
  524.         startAnimation();
  525.     }
  526. }
  527. /*****************************************************************
  528. *
  529. * Function   : animate_upto
  530. *
  531. * Parameters : imgName - string containing the name of the
  532. *                        image to start animating.
  533. *              frameNo - the target frame
  534. *
  535. * Description: Sets the state to ROTATE_UP calls startAnimation.             
  536. *
  537. *****************************************************************/
  538. function animate_upto(frameNo, imgName)
  539. {
  540.     if(!ErrorCheck("animate_upto", imgName) )
  541.     {
  542.         var b=AniImage[ imgName ];
  543.  
  544.         b.target_frame = frameNo;
  545.         b.state       = "ROTATE_UP";
  546.  
  547.         startAnimation();
  548.     }
  549. }
  550. /*****************************************************************
  551. *
  552. * Function   : animate_downto
  553. *
  554. * Parameters : imgName - string containing the name of the
  555. *                        image to start animating.
  556. *              frameNo - the target frame
  557. *
  558. * Description: Sets the state to ROTATE_DOWN calls startAnimation.             
  559. *
  560. *****************************************************************/
  561. function animate_downto(frameNo, imgName)
  562. {
  563.     if(!ErrorCheck("animate_downto", imgName) )
  564.     {
  565.         var b=AniImage[ imgName ];
  566.  
  567.         b.target_frame = frameNo;
  568.         b.state       = "ROTATE_DOWN";
  569.         startAnimation();
  570.     }
  571. }
  572.