/********************************************************************* File    : JSFX_AnimatedRollovers.js © JavaScript-FX.com** Created : 2000/05/16** Author  : Roy Whittle www.Roy.Whittle.com*           * Purpose : To create animated rollovers** History* Date         Version        Description** 2001-09-23	3.0		Completely re-structured to the JSFX naming*					space and to use a more similar interface*					to SimpleRollovers and FadingRollovers* 2001-01-29	3.1		Make "ani" a seperate object of the "img"* 2002-02-21	3.2		Correct a bug in JSFX.findImg* 2002-02-21	3.3		When creating vers 3.1 I broke NS4 nested layers*					This version fixes it by recursing the AnimateRollover function.***********************************************************************/var FrameInterval    = 40;	/*** Time between frames in milliseconds   ***/var BaseHref="images/";		/*** This is now only required for AnimagedGif ***//*** Create some global variables ***/if(!window.JSFX)	JSFX=new Object();JSFX.AnimationRunning = false; /*** Global state of animation ***/JSFX.aniTimer = null;JSFX.AniRollovers = new Array();/************************************************************ Function   : AniImageError** Parameters : *              * Description : If the image being loaded does not exist then*               this function will report an error giving the*               full URL of the image we are trying to load.*              ***********************************************************/JSFX.aniImageError = function(){	alert("JSFX_AnimatedRollover.js has detected an error\nImage not found\n" + this.src);}/************************************************************ Function   : CreateAnimationFrames** Parameters : imgName - the path to the animation frames.*              n       - number of frames in animation*              ext     - the type of image (".GIF", ".JPG")*              * Description : Creates an object that can hold the current*               images for the animation.*               There must be 1 ".ext" file for every frame*               of animation  and they must reside in a *               the directory "imgName" + x + ".ext"*               E.g.*                 "images/email/0.gif"*                 "images/email/1.gif"*                 ....*                 "images/email/x.gif" //where x=(n-1);***********************************************************/JSFX.CreateAnimationFrames = function(imgName, n, ext){	this.num_frames = n;	for(var i=0 ; i<n ; i++)	{		this[i]=new Image();		this[i].src = imgName + i + ext;		this[i].onerror=JSFX.aniImageError;	}}/************************************************************ Function   : initAnimatedImage** Parameters : img      - the image in the document.*              aniName  - the name of the animation effect*                         to use with this image*              * Description : Initialises an image object so that it can hold the current*               state of the animation for a particular the image* NOTE: imgName must match an image defined in the document*	  BODY (e.g. <IMG SRC="xxx.ext" NAME="imgName">)***********************************************************/JSFX.initAnimatedImage = function(img, ani){	img.ani = new Object();	img.ani.name  	 = ani;	img.ani.next_on    = ani;	img.ani.next_off   = ani;	img.ani.index      = 0;	img.ani.target_frame= 0;	img.ani.state      = "CLOSED";}/************************************************************ Function   : AnimatedRollover** Parameters : aniName - the name of the animation effect*              imgName - the path to the images*              n    - number of frames in animation*              ext  - the type of image (".GIF", ".JPG")*              * Description : Creates an object to hold all the frames*               for an animation and stores it in the AniFrames array.***********************************************************/JSFX.AnimatedRollover = function(aniName, imgName, n, ext){	/*** Only download this animation if we don't already have it ***/	if(JSFX.AniRollovers[aniName] == null)		JSFX.AniRollovers[ aniName ]= new JSFX.CreateAnimationFrames(imgName, n, ext);}/************************************************************ Function   : AnimatedGif AnimatedJpg** Parameters : name - the name of the image.*              n    - number of frames in animation*              * Description : These are a couple of helper functions to*               help create simple animations.************************************************************/JSFX.AnimatedGif = function(name, n){	JSFX.AnimatedRollover(name, BaseHref + name + "/", n, ".gif");}JSFX.AnimatedJpg = function(name, n){	JSFX.AnimatedRollover(name, BaseHref + name + "/", n, ".jpg");}/********************************************************************* Function    : getImg** Description : In Netscape 4 images could be in layers so we might*		    have to recurse the layers to find the image******************************************************************/JSFX.getImg = function(n, d) {	var img = d.images[n];	if(!img && d.layers)		for(var i=0 ; !img && i<d.layers.length ; i++)			img=JSFX.getImg(n,d.layers[i].document);	return img;}/********************************************************************* Function    : findImg** Description : gets the image from the document and reports an*		    error if it cannot find it.******************************************************************/JSFX.findImg = function(n, d) {	var img = JSFX.getImg(n, d);	/*** Stop emails because the image was named incorrectly ***/	if(!img)	{		alert("JSFX.findImg - An Error has been detected\n"			+ "----------------------------------\n"			+ "You must define an image in your document\n"			+ "<IMG SRC=\"your_image.ext\" NAME=\""+n+"\">\n"			+ "(check the NAME= attribute of your images)");		return(new Image());	}	return img;}/********************************************************************* Function    : aniRolloverExists** Description : A lot of users make mistakes like creating a rollover*			AnimatedRollover("home", "images/home", 6, ".gif"*		    and then try to us it like this*			JSFX.aniOn("hom");******************************************************************/JSFX.aniRolloverError = function(aniName){	if(JSFX.AniRollovers[aniName])		return false;	else		alert("JSFX.AnimatedRollovers - An Error has been detected\n"			+ "----------------------------------\n"			+ "You must define a JSFX.AnimatedRollover in your document\n"			+ "JSFX.AnimatedRollover(\""+aniName+"\",\"your_img\", n,\".gif\")\n"			+ "(check the spelling of your JSFX.AnimatedRollovers)");	return true;}/****************************************************************** Function    : startAnimation** Description : Set a timeout which will call the animate routine*               and start the animation running*****************************************************************/JSFX.startAnimation = function(){	if(!JSFX.AnimationRunning)		JSFX.AnimateRollovers();}/******************************************************************* Function   : aniOn** Parameters : imgName - string containing the name of the*                        image to start animating.*		   aniName - optional, animation to use to open.** Description: Checks that the imgName is in a valid state to*              start "OPENING". If it is it sets the state to*              "OPENING" and calls startAnimation.             ******************************************************************/JSFX.aniOn = function(imgName, aniName){	if(aniName == null)		aniName = imgName;	var img=JSFX.findImg(imgName, document);	if(JSFX.aniRolloverError(aniName))		return;	if(img.ani == null)		JSFX.initAnimatedImage(img, aniName);	if(img.ani.state == "CLOSED" )	{		img.ani.state = "OPENING";		img.ani.name  = aniName;		JSFX.startAnimation();	}	else if ( img.ani.state == "OPEN_CLOSE"		||  img.ani.state == "CLOSING" 		||  img.ani.state == "CLOSE_OPEN") 	{		if(img.ani.name==aniName)			img.ani.state = "OPENING";		else		{			img.ani.next_on=aniName;			img.ani.state = "CLOSE_OPEN";		}	}	/*** Normally you can only set an opening image to OPEN ***/	/*** However, here we force an already OPEN image to OPENING if we supply a different animation ***/	else if( img.ani.state == "OPENING"		|| img.ani.state == "OPEN")	{		if(aniName && img.ani.name != aniName)		{			img.ani.name=aniName;			img.ani.index=0;			img.ani.state="OPENING";			JSFX.startAnimation();		}	}}/******************************************************************* Function   : aniOff** Parameters : imgName - string containing the name of the*                        image to start reverse animating.*		   aniName - If you really want you can use a completely*				 different "off" animation.* Description: Checks that the imgName is in a valid state to*              start "CLOSING". If it is it sets the state to*              "CLOSING" and calls startAnimation.             ******************************************************************/JSFX.aniOff = function(imgName, aniName){	var img=JSFX.findImg(imgName, document);	if(aniName == null)		aniName = img.ani.name;	if(JSFX.aniRolloverError(aniName))		return;	if( img.ani.state == "OPEN")			{		img.ani.name=aniName;		img.ani.index=JSFX.AniRollovers[aniName].num_frames-1;		img.ani.state = "CLOSING";		JSFX.startAnimation();	}	else if(img.ani.state == "CLOSE_OPEN")	{		img.ani.next_off=null;		img.ani.state="CLOSING"	}	else if( img.ani.state == "OPENING" )	{		img.ani.next_off = aniName;		img.ani.state = "OPEN_CLOSE";	}}/********************************************************************* Function    : AnimateRollovers** Description : Each image object is given a state.*               The states normally go as follows*                   CLOSED->OPENING->OPEN*                   OPEN->CLOSING->CLOSED.*               When a turn_on() event is received, an image in the*               CLOSED state is switched to the OPENING state until OPEN*               is reached. When the turn_off() event is received an image*               in the OPEN state is switched to the CLOSING state until*               the CLOSED state is reached. **               The special cases are what happens when we get turn_off() when*               in the middle of opening. In this case the path is :-*               CLOSED->OPENING->OPEN_CLOSE->CLOSING->CLOSED.*               in this way the image will fully "open" before it starts *               closing. This can be changed by always setting the state*               to "CLOSING" when the turn_off() event is received.**               If the button is "CLOSING" and the turn_on() event is*               received and the new open animation is null or the same*               then the state is set back to "OPENING and the*               button will start opening again immediately.*                 Otherwise the state is set to CLOSE_OPEN so the image*               will get to the CLOSED state and start opening with the*               new animation.********************************************************************/JSFX.AnimateRollovers = function(d){		if(d==null)	{		d=document;		JSFX.AnimationRunning = false; /*** Are there more frames that need displaying? ***/	}	for(var i=0 ; i<d.images.length ; i++)	{		var img = d.images[i];		if(img.ani)		{			var ani=JSFX.AniRollovers[img.ani.name];			if(img.ani.state == "OPENING")			{				/*** Increment the frame index - display the next frame ***/				/*** when fully open, set state to "OPEN"               ***/				if(++img.ani.index < ani.num_frames)				{					img.src=ani[img.ani.index].src;					JSFX.AnimationRunning = true;				}				else				{					img.ani.index=ani.num_frames-1;					img.ani.state = "OPEN";				}			}			else if(img.ani.state == "OPEN_CLOSE")			{				/*** Increment the frame index - display the next frame ***/				/*** when fully open, set state to "CLOSING"            ***/				if(++img.ani.index < ani.num_frames)				{					img.src=ani[img.ani.index].src;				}				else				{					if(img.ani.next_off)					{						img.ani.name=img.ani.next_off;						ani=JSFX.AniRollovers[img.ani.name];						img.ani.next_off=null;					}					img.ani.index=ani.num_frames-1;					img.ani.state = "CLOSING";				}				JSFX.AnimationRunning = true;			}			else if(img.ani.state == "CLOSING")			{				/*** Decrement the frame index - display the next frame ***/				/*** when fully closed, set state to "CLOSED"           ***/				if(--img.ani.index >= 0)				{					img.src=ani[img.ani.index].src;					JSFX.AnimationRunning = true;				}				else				{					img.ani.index=0;					img.ani.state = "CLOSED";				}			}			else if(img.ani.state == "CLOSE_OPEN")			{				/*** Decrement the frame index - display the next frame ***/				/*** when fully closed, set state to "OPENING"           ***/				if(--img.ani.index >= 0)				{					img.src=ani[img.ani.index].src;				}				else				{					img.ani.index=0;					img.ani.name=img.ani.next_on;					img.ani.state = "OPENING";				}				JSFX.AnimationRunning = true;			}			else if(img.ani.state == "ROTATE_UP")			{				/*** Increment the frame index - display the next frame ***/				/*** when target reached, set state to "CLOSED"        ***/				if(img.ani.index != img.ani.target_frame)				{					if(++img.ani.index == ani.num_frames)						img.ani.index = 0;					img.src=ani[img.ani.index].src;					JSFX.AnimationRunning = true;				}				else					img.ani.state = "CLOSED";			}			else if(img.ani.state == "ROTATE_DOWN")			{				/*** Decrement the frame index - display the next frame ***/				/*** when target reached, set state to "CLOSED"        ***/				if(img.ani.index != img.ani.target_frame)				{					if(--img.ani.index < 0)						img.ani.index = ani.num_frames-1;					img.src=ani[img.ani.index].src;					JSFX.AnimationRunning = true;				}				else					img.ani.state = "CLOSED";			}		}	}	//NS4 recurse all layers	if(document.layers)	{		for(var l=0 ; l<d.layers.length ; l++)			JSFX.AnimateRollovers(d.layers[l].document);		//If we are in a sub layer - no need to check the timer		if(d!=document)			return;	}	/*** Check to see if we need to animate any more frames. ***/	if(JSFX.AnimationRunning)	{		if(!JSFX.aniTimer)			JSFX.aniTimer=setInterval("JSFX.AnimateRollovers()",FrameInterval);	}	else	{		clearInterval(JSFX.aniTimer);		JSFX.aniTimer=null;	}}/******************************************************************* Function   : aniTo** Parameters : imgName - string containing the name of the*                        image to start animating.*              frameNo - the target frame** Description: Determines the shortest animation path to the*		   target frame. sets the state and calls startAnimation.             ******************************************************************/JSFX.aniTo = function(frameNo, imgName, aniName){	var img=JSFX.findImg(imgName, document);	if(aniName == null)		aniName = imgName;	if(JSFX.aniRolloverError(aniName))		return;	if(img.ani == null)		JSFX.initAnimatedImage(img, aniName);	var diff = frameNo - img.ani.index;	img.ani.target_frame = frameNo;	var ani=JSFX.AniRollovers[img.ani.name];	if(Math.abs(diff) > (ani.num_frames/2))	{		if(diff < 0)			img.ani.state = "ROTATE_UP";		else			img.ani.state = "ROTATE_DOWN";	}	else	{		if(diff > 0)			img.ani.state = "ROTATE_UP";		else			img.ani.state = "ROTATE_DOWN";	}	JSFX.startAnimation();}/******************************************************************* Function   : aniUpto** Parameters : imgName - string containing the name of the*                        image to start animating.*              frameNo - the target frame** Description: Sets the state to ROTATE_UP calls startAnimation.             ******************************************************************/JSFX.aniUpto = function(frameNo, imgName, aniName){	var img=JSFX.findImg(imgName, document);	if(aniName == null)		aniName = imgName;	if(JSFX.aniRolloverError(aniName))		return;	if(img.ani == null)		JSFX.initAnimatedImage(img, aniName);	img.ani.target_frame = frameNo;	img.ani.state       = "ROTATE_UP";	JSFX.startAnimation();}/******************************************************************* Function   : aniDownto** Parameters : imgName - string containing the name of the*                        image to start animating.*              frameNo - the target frame** Description: Sets the state to ROTATE_DOWN calls startAnimation.             ******************************************************************/JSFX.aniDownto = function(frameNo, imgName, aniName){	var img=JSFX.findImg(imgName, document);	if(aniName == null)		aniName = imgName;	if(JSFX.aniRolloverError(aniName))		return;	var img=JSFX.findImg(imgName, document);	if(img.ani == null)		JSFX.initAnimatedImage(img, aniName);	img.ani.target_frame = frameNo;	img.ani.state       = "ROTATE_DOWN";	JSFX.startAnimation();}/******************************************************************* Function   : aniStop** Parameters : imgName - string containing the name of the*                        image to stop animating.** Description: Sets the state to CLOSED thus stopping the animation******************************************************************/JSFX.aniStop = function(imgName){	var img=JSFX.findImg(imgName, document);	img.ani.state = "CLOSED";}