MyBB Community Forums

Full Version: Slow JavaScript Animation
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I've got an animated collapse function that's designed to be more or less a drop in replacement for MyBB's collapse javascript, but I've got a bit of a problem. It's not as good as it should be in Firefox, even though it's smooth in IE. I have not yet had a chance to try it in other browsers. Currently it should animate in ~30ms steps, though I've designed it so that it can use variable time steps (so that on a slow computer it still only takes ~250ms to close).

I was wondering if anyone could help me improve my code's performance, mainly in the animation update functions.

Here's the code. For those not familiar, '~' is a bitwise inverse operator that I'm using twice to trim floats to ints for the height pixel count, rather than Math.round().

The key things I'm looking at is doExp() and doCol(), though collapse() might be part of problem:
var togglables = {
	togglers: Array(),

	// Variable so I can override on a per-theme basis
	aniLength: 250,
	i: 0,
	
	init: function()
	{
		togglables.togglers = $$('img.toggle');
		if(togglables.togglers.length == 0)
			return true;
		
		togglables.togglers.each(function(toggler)
		{
			if(!toggler.id)
				return;
			
			toggler.indexID = togglables.i++;
			
			toggler.target = $(toggler.id.replace("_img", "_e"));
			
			if(toggler.target.style.display == "none")
				toggler.alt = '[+]';
			
			if(MyBB.browser == "ie")
				toggler.style.cursor = "hand";
			else
				toggler.style.cursor = "pointer";
			
			Event.observe(toggler, 'click', togglables.toggle.bind(togglables));
		}.bind(this));
		
		return true;
	},
	
	toggle: function(e)
	{
		element = Event.element(e);
		
		if(element.isMoving)
			return;
		
		element.target.style.margin = "-1px 0 0 0";
		
		if(element.alt == '[-]')
		{
			element.alt = '[+]';
			element.src = element.src.replace(".gif", "_collapsed.gif");
			this.collapse(element, -1);
		}
		else
		{
			element.alt = '[-]';
			element.src = element.src.replace("_collapsed.gif", ".gif");
			this.collapse(element, 1);
		}
	},
	
	collapse: function(element, dir)
	{
		element.isMoving = true;
		element.moveDir = dir;
		element.aniStart = (new Date()).getTime();
		
		element.target.style.display = "block";
		
		element.realHeight = element.target.scrollHeight;
		
		element.target.style.overflow = "hidden";
		
		if(dir == 1)
		{
			element.target.style.height = "1px";
			element.aniTimer = setInterval('togglables.doExp(togglables.togglers[' + element.indexID + ']);', 30);
		}
		else
		{
			element.aniTimer = setInterval('togglables.doCol(togglables.togglers[' + element.indexID + ']);', 30);
		}
	},
	
	doExp: function(element)
	{
		var elapsed = (new Date()).getTime() - element.aniStart;
		if(elapsed < togglables.aniLength)
			element.target.style.height = (~~((elapsed / togglables.aniLength) * element.realHeight)) + 'px';
		else
			togglables.stop(element);
	},
	
	doCol: function(element)
	{
		var elapsed = (new Date()).getTime() - element.aniStart;
		var rh = element.realHeight;
		if(elapsed < togglables.aniLength)
			element.target.style.height = (rh - ~~((elapsed / togglables.aniLength) * rh)) + 'px';
		else
			togglables.stop(element);
	},
	
	stop: function(element)
	{
		clearInterval(element.aniTimer);
		if(element.moveDir == -1)
			element.target.style.display = 'none';
		delete element.aniTimer;
		element.isMoving = false;
		if(element.moveDir == -1)
			togglables.saveCollapsed(element.id.replace("_img", ""), 1);
		else
		{
			element.target.style.overflow = "inherit";
			element.target.style.height = "auto";
			togglables.saveCollapsed(element.id.replace("_img", ""));
		}
	},

	// Taken from MyBB's implementation
	saveCollapsed: function(id, add)
	{
		var saved = new Array();
		var newCollapsed = new Array();
		var collapsed = Cookie.get("collapsed");

		if(collapsed)
		{
			saved = collapsed.split("|");
			saved.each(function(item) {
				if(item != id && item != "")
				{
					newCollapsed[newCollapsed.length] = item;
				}
			});
		}

		if(add == 1)
		{
			newCollapsed[newCollapsed.length] = id;
		}
		Cookie.set("collapsed", newCollapsed.join("|"));
	}
};
(2011-10-05, 11:29 PM)Firestryke31 Wrote: [ -> ]I've got an animated collapse function that's designed to be more or less a drop in replacement for MyBB's collapse javascript, but I've got a bit of a problem. It's not as good as it should be in Firefox, even though it's smooth in IE. I have not yet had a chance to try it in other browsers. Currently it should animate in ~30ms steps, though I've designed it so that it can use variable time steps (so that on a slow computer it still only takes ~250ms to close).

I was wondering if anyone could help me improve my code's performance, mainly in the animation update functions.

Here's the code. For those not familiar, '~' is a bitwise inverse operator that I'm using twice to trim floats to ints for the height pixel count, rather than Math.round().

The key things I'm looking at is doExp() and doCol(), though collapse() might be part of problem:
var togglables = {
	togglers: Array(),

	// Variable so I can override on a per-theme basis
	aniLength: 250,
	i: 0,
	
	init: function()
	{
		togglables.togglers = $$('img.toggle');
		if(togglables.togglers.length == 0)
			return true;
		
		togglables.togglers.each(function(toggler)
		{
			if(!toggler.id)
				return;
			
			toggler.indexID = togglables.i++;
			
			toggler.target = $(toggler.id.replace("_img", "_e"));
			
			if(toggler.target.style.display == "none")
				toggler.alt = '[+]';
			
			if(MyBB.browser == "ie")
				toggler.style.cursor = "hand";
			else
				toggler.style.cursor = "pointer";
			
			Event.observe(toggler, 'click', togglables.toggle.bind(togglables));
		}.bind(this));
		
		return true;
	},
	
	toggle: function(e)
	{
		element = Event.element(e);
		
		if(element.isMoving)
			return;
		
		element.target.style.margin = "-1px 0 0 0";
		
		if(element.alt == '[-]')
		{
			element.alt = '[+]';
			element.src = element.src.replace(".gif", "_collapsed.gif");
			this.collapse(element, -1);
		}
		else
		{
			element.alt = '[-]';
			element.src = element.src.replace("_collapsed.gif", ".gif");
			this.collapse(element, 1);
		}
	},
	
	collapse: function(element, dir)
	{
		element.isMoving = true;
		element.moveDir = dir;
		element.aniStart = (new Date()).getTime();
		
		element.target.style.display = "block";
		
		element.realHeight = element.target.scrollHeight;
		
		element.target.style.overflow = "hidden";
		
		if(dir == 1)
		{
			element.target.style.height = "1px";
			element.aniTimer = setInterval('togglables.doExp(togglables.togglers[' + element.indexID + ']);', 30);
		}
		else
		{
			element.aniTimer = setInterval('togglables.doCol(togglables.togglers[' + element.indexID + ']);', 30);
		}
	},
	
	doExp: function(element)
	{
		var elapsed = (new Date()).getTime() - element.aniStart;
		if(elapsed < togglables.aniLength)
			element.target.style.height = (~~((elapsed / togglables.aniLength) * element.realHeight)) + 'px';
		else
			togglables.stop(element);
	},
	
	doCol: function(element)
	{
		var elapsed = (new Date()).getTime() - element.aniStart;
		var rh = element.realHeight;
		if(elapsed < togglables.aniLength)
			element.target.style.height = (rh - ~~((elapsed / togglables.aniLength) * rh)) + 'px';
		else
			togglables.stop(element);
	},
	
	stop: function(element)
	{
		clearInterval(element.aniTimer);
		if(element.moveDir == -1)
			element.target.style.display = 'none';
		delete element.aniTimer;
		element.isMoving = false;
		if(element.moveDir == -1)
			togglables.saveCollapsed(element.id.replace("_img", ""), 1);
		else
		{
			element.target.style.overflow = "inherit";
			element.target.style.height = "auto";
			togglables.saveCollapsed(element.id.replace("_img", ""));
		}
	},

	// Taken from MyBB's implementation
	saveCollapsed: function(id, add)
	{
		var saved = new Array();
		var newCollapsed = new Array();
		var collapsed = Cookie.get("collapsed");

		if(collapsed)
		{
			saved = collapsed.split("|");
			saved.each(function(item) {
				if(item != id && item != "")
				{
					newCollapsed[newCollapsed.length] = item;
				}
			});
		}

		if(add == 1)
		{
			newCollapsed[newCollapsed.length] = id;
		}
		Cookie.set("collapsed", newCollapsed.join("|"));
	}
};

Did you find a way to fix this?
No, but with 1.8 on jQuery you should be able to use their animations.
jQuery Will make this easy Smile
I'm a noob with coding. How do i add this to my mybb forum. (Latest version)
Once MyBB 1.8 comes out it'll be a lot easier. Until then it's a bit more complicated but still possible to use jQuery.

I'd suggest not using my code though, like I said it's slow, and IIRC buggy. If for some reason you insist on using it despite it's original author saying it's not worth using you can just save it as toggle.js, include it in headerinclude, have the page call toggleables.init() after the body loads, and replace 'expander' with 'toggle' on all the expander images.
Thank you. However i found this, http://www.bestgamers.it/forum/T-fancy-c...query.html and it's working but it's a little rusty.