diff --git a/lib/sylvester-0.1.3.min.js b/lib/sylvester-0.1.3.min.js index 606a63b..41503ea 100644 --- a/lib/sylvester-0.1.3.min.js +++ b/lib/sylvester-0.1.3.min.js @@ -1 +1,23 @@ -var Sylvester={version:"0.1.3",precision:0.000001};function Vector(){}Vector.prototype={e:function(i){return(i<1||i>this.elements.length)?null:this.elements[i-1]},dimensions:function(){return this.elements.length},modulus:function(){return Math.sqrt(this.dot(this))},eql:function(vector){var n=this.elements.length;var V=vector.elements||vector;if(n!=V.length){return false}do{if(Math.abs(this.elements[n-1]-V[n-1])>Sylvester.precision){return false}}while(--n);return true},dup:function(){return Vector.create(this.elements)},map:function(fn){var elements=[];this.each(function(x,i){elements.push(fn(x,i))});return Vector.create(elements)},each:function(fn){var n=this.elements.length,k=n,i;do{i=k-n;fn(this.elements[i],i+1)}while(--n)},toUnitVector:function(){var r=this.modulus();if(r===0){return this.dup()}return this.map(function(x){return x/r})},angleFrom:function(vector){var V=vector.elements||vector;var n=this.elements.length,k=n,i;if(n!=V.length){return null}var dot=0,mod1=0,mod2=0;this.each(function(x,i){dot+=x*V[i-1];mod1+=x*x;mod2+=V[i-1]*V[i-1]});mod1=Math.sqrt(mod1);mod2=Math.sqrt(mod2);if(mod1*mod2===0){return null}var theta=dot/(mod1*mod2);if(theta<-1){theta=-1}if(theta>1){theta=1}return Math.acos(theta)},isParallelTo:function(vector){var angle=this.angleFrom(vector);return(angle===null)?null:(angle<=Sylvester.precision)},isAntiparallelTo:function(vector){var angle=this.angleFrom(vector);return(angle===null)?null:(Math.abs(angle-Math.PI)<=Sylvester.precision)},isPerpendicularTo:function(vector){var dot=this.dot(vector);return(dot===null)?null:(Math.abs(dot)<=Sylvester.precision)},add:function(vector){var V=vector.elements||vector;if(this.elements.length!=V.length){return null}return this.map(function(x,i){return x+V[i-1]})},subtract:function(vector){var V=vector.elements||vector;if(this.elements.length!=V.length){return null}return this.map(function(x,i){return x-V[i-1]})},multiply:function(k){return this.map(function(x){return x*k})},x:function(k){return this.multiply(k)},dot:function(vector){var V=vector.elements||vector;var i,product=0,n=this.elements.length;if(n!=V.length){return null}do{product+=this.elements[n-1]*V[n-1]}while(--n);return product},cross:function(vector){var B=vector.elements||vector;if(this.elements.length!=3||B.length!=3){return null}var A=this.elements;return Vector.create([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},max:function(){var m=0,n=this.elements.length,k=n,i;do{i=k-n;if(Math.abs(this.elements[i])>Math.abs(m)){m=this.elements[i]}}while(--n);return m},indexOf:function(x){var index=null,n=this.elements.length,k=n,i;do{i=k-n;if(index===null&&this.elements[i]==x){index=i+1}}while(--n);return index},toDiagonalMatrix:function(){return Matrix.Diagonal(this.elements)},round:function(){return this.map(function(x){return Math.round(x)})},snapTo:function(x){return this.map(function(y){return(Math.abs(y-x)<=Sylvester.precision)?x:y})},distanceFrom:function(obj){if(obj.anchor){return obj.distanceFrom(this)}var V=obj.elements||obj;if(V.length!=this.elements.length){return null}var sum=0,part;this.each(function(x,i){part=x-V[i-1];sum+=part*part});return Math.sqrt(sum)},liesOn:function(line){return line.contains(this)},liesIn:function(plane){return plane.contains(this)},rotate:function(t,obj){var V,R,x,y,z;switch(this.elements.length){case 2:V=obj.elements||obj;if(V.length!=2){return null}R=Matrix.Rotation(t).elements;x=this.elements[0]-V[0];y=this.elements[1]-V[1];return Vector.create([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);break;case 3:if(!obj.direction){return null}var C=obj.pointClosestTo(this).elements;R=Matrix.Rotation(t,obj.direction).elements;x=this.elements[0]-C[0];y=this.elements[1]-C[1];z=this.elements[2]-C[2];return Vector.create([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);break;default:return null}},reflectionIn:function(obj){if(obj.anchor){var P=this.elements.slice();var C=obj.pointClosestTo(P).elements;return Vector.create([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}else{var Q=obj.elements||obj;if(this.elements.length!=Q.length){return null}return this.map(function(x,i){return Q[i-1]+(Q[i-1]-x)})}},to3D:function(){var V=this.dup();switch(V.elements.length){case 3:break;case 2:V.elements.push(0);break;default:return null}return V},inspect:function(){return"["+this.elements.join(", ")+"]"},setElements:function(els){this.elements=(els.elements||els).slice();return this}};Vector.create=function(elements){var V=new Vector();return V.setElements(elements)};Vector.i=Vector.create([1,0,0]);Vector.j=Vector.create([0,1,0]);Vector.k=Vector.create([0,0,1]);Vector.Random=function(n){var elements=[];do{elements.push(Math.random())}while(--n);return Vector.create(elements)};Vector.Zero=function(n){var elements=[];do{elements.push(0)}while(--n);return Vector.create(elements)};function Matrix(){}Matrix.prototype={e:function(i,j){if(i<1||i>this.elements.length||j<1||j>this.elements[0].length){return null}return this.elements[i-1][j-1]},row:function(i){if(i>this.elements.length){return null}return Vector.create(this.elements[i-1])},col:function(j){if(j>this.elements[0].length){return null}var col=[],n=this.elements.length,k=n,i;do{i=k-n;col.push(this.elements[i][j-1])}while(--n);return Vector.create(col)},dimensions:function(){return{rows:this.elements.length,cols:this.elements[0].length}},rows:function(){return this.elements.length},cols:function(){return this.elements[0].length},eql:function(matrix){var M=matrix.elements||matrix;if(typeof(M[0][0])=="undefined"){M=Matrix.create(M).elements}if(this.elements.length!=M.length||this.elements[0].length!=M[0].length){return false}var ni=this.elements.length,ki=ni,i,nj,kj=this.elements[0].length,j;do{i=ki-ni;nj=kj;do{j=kj-nj;if(Math.abs(this.elements[i][j]-M[i][j])>Sylvester.precision){return false}}while(--nj)}while(--ni);return true},dup:function(){return Matrix.create(this.elements)},map:function(fn){var els=[],ni=this.elements.length,ki=ni,i,nj,kj=this.elements[0].length,j;do{i=ki-ni;nj=kj;els[i]=[];do{j=kj-nj;els[i][j]=fn(this.elements[i][j],i+1,j+1)}while(--nj)}while(--ni);return Matrix.create(els)},isSameSizeAs:function(matrix){var M=matrix.elements||matrix;if(typeof(M[0][0])=="undefined"){M=Matrix.create(M).elements}return(this.elements.length==M.length&&this.elements[0].length==M[0].length)},add:function(matrix){var M=matrix.elements||matrix;if(typeof(M[0][0])=="undefined"){M=Matrix.create(M).elements}if(!this.isSameSizeAs(M)){return null}return this.map(function(x,i,j){return x+M[i-1][j-1]})},subtract:function(matrix){var M=matrix.elements||matrix;if(typeof(M[0][0])=="undefined"){M=Matrix.create(M).elements}if(!this.isSameSizeAs(M)){return null}return this.map(function(x,i,j){return x-M[i-1][j-1]})},canMultiplyFromLeft:function(matrix){var M=matrix.elements||matrix;if(typeof(M[0][0])=="undefined"){M=Matrix.create(M).elements}return(this.elements[0].length==M.length)},multiply:function(matrix){if(!matrix.elements){return this.map(function(x){return x*matrix})}var returnVector=matrix.modulus?true:false;var M=matrix.elements||matrix;if(typeof(M[0][0])=="undefined"){M=Matrix.create(M).elements}if(!this.canMultiplyFromLeft(M)){return null}var ni=this.elements.length,ki=ni,i,nj,kj=M[0].length,j;var cols=this.elements[0].length,elements=[],sum,nc,c;do{i=ki-ni;elements[i]=[];nj=kj;do{j=kj-nj;sum=0;nc=cols;do{c=cols-nc;sum+=this.elements[i][c]*M[c][j]}while(--nc);elements[i][j]=sum}while(--nj)}while(--ni);var M=Matrix.create(elements);return returnVector?M.col(1):M},x:function(matrix){return this.multiply(matrix)},minor:function(a,b,c,d){var elements=[],ni=c,i,nj,j;var rows=this.elements.length,cols=this.elements[0].length;do{i=c-ni;elements[i]=[];nj=d;do{j=d-nj;elements[i][j]=this.elements[(a+i-1)%rows][(b+j-1)%cols]}while(--nj)}while(--ni);return Matrix.create(elements)},transpose:function(){var rows=this.elements.length,cols=this.elements[0].length;var elements=[],ni=cols,i,nj,j;do{i=cols-ni;elements[i]=[];nj=rows;do{j=rows-nj;elements[i][j]=this.elements[j][i]}while(--nj)}while(--ni);return Matrix.create(elements)},isSquare:function(){return(this.elements.length==this.elements[0].length)},max:function(){var m=0,ni=this.elements.length,ki=ni,i,nj,kj=this.elements[0].length,j;do{i=ki-ni;nj=kj;do{j=kj-nj;if(Math.abs(this.elements[i][j])>Math.abs(m)){m=this.elements[i][j]}}while(--nj)}while(--ni);return m},indexOf:function(x){var index=null,ni=this.elements.length,ki=ni,i,nj,kj=this.elements[0].length,j;do{i=ki-ni;nj=kj;do{j=kj-nj;if(this.elements[i][j]==x){return{i:i+1,j:j+1}}}while(--nj)}while(--ni);return null},diagonal:function(){if(!this.isSquare){return null}var els=[],n=this.elements.length,k=n,i;do{i=k-n;els.push(this.elements[i][i])}while(--n);return Vector.create(els)},toRightTriangular:function(){var M=this.dup(),els;var n=this.elements.length,k=n,i,np,kp=this.elements[0].length,p;do{i=k-n;if(M.elements[i][i]==0){for(j=i+1;jSylvester.precision){rank++;break}}while(--nj)}while(--ni);return rank},rk:function(){return this.rank()},augment:function(matrix){var M=matrix.elements||matrix;if(typeof(M[0][0])=="undefined"){M=Matrix.create(M).elements}var T=this.dup(),cols=T.elements[0].length;var ni=T.elements.length,ki=ni,i,nj,kj=M[0].length,j;if(ni!=M.length){return null}do{i=ki-ni;nj=kj;do{j=kj-nj;T.elements[i][cols+j]=M[i][j]}while(--nj)}while(--ni);return T},inverse:function(){if(!this.isSquare()||this.isSingular()){return null}var ni=this.elements.length,ki=ni,i,j;var M=this.augment(Matrix.I(ni)).toRightTriangular();var np,kp=M.elements[0].length,p,els,divisor;var inverse_elements=[],new_element;do{i=ni-1;els=[];np=kp;inverse_elements[i]=[];divisor=M.elements[i][i];do{p=kp-np;new_element=M.elements[i][p]/divisor;els.push(new_element);if(p>=ki){inverse_elements[i].push(new_element)}}while(--np);M.elements[i]=els;for(j=0;j3||direction.elements.length>3){return null}var mod=direction.modulus();if(mod===0){return null}this.anchor=anchor;this.direction=Vector.create([direction.elements[0]/mod,direction.elements[1]/mod,direction.elements[2]/mod]);return this}};Line.create=function(anchor,direction){var L=new Line();return L.setVectors(anchor,direction)};Line.X=Line.create(Vector.Zero(3),Vector.i);Line.Y=Line.create(Vector.Zero(3),Vector.j);Line.Z=Line.create(Vector.Zero(3),Vector.k);function Plane(){}Plane.prototype={eql:function(plane){return(this.contains(plane.anchor)&&this.isParallelTo(plane))},dup:function(){return Plane.create(this.anchor,this.normal)},translate:function(vector){var V=vector.elements||vector;return Plane.create([this.anchor.elements[0]+V[0],this.anchor.elements[1]+V[1],this.anchor.elements[2]+(V[2]||0)],this.normal)},isParallelTo:function(obj){var theta;if(obj.normal){theta=this.normal.angleFrom(obj.normal);return(Math.abs(theta)<=Sylvester.precision||Math.abs(Math.PI-theta)<=Sylvester.precision)}else{if(obj.direction){return this.normal.isPerpendicularTo(obj.direction)}}return null},isPerpendicularTo:function(plane){var theta=this.normal.angleFrom(plane.normal);return(Math.abs(Math.PI/2-theta)<=Sylvester.precision)},distanceFrom:function(obj){if(this.intersects(obj)||this.contains(obj)){return 0}if(obj.anchor){var A=this.anchor.elements,B=obj.anchor.elements,N=this.normal.elements;return Math.abs((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}else{var P=obj.elements||obj;var A=this.anchor.elements,N=this.normal.elements;return Math.abs((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},contains:function(obj){if(obj.normal){return null}if(obj.direction){return(this.contains(obj.anchor)&&this.contains(obj.anchor.add(obj.direction)))}else{var P=obj.elements||obj;var A=this.anchor.elements,N=this.normal.elements;var diff=Math.abs(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));return(diff<=Sylvester.precision)}},intersects:function(obj){if(typeof(obj.direction)=="undefined"&&typeof(obj.normal)=="undefined"){return null}return !this.isParallelTo(obj)},intersectionWith:function(obj){if(!this.intersects(obj)){return null}if(obj.direction){var A=obj.anchor.elements,D=obj.direction.elements,P=this.anchor.elements,N=this.normal.elements;var multiplier=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);return Vector.create([A[0]+D[0]*multiplier,A[1]+D[1]*multiplier,A[2]+D[2]*multiplier])}else{if(obj.normal){var direction=this.normal.cross(obj.normal).toUnitVector();var N=this.normal.elements,A=this.anchor.elements,O=obj.normal.elements,B=obj.anchor.elements;var solver=Matrix.Zero(2,2),i=0;while(solver.isSingular()){i++;solver=Matrix.create([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}var inverse=solver.inverse().elements;var x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];var y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];var intersection=[inverse[0][0]*x+inverse[0][1]*y,inverse[1][0]*x+inverse[1][1]*y];var anchor=[];for(var j=1;j<=3;j++){anchor.push((i==j)?0:intersection[(j+(5-i)%3)%3])}return Line.create(anchor,direction)}}},pointClosestTo:function(point){var P=point.elements||point;var A=this.anchor.elements,N=this.normal.elements;var dot=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];return Vector.create([P[0]+N[0]*dot,P[1]+N[1]*dot,(P[2]||0)+N[2]*dot])},rotate:function(t,line){var R=Matrix.Rotation(t,line.direction).elements;var C=line.pointClosestTo(this.anchor).elements;var A=this.anchor.elements,N=this.normal.elements;var C1=C[0],C2=C[1],C3=C[2],A1=A[0],A2=A[1],A3=A[2];var x=A1-C1,y=A2-C2,z=A3-C3;return Plane.create([C1+R[0][0]*x+R[0][1]*y+R[0][2]*z,C2+R[1][0]*x+R[1][1]*y+R[1][2]*z,C3+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},reflectionIn:function(obj){if(obj.normal){var A=this.anchor.elements,N=this.normal.elements;var A1=A[0],A2=A[1],A3=A[2],N1=N[0],N2=N[1],N3=N[2];var newA=this.anchor.reflectionIn(obj).elements;var AN1=A1+N1,AN2=A2+N2,AN3=A3+N3;var Q=obj.pointClosestTo([AN1,AN2,AN3]).elements;var newN=[Q[0]+(Q[0]-AN1)-newA[0],Q[1]+(Q[1]-AN2)-newA[1],Q[2]+(Q[2]-AN3)-newA[2]];return Plane.create(newA,newN)}else{if(obj.direction){return this.rotate(Math.PI,obj)}else{var P=obj.elements||obj;return Plane.create(this.anchor.reflectionIn([P[0],P[1],(P[2]||0)]),this.normal)}}},setVectors:function(anchor,v1,v2){anchor=Vector.create(anchor);anchor=anchor.to3D();if(anchor===null){return null}v1=Vector.create(v1);v1=v1.to3D();if(v1===null){return null}if(typeof(v2)=="undefined"){v2=null}else{v2=Vector.create(v2);v2=v2.to3D();if(v2===null){return null}}var A1=anchor.elements[0],A2=anchor.elements[1],A3=anchor.elements[2];var v11=v1.elements[0],v12=v1.elements[1],v13=v1.elements[2];var normal,mod;if(v2!==null){var v21=v2.elements[0],v22=v2.elements[1],v23=v2.elements[2];normal=Vector.create([(v12-A2)*(v23-A3)-(v13-A3)*(v22-A2),(v13-A3)*(v21-A1)-(v11-A1)*(v23-A3),(v11-A1)*(v22-A2)-(v12-A2)*(v21-A1)]);mod=normal.modulus();if(mod===0){return null}normal=Vector.create([normal.elements[0]/mod,normal.elements[1]/mod,normal.elements[2]/mod])}else{mod=Math.sqrt(v11*v11+v12*v12+v13*v13);if(mod===0){return null}normal=Vector.create([v1.elements[0]/mod,v1.elements[1]/mod,v1.elements[2]/mod])}this.anchor=anchor;this.normal=normal;return this}};Plane.create=function(anchor,v1,v2){var P=new Plane();return P.setVectors(anchor,v1,v2)};Plane.XY=Plane.create(Vector.Zero(3),Vector.k);Plane.YZ=Plane.create(Vector.Zero(3),Vector.i);Plane.ZX=Plane.create(Vector.Zero(3),Vector.j);Plane.YX=Plane.XY;Plane.ZY=Plane.YZ;Plane.XZ=Plane.ZX;var $V=Vector.create;var $M=Matrix.create;var $L=Line.create;var $P=Plane.create; \ No newline at end of file +// === Sylvester === +// Vector and Matrix mathematics modules for JavaScript +// Copyright (c) 2007 James Coglan +// +// 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. +// +// 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. + +var Sylvester={version:"0.1.3",precision:0.000001};function Vector(){}Vector.prototype={e:function(a){return(a<1||a>this.elements.length)?null:this.elements[a-1]},dimensions:function(){return this.elements.length},modulus:function(){return Math.sqrt(this.dot(this))},eql:function(b){var c=this.elements.length;var a=b.elements||b;if(c!=a.length){return false}do{if(Math.abs(this.elements[c-1]-a[c-1])>Sylvester.precision){return false}}while(--c);return true},dup:function(){return Vector.create(this.elements)},map:function(a){var b=[];this.each(function(c,d){b.push(a(c,d))});return Vector.create(b)},each:function(c){var d=this.elements.length,a=d,b;do{b=a-d;c(this.elements[b],b+1)}while(--d)},toUnitVector:function(){var a=this.modulus();if(a===0){return this.dup()}return this.map(function(b){return b/a})},angleFrom:function(d){var e=d.elements||d;var c=this.elements.length,f=c,g;if(c!=e.length){return null}var a=0,l=0,h=0;this.each(function(k,m){a+=k*e[m-1];l+=k*k;h+=e[m-1]*e[m-1]});l=Math.sqrt(l);h=Math.sqrt(h);if(l*h===0){return null}var b=a/(l*h);if(b<-1){b=-1}if(b>1){b=1}return Math.acos(b)},isParallelTo:function(a){var b=this.angleFrom(a);return(b===null)?null:(b<=Sylvester.precision)},isAntiparallelTo:function(a){var b=this.angleFrom(a);return(b===null)?null:(Math.abs(b-Math.PI)<=Sylvester.precision)},isPerpendicularTo:function(a){var b=this.dot(a);return(b===null)?null:(Math.abs(b)<=Sylvester.precision)},add:function(b){var a=b.elements||b;if(this.elements.length!=a.length){return null}return this.map(function(c,d){return c+a[d-1]})},subtract:function(b){var a=b.elements||b;if(this.elements.length!=a.length){return null}return this.map(function(c,d){return c-a[d-1]})},multiply:function(a){return this.map(function(b){return b*a})},x:function(a){return this.multiply(a)},dot:function(b){var a=b.elements||b;var c,d=0,e=this.elements.length;if(e!=a.length){return null}do{d+=this.elements[e-1]*a[e-1]}while(--e);return d},cross:function(b){var c=b.elements||b;if(this.elements.length!=3||c.length!=3){return null}var a=this.elements;return Vector.create([(a[1]*c[2])-(a[2]*c[1]),(a[2]*c[0])-(a[0]*c[2]),(a[0]*c[1])-(a[1]*c[0])])},max:function(){var a=0,d=this.elements.length,b=d,c;do{c=b-d;if(Math.abs(this.elements[c])>Math.abs(a)){a=this.elements[c]}}while(--d);return a},indexOf:function(a){var c=null,e=this.elements.length,b=e,d;do{d=b-e;if(c===null&&this.elements[d]==a){c=d+1}}while(--e);return c},toDiagonalMatrix:function(){return Matrix.Diagonal(this.elements)},round:function(){return this.map(function(a){return Math.round(a)})},snapTo:function(a){return this.map(function(b){return(Math.abs(b-a)<=Sylvester.precision)?a:b})},distanceFrom:function(d){if(d.anchor){return d.distanceFrom(this)}var a=d.elements||d;if(a.length!=this.elements.length){return null}var c=0,b;this.each(function(e,f){b=e-a[f-1];c+=b*b});return Math.sqrt(c)},liesOn:function(a){return a.contains(this)},liesIn:function(a){return a.contains(this)},rotate:function(c,e){var b,d,a,h,g;switch(this.elements.length){case 2:b=e.elements||e;if(b.length!=2){return null}d=Matrix.Rotation(c).elements;a=this.elements[0]-b[0];h=this.elements[1]-b[1];return Vector.create([b[0]+d[0][0]*a+d[0][1]*h,b[1]+d[1][0]*a+d[1][1]*h]);break;case 3:if(!e.direction){return null}var f=e.pointClosestTo(this).elements;d=Matrix.Rotation(c,e.direction).elements;a=this.elements[0]-f[0];h=this.elements[1]-f[1];g=this.elements[2]-f[2];return Vector.create([f[0]+d[0][0]*a+d[0][1]*h+d[0][2]*g,f[1]+d[1][0]*a+d[1][1]*h+d[1][2]*g,f[2]+d[2][0]*a+d[2][1]*h+d[2][2]*g]);break;default:return null}},reflectionIn:function(c){if(c.anchor){var b=this.elements.slice();var d=c.pointClosestTo(b).elements;return Vector.create([d[0]+(d[0]-b[0]),d[1]+(d[1]-b[1]),d[2]+(d[2]-(b[2]||0))])}else{var a=c.elements||c;if(this.elements.length!=a.length){return null}return this.map(function(e,f){return a[f-1]+(a[f-1]-e)})}},to3D:function(){var a=this.dup();switch(a.elements.length){case 3:break;case 2:a.elements.push(0);break;default:return null}return a},inspect:function(){return"["+this.elements.join(", ")+"]"},setElements:function(a){this.elements=(a.elements||a).slice();return this}};Vector.create=function(b){var a=new Vector();return a.setElements(b)};Vector.i=Vector.create([1,0,0]);Vector.j=Vector.create([0,1,0]);Vector.k=Vector.create([0,0,1]);Vector.Random=function(b){var a=[];do{a.push(Math.random())}while(--b);return Vector.create(a)};Vector.Zero=function(b){var a=[];do{a.push(0)}while(--b);return Vector.create(a)};function Matrix(){}Matrix.prototype={e:function(b,a){if(b<1||b>this.elements.length||a<1||a>this.elements[0].length){return null}return this.elements[b-1][a-1]},row:function(a){if(a>this.elements.length){return null}return Vector.create(this.elements[a-1])},col:function(c){if(c>this.elements[0].length){return null}var b=[],e=this.elements.length,a=e,d;do{d=a-e;b.push(this.elements[d][c-1])}while(--e);return Vector.create(b)},dimensions:function(){return{rows:this.elements.length,cols:this.elements[0].length}},rows:function(){return this.elements.length},cols:function(){return this.elements[0].length},eql:function(a){var h=a.elements||a;if(typeof(h[0][0])=="undefined"){h=Matrix.create(h).elements}if(this.elements.length!=h.length||this.elements[0].length!=h[0].length){return false}var e=this.elements.length,g=e,d,c,f=this.elements[0].length,b;do{d=g-e;c=f;do{b=f-c;if(Math.abs(this.elements[d][b]-h[d][b])>Sylvester.precision){return false}}while(--c)}while(--e);return true},dup:function(){return Matrix.create(this.elements)},map:function(f){var e=[],d=this.elements.length,h=d,c,b,g=this.elements[0].length,a;do{c=h-d;b=g;e[c]=[];do{a=g-b;e[c][a]=f(this.elements[c][a],c+1,a+1)}while(--b)}while(--d);return Matrix.create(e)},isSameSizeAs:function(a){var b=a.elements||a;if(typeof(b[0][0])=="undefined"){b=Matrix.create(b).elements}return(this.elements.length==b.length&&this.elements[0].length==b[0].length)},add:function(a){var b=a.elements||a;if(typeof(b[0][0])=="undefined"){b=Matrix.create(b).elements}if(!this.isSameSizeAs(b)){return null}return this.map(function(c,e,d){return c+b[e-1][d-1]})},subtract:function(a){var b=a.elements||a;if(typeof(b[0][0])=="undefined"){b=Matrix.create(b).elements}if(!this.isSameSizeAs(b)){return null}return this.map(function(c,e,d){return c-b[e-1][d-1]})},canMultiplyFromLeft:function(a){var b=a.elements||a;if(typeof(b[0][0])=="undefined"){b=Matrix.create(b).elements}return(this.elements[0].length==b.length)},multiply:function(q){if(!q.elements){return this.map(function(c){return c*q})}var h=q.modulus?true:false;var n=q.elements||q;if(typeof(n[0][0])=="undefined"){n=Matrix.create(n).elements}if(!this.canMultiplyFromLeft(n)){return null}var e=this.elements.length,f=e,l,b,d=n[0].length,g;var p=this.elements[0].length,a=[],m,k,o;do{l=f-e;a[l]=[];b=d;do{g=d-b;m=0;k=p;do{o=p-k;m+=this.elements[l][o]*n[o][g]}while(--k);a[l][g]=m}while(--b)}while(--e);var n=Matrix.create(a);return h?n.col(1):n},x:function(a){return this.multiply(a)},minor:function(p,o,m,l){var e=[],g=m,k,f,h;var q=this.elements.length,n=this.elements[0].length;do{k=m-g;e[k]=[];f=l;do{h=l-f;e[k][h]=this.elements[(p+k-1)%q][(o+h-1)%n]}while(--f)}while(--g);return Matrix.create(e)},transpose:function(){var f=this.elements.length,g=this.elements[0].length;var e=[],d=g,c,b,a;do{c=g-d;e[c]=[];b=f;do{a=f-b;e[c][a]=this.elements[a][c]}while(--b)}while(--d);return Matrix.create(e)},isSquare:function(){return(this.elements.length==this.elements[0].length)},max:function(){var a=0,e=this.elements.length,g=e,d,c,f=this.elements[0].length,b;do{d=g-e;c=f;do{b=f-c;if(Math.abs(this.elements[d][b])>Math.abs(a)){a=this.elements[d][b]}}while(--c)}while(--e);return a},indexOf:function(a){var d=null,f=this.elements.length,h=f,e,c,g=this.elements[0].length,b;do{e=h-f;c=g;do{b=g-c;if(this.elements[e][b]==a){return{i:e+1,j:b+1}}}while(--c)}while(--f);return null},diagonal:function(){if(!this.isSquare){return null}var c=[],d=this.elements.length,a=d,b;do{b=a-d;c.push(this.elements[b][b])}while(--d);return Vector.create(c)},toRightTriangular:function(){var f=this.dup(),d;var b=this.elements.length,c=b,e,g,h=this.elements[0].length,a;do{e=c-b;if(f.elements[e][e]==0){for(j=e+1;jSylvester.precision){g++;break}}while(--b)}while(--d);return g},rk:function(){return this.rank()},augment:function(l){var h=l.elements||l;if(typeof(h[0][0])=="undefined"){h=Matrix.create(h).elements}var e=this.dup(),k=e.elements[0].length;var c=e.elements.length,d=c,g,a,b=h[0].length,f;if(c!=h.length){return null}do{g=d-c;a=b;do{f=b-a;e.elements[g][k+f]=h[g][f]}while(--a)}while(--c);return e},inverse:function(){if(!this.isSquare()||this.isSingular()){return null}var c=this.elements.length,d=c,h,g;var k=this.augment(Matrix.I(c)).toRightTriangular();var l,m=k.elements[0].length,a,f,b;var n=[],e;do{h=c-1;f=[];l=m;n[h]=[];b=k.elements[h][h];do{a=m-l;e=k.elements[h][a]/b;f.push(e);if(a>=d){n[h].push(e)}}while(--l);k.elements[h]=f;for(g=0;g3||c.elements.length>3){return null}var b=c.modulus();if(b===0){return null}this.anchor=a;this.direction=Vector.create([c.elements[0]/b,c.elements[1]/b,c.elements[2]/b]);return this}};Line.create=function(b,c){var a=new Line();return a.setVectors(b,c)};Line.X=Line.create(Vector.Zero(3),Vector.i);Line.Y=Line.create(Vector.Zero(3),Vector.j);Line.Z=Line.create(Vector.Zero(3),Vector.k);function Plane(){}Plane.prototype={eql:function(a){return(this.contains(a.anchor)&&this.isParallelTo(a))},dup:function(){return Plane.create(this.anchor,this.normal)},translate:function(b){var a=b.elements||b;return Plane.create([this.anchor.elements[0]+a[0],this.anchor.elements[1]+a[1],this.anchor.elements[2]+(a[2]||0)],this.normal)},isParallelTo:function(b){var a;if(b.normal){a=this.normal.angleFrom(b.normal);return(Math.abs(a)<=Sylvester.precision||Math.abs(Math.PI-a)<=Sylvester.precision)}else{if(b.direction){return this.normal.isPerpendicularTo(b.direction)}}return null},isPerpendicularTo:function(a){var b=this.normal.angleFrom(a.normal);return(Math.abs(Math.PI/2-b)<=Sylvester.precision)},distanceFrom:function(c){if(this.intersects(c)||this.contains(c)){return 0}if(c.anchor){var a=this.anchor.elements,e=c.anchor.elements,d=this.normal.elements;return Math.abs((a[0]-e[0])*d[0]+(a[1]-e[1])*d[1]+(a[2]-e[2])*d[2])}else{var b=c.elements||c;var a=this.anchor.elements,d=this.normal.elements;return Math.abs((a[0]-b[0])*d[0]+(a[1]-b[1])*d[1]+(a[2]-(b[2]||0))*d[2])}},contains:function(d){if(d.normal){return null}if(d.direction){return(this.contains(d.anchor)&&this.contains(d.anchor.add(d.direction)))}else{var b=d.elements||d;var a=this.anchor.elements,e=this.normal.elements;var c=Math.abs(e[0]*(a[0]-b[0])+e[1]*(a[1]-b[1])+e[2]*(a[2]-(b[2]||0)));return(c<=Sylvester.precision)}},intersects:function(a){if(typeof(a.direction)=="undefined"&&typeof(a.normal)=="undefined"){return null}return !this.isParallelTo(a)},intersectionWith:function(k){if(!this.intersects(k)){return null}if(k.direction){var d=k.anchor.elements,a=k.direction.elements,l=this.anchor.elements,n=this.normal.elements;var r=(n[0]*(l[0]-d[0])+n[1]*(l[1]-d[1])+n[2]*(l[2]-d[2]))/(n[0]*a[0]+n[1]*a[1]+n[2]*a[2]);return Vector.create([d[0]+a[0]*r,d[1]+a[1]*r,d[2]+a[2]*r])}else{if(k.normal){var q=this.normal.cross(k.normal).toUnitVector();var n=this.normal.elements,d=this.anchor.elements,m=k.normal.elements,c=k.anchor.elements;var s=Matrix.Zero(2,2),h=0;while(s.isSingular()){h++;s=Matrix.create([[n[h%3],n[(h+1)%3]],[m[h%3],m[(h+1)%3]]])}var f=s.inverse().elements;var p=n[0]*d[0]+n[1]*d[1]+n[2]*d[2];var o=m[0]*c[0]+m[1]*c[1]+m[2]*c[2];var b=[f[0][0]*p+f[0][1]*o,f[1][0]*p+f[1][1]*o];var g=[];for(var e=1;e<=3;e++){g.push((h==e)?0:b[(e+(5-h)%3)%3])}return Line.create(g,q)}}},pointClosestTo:function(b){var d=b.elements||b;var a=this.anchor.elements,e=this.normal.elements;var c=(a[0]-d[0])*e[0]+(a[1]-d[1])*e[1]+(a[2]-(d[2]||0))*e[2];return Vector.create([d[0]+e[0]*c,d[1]+e[1]*c,(d[2]||0)+e[2]*c])},rotate:function(o,p){var f=Matrix.Rotation(o,p.direction).elements;var a=p.pointClosestTo(this.anchor).elements;var c=this.anchor.elements,k=this.normal.elements;var i=a[0],h=a[1],g=a[2],e=c[0],d=c[1],b=c[2];var n=e-i,m=d-h,l=b-g;return Plane.create([i+f[0][0]*n+f[0][1]*m+f[0][2]*l,h+f[1][0]*n+f[1][1]*m+f[1][2]*l,g+f[2][0]*n+f[2][1]*m+f[2][2]*l],[f[0][0]*k[0]+f[0][1]*k[1]+f[0][2]*k[2],f[1][0]*k[0]+f[1][1]*k[1]+f[1][2]*k[2],f[2][0]*k[0]+f[2][1]*k[1]+f[2][2]*k[2]])},reflectionIn:function(f){if(f.normal){var c=this.anchor.elements,k=this.normal.elements;var e=c[0],d=c[1],b=c[2],n=k[0],m=k[1],l=k[2];var a=this.anchor.reflectionIn(f).elements;var q=e+n,p=d+m,o=b+l;var h=f.pointClosestTo([q,p,o]).elements;var g=[h[0]+(h[0]-q)-a[0],h[1]+(h[1]-p)-a[1],h[2]+(h[2]-o)-a[2]];return Plane.create(a,g)}else{if(f.direction){return this.rotate(Math.PI,f)}else{var i=f.elements||f;return Plane.create(this.anchor.reflectionIn([i[0],i[1],(i[2]||0)]),this.normal)}}},setVectors:function(i,o,n){i=Vector.create(i);i=i.to3D();if(i===null){return null}o=Vector.create(o);o=o.to3D();if(o===null){return null}if(typeof(n)=="undefined"){n=null}else{n=Vector.create(n);n=n.to3D();if(n===null){return null}}var f=i.elements[0],e=i.elements[1],d=i.elements[2];var k=o.elements[0],h=o.elements[1],g=o.elements[2];var l,m;if(n!==null){var c=n.elements[0],b=n.elements[1],a=n.elements[2];l=Vector.create([(h-e)*(a-d)-(g-d)*(b-e),(g-d)*(c-f)-(k-f)*(a-d),(k-f)*(b-e)-(h-e)*(c-f)]);m=l.modulus();if(m===0){return null}l=Vector.create([l.elements[0]/m,l.elements[1]/m,l.elements[2]/m])}else{m=Math.sqrt(k*k+h*h+g*g);if(m===0){return null}l=Vector.create([o.elements[0]/m,o.elements[1]/m,o.elements[2]/m])}this.anchor=i;this.normal=l;return this}};Plane.create=function(a,d,c){var b=new Plane();return b.setVectors(a,d,c)};Plane.XY=Plane.create(Vector.Zero(3),Vector.k);Plane.YZ=Plane.create(Vector.Zero(3),Vector.i);Plane.ZX=Plane.create(Vector.Zero(3),Vector.j);Plane.YX=Plane.XY;Plane.ZY=Plane.YZ;Plane.XZ=Plane.ZX;var $V=Vector.create;var $M=Matrix.create;var $L=Line.create;var $P=Plane.create; \ No newline at end of file diff --git a/lib/transform.js b/lib/transform.js deleted file mode 100644 index f215800..0000000 --- a/lib/transform.js +++ /dev/null @@ -1,1097 +0,0 @@ -(function($, window, document, undefined) { - /** - * Converting a radian to a degree - * @const - */ - var RAD_DEG = 180/Math.PI; - - /** - * Converting a degree to a radian - * @const - */ - var DEG_RAD = (Math.PI/180); - - /** - * @var Regex identifies functions that require an angle unit - */ - var unitAngle = /rotate|skew[X|Y]?/; - - /** - * @var Regex identifies functions that require a length unit - */ - var unitLength = /translate[X|Y]?/; - - /** - * @var Regex identifies functions that require a length unit - */ - var unitless = /scale[X|Y]?/; - - /** - * @var Regex looks for units on a string - */ - var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/; - - /** - * @var Regex identify if additional values are hidden in the unit - */ - var rfxmultinum = /^(.*?)\s+([+\-]=)?([\d+.\-]+)(.*)$/; - - /** - * @var Regex identify the matrix filter in IE - */ - var rmatrix = /progid:DXImageTransform\.Microsoft\.Matrix\(.*?\)/; - - /** - * @var Array list of all valid transform functions - */ - var transformFuncs = ['rotate', 'scale', 'scaleX', 'scaleY', 'skew', 'skewX', 'skewY', 'translate', 'translateX', 'translateY']; - - /** - * @param DOMElement | jQueryElement element - * @construct - */ - var o = window['Transform'] = function(element) { - /** - * The element we're working with - * @var jQueryCollection - */ - this.$elem = $(element); - - /** - * Remember the transform property so we don't have to keep looking it up - * @var string - */ - this.transformProperty = this._getTransformProperty(); - - - //IE mangles the height and width, let's try to preserve them - //NOTE: if someone was rude enough to transform it in IE with CSS then we're kind of screwed - //NOTE: if someone is rude enough to alter the height or width then we're also screwed - if (!this.transformProperty && !this.$elem.data('dims')) { - this.$elem.data('dims', { - height: this.$elem.height(), - width: this.$elem.width(), - outerHeight: this.$elem.outerHeight(), - outerWidth: this.$elem.outerWidth(), - innerHeight: this.$elem.innerHeight(), - innerWidth: this.$elem.innerWidth() - }); - } - }, - p = o.prototype; - - /** - * Create Transform as a jQuery plugin - * @param Object funcs - * @param Object options - */ - jQuery.fn.transform = function(funcs, options) { - return this.each(function() { - var t = new o(this); - if (funcs) { - t.transform(funcs, options); - } - }); - }; - - // Extend the jQuery animation to handle transform functions - /** - * Doctors prop values in the event that they contain spaces - * @param Object prop - * @param String speed - * @param String easing - * @param Function callback - * @return bool - */ - var _animate = $.fn.animate; - $.fn.animate = function( prop, speed, easing, callback ) { - if (prop && !jQuery.isEmptyObject(prop)) { - var elem = this[0]; - jQuery.each( prop, function( name, val ) { - // Clean up the numbers for space-sperated prop values - if ($.inArray(transformFuncs, name)) { - var parts = rfxnum.exec(val); - if (parts) { - var end = parseFloat( parts[2] ), - unit = parts[3] || "px", - values = []; - - // Remember the first value - values.push({ - end: (parts[1] ? parts[1] : '') + end, - unit: unit - }); - - // Detect additional values hidden in the unit - var i = 0; - while (parts = rfxmultinum.exec(unit)) { - // Fix the previous unit - values[i].unit = parts[1]; - - // Remember this value - values.push({ - end: (parts[2] ? parts[2] : '') + parseFloat(parts[3]), - unit: parts[4] - }); - unit = parts[4]; - i++; - } - - // Save the values and truncate the property - elem['data-animate-' + name] = values; - prop[name] = values[0].end; - } - } - }); - } - return _animate.apply(this, arguments); - } - - /** - * Returns appropriate start value for transform props - * @param Boolean force - * @return Number - */ - var _cur = $.fx.prototype.cur; - $.fx.prototype.cur = function(force) { - if ($.inArray(transformFuncs, this.prop)) { - // Transform saves the previous values on the element itself, space-seperated and without units - var value = this.elem[this.prop]; - if (rfxmultinum.test(value)) { - value = value.split(/\s/)[0]; - } - - // Scale needs to have 1 as the default, all others take 0; - if (!value && value !== 0) { - value = unitless.test(this.prop) ? 1 : 0; - } - return parseFloat(value); // return only the first value - } - return _cur.apply(this, arguments); - } - - /** - * Detects the existence of a space separated value - * @param Object fx - * @return null - */ - $.fx.multivalueInit = function(fx) { - var parts, - unit = fx.unit, - values = fx.transform.getAttr(fx.prop, true), - initValues = fx.elem['data-animate-' + fx.prop]; - - fx.values = []; - - // Handle the additional values if they exist - if (initValues) { - var start, parts; - $.each(initValues, function(i, val) { - start = values[i]; - if (!start && start !== 0) { - start = unitless.test(fx.prop) ? 1 : 0; - } - start = parseFloat(start); - if (parts = rfxnum.exec(val.end)) { - if (parts[1]) { - val.end = ((parts[1] === "-=" ? -1 : 1) * parseFloat(parts[2])) + start; - } - } - fx.values.push({ - start: start, - end: val.end, - unit: val.unit - }); - }); - } else { - // Save the known value - fx.values.push({ - start: fx.start, - end: fx.end, - unit: fx.unit - }); - } - } - - /** - * Animates a multi value attribute - * @param Object fx - * @return null - */ - $.fx.multivalueStep = { - _default: function(fx) { - $.each(fx.values, function(i, val) { - fx.values[i].now = val.start + ((val.end - val.start) * fx.pos); - }); - } - }; - - /** - * Step for animating tranformations - */ - $.each(transformFuncs, function(i, func) { - $.fx.step[func] = function(fx) { - // Initialize the transformation - if (!fx.transformInit) { - fx.transform = new Transform(fx.elem); - - // Correct for start being NaN - // TODO: this probaly isn't needed anymore - if (isNaN(fx.start)) { - fx.start = fx.transform.getAttr(fx.prop, true); - if ($.isArray(fx.start)) { - fx.start = fx.start[0]; - } - fx.now = fx.start + ((fx.end - fx.start) * fx.pos); - } - - // Handle multiple values - $.fx.multivalueInit(fx); - if (fx.values.length > 1) { - fx.multiple = true; - } - - // Force degrees for angles, Remove units for unitless - if (unitAngle.test(fx.prop)) { - fx.unit = 'deg'; - } else if (unitless.test(fx.prop)) { - fx.unit = ''; - } - - // Force all units on multiple values to be the same - $.each(fx.values, function(i) {fx.values[i].unit = fx.unit}); - - fx.transformInit = true; - - // if start and end are the same then skip this whole mess - if (fx.start == fx.end) { - return fx.step(true); - } - } - - // Increment all of the values - if (fx.multiple) { - ($.fx.multivalueStep[fx.prop] || $.fx.multivalueStep._default)(fx); - } else { - fx.values[0].now = fx.now; - } - - var values = []; - - // Do some value correction and join the values - $.each(fx.values, function(i, value) { - // Keep angles below 360 in either direction. - if (value.unit == 'deg') { - while (value.now >= 360 ) { - value.now -= 360; - } - while (value.now <= -360 ) { - value.now += 360; - } - } - - //Pretty up the final value (use the double parseFloat to correct super small decimals) - values.push(parseFloat(parseFloat(value.now).toFixed(8)) + value.unit); - }); - - // Apply the transformation - var funcs = {}; - funcs[fx.prop] = fx.multiple ? values : values[0]; - fx.transform.transform(funcs, {preserve: true}); - } - }); - - - /** - * Applies all of the transformations - * @param Object funcs - * @param Object options - * forceMatrix: uses the matrix in all browsers - * preserve: tries to preserve the values from previous runs - */ - p.transform = function(funcs, options) { - // determine if the CSS property is known - var property = this.transformProperty; - - // extend options - options = $.extend(true, { - forceMatrix: false, - preserve: false - }, options); - - // preserve the funcs from the previous run - if (options.preserve) { - funcs = $.extend(true, this.getAttrs(true, true), funcs); - } else { - funcs = $.extend(true, {}, funcs); // copy the object to prevent weirdness - } - - // Record the custom attributes on the element itself (helps out the animator) - this.clearAttrs(); - this.setAttrs(funcs); - - // apply the funcs - if (property && !options.forceMatrix) { - // CSS3 is supported - return this.applyFuncs(funcs); - } else if ($.browser.msie || (property && options.forceMatrix)) { - // Internet Explorer or Forced matrix - return this.applyMatrix(funcs); - } - return false; - } - - p.clearAttrs = function() { - $.each(transformFuncs, $.proxy(function (i, func) { - if (this.$elem[0][func] !== undefined) { - this.$elem[0][func] = undefined; - } - }, this)); - } - - /** - * @param Object funcs a list of transform functions to store on this element - * @return void - */ - p.setAttrs = function(funcs) { - $.each(funcs, $.proxy(this.setAttr, this)); - } - - /** - * @param string func name of a transform function - * @param mixed value with proper units - * @return void - */ - p.setAttr = function(func, value) { - if ($.isArray(value)) { - $.each(value, function(i){value[i] = parseFloat(value[i]);}); - value = value.join(' '); - } else if (value || value === 0) { - value = parseFloat(value); - } - this.$elem[0][func] = value; //should be unitless - } - - /** - * @param Bool split splits space separated values into an array - * @param Bool withUnits - * @return Object values with proper units - */ - p.getAttrs = function(split, withUnits) { - var attrs = {}, value; - $.each(transformFuncs, $.proxy(function (i, func) { - value = this.getAttr(func, split, withUnits, true); - if (value || value === 0) { - attrs[func] = value; - } - }, this)); - return attrs; //TODO: should it really return proper units? - } - - /** - * @param String func - * @param Bool split splits space separated values into an array - * @param Bool withUnits - * @return value with proper units - */ - p.getAttr = function(func, split, withUnits, preserveNull) { - var value = this.$elem[0][func]; - if (preserveNull && !value && value !== 0){ - return value; - } else if (unitless.test(func) && !value && value !== 0) { - value = 1; //scale use 1 as the default value - } else if (!value && value !== 0) { - value = 0; - } - var rspace = /\s/; - if (withUnits) { - // we have to split to correct units - if (rspace.test(value)) { - value = value.split(rspace); - } - - // Correct the units - value = _correctUnits(func, value); - if ($.isArray() && !split) { - value = value.join(' '); - } - } else if (split && rspace.test(value)) { - value = value.split(rspace); - } - return value; - } - - /** - * Applies all of the transformations as functions - * var Object funcs - */ - p.applyFuncs = function(funcs, generate) { - var value = ''; - var property = this.transformProperty; - - // construct a CSS string - for (var func in funcs) { - // handle origin separately - if (func == 'origin') { - this[func].apply(this, $.isArray(funcs[func]) ? funcs[func] : [funcs[func]]); - } else if (this[func]) { - value += ' ' + _createTransformFunction(func, funcs[func]); - } - } - - this.$elem.css(property, value); - this.$elem.data('transformed', true); - return true; - } - - /** - * Applies all of the transformations as a matrix - * var Object options - */ - p.applyMatrix = function(options, generate) { - var matrices = []; - var property = this.transformProperty; - - // collect all the matrices - var args; - for (var option in options) { - if (this[option]) { - args = $.isArray(options[option]) ? options[option] : [options[option]]; - - // strip the units - $.each(args, function(i, arg) { - args[i] = parseFloat(arg); - }); - if (option == 'origin') { - this[option].apply(this, args); - } else { - matrices.push(this[option].apply(this, args)); - } - } - } - - // calculate the final matrix - if (!matrices.length) { - return; - } - var matrix = this.matrix(matrices); - - // pull out the relevant values - var a = parseFloat(parseFloat(matrix.e(1,1)).toFixed(8)), - b = parseFloat(parseFloat(matrix.e(2,1)).toFixed(8)), - c = parseFloat(parseFloat(matrix.e(1,2)).toFixed(8)), - d = parseFloat(parseFloat(matrix.e(2,2)).toFixed(8)), - tx = parseFloat(parseFloat(matrix.e(1,3)).toFixed(8)), - ty = parseFloat(parseFloat(matrix.e(2,3)).toFixed(8)); - - //apply the transform to the element - if (property && property.substr(0, 4) == '-moz' && !generate) { // -moz - // @see https://developer.mozilla.org/En/CSS/-moz-transform#matrix - // matrix(a, c, b, d, tx, ty) - _calculateCorners(this.$elem, matrix); - this.$elem.css(property, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + 'px, ' + ty + 'px)'); - } else if (property && !generate) { // -webkit, -o, w3c - // @see http://www.w3.org/TR/SVG/coords.html#TransformMatrixDefined - // matrix(m11, m12, m21, m22, tX, tY) - // NOTE: WebKit and Opera don't allow units on the translate variables - this.$elem.css(property, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + ', ' + ty + ')'); - } else if (jQuery.browser.msie || generate) { // IE - // IE does not allow the transform origin to be set directly - var origin = { // all browsers default to 50%/50% - x: parseFloat(_convertWidthToPx(this.$elem[0], '50%')), - y: parseFloat(_convertHeightToPx(this.$elem[0], '50%')) - } - - var transformOrigin = this.$elem.data('transformOrigin'); - if (transformOrigin && typeof(transformOrigin.x) !== 'undefined') { - origin.x = parseFloat(transformOrigin.x); - } - if (transformOrigin && typeof(transformOrigin.y) !== 'undefined') { - origin.y = parseFloat(transformOrigin.y); - } - var offset = _calculateOriginOffset(this.$elem, matrix, origin); - - // IE glues the top-most and left-most pixels of the transformed object to top/left of the original object - var dims = _calculateDims(this.$elem, matrix, true); - - // Protect against an item that is already positioned - var cssPosition = this.$elem.css('position'); - if (cssPosition == 'static') { - cssPosition = 'relative'; - } - //TODO: if the element is already positioned, we should attempt to respect it - var pos = {top: 0, left: 0}; - - // IE requires the special transform Filter - var style = this.$elem[0].style; - var matrixFilter = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + a + ', M12=' + c + ', M21=' + b + ', M22=' + d + ', sizingMethod=\'auto expand\')'; - var filter = style.filter || jQuery.curCSS( this.$elem[0], "filter" ) || ""; - style.filter = rmatrix.test(filter) ? filter.replace(rmatrix, matrixFilter) : filter ? filter + ' ' + matrixFilter : matrixFilter; - - // Approximates transform-origin, tx, and ty - var css = { - 'position': cssPosition, - 'top': (offset.top + ty + dims.top + pos.top) + 'px', - 'left': (offset.left + tx + dims.left + pos.left) + 'px' - }; - this.$elem.css(css); - } - this.$elem.data('transformed', true); - return true; - } - - /** - * - * @param Number x - * @param Number y - */ - p.origin = function(x, y) { - var property = this.transformProperty; - - // correct for word lengths - switch (x) { - case 'left': x = '0'; break; - case 'right': x = '100%'; break; - case 'center': x = '50%'; break; - } - switch (y) { - case 'top': y = '0'; break; - case 'bottom': y = '100%'; break; - case 'center': y = '50%'; break; - } - - // convert all length units to px - x = _convertWidthToPx(this.$elem[0], x); - if (typeof(y) !== 'undefined') { - y = _convertHeightToPx(this.$elem[0], y); - } - - // Apply the property - if (property) { //Moz, WebKit, Opera - if (!y) { - this.$elem.css(property + '-origin', x); - } else { - this.$elem.css(property + '-origin', x + ' ' + y); - } - } - - // remember the transform origin in an easy place (IE needs this) - if (!y) { - this.$elem.data('transformOrigin', {x: x}); - } else { - this.$elem.data('transformOrigin', {x: x, y: y}); - } - return true; - } - - /** - * Combine all of the matrices to a final matrix - * @param Array matrices - * return Matrix - */ - p.matrix = function (matrices) { - // combine all of the matrices - var matrix; - for (var i = 0, len = matrices.length; i < len; i++) { - if (!matrix) { - matrix = matrices[i]; - } else { - matrix = matrix.x(matrices[i]); - } - } - - return matrix; - } - - /** - * Offset for the transformation - * @param Number tx - * @param Number ty - * @returm Matrix - */ - p.translate = function (tx, ty) { - tx = tx ? tx : 0; - ty = ty ? ty : 0; - return $M([ - [1, 0, tx], - [0, 1, ty], - [0, 0, 1] - ]); - } - - /** - * Offset on the X-axis - * @param Number sx - * @returm Matrix - */ - p.translateX = function (tx) { - return this.translate(tx); - } - - /** - * Offset on the Y-axis - * @param Number sy - * @returm Matrix - */ - p.translateY = function (ty) { - return this.translate(0, ty); - } - - /** - * Scale - * @param Number sx - * @param Number sy - * @returm Matrix - */ - p.scale = function (sx, sy) { - sx = sx || sx === 0 ? sx : 1; - sy = sy || sy === 0 ? sy : 1; - return $M([ - [sx, 0, 0], - [0, sy, 0], - [0, 0, 1] - ]); - } - - /** - * Scale on the X-axis - * @param Number sx - * @returm Matrix - */ - p.scaleX = function (sx) { - return this.scale(sx); - } - - /** - * Scale on the Y-axis - * @param Number sy - * @returm Matrix - */ - p.scaleY = function (sy) { - return this.scale(1, sy); - } - - /** - * Rotates around the origin - * @param Number deg - * @returm Matrix - */ - p.rotate = function (deg) { - var rad = _degreeToRadian(deg); - var costheta = parseFloat(Math.cos(rad)).toFixed(8); - var sintheta = parseFloat(Math.sin(rad)).toFixed(8); - - var a = costheta, - b = sintheta, - c = -sintheta, - d = costheta; - - return $M([ - [a, c, 0], - [b, d, 0], - [0, 0, 1] - ]); - } - - /** - * Skews on the X-axis and Y-axis - * @param Number degX - * @param Number degY - * @returm Matrix - */ - p.skew = function (degX, degY) { - var radX = _degreeToRadian(degX); - var radY = _degreeToRadian(degY); - - var x = parseFloat(Math.tan(radX)).toFixed(8), - y = parseFloat(Math.tan(radY)).toFixed(8); - - return $M([ - [1, x, 0], - [y, 1, 0], - [0, 0, 1] - ]); - } - - /** - * Skews on the X-axis - * @param Number deg - * @returm Matrix - */ - p.skewX = function (deg) { - var rad = _degreeToRadian(deg); - - var x = parseFloat(Math.tan(rad)).toFixed(8); - - return $M([ - [1, x, 0], - [0, 1, 0], - [0, 0, 1] - ]); - - } - - /** - * Skews on the Y-axis - * @param Number deg - * @returm Matrix - */ - p.skewY = function (deg) { - var rad = _degreeToRadian(deg); - - var y = parseFloat(Math.tan(rad)).toFixed(8); - - return $M([ - [1, 0, 0], - [y, 1, 0], - [0, 0, 1] - ]); - - } - - - /** - * try to determine which browser we're in by the existence of a custom transform property - * @param void - * @return String - */ - p._getTransformProperty = function() { - if (this.transformProperty) { - return this.transformProperty; - } - var elem = this.$elem[0]; - var transformProperty; - var property = { - transform : 'transform', - MozTransform : '-moz-transform', - WebkitTransform : '-webkit-transform', - OTransform : '-o-transform' - } - for (var p in property) { - if (typeof elem.style[p] != 'undefined') { - transformProperty = property[p]; - return transformProperty; - } - } - // Default to transform also - return null; - } - - /** - * Create a function suitable for a CSS value - * @param string funcName - * @param Mixed value - */ - function _createTransformFunction(funcName, value) { - value = _correctUnits(funcName, value); - if (!$.isArray(value)) { - return funcName + '(' + value + ')'; - } else { - return funcName + '(' + value[0] + ', ' + value[1] + ')'; - } - } - - /** - * Ensure that the appropriate values have units on them - * @param string funcName - * @param Mixed value - */ - function _correctUnits(funcName, value) { - var result = !$.isArray(value)? [value] : [value[0], value[1]]; - - //TODO: what does jQuery do for units? I may be complicating this. - for (var i = 0, len = result.length; i < len; i++) { - var parts = rfxnum.exec(result[i]); - - //TODO: we also need to know what units are being used, not just if they're missing - if (unitAngle.test(funcName) && (!parts || !parts[3])) { - result[i] += "deg"; - } else if (unitLength.test(funcName) && (!parts || !parts[3])) { - result[i] += "px"; - } - } - return len == 1 ? result[0] : result; - } - - /** - * Convert a radian into a degree - * @param Number rad - * @returm Number - */ - function _radianToDegree(rad) { - return rad * RAD_DEG; - } - - /** - * Convert a degree into a radian - * @param Number deg - * @returm Number - */ - function _degreeToRadian(deg) { - return deg * DEG_RAD; - } - - /** - * Calculate the corners of the new object - * @param jQuery Collection el - * @param Matrix matrix - * @param boolean outer - * @return Object - */ - function _calculateCorners($elem, matrix, outer) { - // get the original coords - if (outer) { - var y = $elem.data('dims').outerHeight || $elem.outerHeight(), - x = $elem.data('dims').outerWidth || $elem.outerWidth(); - } else { - var y = $elem.data('dims').height || $elem.height(), - x = $elem.data('dims').width || $elem.width(); - } - - // create corners for the original element - var matrices = { - tl: matrix.x($M([[0], [0], [1]])), - bl: matrix.x($M([[0], [y], [1]])), - tr: matrix.x($M([[x], [0], [1]])), - br: matrix.x($M([[x], [y], [1]])) - }; - - return { - tl: { - x: parseFloat(parseFloat(matrices.tl.e(1, 1)).toFixed(8)), - y: parseFloat(parseFloat(matrices.tl.e(2, 1)).toFixed(8)) - }, - bl: { - x: parseFloat(parseFloat(matrices.bl.e(1, 1)).toFixed(8)), - y: parseFloat(parseFloat(matrices.bl.e(2, 1)).toFixed(8)) - }, - tr: { - x: parseFloat(parseFloat(matrices.tr.e(1, 1)).toFixed(8)), - y: parseFloat(parseFloat(matrices.tr.e(2, 1)).toFixed(8)) - }, - br: { - x: parseFloat(parseFloat(matrices.br.e(1, 1)).toFixed(8)), - y: parseFloat(parseFloat(matrices.br.e(2, 1)).toFixed(8)) - } - }; - } - - /** - * Calculate the dimensions of the new object - * @param jQuery Collection el - * @param Matrix matrix - * @param boolean outer - * @return Object - */ - function _calculateDims($elem, matrix, outer) { - //NOTE: Are these called sides? This should probably be calculateSides - // the corners of the box - var corners = _calculateCorners($elem, matrix, outer); - - // create empty dimensions - var dims = { - top: 0, - bottom: 0, - left: 0, - right: 0 - }; - - //find the extreme corners - for (var pos in corners) { - // transform the coords - var corner = corners[pos]; - var x = corner.x, - y = corner.y; - - // record the extreme corners - if (y < dims.top) { - dims.top = y; - } - if (y > dims.bottom) { - dims.bottom = y; - } - if (x < dims.left) { - dims.left = x; - } - if (x > dims.right) { - dims.right = x; - } - } - - return dims; - } - - /** - * Calculate the size of the new object - * @param jQuery Collection el - * @param Matrix matrix - * @return Object - */ - function _calculateSize($elem, matrix){ - var dims = _calculateDims($elem, matrix); - - // return size - return { - height: Math.abs(dims.bottom - dims.top), - width: Math.abs(dims.right - dims.left) - }; - } - - /** - * Calculate a proper top and left for IE - * @param Matrix matrix - * @param Object toOrigin - * @param Object fromOrigin - * @return Object - */ - function _calculateOriginOffset($elem, matrix, toOrigin, fromOrigin) { - // the origin to translate to - toOrigin = toOrigin ? toOrigin : { - x: parseFloat(_convertWidthToPx($elem[0], '50%')), - y: parseFloat(_convertHeightToPx($elem[0], '50%')) - }; - - // the origin to translate from (IE has a fixed origin of 0, 0) - fromOrigin = fromOrigin ? fromOrigin : { - x: 0, - y: 0 - }; - - // transform the origins - var toCenter = matrix.x($M([ - [toOrigin.x], - [toOrigin.y], - [1] - ])); - var fromCenter = matrix.x($M([ - [fromOrigin.x], - [fromOrigin.y], - [1] - ])); - - // return the offset - return { - top: parseFloat(parseFloat((fromCenter.e(2, 1) - fromOrigin.y) - (toCenter.e(2, 1) - toOrigin.y)).toFixed(8)), - left: parseFloat(parseFloat((fromCenter.e(1, 1) - fromOrigin.x) - (toCenter.e(1, 1) - toOrigin.x)).toFixed(8)) - } - } - - //----------------------------------- - // Convert units to PX - //----------------------------------- - /** - * @var regex - */ - var rnumpx = /^-?\d+(?:px)?$/i, - rnum = /^-?\d/, - rnumUnitless = /^-?\d+$/, - rnumPercent = /^-?\d+%$/; - - /** - * @param DOMElement el - * @param string length with attached units - * @param boolean inside measure inside the element instead of outside - */ - function _convertWidthToPx(elem, length, inside) { - return _convertLengthToPx(elem, length, inside, 'x'); - } - - /** - * @param DOMElement el - * @param string length with attached units - * @param boolean inside measure inside the element instead of outside - */ - function _convertHeightToPx(elem, length, inside) { - return _convertLengthToPx(elem, length, inside, 'y'); - } - - /** - * Convert a length unit into pixels - * Currently this is only being used for transformOrigin - * @param DOMElement el - * @param string length with attached units - * @param boolean inside measure inside the element instead of outside - * @param string axis - */ - function _convertLengthToPx(elem, length, inside, axis) { - $elem = $(elem); - // make sure we've provided a unit - if (rnumUnitless.test(length)) { - return length + 'px'; - } - - // percentages are easy - if (rnumPercent.test(length)) { - var dims = $elem.data('dims'); - switch (axis) { - case 'y' : - if (dims) { - var len = inside ? dims.height : dims.outerHeight; - } else { - var len = inside ? $elem.height() : $elem.outerHeight(); - } - break; - case 'x' : //no break - default: - if (dims) { - var len = inside ? dims.width : dims.outerWidth; - } else { - var len = inside ? $elem.width(): $elem.outerWidth(); - } - - } - return len * (parseFloat(length)/100) + 'px'; - } - - // convert all other units into pixels. - if ( !rnumpx.test( length ) && rnum.test( length ) ) { - // some lengths are relative to the item itself. - if (inside) { - var div = $elem.append('
temporary
').find(':last'); - elem = div[0]; - } - - //decide which side to alter (this really only applies to percentages which we handle above) - var side = axis == 'y' ? 'top' : 'left'; - - // TODO: there's some duplicated code going on here. - if (!elem.runtimeStyle && document.defaultView && document.defaultView.getComputedStyle) { // FF, WebKit, Opera - // remember the originals - var style = elem.style[side]; - var position = elem.style.position; - - // set some new styles - elem.style[side] = length || 0; - elem.style.position = 'relative'; // we need to be positioned for Moz to work - - // pull out the pixel values - length = document.defaultView.getComputedStyle(elem, null)[side]; - - // undo our mess - elem.style[side] = style; - elem.style.position = position; - } else { //IE - // remember the originals - var style = elem.style[side]; - var runtimeStyle = elem.runtimeStyle[side]; - - // set some new styles - elem.runtimeStyle[side] = elem.currentStyle[side]; - elem.style[side] = length || 0; - - // pull out the pixel values - length = axis == 'y' ? elem.style.pixelTop : elem.style.pixelLeft + 'px'; - - // undo our mess - elem.style[side] = style; - elem.runtimeStyle[side] = runtimeStyle; - } - - // remove the div we created - if (inside) { - div.remove(); - } - } - return length; - } -})(jQuery, this, this.document); diff --git a/matrix.html b/matrix.html deleted file mode 100644 index 9693344..0000000 --- a/matrix.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - Matrix - - - - - -
-

Standard transform

-
-
Standard
-
-
-

Forced top, left origin (uses absolute positioning)

-
-
Forced
-
-
- - - - - - diff --git a/animate.html b/transform.html similarity index 96% rename from animate.html rename to transform.html index 65efbf7..f5f21cd 100644 --- a/animate.html +++ b/transform.html @@ -123,17 +123,18 @@

Forced top, left origin

- + - + +