/[svn]/doc/tmpl/js/jquery.transform2d.js
ViewVC logotype

Annotation of /doc/tmpl/js/jquery.transform2d.js

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2732 - (hide annotations) (download) (as text)
Sun Apr 26 20:54:00 2015 UTC (9 years ago) by schoenebeck
File MIME type: application/javascript
File size: 14710 byte(s)
* Initial import of doc.linuxsampler.org.

1 schoenebeck 2732 /*
2     * transform: A jQuery cssHooks adding cross-browser 2d transform capabilities to $.fn.css() and $.fn.animate()
3     *
4     * limitations:
5     * - requires jQuery 1.4.3+
6     * - Should you use the *translate* property, then your elements need to be absolutely positionned in a relatively positionned wrapper **or it will fail in IE678**.
7     * - transformOrigin is not accessible
8     *
9     * latest version and complete README available on Github:
10     * https://github.com/louisremi/jquery.transform.js
11     *
12     * Copyright 2011 @louis_remi
13     * Licensed under the MIT license.
14     *
15     * This saved you an hour of work?
16     * Send me music http://www.amazon.co.uk/wishlist/HNTU0468LQON
17     *
18     */
19     (function( $, window, document, Math, undefined ) {
20    
21     /*
22     * Feature tests and global variables
23     */
24     var div = document.createElement("div"),
25     divStyle = div.style,
26     suffix = "Transform",
27     testProperties = [
28     "O" + suffix,
29     "ms" + suffix,
30     "Webkit" + suffix,
31     "Moz" + suffix
32     ],
33     i = testProperties.length,
34     supportProperty,
35     supportMatrixFilter,
36     supportFloat32Array = "Float32Array" in window,
37     propertyHook,
38     propertyGet,
39     rMatrix = /Matrix([^)]*)/,
40     rAffine = /^\s*matrix\(\s*1\s*,\s*0\s*,\s*0\s*,\s*1\s*(?:,\s*0(?:px)?\s*){2}\)\s*$/,
41     _transform = "transform",
42     _transformOrigin = "transformOrigin",
43     _translate = "translate",
44     _rotate = "rotate",
45     _scale = "scale",
46     _skew = "skew",
47     _matrix = "matrix";
48    
49     // test different vendor prefixes of these properties
50     while ( i-- ) {
51     if ( testProperties[i] in divStyle ) {
52     $.support[_transform] = supportProperty = testProperties[i];
53     $.support[_transformOrigin] = supportProperty + "Origin";
54     continue;
55     }
56     }
57     // IE678 alternative
58     if ( !supportProperty ) {
59     $.support.matrixFilter = supportMatrixFilter = divStyle.filter === "";
60     }
61    
62     // px isn't the default unit of these properties
63     $.cssNumber[_transform] = $.cssNumber[_transformOrigin] = true;
64    
65     /*
66     * fn.css() hooks
67     */
68     if ( supportProperty && supportProperty != _transform ) {
69     // Modern browsers can use jQuery.cssProps as a basic hook
70     $.cssProps[_transform] = supportProperty;
71     $.cssProps[_transformOrigin] = supportProperty + "Origin";
72    
73     // Firefox needs a complete hook because it stuffs matrix with "px"
74     if ( supportProperty == "Moz" + suffix ) {
75     propertyHook = {
76     get: function( elem, computed ) {
77     return (computed ?
78     // remove "px" from the computed matrix
79     $.css( elem, supportProperty ).split("px").join(""):
80     elem.style[supportProperty]
81     );
82     },
83     set: function( elem, value ) {
84     // add "px" to matrices
85     elem.style[supportProperty] = /matrix\([^)p]*\)/.test(value) ?
86     value.replace(/matrix((?:[^,]*,){4})([^,]*),([^)]*)/, _matrix+"$1$2px,$3px"):
87     value;
88     }
89     };
90     /* Fix two jQuery bugs still present in 1.5.1
91     * - rupper is incompatible with IE9, see http://jqbug.com/8346
92     * - jQuery.css is not really jQuery.cssProps aware, see http://jqbug.com/8402
93     */
94     } else if ( /^1\.[0-5](?:\.|$)/.test($.fn.jquery) ) {
95     propertyHook = {
96     get: function( elem, computed ) {
97     return (computed ?
98     $.css( elem, supportProperty.replace(/^ms/, "Ms") ):
99     elem.style[supportProperty]
100     );
101     }
102     };
103     }
104     /* TODO: leverage hardware acceleration of 3d transform in Webkit only
105     else if ( supportProperty == "Webkit" + suffix && support3dTransform ) {
106     propertyHook = {
107     set: function( elem, value ) {
108     elem.style[supportProperty] =
109     value.replace();
110     }
111     }
112     }*/
113    
114     } else if ( supportMatrixFilter ) {
115     propertyHook = {
116     get: function( elem, computed, asArray ) {
117     var elemStyle = ( computed && elem.currentStyle ? elem.currentStyle : elem.style ),
118     matrix, data;
119    
120     if ( elemStyle && rMatrix.test( elemStyle.filter ) ) {
121     matrix = RegExp.$1.split(",");
122     matrix = [
123     matrix[0].split("=")[1],
124     matrix[2].split("=")[1],
125     matrix[1].split("=")[1],
126     matrix[3].split("=")[1]
127     ];
128     } else {
129     matrix = [1,0,0,1];
130     }
131    
132     if ( ! $.cssHooks[_transformOrigin] ) {
133     matrix[4] = elemStyle ? parseInt(elemStyle.left, 10) || 0 : 0;
134     matrix[5] = elemStyle ? parseInt(elemStyle.top, 10) || 0 : 0;
135    
136     } else {
137     data = $._data( elem, "transformTranslate", undefined );
138     matrix[4] = data ? data[0] : 0;
139     matrix[5] = data ? data[1] : 0;
140     }
141    
142     return asArray ? matrix : _matrix+"(" + matrix + ")";
143     },
144     set: function( elem, value, animate ) {
145     var elemStyle = elem.style,
146     currentStyle,
147     Matrix,
148     filter,
149     centerOrigin;
150    
151     if ( !animate ) {
152     elemStyle.zoom = 1;
153     }
154    
155     value = matrix(value);
156    
157     // rotate, scale and skew
158     Matrix = [
159     "Matrix("+
160     "M11="+value[0],
161     "M12="+value[2],
162     "M21="+value[1],
163     "M22="+value[3],
164     "SizingMethod='auto expand'"
165     ].join();
166     filter = ( currentStyle = elem.currentStyle ) && currentStyle.filter || elemStyle.filter || "";
167    
168     elemStyle.filter = rMatrix.test(filter) ?
169     filter.replace(rMatrix, Matrix) :
170     filter + " progid:DXImageTransform.Microsoft." + Matrix + ")";
171    
172     if ( ! $.cssHooks[_transformOrigin] ) {
173    
174     // center the transform origin, from pbakaus's Transformie http://github.com/pbakaus/transformie
175     if ( (centerOrigin = $.transform.centerOrigin) ) {
176     elemStyle[centerOrigin == "margin" ? "marginLeft" : "left"] = -(elem.offsetWidth/2) + (elem.clientWidth/2) + "px";
177     elemStyle[centerOrigin == "margin" ? "marginTop" : "top"] = -(elem.offsetHeight/2) + (elem.clientHeight/2) + "px";
178     }
179    
180     // translate
181     // We assume that the elements are absolute positionned inside a relative positionned wrapper
182     elemStyle.left = value[4] + "px";
183     elemStyle.top = value[5] + "px";
184    
185     } else {
186     $.cssHooks[_transformOrigin].set( elem, value );
187     }
188     }
189     };
190     }
191     // populate jQuery.cssHooks with the appropriate hook if necessary
192     if ( propertyHook ) {
193     $.cssHooks[_transform] = propertyHook;
194     }
195     // we need a unique setter for the animation logic
196     propertyGet = propertyHook && propertyHook.get || $.css;
197    
198     /*
199     * fn.animate() hooks
200     */
201     $.fx.step.transform = function( fx ) {
202     var elem = fx.elem,
203     start = fx.start,
204     end = fx.end,
205     pos = fx.pos,
206     transform = "",
207     precision = 1E5,
208     i, startVal, endVal, unit;
209    
210     // fx.end and fx.start need to be converted to interpolation lists
211     if ( !start || typeof start === "string" ) {
212    
213     // the following block can be commented out with jQuery 1.5.1+, see #7912
214     if ( !start ) {
215     start = propertyGet( elem, supportProperty );
216     }
217    
218     // force layout only once per animation
219     if ( supportMatrixFilter ) {
220     elem.style.zoom = 1;
221     }
222    
223     // replace "+=" in relative animations (-= is meaningless with transforms)
224     end = end.split("+=").join(start);
225    
226     // parse both transform to generate interpolation list of same length
227     $.extend( fx, interpolationList( start, end ) );
228     start = fx.start;
229     end = fx.end;
230     }
231    
232     i = start.length;
233    
234     // interpolate functions of the list one by one
235     while ( i-- ) {
236     startVal = start[i];
237     endVal = end[i];
238     unit = +false;
239    
240     switch ( startVal[0] ) {
241    
242     case _translate:
243     unit = "px";
244     case _scale:
245     unit || ( unit = "");
246    
247     transform = startVal[0] + "(" +
248     Math.round( (startVal[1][0] + (endVal[1][0] - startVal[1][0]) * pos) * precision ) / precision + unit +","+
249     Math.round( (startVal[1][1] + (endVal[1][1] - startVal[1][1]) * pos) * precision ) / precision + unit + ")"+
250     transform;
251     break;
252    
253     case _skew + "X":
254     case _skew + "Y":
255     case _rotate:
256     transform = startVal[0] + "(" +
257     Math.round( (startVal[1] + (endVal[1] - startVal[1]) * pos) * precision ) / precision +"rad)"+
258     transform;
259     break;
260     }
261     }
262    
263     fx.origin && ( transform = fx.origin + transform );
264    
265     propertyHook && propertyHook.set ?
266     propertyHook.set( elem, transform, +true ):
267     elem.style[supportProperty] = transform;
268     };
269    
270     /*
271     * Utility functions
272     */
273    
274     // turns a transform string into its "matrix(A,B,C,D,X,Y)" form (as an array, though)
275     function matrix( transform ) {
276     transform = transform.split(")");
277     var
278     trim = $.trim
279     , i = -1
280     // last element of the array is an empty string, get rid of it
281     , l = transform.length -1
282     , split, prop, val
283     , prev = supportFloat32Array ? new Float32Array(6) : []
284     , curr = supportFloat32Array ? new Float32Array(6) : []
285     , rslt = supportFloat32Array ? new Float32Array(6) : [1,0,0,1,0,0]
286     ;
287    
288     prev[0] = prev[3] = rslt[0] = rslt[3] = 1;
289     prev[1] = prev[2] = prev[4] = prev[5] = 0;
290    
291     // Loop through the transform properties, parse and multiply them
292     while ( ++i < l ) {
293     split = transform[i].split("(");
294     prop = trim(split[0]);
295     val = split[1];
296     curr[0] = curr[3] = 1;
297     curr[1] = curr[2] = curr[4] = curr[5] = 0;
298    
299     switch (prop) {
300     case _translate+"X":
301     curr[4] = parseInt(val, 10);
302     break;
303    
304     case _translate+"Y":
305     curr[5] = parseInt(val, 10);
306     break;
307    
308     case _translate:
309     val = val.split(",");
310     curr[4] = parseInt(val[0], 10);
311     curr[5] = parseInt(val[1] || 0, 10);
312     break;
313    
314     case _rotate:
315     val = toRadian(val);
316     curr[0] = Math.cos(val);
317     curr[1] = Math.sin(val);
318     curr[2] = -Math.sin(val);
319     curr[3] = Math.cos(val);
320     break;
321    
322     case _scale+"X":
323     curr[0] = +val;
324     break;
325    
326     case _scale+"Y":
327     curr[3] = val;
328     break;
329    
330     case _scale:
331     val = val.split(",");
332     curr[0] = val[0];
333     curr[3] = val.length>1 ? val[1] : val[0];
334     break;
335    
336     case _skew+"X":
337     curr[2] = Math.tan(toRadian(val));
338     break;
339    
340     case _skew+"Y":
341     curr[1] = Math.tan(toRadian(val));
342     break;
343    
344     case _matrix:
345     val = val.split(",");
346     curr[0] = val[0];
347     curr[1] = val[1];
348     curr[2] = val[2];
349     curr[3] = val[3];
350     curr[4] = parseInt(val[4], 10);
351     curr[5] = parseInt(val[5], 10);
352     break;
353     }
354    
355     // Matrix product (array in column-major order)
356     rslt[0] = prev[0] * curr[0] + prev[2] * curr[1];
357     rslt[1] = prev[1] * curr[0] + prev[3] * curr[1];
358     rslt[2] = prev[0] * curr[2] + prev[2] * curr[3];
359     rslt[3] = prev[1] * curr[2] + prev[3] * curr[3];
360     rslt[4] = prev[0] * curr[4] + prev[2] * curr[5] + prev[4];
361     rslt[5] = prev[1] * curr[4] + prev[3] * curr[5] + prev[5];
362    
363     prev = [rslt[0],rslt[1],rslt[2],rslt[3],rslt[4],rslt[5]];
364     }
365     return rslt;
366     }
367    
368     // turns a matrix into its rotate, scale and skew components
369     // algorithm from http://hg.mozilla.org/mozilla-central/file/7cb3e9795d04/layout/style/nsStyleAnimation.cpp
370     function unmatrix(matrix) {
371     var
372     scaleX
373     , scaleY
374     , skew
375     , A = matrix[0]
376     , B = matrix[1]
377     , C = matrix[2]
378     , D = matrix[3]
379     ;
380    
381     // Make sure matrix is not singular
382     if ( A * D - B * C ) {
383     // step (3)
384     scaleX = Math.sqrt( A * A + B * B );
385     A /= scaleX;
386     B /= scaleX;
387     // step (4)
388     skew = A * C + B * D;
389     C -= A * skew;
390     D -= B * skew;
391     // step (5)
392     scaleY = Math.sqrt( C * C + D * D );
393     C /= scaleY;
394     D /= scaleY;
395     skew /= scaleY;
396     // step (6)
397     if ( A * D < B * C ) {
398     A = -A;
399     B = -B;
400     skew = -skew;
401     scaleX = -scaleX;
402     }
403    
404     // matrix is singular and cannot be interpolated
405     } else {
406     // In this case the elem shouldn't be rendered, hence scale == 0
407     scaleX = scaleY = skew = 0;
408     }
409    
410     // The recomposition order is very important
411     // see http://hg.mozilla.org/mozilla-central/file/7cb3e9795d04/layout/style/nsStyleAnimation.cpp#l971
412     return [
413     [_translate, [+matrix[4], +matrix[5]]],
414     [_rotate, Math.atan2(B, A)],
415     [_skew + "X", Math.atan(skew)],
416     [_scale, [scaleX, scaleY]]
417     ];
418     }
419    
420     // build the list of transform functions to interpolate
421     // use the algorithm described at http://dev.w3.org/csswg/css3-2d-transforms/#animation
422     function interpolationList( start, end ) {
423     var list = {
424     start: [],
425     end: []
426     },
427     i = -1, l,
428     currStart, currEnd, currType;
429    
430     // get rid of affine transform matrix
431     ( start == "none" || isAffine( start ) ) && ( start = "" );
432     ( end == "none" || isAffine( end ) ) && ( end = "" );
433    
434     // if end starts with the current computed style, this is a relative animation
435     // store computed style as the origin, remove it from start and end
436     if ( start && end && !end.indexOf("matrix") && toArray( start ).join() == toArray( end.split(")")[0] ).join() ) {
437     list.origin = start;
438     start = "";
439     end = end.slice( end.indexOf(")") +1 );
440     }
441    
442     if ( !start && !end ) { return; }
443    
444     // start or end are affine, or list of transform functions are identical
445     // => functions will be interpolated individually
446     if ( !start || !end || functionList(start) == functionList(end) ) {
447    
448     start && ( start = start.split(")") ) && ( l = start.length );
449     end && ( end = end.split(")") ) && ( l = end.length );
450    
451     while ( ++i < l-1 ) {
452     start[i] && ( currStart = start[i].split("(") );
453     end[i] && ( currEnd = end[i].split("(") );
454     currType = $.trim( ( currStart || currEnd )[0] );
455    
456     append( list.start, parseFunction( currType, currStart ? currStart[1] : 0 ) );
457     append( list.end, parseFunction( currType, currEnd ? currEnd[1] : 0 ) );
458     }
459    
460     // otherwise, functions will be composed to a single matrix
461     } else {
462     list.start = unmatrix(matrix(start));
463     list.end = unmatrix(matrix(end))
464     }
465    
466     return list;
467     }
468    
469     function parseFunction( type, value ) {
470     var
471     // default value is 1 for scale, 0 otherwise
472     defaultValue = +(!type.indexOf(_scale)),
473     scaleX,
474     // remove X/Y from scaleX/Y & translateX/Y, not from skew
475     cat = type.replace( /e[XY]/, "e" );
476    
477     switch ( type ) {
478     case _translate+"Y":
479     case _scale+"Y":
480    
481     value = [
482     defaultValue,
483     value ?
484     parseFloat( value ):
485     defaultValue
486     ];
487     break;
488    
489     case _translate+"X":
490     case _translate:
491     case _scale+"X":
492     scaleX = 1;
493     case _scale:
494    
495     value = value ?
496     ( value = value.split(",") ) && [
497     parseFloat( value[0] ),
498     parseFloat( value.length>1 ? value[1] : type == _scale ? scaleX || value[0] : defaultValue+"" )
499     ]:
500     [defaultValue, defaultValue];
501     break;
502    
503     case _skew+"X":
504     case _skew+"Y":
505     case _rotate:
506     value = value ? toRadian( value ) : 0;
507     break;
508    
509     case _matrix:
510     return unmatrix( value ? toArray(value) : [1,0,0,1,0,0] );
511     break;
512     }
513    
514     return [[ cat, value ]];
515     }
516    
517     function isAffine( matrix ) {
518     return rAffine.test(matrix);
519     }
520    
521     function functionList( transform ) {
522     return transform.replace(/(?:\([^)]*\))|\s/g, "");
523     }
524    
525     function append( arr1, arr2, value ) {
526     while ( value = arr2.shift() ) {
527     arr1.push( value );
528     }
529     }
530    
531     // converts an angle string in any unit to a radian Float
532     function toRadian(value) {
533     return ~value.indexOf("deg") ?
534     parseInt(value,10) * (Math.PI * 2 / 360):
535     ~value.indexOf("grad") ?
536     parseInt(value,10) * (Math.PI/200):
537     parseFloat(value);
538     }
539    
540     // Converts "matrix(A,B,C,D,X,Y)" to [A,B,C,D,X,Y]
541     function toArray(matrix) {
542     // remove the unit of X and Y for Firefox
543     matrix = /([^,]*),([^,]*),([^,]*),([^,]*),([^,p]*)(?:px)?,([^)p]*)(?:px)?/.exec(matrix);
544     return [matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]];
545     }
546    
547     $.transform = {
548     centerOrigin: "margin"
549     };
550    
551     })( jQuery, window, document, Math );

  ViewVC Help
Powered by ViewVC