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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2732 - (show 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 /*
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