jquery.text.shadow.performance

JavaScript performance comparison

Revision 12 of this test case created by

Preparation code

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<style type="text/css">
			div.testing{background:black;color:red;height:200px;width:100%;text-align:center;margin:20px 0 0;text-shadow:0 1px 0 #FFF;}
			div.testing > span {text-align:center;}
		</style>
<div class="testing">
			testing string
		</div>
      
<script>
Benchmark.prototype.setup = function() {
  /*
   * Plugin: jquery.text.shadow
   * Version: 1.5
   *
   * Description:
   * - Improved text-shadow plugin for jQuery.
   */
  (function($){
  	var methods=[function(rx){return {x:0,y:0};},function(rx){return {x:rx[0],y:rx[0]};},function(rx){return {x:rx[0],y:rx[1]};},function(rx){return {x:rx[0],y:rx[1],radius:rx[2]};}];
  	$.extend($,{
  		textShadowParseEx:function(value){
  			var position=value.match(/(^|\s)-?(\d+)(?=[a-z%]+|\s|$)/gi),
  				color=value.match(/#[\da-f]{3,6}|(?:rgb|hsb)a?\(.*?\)|\b[a-z]+\b/i),
  				shadow={x:0,y:0,radius:0,color:color[0] || 'transparent'},
  				posLength=position.length || 0,
  				colorLength=color.length || 0;
  			
  			if (posLength>0 || colorLength>0)
  			{
  				$.extend(shadow,methods[Math.min(3,posLength)](position));
  				if ((!shadow.x && !shadow.y && !shadow.radius) || shadow.color == 'transparent')
  					$.extend(shadow,{x:0,y:0,radius:0,color:null});
  			}
  			
  			return shadow;
  		},
  		textShadowParse:function(str){
  			var values=str.split(','),index=values.length;
  		
  			if (index>0)
  			{
  				var stack=[];
  			
  				while(index--)
  					stack.push(this.textShadowParseEx(values[index]))
  
  				return stack;
  			}
  			
  			return [this.textShadowParseEx(str)];
  		}
  	});
  	$.fn.stextShadowParse=function(value){
  		return $.textShadowParse(value);
  	}
  })(jQuery);
  $.browser.msie 
  	? (function($){
  		var textShadow=function(element){
  			var shadowElement=document.createElement('span');
  		
  			return $.extend(this,{
  				append:function(){
  					var nodes=element.childNodes;
  					for (var i=0,il=nodes.length;i<il;i++)
  						if (! /jQueryTextShadow/i.test(nodes[i].className))
  							shadowElement.appendChild(nodes[i].cloneNode(true));
  						
  					element.appendChild(shadowElement);
  					
  					if ((element.offsetHeight || element.clientHeight)<(shadowElement.offsetHeight || shadowElement.clientHeight))
  							shadowElement.style.width=(parseInt(shadowElement.style.width)+1)+'px';
  				},
  				set:function(options){
  					shadowElement.className='jQueryTextShadow index'+options.index;
  
  					try
  					{
  						$.extend(shadowElement.style,{
  							padding:options.padding,
  							width:options.width+'px',
  							position:'absolute',
  							zIndex:'-1',
  							color:options.color,
  							left:options.posX+'px',
  							top:options.posY+'px'
  						});
  					} 
  					catch(e) {return false;}
  
  					if (options.radius!=0)
  						shadowElement.style.filter=options.opacity!=null 
  							? 'progid:DXImageTransform.Microsoft.Blur(pixelradius='+parseInt(options.radius)+', enabled=\'true\', makeShadow=\'true\', ShadowOpacity='+options.opacity+')'
  							: 'progid:DXImageTransform.Microsoft.Blur(pixelradius='+parseInt(options.radius)+', enabled=\'true\')';
  							
  					return true;
  				},
  				destroy:function(){
  					if (shadowElement.parentNode) element.removeChild(shadowElement);
  				}
  			});
  		};
  		$.extend(textShadow,{
  			prepareParent:$.browser.version<8 
  				? function (element) {
  					element.style.zoom=1;
  					element.style.zIndex=0;
  					if (element.currentStyle['position']!='absolute') element.style.position='relative';
  				} 
  				: function (element) {;
  					element.style.zIndex=0;
  					if (element.currentStyle['position']!='absolute') element.style.position='relative';
  				},
  			getIndex:function(el,shadow)
  			{
  				if (!('textShadowController' in el))
  				{
  					textShadow.prepareParent(el);
  					el.textShadowController={stackSize:1,stack:[shadow],freeSize:0,free:[]};
  					
  					return 0;
  				}
  				
  				var index=el.textShadowController.freeSize>0 ? el.textShadowController.free[--el.textShadowController.freeSize] : el.textShadowController.stackSize++;
  				el.textShadowController.stack[index]=shadow;
  				
  				return index;
  			},
  			add:function(el,props){
  				if (props.x==0 && props.y==0 && props.radius==0) return false;
  			
  				var style=el.currentStyle,
  					shadow=new textShadow(el),
  					index=textShadow.getIndex(el,shadow),
  					config={
  					padding:style["padding"],
  					width:Math.max(0,(el.offsetWidth || el.clientWidth)-parseInt(style['padding-left'])-parseInt(style['padding-right'])),
  					color:props.color!=null ? props.color : el.style.color,
  					posX:(-parseInt(props.radius)+parseInt(props.x)),
  					posY:(-parseInt(props.radius)+parseInt(props.y)),
  					radius: props.radius || 0,
  					index: index
  				};
  				
  				shadow.set(config) ? shadow.append() : textShadow.remove(el,index);	
  			},
  			remove:function(el,textShadowIndex){
  				if (textShadowIndex in el.textShadowController.stack)
  				{
  					el.textShadowController.stack[textShadowIndex].destroy();
  					el.textShadowController.stack[textShadowIndex]=null;
  					delete el.textShadowController.stack[textShadowIndex];
  					el.textShadowController.free[el.textShadowController.freeSize++]=textShadowIndex;
  					
  					return true;
  				}
  				
  				return false;
  			},
  			addMethods:{
  				0:function(c){
  					for (var index=0,indexLength=c.length;index<indexLength;index++)
  					{
  						var parse=$.textShadowParse(c[index].currentStyle['text-shadow']);
  						for (var j=0,jl=parse.length;j<jl;j++)
  							textShadow.add(c[index],parse[j]);
  					}
  				},
  				1:function(c,options){
  					for (var index=0,indexLength=c.length;index<indexLength;index++)
  					{
  						if ("length" in options)
  							for (var j=0,jl=options.length;j<jl;j++)
  								textShadow.add(c[index],$.extend({x:0,y:0,radius:0,color:null},options[j]));
  						else
  							textShadow.add(c[index],$.extend({x:0,y:0,radius:0,color:null},options));
  					}
  				},
  				2:function(c,options){
  					for (var index=0,indexLength=c.length;index<indexLength;index++)
  					{
  						var parse=$.textShadowParse(c[index].currentStyle['text-shadow']),
  							j=Math.max(options.length || 0,parse.length);
  					
  						if (j>0)
  						{
  							while(j--)
  								textShadow.add(c[index],(options[j] && parse[j]) 
  															? $.extend(options[j],parse[j]) 
  															: (options[j])
  																? options[j]
  																: parse[j]);
  						}
  						else
  							textShadow.add(c[index],$.extend(options,parse[0]));
  					}
  				}
  			}
  		});
  		$.extend($.fn,{
  			stextShadow:function(options,auto){
  				var argsLength=arguments.length;
  			
  				if (argsLength in textShadow.addMethods)
  					textShadow.addMethods[argsLength](this,options);
  			},
  			stextShadowRemove:function(textShadowIndex){
  				for (var index=0,indexLength=this.length;index<indexLength;index++)
  				{
  					var el=this[index];
  					if ('textShadowController' in el)
  					{
  						if (arguments.length>0)
  							textShadow.remove(el,textShadowIndex);
  						else
  							for (var index=0,indexLength=el.textShadowController.stack.length;index<indexLength;index++)
  								textShadow.remove(el,index);
  					}
  				}
  			}
  		});
  	})(jQuery)
  	: (function($){
  		$.extend($.fn,{
  			stextShadow:function(){return true},
  			stextShadowRemove:function(){return true}
  		});
  	})(jQuery);
  
  
  //---------------------------------------------------------
  
  $.browser.msie 
  ? (function($) {
  	var posShadowMethods={
  			0:function(rx){return {x:0,y:0};},
  			1:function(rx){return {x:rx[0],y:rx[0]};},
  			2:function(rx){return {x:rx[0],y:rx[1]};},
  			3:function(rx){return {x:rx[0],y:rx[1],radius:rx[2]};}
  		},
  		setStyle=$.browser.version<7 
  				? function (el) {
  					el.style.zIndex=0;
  					el.style.position="relative";
  				} 
  				: function (el) {
  					el.style.zoom=1;
  					el.style.zIndex=0;
  					el.style.position="relative";
  				}
  		fTextShadowParse=function(value) 
  		{
  			if (!value) return {x:0,y:0,radius:0,color:null};
  
  			var position=value.match(/(\d+)(?=[a-z%]+)/gi),
  				color=value.match(/#[0-9a-f]+|(?:rgb|hsb)a?\([^\)]*\)|\b[a-z]+\b/i),
  				shadow={x:0,y:0,radius:0,color:null},
  				posLength=position ? position.length : 0,
  				colorLength=color ? color.length : 0;
  				
  			if (posLength>0 || colorLength>0)
  			{
  				$.extend(shadow,posShadowMethods[posLength](position));
  				if ((!shadow.x && !shadow.y && !shadow.radius) || shadow.color == 'transparent')
  					$.extend(shadow,{x:0,y:0,radius:0,color:null});
  			}
  			
  			return shadow;
  		};
  		
  	$.fn.fTextShadow = function(option) {		
  		for (var index=0,indexLength=this.length;index<indexLength;index++)
  		{
  			var jel=$(this[index]),
  				el=this[index],
  				shadow=fTextShadowParse(el.currentStyle['text-shadow']);
  				
  			shadow = $.extend(shadow,option);
  			jel.fTextShadowRemove();
  			
  			if (shadow.x==0 && shadow.y==0 && shadow.radius==0)
  				return;
  			
  			setStyle(el);
  				
  			var span=document.createElement("span");		
  			span.className="jQueryTextShadow";
  			span.appendChild(document.createTextNode(el.textContent || el.innerText));
  
  			$.extend(span.style,{
  				padding:el.currentStyle['padding'],
  				width:(jel.width()+1)+'px',
  				position:'absolute',
  				zIndex:'-1',
  				color:shadow.color!=null ? shadow.color : el.style.color,
  				left:(-parseInt(shadow.radius)+parseInt(shadow.x))+'px',
  				top:(-parseInt(shadow.radius)+parseInt(shadow.y))+'px'
  			});	
  			
  			if (shadow.radius!=0)
  				span.style.filter=shadow.opacity!=null 
  									? "progid:DXImageTransform.Microsoft.Blur(pixelradius="+parseInt(shadow.radius)+", enabled='true', makeShadow='true', ShadowOpacity="+shadow.opacity+")"
  									: "progid:DXImageTransform.Microsoft.Blur(pixelradius="+parseInt(shadow.radius)+", enabled='true')";
  			
  			jel.append(span);
  		}
  		
  		return true;
  	};
  	$.fn.fTextShadowRemove = function() {
  		if (!$.browser.msie) return;
  		return this.children("span.jQueryTextShadow").remove();
  	};
  })(jQuery)
  : (function($) {
  	$.fn.fTextShadow = $.fn.fTextShadowRemove = function() {return true;};
  })(jQuery);
  
  /**** Textshadow START -->> *****/
  (function($) {
  	$.fn.textShadow = function(option) {
  		if (!$.browser.msie) return;
  		var IE6 = $.browser.version < 7;
  		return this.each(function() {
  			var el = $(this);
  			var shadow = el.textShadowParse(this.currentStyle["text-shadow"]);
  			shadow = $.extend(shadow, option);
  			el.textShadowRemove();
  			if (shadow.x == 0 && shadow.y == 0 && shadow.radius == 0) return;
  			if (el.css("position")=="static") {
  				el.css({position:"relative"});
  			}
  			el.css({zIndex:"0"});
  			if (IE6) {
  				el.css({zoom:"1"});
  			}
  			var span=document.createElement("span");
  			$(span).addClass("jQueryTextShadow");
  			$(span).html(el.html());
  			$(span).css({
  				padding:		this.currentStyle["padding"],	
  				width:		el.width()+1,
  				position:	"absolute",
  				zIndex:		"-1",
  				color:		shadow.color!=null?shadow.color:el.css("color"),
  				left:			(-parseInt(shadow.radius)+parseInt(shadow.x))+"px",
  				top:			(-parseInt(shadow.radius)+parseInt(shadow.y))+"px"
  			});
  			if (shadow.radius != 0) {
  				if (shadow.opacity != null) {
  					$(span).css("filter", "progid:DXImageTransform.Microsoft.Blur(pixelradius="+parseInt(shadow.radius)+", enabled='true', makeShadow='true', ShadowOpacity="+shadow.opacity+")");
  				} else {
  					$(span).css("filter", "progid:DXImageTransform.Microsoft.Blur(pixelradius="+parseInt(shadow.radius)+", enabled='true')");
  				}
  			}	
  			el.append(span);
  		
  	  });
  	};
  	$.fn.textShadowParse = function(value) 
  	{
  		value = String(value)
  			.replace(/^\s+|\s+$/gi, '')
  			.replace(/\s*!\s*important/i, '')
  			.replace(/\(\s*([^,\)]+)\s*,\s*([^,\)]+)\s*,\s*([^,\)]+)\s*,\s*([^\)]+)\s*\)/g, '($1/$2/$3/$4)')
  			.replace(/\(\s*([^,\)]+)\s*,\s*([^,\)]+)\s*,\s*([^\)]+)\s*\)/g, '($1/$2/$3)')
  		var shadow = {
  			x      : 0,
  			y      : 0,
  			radius : 0,
  			color  : null
  		};
  		if (value.length > 1 || value[0].toLowerCase() != 'none') {
  			value = value.replace(/\//g, ',');
  			var color;
  			if ( value.match(/(\#[0-9a-f]{6}|\#[0-9a-f]{3}|(rgb|hsb)a?\([^\)]*\)|\b[a-z]+\b)/i) && (color = RegExp.$1) ) {
  				shadow.color = color.replace(/^\s+/, '');
  				value = value.replace(shadow.color, '');
  			}
  			value = value
  				.replace(/^\s+|\s+$/g, '')
  				.split(/\s+/)
  				.map(function(item) {
  						return (item || '').replace(/^0[a-z]*$/, '') ? item : 0 ;
  					});
  			switch (value.length)
  			{
  				case 1:
  					shadow.x = shadow.y = value[0];
  					break;
  				case 2:
  					shadow.x = value[0];
  					shadow.y = value[1];
  					break;
  				case 3:
  					shadow.x = value[0];
  					shadow.y = value[1];
  					shadow.radius = value[2];
  					break;
  			}
  			if ((!shadow.x && !shadow.y && !shadow.radius) || shadow.color == 'transparent') {
  				shadow.x = shadow.y = shadow.radius = 0;
  				shadow.color = null;
  			}
  		}
  		return shadow;
  	};
  	$.fn.textShadowRemove = function() {
  		if (!$.browser.msie) return;
  		return this.each(function() {
  			$(this).children("span.jQueryTextShadow").remove();
  		});
  	};
  })(jQuery);
  
  if(typeof Array.prototype.map == 'undefined') {
  	Array.prototype.map = function(fnc) {
  		var a = new Array(this.length);
  		for (var i = 0; i < this.length; i++) {
  			a[i] = fnc(this[i]);
  		}
  		return a;
  	}
  }
  /**** Textshadow ENDE -->> *****/
  testElement=$('.testing');

};

Benchmark.prototype.teardown = function() {
  testElement.textShadowRemove();
  testElement.fTextShadowRemove();

};
</script>

Preparation code output

<style type="text/css"> div.testing{background:black;color:red;height:200px;width:100%;text-align:center;margin:20px 0 0;text-shadow:0 1px 0 #FFF;} div.testing > span {text-align:center;} </style> <div class="testing"> testing string </div>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
jquery.text.shadow
testElement.stextShadow();
testElement.stextShadowRemove();
pending…
normal textshadow
testElement.textShadow();
pending…
optimized textshadow
testElement.fTextShadow();
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL.

0 Comments

testing string