/* * based off of Louis-Rémi Babé rotate plugin (https://github.com/lrbabe/jquery.rotate.js) * * cssTransforms: jQuery cssHooks adding a cross browser, animatible transforms * * Author Bobby Schultz */ // (function($) { var div = document.createElement('div'), divStyle = div.style; //give props to those who dont have them $.cssProps.transform = divStyle.MozTransform === '' ? 'MozTransform' : (divStyle.msTransform === '' ? 'msTransform' : (divStyle.WebkitTransform === '' ? 'WebkitTransform' : (divStyle.OTransform === '' ? 'OTransform' : (divStyle.Transform === '' ? 'Transform' : false)))); $.cssProps.transformOrigin = divStyle.MozTransformOrigin === '' ? 'MozTransformOrigin' : (divStyle.msTransformOrigin === '' ? 'msTransformOrigin' : (divStyle.WebkitTransformOrigin === '' ? 'WebkitTransformOrigin' : (divStyle.OTransformOrigin === '' ? 'OTransformOrigin' : (divStyle.TransformOrigin === '' ? 'TransformOrigin' : false)))); //define supported or not $.support.transform = $.cssProps.transform !== false || divStyle.filter === '' ? true : false; $.support.transformOrigin = $.cssProps.transformOrigin !== false ? true : false; //if ONLY IE matrixes are supported (IE9 beta6 will use css3) $.support.matrixFilter = (divStyle.filter === '' && $.cssProps.transform === false) ? true : false; div = null; //stop if no form of transforms are supported if($.support.transform === false) return; //opt out of letting jquery handle the units for custom setters/getters $.cssNumber.skew = $.cssNumber.skewX = $.cssNumber.skewY = $.cssNumber.scale = $.cssNumber.scaleX = $.cssNumber.scaleY = $.cssNumber.rotate = $.cssNumber.matrix = true; $.cssNumber.transformOrigin = $.cssNumber.transformOriginX = $.cssNumber.transformOriginY = true; if($.support.matrixFilter) { $.cssNumber.transformOrigin = $.cssNumber.transformOriginX = $.cssNumber.transformOriginY = true; $.cssProps.transformOrigin = 'matrixFilter'; } $.cssHooks.transform = { set: function(elem, val, unit) { if($.support.matrixFilter) { elem.style.filter = [val].join(''); } else { elem.style[$.cssProps.transform] = val+'%'; } }, get: function(elem, computed) { if($.support.matrixFilter) { return elem.style.filter; } else { return elem.style[$.cssProps.transform]; } } }; $.cssHooks.transformOrigin = { set: function(elem, val, unit) { if(!$.support.matrixFilter) { val = (typeof val === 'string') ? val : val+(unit || '%'); elem.style[$.cssProps.transformOrigin] = val; } else { val = val.split(","); $.cssHooks.transformOriginX.set( elem, val[0] ); if(val.length > 1) { $.cssHooks.transformOriginY.set( elem, val[1] ); } } }, get: function(elem, computed) { if(!$.support.matrixFilter) { return elem.style[$.cssProps.transformOrigin]; } else { var originX = $.data( elem, 'transformOriginX' ); var originY = $.data( elem, 'transformOriginY' ); return originX && originY && originX === originY ? originX : '50%'; } } }; $.fx.step.transformOrigin = function( fx ) { $.cssHooks.transformOrigin.set( fx.elem, fx.now, fx.unit); }; $.cssHooks.transformOriginX = { set: function(elem, val, unit) { if(!$.support.matrixFilter) { val = (typeof val === 'string') ? val : val+(unit || '%'); elem.style[$.cssProps.transformOrigin+'X'] = val; } else { $.data( elem, 'transformOriginX', unit ? val+unit : val ); setIEMatrix(elem); } }, get: function(elem, computed) { if(!$.support.matrixFilter) { return elem.style[$.cssProps.transformOrigin+'X']; } else { var originX = $.data( elem, 'transformOriginX' ); switch(originX) { case 'left': return '0%'; case 'center': return '50%'; case 'right': return '100%'; } return originX ? originX : '50%'; } } }; $.fx.step.transformOriginX = function( fx ) { $.cssHooks.transformOriginX.set( fx.elem, fx.now, fx.unit); }; $.cssHooks.transformOriginY = { set: function(elem, val, unit) { if(!$.support.matrixFilter) { val = (typeof val === 'string') ? val : val+(unit || '%'); elem.style[$.cssProps.transformOrigin+'Y'] = val; } else { $.data( elem, 'transformOriginY', unit ? val+unit : val ); setIEMatrix(elem); } }, get: function(elem, computed) { if(!$.support.matrixFilter) { return elem.style[$.cssProps.transformOrigin+'Y']; } else { var originY = $.data( elem, 'transformOriginY' ); switch(originY) { case 'top': return '0%'; case 'center': return '50%'; case 'bottom': return '100%'; } return originY ? originY : '50%'; } } }; $.fx.step.transformOriginY = function( fx ) { $.cssHooks.transformOriginY.set( fx.elem, fx.now, fx.unit); }; //create hooks for css transforms var rtn = function(v){return v;}; var xy = [['X','Y'],'X','Y']; var abcdxy = [['A','B','C','D','X','Y'],'A','B','C','D','X','Y'] var props = [ {prop: 'rotate', matrix: [function(v){ return Math.cos(v); }, function(v){ return -Math.sin(v); }, function(v){ return Math.sin(v); }, function(v){ return Math.cos(v); } ], unit: 'rad', subProps: [''], fnc: toRadian}, {prop: 'scale', matrix: [[rtn,0,0,rtn], [rtn,0,0,1], [1,0,0,rtn]], unit: '', subProps: xy, fnc: parseFloat, _default:1}, {prop: 'skew', matrix: [[1,rtn,rtn,1], [1,rtn,0,1], [1,0,rtn,1]], unit: 'rad', subProps: xy, fnc: toRadian}, {prop: 'translate', matrix: [[1,0,0,1,rtn,rtn], [1,0,0,1,rtn,0], [1,0,0,1,0,rtn]], standardUnit: 'px', subProps: xy, fnc: parseFloat}, {prop: 'matrix', matrix: [[rtn,rtn,rtn,rtn,rtn,rtn], [rtn,0,0,1,0,0], [1,rtn,0,1,0,0], [1,0,rtn,1,0,0], [1,0,0,rtn,0,0], [1,0,0,1,0,rtn]], subProps: abcdxy, fnc: parseFloat} ]; jQuery.each(props, function(n,prop){ jQuery.each(prop.subProps, function(num, sub){ var _cssProp, _prop = prop; if( $.isArray(sub) ) { //composite transform _cssProp = _prop.prop; var _sub = sub; $.cssHooks[_cssProp] = { set: function( elem, val, unit ) { jQuery.each(_sub, function(num, x){ $.cssHooks[_cssProp+x].set(elem, val, unit); }); }, get: function( elem, computed ) { var val = []; jQuery.each(_sub, function(num, x){ val.push( $.cssHooks[_cssProp+x].get(elem, val) ); }); //hack until jQuery supports animating multiple properties return val[0] || val[1]; } } } else { //independent transfrom _cssProp = _prop.prop+sub; //alert(_cssProp); //******** $.cssHooks[_cssProp] = { set: function( elem, val, unit ) { $.data( elem, _cssProp, unit ? val+unit : val); setCSSTransform( elem, _prop.fnc(unit ? val+unit : val), _cssProp, _prop.unit || unit || _prop.standardUnit); }, get: function( elem, computed ) { var p = $.data( elem, _cssProp ); //console.log(_cssProp+'get:'+p); return p && p !== undefined ? p : _prop._default || 0; } }; } $.fx.step[_cssProp] = function( fx ) { fx.unit = fx.unit === 'px' && $.cssNumber[_cssProp] ? _prop.standardUnit : fx.unit; var unit = ($.cssNumber[_cssProp] ? '' : fx.unit); $.cssHooks[_cssProp].set( fx.elem, fx.now, fx.unit); }; }) }); function setCSSTransform( elem, val, prop, unit ){ if($.support.matrixFilter) { return setIEMatrix(elem, val); } //parse css string var allProps = parseCSSTransform(elem); //check for value to be set var a = /[X|Y]/.exec(prop); a = (a === null ? '' : a[0] ? a[0] : a); prop = /.*[^XY]/.exec(prop)[0]; unit = unit === undefined ? '' : unit; //create return string var result = ''; var wasUpdated = false; var arr; if(allProps !== null) { for(var item in allProps) { arr = allProps[item]; if(prop === item) { //update parsed data with new value if(prop !== 'matrix') { result += prop+'('; result += a === 'X' || a === '' ? val+unit : (arr[0] !== '' ? arr[0] : $.cssHooks[prop+'X'].get(elem)+unit); result += a === 'Y' ? ', '+val+unit : (arr[1] !== '' ? ', '+arr[1] : (prop+'Y' in $.cssHooks ? ', '+$.cssHooks[prop+'Y'].get(elem)+unit : '')); result += ') '; } else { result += val+' '; } wasUpdated = true; } else { //dump parsed data to string result += item + '('; for(var i=0; i 0 ? (/[\d]*/.exec(Wp) / 100) : Wp; Hp = Hp.indexOf('%') > 0 ? (/[\d]*/.exec(Hp) / 100) : Hp; var Wb = elem.offsetWidth; var Hb = elem.offsetHeight; } //multiply old matrix to new matrix if( typeof mat !== 'array' || mat.length !== 6 ) { mat = current; } else { mat = [ ( (current[0]*mat[0]) + (current[1]*mat[2]) ), ( (current[0]*mat[1]) + (current[1]*mat[3]) ), ( (current[2]*mat[0]) + (current[3]*mat[2]) ), ( (current[2]*mat[1]) + (current[3]*mat[3]) ), mat[4], mat[5] ]; } //multiply the transform and rotation matrixes ang = $.data(elem, 'rotate'); if(ang) { ang = toRadian(ang); var cos = Math.cos(ang); var sin = Math.sin(ang); ang = [cos, -sin, sin, cos]; mat = [ ( (mat[0]*ang[0]) + (mat[1]*ang[2]) ), ( (mat[0]*ang[1]) + (mat[1]*ang[3]) ), ( (mat[2]*ang[0]) + (mat[3]*ang[2]) ), ( (mat[2]*ang[1]) + (mat[3]*ang[3]) ), mat[4], mat[5] ]; } //apply the matrix as a IE filter elem.style.filter = [ "progid:DXImageTransform.Microsoft.Matrix(", "M11="+mat[0]+", ", "M12="+mat[1]+", ", "M21="+mat[2]+", ", "M22="+mat[3]+", ", "SizingMethod='auto expand'", ")" ].join(''); if (runTransform) { var Wo = elem.offsetWidth; var Ho = elem.offsetHeight; elem.style.position = 'relative'; elem.style.left = Wp * (Wb - Wo) + (parseInt(mat[4]) || 0); elem.style.top = Hp * (Hb - Ho) + (parseInt(mat[5]) || 0); } //$('#console').append('
trans:'+Wp+":"+Wb+":"+Wo+":"+mat[4]+":"+elem.style.left+'
'); } })(jQuery);