JavaScript Tween function

This is a small library I wrote for creating simple and complicated easing effects without using JQuery, MooTools or other JS libraries.

The library is small 13.4 KB or 5.6 KB compressed,

The function can be called as follows:

tween(element, property, from, to, duration, [optional] function)

Parameters

element: The idĀ  of the HTML element you want to animate likeĀ  “my_div”, “left_sidebar”, DOM objects are also accepted

property: The CSS property that you want to animate like “color”, background-color”, “left”, “margin-top”…

from: The initial value, like 0px, top, none, 0.5…

to: The final value

duration: the animation duration in ms

function (optional): the easing function to use, by default the tween function uses the linear tween, there are nine other functions included (easeInBack, easeOutBack, easeInOutBack, easeInCirc, easeOutCirc, easeInOutCirc, easeInBounce, easeOutBounce & easeInOutBounce)

Examples

Demos available here

Minified version

Function available here

Full version

var fps = 40;
 
var debugging = 0;
var tw = [];
var rand_str = generatePassword();
var float_pcre = new RegExp("(\\+|-)?(\\d*\\.)?\\d+",'g');
var color_at_end = new RegExp("[Cc]olor$");
 
function tween(element, property, from, to, duration){ 
 
	if (arguments.length < 5) 		return false; 		 	// Let's first remove old tweens from the tw table to gain performance 	if(Math.random()>=0.75){
		for(var i=0; i<=tw[tw_id]["steps"] && tw[tw_id]["step"]!==0 && tw[tw_id]["status"] === 'playing'){ 		if(tw[tw_id]["is_color_tween"]){ 			var red 	= parseInt(eval(tw[tw_id]["f"])(tw[tw_id]["step"], parseInt(tw[tw_id]["from"]["red"])	, parseInt(tw[tw_id]["change"]["red"])	, tw[tw_id]["steps"])); 			var green 	= parseInt(eval(tw[tw_id]["f"])(tw[tw_id]["step"], parseInt(tw[tw_id]["from"]["green"])	, parseInt(tw[tw_id]["change"]["green"])	, tw[tw_id]["steps"])); 			var blue 	= parseInt(eval(tw[tw_id]["f"])(tw[tw_id]["step"], parseInt(tw[tw_id]["from"]["blue"])	, parseInt(tw[tw_id]["change"]["blue"])	, tw[tw_id]["steps"])); 			tw[tw_id]["ez"] = "rgb("+red+","+green+","+blue+")"; 		} 		else{ 			tw[tw_id]["ez"] = parseInt(eval(tw[tw_id]["f"])(tw[tw_id]["step"], tw[tw_id]["from"], tw[tw_id]["change"], tw[tw_id]["steps"])*100)/100; 			tw[tw_id]["ez"] = tw[tw_id]["prefix"]+ tw[tw_id]["ez"] + tw[tw_id]["suffix"]; 		} 		tw[tw_id]["timer"] = setTimeout("ease_repeat("+tw_id+")",tw[tw_id]["interval"]); 	} 	 	if(tw[tw_id]["step"]>=tw[tw_id]["steps"]){
		tw[tw_id]["status"] = "complete";
	}
 
}
 
function ease_repeat(tw_id){
	try{
		tw[tw_id]["element"].style[tw[tw_id]["property"]] = tw[tw_id]["ez"];
		ease(tw_id);
	}
	catch(e){}
}
 
/* Keep it simple with these nice functions */
 
function h2d(h) {
	// hex to decimal
	return parseInt(h,16);
} 
 
function str_replace (search, replace, subject, count) {
	// version: 908.406
	// discuss at: http://phpjs.org/functions/str_replace
 
    var i = 0, j = 0, temp = '', repl = '', sl = 0, fl = 0,
  	f = [].concat(search),
		r = [].concat(replace),
		s = subject,
		ra = r instanceof Array, sa = s instanceof Array;
	s = [].concat(s);
	if (count)
		this.window[count] = 0;
	for (i=0, sl=s.length; i < sl; i++) {
		if (s[i] === '')
			continue;
		for (j=0, fl=f.length; j < fl; j++) { 			temp = s[i]+''; 			repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0]; 			s[i] = (temp).split(f[j]).join(repl); 			if (count && s[i] !== temp) { 				this.window[count] += (temp.length-s[i].length)/f[j].length;} 		}    }     return sa ? s : s[0]; } function resolve_element(element){ 	if(typeof(element) == "object") 		; 	else if(typeof(element) == "string") 		element = document.getElementById(element); 	if(element.tagName != "undefined") 		return element; 	return  false; } function resolve_property(property){  	//  resolve_property("-moz-border-radius") => "MozBorderRadius";
	var matched;
	var dash_letter = new RegExp("-[a-z]");
	while(1){
		if(matched = property.match(dash_letter)){
		  matched = matched.toString();
			property = str_replace(matched, matched.charAt(1).toUpperCase(), property);
		}
		else
			break;
	}
	return property;
}
 
function resolve_color(color){
	// return an array containing R, G and B values
	if(color === 'transparent')// IE (6 and ?)
		color = '#FFF';
	var r,g,b;
	var hex_color_pcre = new RegExp("^#[0-9a-f]{3}([0-9a-f]{3})?$",'gi');
	var rgb_color_pcre = new RegExp("rgb\\(\\s*((?:[0-2]?[0-9])?[0-9])\\s*,\\s*((?:[0-2]?[0-9])?[0-9])\\s*,\\s*((?:[0-2]?[0-9])?[0-9])\\s*\\)$",'gi');
	var rgb_percent_color_pcre = new RegExp("rgb\\(\\s*((?:[0-1]?[0-9])?[0-9])%\\s*,\\s*((?:[0-1]?[0-9])?[0-9])%\\s*,\\s*((?:[0-1]?[0-9])?[0-9])%\\s*\\)$",'gi');
	if(color.match(hex_color_pcre)){
		if(color.length == 4){
			r  = color.charAt(1)+""+color.charAt(1);
			g  = color.charAt(2)+""+color.charAt(2);
			b  = color.charAt(3)+""+color.charAt(3);
		}
		else{
			r  = color.charAt(1)+""+color.charAt(2);
			g  = color.charAt(3)+""+color.charAt(4);
			b  = color.charAt(5)+""+color.charAt(6);
		}
		r = h2d(r);
		g = h2d(g);
		b = h2d(b);
	}
	else if(color.match(rgb_color_pcre)){
		r = RegExp.$1;
		g = RegExp.$2;
		b = RegExp.$3;
	}
	else if(color.match(rgb_percent_color_pcre)){
		r = parseInt((RegExp.$1)*2.55);
		g = parseInt((RegExp.$2)*2.55);
		b = parseInt((RegExp.$3)*2.55);
	}
	else
		return false;
 
	var returned =[];
	returned['red'] = r;
	returned['green'] = g;
	returned['blue'] = b;
	return returned;
}
 
function getStyle(oElm, strCssRule){
	// http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
	var strValue = "";
	if(document.defaultView && document.defaultView.getComputedStyle){
		strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
	}
	else if(oElm.currentStyle){
		strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
			return p1.toUpperCase();
		});
		strValue = oElm.currentStyle[strCssRule];
	}
	return strValue;
}
 
function generatePassword(len){
	// http://www.kadimi.com/en/javascript/random-password-string/
	len	= parseInt(len);
	if(!len)
		len = 6;
	var password = "";
	var chars    = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	var charsN   = chars.length;
	var nextChar;
 
	for(i=0;i< 0) {
        f_start += f_string.length;
    }
 
    if (f_length == undefined) {
        f_length = f_string.length;
    } else if (f_length < 0){
        f_length += f_string.length;
    } else {
        f_length += f_start;
    }
 
    if (f_length < f_start) {         f_length = f_start;     }     return f_string.substring(f_start, f_length); } function microtime (get_as_float) {     // Returns either a string or a float containing the current time in seconds and microseconds       // discuss at: http://phpjs.org/functions/microtime     // +   original by: Paulo Ricardo F. Santos     // *     example 1: timeStamp = microtime(true);     // *     results 1: timeStamp > 1000000000 && timeStamp < 2000000000
    var now = new Date().getTime() / 1000;
    var s = parseInt(now, 10);
 
    return (get_as_float) ? now : (Math.round((now - s) * 1000) / 1000) + ' ' + s;
}
 
// My favorite $()
function $() {
	//http://v3.thewatchmakerproject.com/code/extended-dollar.txt
	var elements = new Array();
	for (var i=0,len=arguments.length;i< 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
	return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
};
 
//Circulat
easeInCirc = function (t, b, c, d) {
	return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
};
 
easeOutCirc = function (t, b, c, d) {
	return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
};
 
easeInOutCirc = function (t, b, c, d) {
	if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
	return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
};
 
//Bounce
easeInBounce = function (t, b, c, d) {
	return c - easeOutBounce (d-t, 0, c, d) + b;
};
 
easeOutBounce = function (t, b, c, d) {
	if ((t/=d) < (1/2.75)) {
		return c*(7.5625*t*t) + b;
	} else if (t < (2/2.75)) {
		return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
	} else if (t < (2.5/2.75)) {
		return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
	} else {
		return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
	}
};
easeInOutBounce = function (t, b, c, d) {
	if (t < d/2) return easeInBounce (t*2, 0, c, d) * .5 + b;
	return easeOutBounce (t*2-d, 0, c, d) * .5 + c*.5 + b;
};
//*/

4 Comments

  1. Peter Bowey says:

    Thanks Kadimi for sharing this tween() javascript function:

    I have taken the original ‘minimized’ tween() js code and expanded it back to a human readable source. I have corrected some JSLint issues presented with code and additionally corrected two js ‘if conditionals’ that had no ‘TRUE’ state code to execute. I think this code you have created is educational in human readable code format:

    >————————————-<

    // Use: tween(element, property, from, to, duration, [optional] function)
    // Where: element: ID of HTML element, property: CSS property for tween'ing, from: initial value, to: final value

    var fps = 40;
    var debugging = 0;
    var tw = [];
    [...] code removed by Nabil Kadimi

    >-------------------------------------<

    Peter Bowey

    • Nabil says:

      Thank you for your interest, this small library is a draft and I will put more effort on improving if I see that people like you are willing to support it by providing bug reports and feedback.

      I posted the full version of the function and I will – in the near future – have a repository and a bug tracker.

  2. Peter Bowey says:

    Notes: The two (original) failed ‘if’ conditionals occur on the following code:

    1) if (tw[f]["from_orig"] === ‘current’); // line 53
    2) if (typeof(a) == “object”); // line 155

    There is no ‘TRUE’ state code to execute after either of the above condtions. Note the semicolon; ending each condition

    Peter Bowey

    • Nabil says:

      I wrote that on purpose, this doesn’t hurt but sure there is a better way to write it.

      Actually I should have wrote a comment to remember me why I coded it that way… oops.

      But the way, I forgot to tell you that I was very busy with my personal life, I apologize for not responding to your comments/requests earlier.

Leave a Reply