Click here to Skip to main content
15,893,622 members
Articles / Web Development / XHTML

MS Agent style critters for your web pages

Rate me:
Please Sign up or sign in to vote.
4.53/5 (23 votes)
13 Feb 2009BSD6 min read 74.9K   450   63  
Implementing MS Agent style critters for your web pages.
/*jslint browser: true */

//Copyright (c) 2007 Lewis Linn White Jr.
//Author: Lewis Linn White Jr.

//Permission is hereby granted, free of charge, to any person
//obtaining a copy of this software and associated documentation
//files (the "Software"), to deal in the Software without
//restriction, including without limitation the rights to use,
//copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the
//Software is furnished to do so, subject to the following
//conditions:

//The above copyright notice and this permission notice shall be
//included in all copies or substantial portions of the Software.
//Except as contained in this notice, the name(s) of the above 
//copyright holders shall not be used in advertising or otherwise 
//to promote the sale, use or other dealings in this Software without 
//prior written authorization.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.

//All images distributed with this project are public domain

//Constructor.  Sets up a few methods and registers a few events that need to be registered
//at create time.  Also creates a internal namespace for our internal class/objects
function JCritter(agent)
{
    var me, div, divArray, i, e;
	me = this;
	
	//States
	this.isHidden = true;
	this.isSpeaking = false;
	this.isMute = false;

	//create an internal namespace that we can reference in our prototype
	this.internal = {};
	
	//Cretae an IE6 flag for use later
	this.internal.IE6 = (document.all && window.external && (typeof document.documentElement.style.maxHeight === 'undefined')) ? true : false;	
	
	//Assign agent
	this.internal.agent = agent;
	
	//Semi-internal page functions
	this.internal.getPageWidth = function ()
	{
		return window.innerWidth || (document.documentElement.clientWidth || (document.body.clientWidth || 0));
	};
	
	this.internal.getPageHeight = function ()
	{
	    return window.innerHeight || (document.documentElement.clientHeight || (document.body.clientHeight || 0));
	};
	
	//Create divs for our agent
    divArray = ['bubbleDiv', 'bubbleTop', 'bubbleBottom', 'bubbleText', 'critterDiv'];
    for(i = 0, e = divArray.length; i < e; i++)
    {
            this.internal[divArray[i]] = document.createElement('div');
    }
	this.internal.critterImg = document.createElement('img');
	
	//bubbleDiv  Holds top and bottom bubble divs
	this.internal.bubbleDiv.style.position = this.internal.IE6 ? 'absolute' : 'fixed';
	this.internal.bubbleDiv.style.visibility = 'hidden';
	this.internal.bubbleDiv.style.width = '275px';
	
	//bubbleTop
	//this.internal.bubbleTop.style.textAlign = 'center';
	this.internal.bubbleTop.style.background = 'url(bubble.gif) no-repeat top';
	this.internal.bubbleTop.style.padding = '25px 8px 0px';
	
	//bubbleBottom
	//this.internal.bubbleBottom.style.textAlign = 'center';
	this.internal.bubbleBottom.innerHTML = '&nbsp;';
	this.internal.bubbleBottom.style.background = 'url(bubble.gif) no-repeat bottom';
	this.internal.bubbleBottom.style.padding = '35px 8px 0px';
	
	//bubbleText
	this.internal.bubbleText.style.paddingLeft = '10px';
	this.internal.bubbleText.style.paddingRight = '10px';
	this.internal.bubbleText.style.textAlign = 'center';
	
	//critterDiv
	this.internal.critterDiv.style.position = this.internal.IE6 ? 'absolute' : 'fixed';
	this.internal.critterDiv.style.visibility = 'hidden';
	
	//critterImg
	this.internal.critterImg.onclick = function ()
	{
		me.onClick();
	};
	this.internal.critterImg.onmouseover = function ()
	{
		me.onMouseIn();
	};
	this.internal.critterImg.onmouseout = function ()
	{
		me.onMouseOut();
	};
	
	//Add critter to page
	this.internal.bubbleTop.appendChild(this.internal.bubbleText);
	this.internal.bubbleDiv.appendChild(this.internal.bubbleTop);
	this.internal.bubbleDiv.appendChild(this.internal.bubbleBottom);
	this.internal.critterDiv.appendChild(this.internal.critterImg);
	document.body.appendChild(this.internal.critterDiv);
	document.body.appendChild(this.internal.bubbleDiv);
	
	//If we are IE6, we need to add the draw() event to the window.onscroll event.
	if (this.internal.IE6)
	{
		window.onscroll = function ()
		{
			me.draw();
		};
	}
}

JCritter.prototype =
{
	//Drawing functions
	drawBalloon: function ()
	{
		this.internal.bubbleDiv.style.left = this.internal.critterDiv.offsetLeft - this.internal.bubbleDiv.offsetWidth + this.internal.agent.speechLeft + 'px';
		this.internal.bubbleDiv.style.top = this.internal.critterDiv.offsetTop - this.internal.bubbleDiv.offsetHeight + this.internal.agent.speechTop + 'px';
	},
	drawAgent: function ()
	{
		var pageY, pageX;
		this.internal.critterImg.src = this.internal.agent.src;
		this.internal.critterImg.style.width = this.internal.agent.width + 'px';
		this.internal.critterImg.style.height = this.internal.agent.height + 'px';
		pageY = this.internal.IE6 ? (window.pageYOffset || (document.documentElement.scrollTop || 0)) : 0;
		pageX = this.internal.IE6 ? (window.pageXOffset || (document.documentElement.scrollLeft || 0)) : 0;
		this.internal.critterDiv.style.left = this.internal.getPageWidth() + pageX - this.internal.agent.width - this.internal.agent.adjustLeft + 'px';
		this.internal.critterDiv.style.top = this.internal.getPageHeight() + pageY - this.internal.agent.height - this.internal.agent.adjustTop  + 'px';
	},
	draw: function ()
	{
		this.drawAgent();
		this.drawBalloon();
	},
	
	//Methods
	show: function ()
	{
		this.isHidden = false;
		this.internal.critterDiv.style.visibility = 'visible';
	},
	say: function (text, align)
	{
		if (!text)
		{
			return this.internal.bubbleText.innerHTML;
		}
		if (this.isHidden || this.isMute)
		{ 
			return;
		}
		this.isSpeaking = true;
		this.show();
		if (align)
		{
			this.internal.bubbleText.style.textAlign = align;
		}
		this.internal.bubbleText.innerHTML = text;
		this.drawBalloon();
		this.internal.bubbleDiv.style.visibility = 'visible';		
	},
	hush: function ()
	{
		this.isSpeaking = false;
		this.internal.bubbleText.innerHTML = '';
		this.internal.bubbleDiv.style.visibility = 'hidden';
	},
	hide: function ()
	{
		this.isHidden = true;
		this.hush();
		this.internal.critterDiv.style.visibility = 'hidden';
	},
	play: function (animationName)
	{
		this.internal.critterImg.src = this.internal.agent.animations[animationName];
		this.draw();
	},
	mute: function ()
	{
		this.isMute = true;
		this.hush();
	},
	unMute: function ()
	{
		this.isMute = false;
	},
	setFontColor: function (color)
	{
		this.internal.bubbleText.style.color = color;
	},
	setFontSize: function (size)
	{
		this.internal.bubbleText.style.fontSize = size;
	},
	setAgent: function (agent)
	{
		this.internal.agent = agent;
		this.draw();
	},
	
	//Event Handlers
	onClick: function ()
	{
		this.hush();
	},
	onMouseIn: function ()
	{
		return;
	},
	onMouseOut: function ()
	{
		return;
	},
	
	//Desstructor
	destroy: function ()
	{
		var i, prop;
		//We can't destroy our methods, since they are prototyped.  However, we can destroy all our objects;
		for (i in this.internal)
		{
			//delete our html elements
			if (this.internal[i].parentNode)
			{
				this.internal[i].onclick = null;
				this.internal[i].onmousein = null;
				this.internal[i].onmouseout = null;
				this.internal[i].parentNode.removeChild(this.internal[i]);
				delete this.internal[i];
			}
			//delete everything else in internal
			else
			{
				delete this.internal[i];
			}
		}
		//delete everything else;
		for (prop in this)
		{
			if (true)
			{
				this[prop] = null;
				delete this[prop];
			}
		}
		this.onClick = null;
		this.onMouseIn = null;
		this.onMouseOut =  null;
	}
};

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions