zui53 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +9 -0
- data/LICENSE +20 -0
- data/README.markdown +25 -0
- data/Rakefile +25 -0
- data/build/zui53.js +4014 -0
- data/demos/css_surface.html +30 -0
- data/demos/svg_surface.html +33 -0
- data/lib/assets/javascripts/zui53/.DS_Store +0 -0
- data/lib/assets/javascripts/zui53/helper.js +43 -0
- data/lib/assets/javascripts/zui53/index.js +4 -0
- data/lib/assets/javascripts/zui53/surfaces/css_surface.js.coffee +27 -0
- data/lib/assets/javascripts/zui53/surfaces/svg_surface.js.coffee +16 -0
- data/lib/assets/javascripts/zui53/tools/pan_tool.js.coffee +76 -0
- data/lib/assets/javascripts/zui53/tools/toolset.js.coffee +84 -0
- data/lib/assets/javascripts/zui53/tools/zoom_tool.js.coffee +167 -0
- data/lib/assets/javascripts/zui53/zui53.js.coffee +257 -0
- data/lib/generators/zui53/install_generator.rb +21 -0
- data/lib/zui53.rb +7 -0
- data/vendor/assets/javascripts/jquery.mousewheel.js +78 -0
- data/vendor/assets/javascripts/jquery.transform.js +1961 -0
- data/vendor/assets/javascripts/sylvester.js +1254 -0
- data/zui53.gemspec +20 -0
- metadata +75 -0
@@ -0,0 +1,1961 @@
|
|
1
|
+
/*!
|
2
|
+
* jQuery 2d Transform v0.9.3
|
3
|
+
* http://wiki.github.com/heygrady/transform/
|
4
|
+
*
|
5
|
+
* Copyright 2010, Grady Kuhnline
|
6
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
7
|
+
* http://jquery.org/license
|
8
|
+
*
|
9
|
+
* Date: Sat Dec 4 15:46:09 2010 -0800
|
10
|
+
*/
|
11
|
+
///////////////////////////////////////////////////////
|
12
|
+
// Transform
|
13
|
+
///////////////////////////////////////////////////////
|
14
|
+
(function($, window, document, undefined) {
|
15
|
+
/**
|
16
|
+
* @var Regex identify the matrix filter in IE
|
17
|
+
*/
|
18
|
+
var rmatrix = /progid:DXImageTransform\.Microsoft\.Matrix\(.*?\)/,
|
19
|
+
rfxnum = /^([\+\-]=)?([\d+.\-]+)(.*)$/,
|
20
|
+
rperc = /%/;
|
21
|
+
|
22
|
+
// Steal some code from Modernizr
|
23
|
+
var m = document.createElement( 'modernizr' ),
|
24
|
+
m_style = m.style;
|
25
|
+
|
26
|
+
function stripUnits(arg) {
|
27
|
+
return parseFloat(arg);
|
28
|
+
}
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Find the prefix that this browser uses
|
32
|
+
*/
|
33
|
+
function getVendorPrefix() {
|
34
|
+
var property = {
|
35
|
+
transformProperty : '',
|
36
|
+
MozTransform : '-moz-',
|
37
|
+
WebkitTransform : '-webkit-',
|
38
|
+
OTransform : '-o-',
|
39
|
+
msTransform : '-ms-'
|
40
|
+
};
|
41
|
+
for (var p in property) {
|
42
|
+
if (typeof m_style[p] != 'undefined') {
|
43
|
+
return property[p];
|
44
|
+
}
|
45
|
+
}
|
46
|
+
return null;
|
47
|
+
}
|
48
|
+
|
49
|
+
function supportCssTransforms() {
|
50
|
+
if (typeof(window.Modernizr) !== 'undefined') {
|
51
|
+
return Modernizr.csstransforms;
|
52
|
+
}
|
53
|
+
|
54
|
+
var props = [ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ];
|
55
|
+
for ( var i in props ) {
|
56
|
+
if ( m_style[ props[i] ] !== undefined ) {
|
57
|
+
return true;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
// Capture some basic properties
|
63
|
+
var vendorPrefix = getVendorPrefix(),
|
64
|
+
transformProperty = vendorPrefix !== null ? vendorPrefix + 'transform' : false,
|
65
|
+
transformOriginProperty = vendorPrefix !== null ? vendorPrefix + 'transform-origin' : false;
|
66
|
+
|
67
|
+
// store support in the jQuery Support object
|
68
|
+
$.support.csstransforms = supportCssTransforms();
|
69
|
+
|
70
|
+
// IE9 public preview 6 requires the DOM names
|
71
|
+
if (vendorPrefix == '-ms-') {
|
72
|
+
transformProperty = 'msTransform';
|
73
|
+
transformOriginProperty = 'msTransformOrigin';
|
74
|
+
}
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Class for creating cross-browser transformations
|
78
|
+
* @constructor
|
79
|
+
*/
|
80
|
+
$.extend({
|
81
|
+
transform: function(elem) {
|
82
|
+
// Cache the transform object on the element itself
|
83
|
+
elem.transform = this;
|
84
|
+
|
85
|
+
/**
|
86
|
+
* The element we're working with
|
87
|
+
* @var jQueryCollection
|
88
|
+
*/
|
89
|
+
this.$elem = $(elem);
|
90
|
+
|
91
|
+
/**
|
92
|
+
* Remember the matrix we're applying to help the safeOuterLength func
|
93
|
+
*/
|
94
|
+
this.applyingMatrix = false;
|
95
|
+
this.matrix = null;
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Remember the css height and width to save time
|
99
|
+
* This is only really used in IE
|
100
|
+
* @var Number
|
101
|
+
*/
|
102
|
+
this.height = null;
|
103
|
+
this.width = null;
|
104
|
+
this.outerHeight = null;
|
105
|
+
this.outerWidth = null;
|
106
|
+
|
107
|
+
/**
|
108
|
+
* We need to know the box-sizing in IE for building the outerHeight and outerWidth
|
109
|
+
* @var string
|
110
|
+
*/
|
111
|
+
this.boxSizingValue = null;
|
112
|
+
this.boxSizingProperty = null;
|
113
|
+
|
114
|
+
this.attr = null;
|
115
|
+
this.transformProperty = transformProperty;
|
116
|
+
this.transformOriginProperty = transformOriginProperty;
|
117
|
+
}
|
118
|
+
});
|
119
|
+
|
120
|
+
$.extend($.transform, {
|
121
|
+
/**
|
122
|
+
* @var Array list of all valid transform functions
|
123
|
+
*/
|
124
|
+
funcs: ['matrix', 'origin', 'reflect', 'reflectX', 'reflectXY', 'reflectY', 'rotate', 'scale', 'scaleX', 'scaleY', 'skew', 'skewX', 'skewY', 'translate', 'translateX', 'translateY']
|
125
|
+
});
|
126
|
+
|
127
|
+
/**
|
128
|
+
* Create Transform as a jQuery plugin
|
129
|
+
* @param Object funcs
|
130
|
+
* @param Object options
|
131
|
+
*/
|
132
|
+
$.fn.transform = function(funcs, options) {
|
133
|
+
return this.each(function() {
|
134
|
+
var t = this.transform || new $.transform(this);
|
135
|
+
if (funcs) {
|
136
|
+
t.exec(funcs, options);
|
137
|
+
}
|
138
|
+
});
|
139
|
+
};
|
140
|
+
|
141
|
+
$.transform.prototype = {
|
142
|
+
/**
|
143
|
+
* Applies all of the transformations
|
144
|
+
* @param Object funcs
|
145
|
+
* @param Object options
|
146
|
+
* forceMatrix - uses the matrix in all browsers
|
147
|
+
* preserve - tries to preserve the values from previous runs
|
148
|
+
*/
|
149
|
+
exec: function(funcs, options) {
|
150
|
+
// extend options
|
151
|
+
options = $.extend(true, {
|
152
|
+
forceMatrix: false,
|
153
|
+
preserve: false
|
154
|
+
}, options);
|
155
|
+
|
156
|
+
// preserve the funcs from the previous run
|
157
|
+
this.attr = null;
|
158
|
+
if (options.preserve) {
|
159
|
+
funcs = $.extend(true, this.getAttrs(true, true), funcs);
|
160
|
+
} else {
|
161
|
+
funcs = $.extend(true, {}, funcs); // copy the object to prevent weirdness
|
162
|
+
}
|
163
|
+
|
164
|
+
// Record the custom attributes on the element itself
|
165
|
+
this.setAttrs(funcs);
|
166
|
+
|
167
|
+
// apply the funcs
|
168
|
+
if ($.support.csstransforms && !options.forceMatrix) {
|
169
|
+
// CSS3 is supported
|
170
|
+
return this.execFuncs(funcs);
|
171
|
+
} else if ($.browser.msie || ($.support.csstransforms && options.forceMatrix)) {
|
172
|
+
// Internet Explorer or Forced matrix
|
173
|
+
return this.execMatrix(funcs);
|
174
|
+
}
|
175
|
+
return false;
|
176
|
+
},
|
177
|
+
|
178
|
+
/**
|
179
|
+
* Applies all of the transformations as functions
|
180
|
+
* @param Object funcs
|
181
|
+
*/
|
182
|
+
execFuncs: function(funcs) {
|
183
|
+
var values = [];
|
184
|
+
|
185
|
+
// construct a CSS string
|
186
|
+
for (var func in funcs) {
|
187
|
+
// handle origin separately
|
188
|
+
if (func == 'origin') {
|
189
|
+
this[func].apply(this, $.isArray(funcs[func]) ? funcs[func] : [funcs[func]]);
|
190
|
+
} else if ($.inArray(func, $.transform.funcs) !== -1) {
|
191
|
+
values.push(this.createTransformFunc(func, funcs[func]));
|
192
|
+
}
|
193
|
+
}
|
194
|
+
this.$elem.css(transformProperty, values.join(' '));
|
195
|
+
return true;
|
196
|
+
},
|
197
|
+
|
198
|
+
/**
|
199
|
+
* Applies all of the transformations as a matrix
|
200
|
+
* @param Object funcs
|
201
|
+
*/
|
202
|
+
execMatrix: function(funcs) {
|
203
|
+
var matrix,
|
204
|
+
tempMatrix,
|
205
|
+
args;
|
206
|
+
|
207
|
+
var elem = this.$elem[0],
|
208
|
+
_this = this;
|
209
|
+
function normalPixels(val, i) {
|
210
|
+
if (rperc.test(val)) {
|
211
|
+
// this really only applies to translation
|
212
|
+
return parseFloat(val) / 100 * _this['safeOuter' + (i ? 'Height' : 'Width')]();
|
213
|
+
}
|
214
|
+
return toPx(elem, val);
|
215
|
+
}
|
216
|
+
|
217
|
+
var rtranslate = /translate[X|Y]?/,
|
218
|
+
trans = [];
|
219
|
+
|
220
|
+
for (var func in funcs) {
|
221
|
+
switch ($.type(funcs[func])) {
|
222
|
+
case 'array': args = funcs[func]; break;
|
223
|
+
case 'string': args = $.map(funcs[func].split(','), $.trim); break;
|
224
|
+
default: args = [funcs[func]];
|
225
|
+
}
|
226
|
+
|
227
|
+
if ($.matrix[func]) {
|
228
|
+
|
229
|
+
if ($.cssAngle[func]) {
|
230
|
+
// normalize on degrees
|
231
|
+
args = $.map(args, $.angle.toDegree);
|
232
|
+
} else if (!$.cssNumber[func]) {
|
233
|
+
// normalize to pixels
|
234
|
+
args = $.map(args, normalPixels);
|
235
|
+
} else {
|
236
|
+
// strip units
|
237
|
+
args = $.map(args, stripUnits);
|
238
|
+
}
|
239
|
+
|
240
|
+
tempMatrix = $.matrix[func].apply(this, args);
|
241
|
+
if (rtranslate.test(func)) {
|
242
|
+
//defer translation
|
243
|
+
trans.push(tempMatrix);
|
244
|
+
} else {
|
245
|
+
matrix = matrix ? matrix.x(tempMatrix) : tempMatrix;
|
246
|
+
}
|
247
|
+
} else if (func == 'origin') {
|
248
|
+
this[func].apply(this, args);
|
249
|
+
}
|
250
|
+
}
|
251
|
+
|
252
|
+
// check that we have a matrix
|
253
|
+
matrix = matrix || $.matrix.identity();
|
254
|
+
|
255
|
+
// Apply translation
|
256
|
+
$.each(trans, function(i, val) { matrix = matrix.x(val); });
|
257
|
+
|
258
|
+
// pull out the relevant values
|
259
|
+
var a = parseFloat(matrix.e(1,1).toFixed(6)),
|
260
|
+
b = parseFloat(matrix.e(2,1).toFixed(6)),
|
261
|
+
c = parseFloat(matrix.e(1,2).toFixed(6)),
|
262
|
+
d = parseFloat(matrix.e(2,2).toFixed(6)),
|
263
|
+
tx = matrix.rows === 3 ? parseFloat(matrix.e(1,3).toFixed(6)) : 0,
|
264
|
+
ty = matrix.rows === 3 ? parseFloat(matrix.e(2,3).toFixed(6)) : 0;
|
265
|
+
|
266
|
+
//apply the transform to the element
|
267
|
+
if ($.support.csstransforms && vendorPrefix === '-moz-') {
|
268
|
+
// -moz-
|
269
|
+
this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + 'px, ' + ty + 'px)');
|
270
|
+
} else if ($.support.csstransforms) {
|
271
|
+
// -webkit, -o-, w3c
|
272
|
+
// NOTE: WebKit and Opera don't allow units on the translate variables
|
273
|
+
this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + ', ' + ty + ')');
|
274
|
+
} else if ($.browser.msie) {
|
275
|
+
// IE requires the special transform Filter
|
276
|
+
|
277
|
+
//TODO: Use Nearest Neighbor during animation FilterType=\'nearest neighbor\'
|
278
|
+
var filterType = ', FilterType=\'nearest neighbor\''; //bilinear
|
279
|
+
var style = this.$elem[0].style;
|
280
|
+
var matrixFilter = 'progid:DXImageTransform.Microsoft.Matrix(' +
|
281
|
+
'M11=' + a + ', M12=' + c + ', M21=' + b + ', M22=' + d +
|
282
|
+
', sizingMethod=\'auto expand\'' + filterType + ')';
|
283
|
+
var filter = style.filter || $.curCSS( this.$elem[0], "filter" ) || "";
|
284
|
+
style.filter = rmatrix.test(filter) ? filter.replace(rmatrix, matrixFilter) : filter ? filter + ' ' + matrixFilter : matrixFilter;
|
285
|
+
|
286
|
+
// Let's know that we're applying post matrix fixes and the height/width will be static for a bit
|
287
|
+
this.applyingMatrix = true;
|
288
|
+
this.matrix = matrix;
|
289
|
+
|
290
|
+
// IE can't set the origin or translate directly
|
291
|
+
this.fixPosition(matrix, tx, ty);
|
292
|
+
|
293
|
+
this.applyingMatrix = false;
|
294
|
+
this.matrix = null;
|
295
|
+
}
|
296
|
+
return true;
|
297
|
+
},
|
298
|
+
|
299
|
+
/**
|
300
|
+
* Sets the transform-origin
|
301
|
+
* This really needs to be percentages
|
302
|
+
* @param Number x length
|
303
|
+
* @param Number y length
|
304
|
+
*/
|
305
|
+
origin: function(x, y) {
|
306
|
+
// use CSS in supported browsers
|
307
|
+
if ($.support.csstransforms) {
|
308
|
+
if (typeof y === 'undefined') {
|
309
|
+
this.$elem.css(transformOriginProperty, x);
|
310
|
+
} else {
|
311
|
+
this.$elem.css(transformOriginProperty, x + ' ' + y);
|
312
|
+
}
|
313
|
+
return true;
|
314
|
+
}
|
315
|
+
|
316
|
+
// correct for keyword lengths
|
317
|
+
switch (x) {
|
318
|
+
case 'left': x = '0'; break;
|
319
|
+
case 'right': x = '100%'; break;
|
320
|
+
case 'center': // no break
|
321
|
+
case undefined: x = '50%';
|
322
|
+
}
|
323
|
+
switch (y) {
|
324
|
+
case 'top': y = '0'; break;
|
325
|
+
case 'bottom': y = '100%'; break;
|
326
|
+
case 'center': // no break
|
327
|
+
case undefined: y = '50%'; //TODO: does this work?
|
328
|
+
}
|
329
|
+
|
330
|
+
// store mixed values with units, assumed pixels
|
331
|
+
this.setAttr('origin', [
|
332
|
+
rperc.test(x) ? x : toPx(this.$elem[0], x) + 'px',
|
333
|
+
rperc.test(y) ? y : toPx(this.$elem[0], y) + 'px'
|
334
|
+
]);
|
335
|
+
//console.log(this.getAttr('origin'));
|
336
|
+
return true;
|
337
|
+
},
|
338
|
+
|
339
|
+
/**
|
340
|
+
* Create a function suitable for a CSS value
|
341
|
+
* @param string func
|
342
|
+
* @param Mixed value
|
343
|
+
*/
|
344
|
+
createTransformFunc: function(func, value) {
|
345
|
+
if (func.substr(0, 7) === 'reflect') {
|
346
|
+
// let's fake reflection, false value
|
347
|
+
// falsey sets an identity matrix
|
348
|
+
var m = value ? $.matrix[func]() : $.matrix.identity();
|
349
|
+
return 'matrix(' + m.e(1,1) + ', ' + m.e(2,1) + ', ' + m.e(1,2) + ', ' + m.e(2,2) + ', 0, 0)';
|
350
|
+
}
|
351
|
+
|
352
|
+
//value = _correctUnits(func, value);
|
353
|
+
|
354
|
+
if (func == 'matrix') {
|
355
|
+
if (vendorPrefix === '-moz-') {
|
356
|
+
value[4] = value[4] ? value[4] + 'px' : 0;
|
357
|
+
value[5] = value[5] ? value[5] + 'px' : 0;
|
358
|
+
}
|
359
|
+
}
|
360
|
+
return func + '(' + ($.isArray(value) ? value.join(', ') : value) + ')';
|
361
|
+
},
|
362
|
+
|
363
|
+
/**
|
364
|
+
* @param Matrix matrix
|
365
|
+
* @param Number tx
|
366
|
+
* @param Number ty
|
367
|
+
* @param Number height
|
368
|
+
* @param Number width
|
369
|
+
*/
|
370
|
+
fixPosition: function(matrix, tx, ty, height, width) {
|
371
|
+
// now we need to fix it!
|
372
|
+
var calc = new $.matrix.calc(matrix, this.safeOuterHeight(), this.safeOuterWidth()),
|
373
|
+
origin = this.getAttr('origin'); // mixed percentages and px
|
374
|
+
|
375
|
+
// translate a 0, 0 origin to the current origin
|
376
|
+
var offset = calc.originOffset(new $.matrix.V2(
|
377
|
+
rperc.test(origin[0]) ? parseFloat(origin[0])/100*calc.outerWidth : parseFloat(origin[0]),
|
378
|
+
rperc.test(origin[1]) ? parseFloat(origin[1])/100*calc.outerHeight : parseFloat(origin[1])
|
379
|
+
));
|
380
|
+
|
381
|
+
// IE glues the top-most and left-most pixels of the transformed object to top/left of the original object
|
382
|
+
//TODO: This seems wrong in the calculations
|
383
|
+
var sides = calc.sides();
|
384
|
+
|
385
|
+
// Protect against an item that is already positioned
|
386
|
+
var cssPosition = this.$elem.css('position');
|
387
|
+
if (cssPosition == 'static') {
|
388
|
+
cssPosition = 'relative';
|
389
|
+
}
|
390
|
+
|
391
|
+
//TODO: if the element is already positioned, we should attempt to respect it (somehow)
|
392
|
+
//NOTE: we could preserve our offset top and left in an attr on the elem
|
393
|
+
var pos = {top: 0, left: 0};
|
394
|
+
|
395
|
+
// Approximates transform-origin, tx, and ty
|
396
|
+
var css = {
|
397
|
+
'position': cssPosition,
|
398
|
+
'top': (offset.top + ty + sides.top + pos.top) + 'px',
|
399
|
+
'left': (offset.left + tx + sides.left + pos.left) + 'px',
|
400
|
+
'zoom': 1
|
401
|
+
};
|
402
|
+
|
403
|
+
this.$elem.css(css);
|
404
|
+
}
|
405
|
+
};
|
406
|
+
|
407
|
+
/**
|
408
|
+
* Ensure that values have the appropriate units on them
|
409
|
+
* @param string func
|
410
|
+
* @param Mixed value
|
411
|
+
*/
|
412
|
+
function toPx(elem, val) {
|
413
|
+
var parts = rfxnum.exec($.trim(val));
|
414
|
+
|
415
|
+
if (parts[3] && parts[3] !== 'px') {
|
416
|
+
var prop = 'paddingBottom',
|
417
|
+
orig = $.style( elem, prop );
|
418
|
+
|
419
|
+
$.style( elem, prop, val );
|
420
|
+
val = cur( elem, prop );
|
421
|
+
$.style( elem, prop, orig );
|
422
|
+
return val;
|
423
|
+
}
|
424
|
+
return parseFloat( val );
|
425
|
+
}
|
426
|
+
|
427
|
+
function cur(elem, prop) {
|
428
|
+
if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
|
429
|
+
return elem[ prop ];
|
430
|
+
}
|
431
|
+
|
432
|
+
var r = parseFloat( $.css( elem, prop ) );
|
433
|
+
return r && r > -10000 ? r : 0;
|
434
|
+
}
|
435
|
+
})(jQuery, this, this.document);
|
436
|
+
|
437
|
+
|
438
|
+
///////////////////////////////////////////////////////
|
439
|
+
// Safe Outer Length
|
440
|
+
///////////////////////////////////////////////////////
|
441
|
+
(function($, window, document, undefined) {
|
442
|
+
$.extend($.transform.prototype, {
|
443
|
+
/**
|
444
|
+
* @param void
|
445
|
+
* @return Number
|
446
|
+
*/
|
447
|
+
safeOuterHeight: function() {
|
448
|
+
return this.safeOuterLength('height');
|
449
|
+
},
|
450
|
+
|
451
|
+
/**
|
452
|
+
* @param void
|
453
|
+
* @return Number
|
454
|
+
*/
|
455
|
+
safeOuterWidth: function() {
|
456
|
+
return this.safeOuterLength('width');
|
457
|
+
},
|
458
|
+
|
459
|
+
/**
|
460
|
+
* Returns reliable outer dimensions for an object that may have been transformed.
|
461
|
+
* Only use this if the matrix isn't handy
|
462
|
+
* @param String dim height or width
|
463
|
+
* @return Number
|
464
|
+
*/
|
465
|
+
safeOuterLength: function(dim) {
|
466
|
+
var funcName = 'outer' + (dim == 'width' ? 'Width' : 'Height');
|
467
|
+
|
468
|
+
if (!$.support.csstransforms && $.browser.msie) {
|
469
|
+
// make the variables more generic
|
470
|
+
dim = dim == 'width' ? 'width' : 'height';
|
471
|
+
|
472
|
+
// if we're transforming and have a matrix; we can shortcut.
|
473
|
+
// the true outerHeight is the transformed outerHeight divided by the ratio.
|
474
|
+
// the ratio is equal to the height of a 1px by 1px box that has been transformed by the same matrix.
|
475
|
+
if (this.applyingMatrix && !this[funcName] && this.matrix) {
|
476
|
+
// calculate and return the correct size
|
477
|
+
var calc = new $.matrix.calc(this.matrix, 1, 1),
|
478
|
+
ratio = calc.offset(),
|
479
|
+
length = this.$elem[funcName]() / ratio[dim];
|
480
|
+
this[funcName] = length;
|
481
|
+
|
482
|
+
return length;
|
483
|
+
} else if (this.applyingMatrix && this[funcName]) {
|
484
|
+
// return the cached calculation
|
485
|
+
return this[funcName];
|
486
|
+
}
|
487
|
+
|
488
|
+
// map dimensions to box sides
|
489
|
+
var side = {
|
490
|
+
height: ['top', 'bottom'],
|
491
|
+
width: ['left', 'right']
|
492
|
+
};
|
493
|
+
|
494
|
+
// setup some variables
|
495
|
+
var elem = this.$elem[0],
|
496
|
+
outerLen = parseFloat($.curCSS(elem, dim, true)), //TODO: this can be cached on animations that do not animate height/width
|
497
|
+
boxSizingProp = this.boxSizingProperty,
|
498
|
+
boxSizingValue = this.boxSizingValue;
|
499
|
+
|
500
|
+
// IE6 && IE7 will never have a box-sizing property, so fake it
|
501
|
+
if (!this.boxSizingProperty) {
|
502
|
+
boxSizingProp = this.boxSizingProperty = _findBoxSizingProperty() || 'box-sizing';
|
503
|
+
boxSizingValue = this.boxSizingValue = this.$elem.css(boxSizingProp) || 'content-box';
|
504
|
+
}
|
505
|
+
|
506
|
+
// return it immediately if we already know it
|
507
|
+
if (this[funcName] && this[dim] == outerLen) {
|
508
|
+
return this[funcName];
|
509
|
+
} else {
|
510
|
+
this[dim] = outerLen;
|
511
|
+
}
|
512
|
+
|
513
|
+
// add in the padding and border
|
514
|
+
if (boxSizingProp && (boxSizingValue == 'padding-box' || boxSizingValue == 'content-box')) {
|
515
|
+
outerLen += parseFloat($.curCSS(elem, 'padding-' + side[dim][0], true)) || 0 +
|
516
|
+
parseFloat($.curCSS(elem, 'padding-' + side[dim][1], true)) || 0;
|
517
|
+
}
|
518
|
+
if (boxSizingProp && boxSizingValue == 'content-box') {
|
519
|
+
outerLen += parseFloat($.curCSS(elem, 'border-' + side[dim][0] + '-width', true)) || 0 +
|
520
|
+
parseFloat($.curCSS(elem, 'border-' + side[dim][1] + '-width', true)) || 0;
|
521
|
+
}
|
522
|
+
|
523
|
+
// remember and return the outerHeight
|
524
|
+
this[funcName] = outerLen;
|
525
|
+
return outerLen;
|
526
|
+
}
|
527
|
+
return this.$elem[funcName]();
|
528
|
+
}
|
529
|
+
});
|
530
|
+
|
531
|
+
/**
|
532
|
+
* Determine the correct property for checking the box-sizing property
|
533
|
+
* @param void
|
534
|
+
* @return string
|
535
|
+
*/
|
536
|
+
var _boxSizingProperty = null;
|
537
|
+
function _findBoxSizingProperty () {
|
538
|
+
if (_boxSizingProperty) {
|
539
|
+
return _boxSizingProperty;
|
540
|
+
}
|
541
|
+
|
542
|
+
var property = {
|
543
|
+
boxSizing : 'box-sizing',
|
544
|
+
MozBoxSizing : '-moz-box-sizing',
|
545
|
+
WebkitBoxSizing : '-webkit-box-sizing',
|
546
|
+
OBoxSizing : '-o-box-sizing'
|
547
|
+
},
|
548
|
+
elem = document.body;
|
549
|
+
|
550
|
+
for (var p in property) {
|
551
|
+
if (typeof elem.style[p] != 'undefined') {
|
552
|
+
_boxSizingProperty = property[p];
|
553
|
+
return _boxSizingProperty;
|
554
|
+
}
|
555
|
+
}
|
556
|
+
return null;
|
557
|
+
}
|
558
|
+
})(jQuery, this, this.document);
|
559
|
+
|
560
|
+
|
561
|
+
///////////////////////////////////////////////////////
|
562
|
+
// Attr
|
563
|
+
///////////////////////////////////////////////////////
|
564
|
+
(function($, window, document, undefined) {
|
565
|
+
var rfuncvalue = /([\w\-]*?)\((.*?)\)/g, // with values
|
566
|
+
attr = 'data-transform',
|
567
|
+
rspace = /\s/,
|
568
|
+
rcspace = /,\s?/;
|
569
|
+
|
570
|
+
$.extend($.transform.prototype, {
|
571
|
+
/**
|
572
|
+
* This overrides all of the attributes
|
573
|
+
* @param Object funcs a list of transform functions to store on this element
|
574
|
+
* @return void
|
575
|
+
*/
|
576
|
+
setAttrs: function(funcs) {
|
577
|
+
var string = '',
|
578
|
+
value;
|
579
|
+
for (var func in funcs) {
|
580
|
+
value = funcs[func];
|
581
|
+
if ($.isArray(value)) {
|
582
|
+
value = value.join(', ');
|
583
|
+
}
|
584
|
+
string += ' ' + func + '(' + value + ')';
|
585
|
+
}
|
586
|
+
this.attr = $.trim(string);
|
587
|
+
this.$elem.attr(attr, this.attr);
|
588
|
+
},
|
589
|
+
|
590
|
+
/**
|
591
|
+
* This sets only a specific atribute
|
592
|
+
* @param string func name of a transform function
|
593
|
+
* @param mixed value with proper units
|
594
|
+
* @return void
|
595
|
+
*/
|
596
|
+
setAttr: function(func, value) {
|
597
|
+
// stringify the value
|
598
|
+
if ($.isArray(value)) {
|
599
|
+
value = value.join(', ');
|
600
|
+
}
|
601
|
+
|
602
|
+
// pull from a local variable to look it up
|
603
|
+
var transform = this.attr || this.$elem.attr(attr);
|
604
|
+
if (!transform || transform.indexOf(func) == -1) {
|
605
|
+
// we don't have any existing values, save it
|
606
|
+
// we don't have this function yet, save it
|
607
|
+
this.attr = $.trim(transform + ' ' + func + '(' + value + ')');
|
608
|
+
this.$elem.attr(attr, this.attr);
|
609
|
+
} else {
|
610
|
+
// replace the existing value
|
611
|
+
var funcs = [], parts;
|
612
|
+
|
613
|
+
// regex split
|
614
|
+
rfuncvalue.lastIndex = 0; // reset the regex pointer
|
615
|
+
while (parts = rfuncvalue.exec(transform)) {
|
616
|
+
if (func == parts[1]) {
|
617
|
+
funcs.push(func + '(' + value + ')');
|
618
|
+
} else {
|
619
|
+
funcs.push(parts[0]);
|
620
|
+
}
|
621
|
+
}
|
622
|
+
this.attr = funcs.join(' ');
|
623
|
+
this.$elem.attr(attr, this.attr);
|
624
|
+
}
|
625
|
+
},
|
626
|
+
|
627
|
+
/**
|
628
|
+
* @return Object
|
629
|
+
*/
|
630
|
+
getAttrs: function() {
|
631
|
+
var transform = this.attr || this.$elem.attr(attr);
|
632
|
+
if (!transform) {
|
633
|
+
// We don't have any existing values, return empty object
|
634
|
+
return {};
|
635
|
+
}
|
636
|
+
|
637
|
+
// replace the existing value
|
638
|
+
var attrs = {}, parts, value;
|
639
|
+
|
640
|
+
rfuncvalue.lastIndex = 0; // reset the regex pointer
|
641
|
+
while ((parts = rfuncvalue.exec(transform)) !== null) {
|
642
|
+
if (parts) {
|
643
|
+
value = parts[2].split(rcspace);
|
644
|
+
attrs[parts[1]] = value.length == 1 ? value[0] : value;
|
645
|
+
}
|
646
|
+
}
|
647
|
+
return attrs;
|
648
|
+
},
|
649
|
+
|
650
|
+
/**
|
651
|
+
* @param String func
|
652
|
+
* @return mixed
|
653
|
+
*/
|
654
|
+
getAttr: function(func) {
|
655
|
+
var attrs = this.getAttrs();
|
656
|
+
if (typeof attrs[func] !== 'undefined') {
|
657
|
+
return attrs[func];
|
658
|
+
}
|
659
|
+
|
660
|
+
//TODO: move the origin to a function
|
661
|
+
if (func === 'origin' && $.support.csstransforms) {
|
662
|
+
// supported browsers return percentages always
|
663
|
+
return this.$elem.css(this.transformOriginProperty).split(rspace);
|
664
|
+
} else if (func === 'origin') {
|
665
|
+
// just force IE to also return a percentage
|
666
|
+
return ['50%', '50%'];
|
667
|
+
}
|
668
|
+
|
669
|
+
return $.cssDefault[func] || 0;
|
670
|
+
}
|
671
|
+
});
|
672
|
+
|
673
|
+
// Define
|
674
|
+
if (typeof($.cssAngle) == 'undefined') {
|
675
|
+
$.cssAngle = {};
|
676
|
+
}
|
677
|
+
$.extend($.cssAngle, {
|
678
|
+
rotate: true,
|
679
|
+
skew: true,
|
680
|
+
skewX: true,
|
681
|
+
skewY: true
|
682
|
+
});
|
683
|
+
|
684
|
+
// Define default values
|
685
|
+
if (typeof($.cssDefault) == 'undefined') {
|
686
|
+
$.cssDefault = {};
|
687
|
+
}
|
688
|
+
|
689
|
+
$.extend($.cssDefault, {
|
690
|
+
scale: [1, 1],
|
691
|
+
scaleX: 1,
|
692
|
+
scaleY: 1,
|
693
|
+
matrix: [1, 0, 0, 1, 0, 0],
|
694
|
+
origin: ['50%', '50%'], // TODO: allow this to be a function, like get
|
695
|
+
reflect: [1, 0, 0, 1, 0, 0],
|
696
|
+
reflectX: [1, 0, 0, 1, 0, 0],
|
697
|
+
reflectXY: [1, 0, 0, 1, 0, 0],
|
698
|
+
reflectY: [1, 0, 0, 1, 0, 0]
|
699
|
+
});
|
700
|
+
|
701
|
+
// Define functons with multiple values
|
702
|
+
if (typeof($.cssMultipleValues) == 'undefined') {
|
703
|
+
$.cssMultipleValues = {};
|
704
|
+
}
|
705
|
+
$.extend($.cssMultipleValues, {
|
706
|
+
matrix: 6,
|
707
|
+
origin: {
|
708
|
+
length: 2,
|
709
|
+
duplicate: true
|
710
|
+
},
|
711
|
+
reflect: 6,
|
712
|
+
reflectX: 6,
|
713
|
+
reflectXY: 6,
|
714
|
+
reflectY: 6,
|
715
|
+
scale: {
|
716
|
+
length: 2,
|
717
|
+
duplicate: true
|
718
|
+
},
|
719
|
+
skew: 2,
|
720
|
+
translate: 2
|
721
|
+
});
|
722
|
+
|
723
|
+
// specify unitless funcs
|
724
|
+
$.extend($.cssNumber, {
|
725
|
+
matrix: true,
|
726
|
+
reflect: true,
|
727
|
+
reflectX: true,
|
728
|
+
reflectXY: true,
|
729
|
+
reflectY: true,
|
730
|
+
scale: true,
|
731
|
+
scaleX: true,
|
732
|
+
scaleY: true
|
733
|
+
});
|
734
|
+
|
735
|
+
// override all of the css functions
|
736
|
+
$.each($.transform.funcs, function(i, func) {
|
737
|
+
$.cssHooks[func] = {
|
738
|
+
set: function(elem, value) {
|
739
|
+
var transform = elem.transform || new $.transform(elem),
|
740
|
+
funcs = {};
|
741
|
+
funcs[func] = value;
|
742
|
+
transform.exec(funcs, {preserve: true});
|
743
|
+
},
|
744
|
+
get: function(elem, computed) {
|
745
|
+
var transform = elem.transform || new $.transform(elem);
|
746
|
+
return transform.getAttr(func);
|
747
|
+
}
|
748
|
+
};
|
749
|
+
});
|
750
|
+
|
751
|
+
// Support Reflection animation better by returning a matrix
|
752
|
+
$.each(['reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
|
753
|
+
$.cssHooks[func].get = function(elem, computed) {
|
754
|
+
var transform = elem.transform || new $.transform(elem);
|
755
|
+
return transform.getAttr('matrix') || $.cssDefault[func];
|
756
|
+
};
|
757
|
+
});
|
758
|
+
})(jQuery, this, this.document);
|
759
|
+
///////////////////////////////////////////////////////
|
760
|
+
// Animation
|
761
|
+
///////////////////////////////////////////////////////
|
762
|
+
(function($, window, document, undefined) {
|
763
|
+
/**
|
764
|
+
* @var Regex looks for units on a string
|
765
|
+
*/
|
766
|
+
var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
|
767
|
+
|
768
|
+
/**
|
769
|
+
* Doctors prop values in the event that they contain spaces
|
770
|
+
* @param Object prop
|
771
|
+
* @param String speed
|
772
|
+
* @param String easing
|
773
|
+
* @param Function callback
|
774
|
+
* @return bool
|
775
|
+
*/
|
776
|
+
var _animate = $.fn.animate;
|
777
|
+
$.fn.animate = function( prop, speed, easing, callback ) {
|
778
|
+
var optall = $.speed(speed, easing, callback),
|
779
|
+
mv = $.cssMultipleValues;
|
780
|
+
|
781
|
+
// Speed always creates a complete function that must be reset
|
782
|
+
optall.complete = optall.old;
|
783
|
+
|
784
|
+
// Capture multiple values
|
785
|
+
if (!$.isEmptyObject(prop)) {
|
786
|
+
if (typeof optall.original === 'undefined') {
|
787
|
+
optall.original = {};
|
788
|
+
}
|
789
|
+
$.each( prop, function( name, val ) {
|
790
|
+
if (mv[name]
|
791
|
+
|| $.cssAngle[name]
|
792
|
+
|| (!$.cssNumber[name] && $.inArray(name, $.transform.funcs) !== -1)) {
|
793
|
+
|
794
|
+
// Handle special easing
|
795
|
+
var specialEasing = null;
|
796
|
+
if (jQuery.isArray(prop[name])) {
|
797
|
+
var mvlen = 1, len = val.length;
|
798
|
+
if (mv[name]) {
|
799
|
+
mvlen = (typeof mv[name].length === 'undefined' ? mv[name] : mv[name].length);
|
800
|
+
}
|
801
|
+
if ( len > mvlen
|
802
|
+
|| (len < mvlen && len == 2)
|
803
|
+
|| (len == 2 && mvlen == 2 && isNaN(parseFloat(val[len - 1])))) {
|
804
|
+
|
805
|
+
specialEasing = val[len - 1];
|
806
|
+
val.splice(len - 1, 1);
|
807
|
+
}
|
808
|
+
}
|
809
|
+
|
810
|
+
// Store the original values onto the optall
|
811
|
+
optall.original[name] = val.toString();
|
812
|
+
|
813
|
+
// reduce to a unitless number (to trick animate)
|
814
|
+
prop[name] = parseFloat(val);
|
815
|
+
}
|
816
|
+
} );
|
817
|
+
}
|
818
|
+
|
819
|
+
//NOTE: we edited prop above to trick animate
|
820
|
+
//NOTE: we pre-convert to an optall so we can doctor it
|
821
|
+
return _animate.apply(this, [arguments[0], optall]);
|
822
|
+
};
|
823
|
+
|
824
|
+
var prop = 'paddingBottom';
|
825
|
+
function cur(elem, prop) {
|
826
|
+
if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) {
|
827
|
+
//return elem[ prop ];
|
828
|
+
}
|
829
|
+
|
830
|
+
var r = parseFloat( $.css( elem, prop ) );
|
831
|
+
return r && r > -10000 ? r : 0;
|
832
|
+
}
|
833
|
+
|
834
|
+
var _custom = $.fx.prototype.custom;
|
835
|
+
$.fx.prototype.custom = function(from, to, unit) {
|
836
|
+
var multiple = $.cssMultipleValues[this.prop],
|
837
|
+
angle = $.cssAngle[this.prop];
|
838
|
+
|
839
|
+
//TODO: simply check for the existence of CSS Hooks?
|
840
|
+
if (multiple || (!$.cssNumber[this.prop] && $.inArray(this.prop, $.transform.funcs) !== -1)) {
|
841
|
+
this.values = [];
|
842
|
+
|
843
|
+
if (!multiple) {
|
844
|
+
multiple = 1;
|
845
|
+
}
|
846
|
+
|
847
|
+
// Pull out the known values
|
848
|
+
var values = this.options.original[this.prop],
|
849
|
+
currentValues = $(this.elem).css(this.prop),
|
850
|
+
defaultValues = $.cssDefault[this.prop] || 0;
|
851
|
+
|
852
|
+
// make sure the current css value is an array
|
853
|
+
if (!$.isArray(currentValues)) {
|
854
|
+
currentValues = [currentValues];
|
855
|
+
}
|
856
|
+
|
857
|
+
// make sure the new values are an array
|
858
|
+
if (!$.isArray(values)) {
|
859
|
+
if ($.type(values) === 'string') {
|
860
|
+
values = values.split(',');
|
861
|
+
} else {
|
862
|
+
values = [values];
|
863
|
+
}
|
864
|
+
}
|
865
|
+
|
866
|
+
// make sure we have enough new values
|
867
|
+
var length = multiple.length || multiple, i = 0;
|
868
|
+
while (values.length < length) {
|
869
|
+
values.push(multiple.duplicate ? values[0] : defaultValues[i] || 0);
|
870
|
+
i++;
|
871
|
+
}
|
872
|
+
|
873
|
+
// calculate a start, end and unit for each new value
|
874
|
+
var start, parts, end, //unit,
|
875
|
+
fx = this,
|
876
|
+
transform = fx.elem.transform;
|
877
|
+
orig = $.style(fx.elem, prop);
|
878
|
+
|
879
|
+
$.each(values, function(i, val) {
|
880
|
+
// find a sensible start value
|
881
|
+
if (currentValues[i]) {
|
882
|
+
start = currentValues[i];
|
883
|
+
} else if (defaultValues[i] && !multiple.duplicate) {
|
884
|
+
start = defaultValues[i];
|
885
|
+
} else if (multiple.duplicate) {
|
886
|
+
start = currentValues[0];
|
887
|
+
} else {
|
888
|
+
start = 0;
|
889
|
+
}
|
890
|
+
|
891
|
+
// Force the correct unit on the start
|
892
|
+
if (angle) {
|
893
|
+
start = $.angle.toDegree(start);
|
894
|
+
} else if (!$.cssNumber[fx.prop]) {
|
895
|
+
parts = rfxnum.exec($.trim(start));
|
896
|
+
if (parts[3] && parts[3] !== 'px') {
|
897
|
+
if (parts[3] === '%') {
|
898
|
+
start = parseFloat( parts[2] ) / 100 * transform['safeOuter' + (i ? 'Height' : 'Width')]();
|
899
|
+
} else {
|
900
|
+
$.style( fx.elem, prop, start);
|
901
|
+
start = cur(fx.elem, prop);
|
902
|
+
$.style( fx.elem, prop, orig);
|
903
|
+
}
|
904
|
+
}
|
905
|
+
}
|
906
|
+
start = parseFloat(start);
|
907
|
+
|
908
|
+
// parse the value with a regex
|
909
|
+
parts = rfxnum.exec($.trim(val));
|
910
|
+
|
911
|
+
if (parts) {
|
912
|
+
// we found a sensible value and unit
|
913
|
+
end = parseFloat( parts[2] );
|
914
|
+
unit = parts[3] || "px"; //TODO: change to an appropriate default unit
|
915
|
+
|
916
|
+
if (angle) {
|
917
|
+
end = $.angle.toDegree(end + unit);
|
918
|
+
unit = 'deg';
|
919
|
+
} else if (!$.cssNumber[fx.prop] && unit === '%') {
|
920
|
+
start = (start / transform['safeOuter' + (i ? 'Height' : 'Width')]()) * 100;
|
921
|
+
} else if (!$.cssNumber[fx.prop] && unit !== 'px') {
|
922
|
+
$.style( fx.elem, prop, (end || 1) + unit);
|
923
|
+
start = ((end || 1) / cur(fx.elem, prop)) * start;
|
924
|
+
$.style( fx.elem, prop, orig);
|
925
|
+
}
|
926
|
+
|
927
|
+
// If a +=/-= token was provided, we're doing a relative animation
|
928
|
+
if (parts[1]) {
|
929
|
+
end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
|
930
|
+
}
|
931
|
+
} else {
|
932
|
+
// I don't know when this would happen
|
933
|
+
end = val;
|
934
|
+
unit = '';
|
935
|
+
}
|
936
|
+
|
937
|
+
// Save the values
|
938
|
+
fx.values.push({
|
939
|
+
start: start,
|
940
|
+
end: end,
|
941
|
+
unit: unit
|
942
|
+
});
|
943
|
+
});
|
944
|
+
}
|
945
|
+
return _custom.apply(this, arguments);
|
946
|
+
};
|
947
|
+
|
948
|
+
/**
|
949
|
+
* Animates a multi value attribute
|
950
|
+
* @param Object fx
|
951
|
+
* @return null
|
952
|
+
*/
|
953
|
+
$.fx.multipleValueStep = {
|
954
|
+
_default: function(fx) {
|
955
|
+
$.each(fx.values, function(i, val) {
|
956
|
+
fx.values[i].now = val.start + ((val.end - val.start) * fx.pos);
|
957
|
+
});
|
958
|
+
}
|
959
|
+
};
|
960
|
+
$.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
|
961
|
+
$.fx.multipleValueStep[func] = function(fx) {
|
962
|
+
var d = fx.decomposed,
|
963
|
+
$m = $.matrix;
|
964
|
+
m = $m.identity();
|
965
|
+
|
966
|
+
d.now = {};
|
967
|
+
|
968
|
+
// increment each part of the decomposition and recompose it
|
969
|
+
$.each(d.start, function(k) {
|
970
|
+
// calculate the current value
|
971
|
+
d.now[k] = parseFloat(d.start[k]) + ((parseFloat(d.end[k]) - parseFloat(d.start[k])) * fx.pos);
|
972
|
+
|
973
|
+
// skip functions that won't affect the transform
|
974
|
+
if (((k === 'scaleX' || k === 'scaleY') && d.now[k] === 1) ||
|
975
|
+
(k !== 'scaleX' && k !== 'scaleY' && d.now[k] === 0)) {
|
976
|
+
return true;
|
977
|
+
}
|
978
|
+
|
979
|
+
// calculating
|
980
|
+
m = m.x($m[k](d.now[k]));
|
981
|
+
});
|
982
|
+
|
983
|
+
// save the correct matrix values for the value of now
|
984
|
+
var val;
|
985
|
+
$.each(fx.values, function(i) {
|
986
|
+
switch (i) {
|
987
|
+
case 0: val = parseFloat(m.e(1, 1).toFixed(6)); break;
|
988
|
+
case 1: val = parseFloat(m.e(2, 1).toFixed(6)); break;
|
989
|
+
case 2: val = parseFloat(m.e(1, 2).toFixed(6)); break;
|
990
|
+
case 3: val = parseFloat(m.e(2, 2).toFixed(6)); break;
|
991
|
+
case 4: val = parseFloat(m.e(1, 3).toFixed(6)); break;
|
992
|
+
case 5: val = parseFloat(m.e(2, 3).toFixed(6)); break;
|
993
|
+
}
|
994
|
+
fx.values[i].now = val;
|
995
|
+
});
|
996
|
+
};
|
997
|
+
});
|
998
|
+
/**
|
999
|
+
* Step for animating tranformations
|
1000
|
+
*/
|
1001
|
+
$.each($.transform.funcs, function(i, func) {
|
1002
|
+
$.fx.step[func] = function(fx) {
|
1003
|
+
var transform = fx.elem.transform || new $.transform(fx.elem),
|
1004
|
+
funcs = {};
|
1005
|
+
|
1006
|
+
if ($.cssMultipleValues[func] || (!$.cssNumber[func] && $.inArray(func, $.transform.funcs) !== -1)) {
|
1007
|
+
($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
|
1008
|
+
funcs[fx.prop] = [];
|
1009
|
+
$.each(fx.values, function(i, val) {
|
1010
|
+
funcs[fx.prop].push(val.now + ($.cssNumber[fx.prop] ? '' : val.unit));
|
1011
|
+
});
|
1012
|
+
} else {
|
1013
|
+
funcs[fx.prop] = fx.now + ($.cssNumber[fx.prop] ? '' : fx.unit);
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
transform.exec(funcs, {preserve: true});
|
1017
|
+
};
|
1018
|
+
});
|
1019
|
+
|
1020
|
+
// Support matrix animation
|
1021
|
+
$.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) {
|
1022
|
+
$.fx.step[func] = function(fx) {
|
1023
|
+
var transform = fx.elem.transform || new $.transform(fx.elem),
|
1024
|
+
funcs = {};
|
1025
|
+
|
1026
|
+
if (!fx.initialized) {
|
1027
|
+
fx.initialized = true;
|
1028
|
+
|
1029
|
+
// Reflections need a sensible end value set
|
1030
|
+
if (func !== 'matrix') {
|
1031
|
+
var values = $.matrix[func]().elements;
|
1032
|
+
var val;
|
1033
|
+
$.each(fx.values, function(i) {
|
1034
|
+
switch (i) {
|
1035
|
+
case 0: val = values[0]; break;
|
1036
|
+
case 1: val = values[2]; break;
|
1037
|
+
case 2: val = values[1]; break;
|
1038
|
+
case 3: val = values[3]; break;
|
1039
|
+
default: val = 0;
|
1040
|
+
}
|
1041
|
+
fx.values[i].end = val;
|
1042
|
+
});
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
// Decompose the start and end
|
1046
|
+
fx.decomposed = {};
|
1047
|
+
var v = fx.values;
|
1048
|
+
|
1049
|
+
fx.decomposed.start = $.matrix.matrix(v[0].start, v[1].start, v[2].start, v[3].start, v[4].start, v[5].start).decompose();
|
1050
|
+
fx.decomposed.end = $.matrix.matrix(v[0].end, v[1].end, v[2].end, v[3].end, v[4].end, v[5].end).decompose();
|
1051
|
+
}
|
1052
|
+
|
1053
|
+
($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx);
|
1054
|
+
funcs.matrix = [];
|
1055
|
+
$.each(fx.values, function(i, val) {
|
1056
|
+
funcs.matrix.push(val.now);
|
1057
|
+
});
|
1058
|
+
|
1059
|
+
transform.exec(funcs, {preserve: true});
|
1060
|
+
};
|
1061
|
+
});
|
1062
|
+
})(jQuery, this, this.document);
|
1063
|
+
///////////////////////////////////////////////////////
|
1064
|
+
// Angle
|
1065
|
+
///////////////////////////////////////////////////////
|
1066
|
+
(function($, window, document, undefined) {
|
1067
|
+
/**
|
1068
|
+
* Converting a radian to a degree
|
1069
|
+
* @const
|
1070
|
+
*/
|
1071
|
+
var RAD_DEG = 180/Math.PI;
|
1072
|
+
|
1073
|
+
/**
|
1074
|
+
* Converting a radian to a grad
|
1075
|
+
* @const
|
1076
|
+
*/
|
1077
|
+
var RAD_GRAD = 200/Math.PI;
|
1078
|
+
|
1079
|
+
/**
|
1080
|
+
* Converting a degree to a radian
|
1081
|
+
* @const
|
1082
|
+
*/
|
1083
|
+
var DEG_RAD = Math.PI/180;
|
1084
|
+
|
1085
|
+
/**
|
1086
|
+
* Converting a degree to a grad
|
1087
|
+
* @const
|
1088
|
+
*/
|
1089
|
+
var DEG_GRAD = 2/1.8;
|
1090
|
+
|
1091
|
+
/**
|
1092
|
+
* Converting a grad to a degree
|
1093
|
+
* @const
|
1094
|
+
*/
|
1095
|
+
var GRAD_DEG = 0.9;
|
1096
|
+
|
1097
|
+
/**
|
1098
|
+
* Converting a grad to a radian
|
1099
|
+
* @const
|
1100
|
+
*/
|
1101
|
+
var GRAD_RAD = Math.PI/200;
|
1102
|
+
|
1103
|
+
|
1104
|
+
var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
|
1105
|
+
|
1106
|
+
/**
|
1107
|
+
* Functions for converting angles
|
1108
|
+
* @var Object
|
1109
|
+
*/
|
1110
|
+
$.extend({
|
1111
|
+
angle: {
|
1112
|
+
/**
|
1113
|
+
* available units for an angle
|
1114
|
+
* @var Regex
|
1115
|
+
*/
|
1116
|
+
runit: /(deg|g?rad)/,
|
1117
|
+
|
1118
|
+
/**
|
1119
|
+
* Convert a radian into a degree
|
1120
|
+
* @param Number rad
|
1121
|
+
* @return Number
|
1122
|
+
*/
|
1123
|
+
radianToDegree: function(rad) {
|
1124
|
+
return rad * RAD_DEG;
|
1125
|
+
},
|
1126
|
+
|
1127
|
+
/**
|
1128
|
+
* Convert a radian into a degree
|
1129
|
+
* @param Number rad
|
1130
|
+
* @return Number
|
1131
|
+
*/
|
1132
|
+
radianToGrad: function(rad) {
|
1133
|
+
return rad * RAD_GRAD;
|
1134
|
+
},
|
1135
|
+
|
1136
|
+
/**
|
1137
|
+
* Convert a degree into a radian
|
1138
|
+
* @param Number deg
|
1139
|
+
* @return Number
|
1140
|
+
*/
|
1141
|
+
degreeToRadian: function(deg) {
|
1142
|
+
return deg * DEG_RAD;
|
1143
|
+
},
|
1144
|
+
|
1145
|
+
/**
|
1146
|
+
* Convert a degree into a radian
|
1147
|
+
* @param Number deg
|
1148
|
+
* @return Number
|
1149
|
+
*/
|
1150
|
+
degreeToGrad: function(deg) {
|
1151
|
+
return deg * DEG_GRAD;
|
1152
|
+
},
|
1153
|
+
|
1154
|
+
/**
|
1155
|
+
* Convert a grad into a degree
|
1156
|
+
* @param Number grad
|
1157
|
+
* @return Number
|
1158
|
+
*/
|
1159
|
+
gradToDegree: function(grad) {
|
1160
|
+
return grad * GRAD_DEG;
|
1161
|
+
},
|
1162
|
+
|
1163
|
+
/**
|
1164
|
+
* Convert a grad into a radian
|
1165
|
+
* @param Number grad
|
1166
|
+
* @return Number
|
1167
|
+
*/
|
1168
|
+
gradToRadian: function(grad) {
|
1169
|
+
return grad * GRAD_RAD;
|
1170
|
+
},
|
1171
|
+
|
1172
|
+
/**
|
1173
|
+
* Convert an angle with a unit to a degree
|
1174
|
+
* @param String val angle with a unit
|
1175
|
+
* @return Number
|
1176
|
+
*/
|
1177
|
+
toDegree: function (val) {
|
1178
|
+
var parts = rfxnum.exec(val);
|
1179
|
+
if (parts) {
|
1180
|
+
val = parseFloat( parts[2] );
|
1181
|
+
switch (parts[3] || 'deg') {
|
1182
|
+
case 'grad':
|
1183
|
+
val = $.angle.gradToDegree(val);
|
1184
|
+
break;
|
1185
|
+
case 'rad':
|
1186
|
+
val = $.angle.radianToDegree(val);
|
1187
|
+
break;
|
1188
|
+
}
|
1189
|
+
return val;
|
1190
|
+
}
|
1191
|
+
return 0;
|
1192
|
+
}
|
1193
|
+
}
|
1194
|
+
});
|
1195
|
+
})(jQuery, this, this.document);
|
1196
|
+
///////////////////////////////////////////////////////
|
1197
|
+
// Matrix
|
1198
|
+
///////////////////////////////////////////////////////
|
1199
|
+
(function($, window, document, undefined) {
|
1200
|
+
/**
|
1201
|
+
* Matrix object for creating matrices relevant for 2d Transformations
|
1202
|
+
* @var Object
|
1203
|
+
*/
|
1204
|
+
if (typeof($.matrix) == 'undefined') {
|
1205
|
+
$.extend({
|
1206
|
+
matrix: {}
|
1207
|
+
});
|
1208
|
+
}
|
1209
|
+
var $m = $.matrix;
|
1210
|
+
|
1211
|
+
$.extend( $m, {
|
1212
|
+
/**
|
1213
|
+
* A 2-value vector
|
1214
|
+
* @param Number x
|
1215
|
+
* @param Number y
|
1216
|
+
* @constructor
|
1217
|
+
*/
|
1218
|
+
V2: function(x, y){
|
1219
|
+
if ($.isArray(arguments[0])) {
|
1220
|
+
this.elements = arguments[0].slice(0, 2);
|
1221
|
+
} else {
|
1222
|
+
this.elements = [x, y];
|
1223
|
+
}
|
1224
|
+
this.length = 2;
|
1225
|
+
},
|
1226
|
+
|
1227
|
+
/**
|
1228
|
+
* A 2-value vector
|
1229
|
+
* @param Number x
|
1230
|
+
* @param Number y
|
1231
|
+
* @param Number z
|
1232
|
+
* @constructor
|
1233
|
+
*/
|
1234
|
+
V3: function(x, y, z){
|
1235
|
+
if ($.isArray(arguments[0])) {
|
1236
|
+
this.elements = arguments[0].slice(0, 3);
|
1237
|
+
} else {
|
1238
|
+
this.elements = [x, y, z];
|
1239
|
+
}
|
1240
|
+
this.length = 3;
|
1241
|
+
},
|
1242
|
+
|
1243
|
+
/**
|
1244
|
+
* A 2x2 Matrix, useful for 2D-transformations without translations
|
1245
|
+
* @param Number mn
|
1246
|
+
* @constructor
|
1247
|
+
*/
|
1248
|
+
M2x2: function(m11, m12, m21, m22) {
|
1249
|
+
if ($.isArray(arguments[0])) {
|
1250
|
+
this.elements = arguments[0].slice(0, 4);
|
1251
|
+
} else {
|
1252
|
+
this.elements = Array.prototype.slice.call(arguments).slice(0, 4);
|
1253
|
+
}
|
1254
|
+
this.rows = 2;
|
1255
|
+
this.cols = 2;
|
1256
|
+
},
|
1257
|
+
|
1258
|
+
/**
|
1259
|
+
* A 3x3 Matrix, useful for 3D-transformations without translations
|
1260
|
+
* @param Number mn
|
1261
|
+
* @constructor
|
1262
|
+
*/
|
1263
|
+
M3x3: function(m11, m12, m13, m21, m22, m23, m31, m32, m33) {
|
1264
|
+
if ($.isArray(arguments[0])) {
|
1265
|
+
this.elements = arguments[0].slice(0, 9);
|
1266
|
+
} else {
|
1267
|
+
this.elements = Array.prototype.slice.call(arguments).slice(0, 9);
|
1268
|
+
}
|
1269
|
+
this.rows = 3;
|
1270
|
+
this.cols = 3;
|
1271
|
+
}
|
1272
|
+
});
|
1273
|
+
|
1274
|
+
/** generic matrix prototype */
|
1275
|
+
var Matrix = {
|
1276
|
+
/**
|
1277
|
+
* Return a specific element from the matrix
|
1278
|
+
* @param Number row where 1 is the 0th row
|
1279
|
+
* @param Number col where 1 is the 0th column
|
1280
|
+
* @return Number
|
1281
|
+
*/
|
1282
|
+
e: function(row, col) {
|
1283
|
+
var rows = this.rows,
|
1284
|
+
cols = this.cols;
|
1285
|
+
|
1286
|
+
// return 0 on nonsense rows and columns
|
1287
|
+
if (row > rows || col > rows || row < 1 || col < 1) {
|
1288
|
+
return 0;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
return this.elements[(row - 1) * cols + col - 1];
|
1292
|
+
},
|
1293
|
+
|
1294
|
+
/**
|
1295
|
+
* Taken from Zoomooz
|
1296
|
+
* https://github.com/jaukia/zoomooz/blob/c7a37b9a65a06ba730bd66391bbd6fe8e55d3a49/js/jquery.zoomooz.js
|
1297
|
+
*/
|
1298
|
+
decompose: function() {
|
1299
|
+
var a = this.e(1, 1),
|
1300
|
+
b = this.e(2, 1),
|
1301
|
+
c = this.e(1, 2),
|
1302
|
+
d = this.e(2, 2),
|
1303
|
+
e = this.e(1, 3),
|
1304
|
+
f = this.e(2, 3);
|
1305
|
+
|
1306
|
+
// In case the matrix can't be decomposed
|
1307
|
+
if (Math.abs(a * d - b * c) < 0.01) {
|
1308
|
+
return {
|
1309
|
+
rotate: 0 + 'deg',
|
1310
|
+
skewX: 0 + 'deg',
|
1311
|
+
scaleX: 1,
|
1312
|
+
scaleY: 1,
|
1313
|
+
translateX: 0 + 'px',
|
1314
|
+
translateY: 0 + 'px'
|
1315
|
+
};
|
1316
|
+
}
|
1317
|
+
|
1318
|
+
// Translate is easy
|
1319
|
+
var tx = e, ty = f;
|
1320
|
+
|
1321
|
+
// factor out the X scale
|
1322
|
+
var sx = Math.sqrt(a * a + b * b);
|
1323
|
+
a = a/sx;
|
1324
|
+
b = b/sx;
|
1325
|
+
|
1326
|
+
// factor out the skew
|
1327
|
+
var k = a * c + b * d;
|
1328
|
+
c -= a * k;
|
1329
|
+
d -= b * k;
|
1330
|
+
|
1331
|
+
// factor out the Y scale
|
1332
|
+
var sy = Math.sqrt(c * c + d * d);
|
1333
|
+
c = c / sy;
|
1334
|
+
d = d / sy;
|
1335
|
+
k = k / sy;
|
1336
|
+
|
1337
|
+
// account for negative scale
|
1338
|
+
if ((a * d - b * c) < 0.0) {
|
1339
|
+
a = -a;
|
1340
|
+
b = -b;
|
1341
|
+
//c = -c; // accomplishes nothing to negate it
|
1342
|
+
//d = -d; // accomplishes nothing to negate it
|
1343
|
+
sx = -sx;
|
1344
|
+
//sy = -sy //Scale Y shouldn't ever be negated
|
1345
|
+
}
|
1346
|
+
|
1347
|
+
// calculate the rotation angle and skew angle
|
1348
|
+
var rad2deg = $.angle.radianToDegree;
|
1349
|
+
var r = rad2deg(Math.atan2(b, a));
|
1350
|
+
k = rad2deg(Math.atan(k));
|
1351
|
+
|
1352
|
+
return {
|
1353
|
+
rotate: r + 'deg',
|
1354
|
+
skewX: k + 'deg',
|
1355
|
+
scaleX: sx,
|
1356
|
+
scaleY: sy,
|
1357
|
+
translateX: tx + 'px',
|
1358
|
+
translateY: ty + 'px'
|
1359
|
+
};
|
1360
|
+
}
|
1361
|
+
};
|
1362
|
+
|
1363
|
+
/** Extend all of the matrix types with the same prototype */
|
1364
|
+
$.extend($m.M2x2.prototype, Matrix, {
|
1365
|
+
toM3x3: function() {
|
1366
|
+
var a = this.elements;
|
1367
|
+
return new $m.M3x3(
|
1368
|
+
a[0], a[1], 0,
|
1369
|
+
a[2], a[3], 0,
|
1370
|
+
0, 0, 1
|
1371
|
+
);
|
1372
|
+
},
|
1373
|
+
|
1374
|
+
/**
|
1375
|
+
* Multiply a 2x2 matrix by a similar matrix or a vector
|
1376
|
+
* @param M2x2 | V2 matrix
|
1377
|
+
* @return M2x2 | V2
|
1378
|
+
*/
|
1379
|
+
x: function(matrix) {
|
1380
|
+
var isVector = typeof(matrix.rows) === 'undefined';
|
1381
|
+
|
1382
|
+
// Ensure the right-sized matrix
|
1383
|
+
if (!isVector && matrix.rows == 3) {
|
1384
|
+
return this.toM3x3().x(matrix);
|
1385
|
+
}
|
1386
|
+
|
1387
|
+
var a = this.elements,
|
1388
|
+
b = matrix.elements;
|
1389
|
+
|
1390
|
+
if (isVector && b.length == 2) {
|
1391
|
+
// b is actually a vector
|
1392
|
+
return new $m.V2(
|
1393
|
+
a[0] * b[0] + a[1] * b[1],
|
1394
|
+
a[2] * b[0] + a[3] * b[1]
|
1395
|
+
);
|
1396
|
+
} else if (b.length == a.length) {
|
1397
|
+
// b is a 2x2 matrix
|
1398
|
+
return new $m.M2x2(
|
1399
|
+
a[0] * b[0] + a[1] * b[2],
|
1400
|
+
a[0] * b[1] + a[1] * b[3],
|
1401
|
+
|
1402
|
+
a[2] * b[0] + a[3] * b[2],
|
1403
|
+
a[2] * b[1] + a[3] * b[3]
|
1404
|
+
);
|
1405
|
+
}
|
1406
|
+
return false; // fail
|
1407
|
+
},
|
1408
|
+
|
1409
|
+
/**
|
1410
|
+
* Generates an inverse of the current matrix
|
1411
|
+
* @param void
|
1412
|
+
* @return M2x2
|
1413
|
+
* @link http://www.dr-lex.be/random/matrix_inv.html
|
1414
|
+
*/
|
1415
|
+
inverse: function() {
|
1416
|
+
var d = 1/this.determinant(),
|
1417
|
+
a = this.elements;
|
1418
|
+
return new $m.M2x2(
|
1419
|
+
d * a[3], d * -a[1],
|
1420
|
+
d * -a[2], d * a[0]
|
1421
|
+
);
|
1422
|
+
},
|
1423
|
+
|
1424
|
+
/**
|
1425
|
+
* Calculates the determinant of the current matrix
|
1426
|
+
* @param void
|
1427
|
+
* @return Number
|
1428
|
+
* @link http://www.dr-lex.be/random/matrix_inv.html
|
1429
|
+
*/
|
1430
|
+
determinant: function() {
|
1431
|
+
var a = this.elements;
|
1432
|
+
return a[0] * a[3] - a[1] * a[2];
|
1433
|
+
}
|
1434
|
+
});
|
1435
|
+
|
1436
|
+
$.extend($m.M3x3.prototype, Matrix, {
|
1437
|
+
/**
|
1438
|
+
* Multiply a 3x3 matrix by a similar matrix or a vector
|
1439
|
+
* @param M3x3 | V3 matrix
|
1440
|
+
* @return M3x3 | V3
|
1441
|
+
*/
|
1442
|
+
x: function(matrix) {
|
1443
|
+
var isVector = typeof(matrix.rows) === 'undefined';
|
1444
|
+
|
1445
|
+
// Ensure the right-sized matrix
|
1446
|
+
if (!isVector && matrix.rows < 3) {
|
1447
|
+
matrix = matrix.toM3x3();
|
1448
|
+
}
|
1449
|
+
|
1450
|
+
var a = this.elements,
|
1451
|
+
b = matrix.elements;
|
1452
|
+
|
1453
|
+
if (isVector && b.length == 3) {
|
1454
|
+
// b is actually a vector
|
1455
|
+
return new $m.V3(
|
1456
|
+
a[0] * b[0] + a[1] * b[1] + a[2] * b[2],
|
1457
|
+
a[3] * b[0] + a[4] * b[1] + a[5] * b[2],
|
1458
|
+
a[6] * b[0] + a[7] * b[1] + a[8] * b[2]
|
1459
|
+
);
|
1460
|
+
} else if (b.length == a.length) {
|
1461
|
+
// b is a 3x3 matrix
|
1462
|
+
return new $m.M3x3(
|
1463
|
+
a[0] * b[0] + a[1] * b[3] + a[2] * b[6],
|
1464
|
+
a[0] * b[1] + a[1] * b[4] + a[2] * b[7],
|
1465
|
+
a[0] * b[2] + a[1] * b[5] + a[2] * b[8],
|
1466
|
+
|
1467
|
+
a[3] * b[0] + a[4] * b[3] + a[5] * b[6],
|
1468
|
+
a[3] * b[1] + a[4] * b[4] + a[5] * b[7],
|
1469
|
+
a[3] * b[2] + a[4] * b[5] + a[5] * b[8],
|
1470
|
+
|
1471
|
+
a[6] * b[0] + a[7] * b[3] + a[8] * b[6],
|
1472
|
+
a[6] * b[1] + a[7] * b[4] + a[8] * b[7],
|
1473
|
+
a[6] * b[2] + a[7] * b[5] + a[8] * b[8]
|
1474
|
+
);
|
1475
|
+
}
|
1476
|
+
return false; // fail
|
1477
|
+
},
|
1478
|
+
|
1479
|
+
/**
|
1480
|
+
* Generates an inverse of the current matrix
|
1481
|
+
* @param void
|
1482
|
+
* @return M3x3
|
1483
|
+
* @link http://www.dr-lex.be/random/matrix_inv.html
|
1484
|
+
*/
|
1485
|
+
inverse: function() {
|
1486
|
+
var d = 1/this.determinant(),
|
1487
|
+
a = this.elements;
|
1488
|
+
return new $m.M3x3(
|
1489
|
+
d * ( a[8] * a[4] - a[7] * a[5]),
|
1490
|
+
d * (-(a[8] * a[1] - a[7] * a[2])),
|
1491
|
+
d * ( a[5] * a[1] - a[4] * a[2]),
|
1492
|
+
|
1493
|
+
d * (-(a[8] * a[3] - a[6] * a[5])),
|
1494
|
+
d * ( a[8] * a[0] - a[6] * a[2]),
|
1495
|
+
d * (-(a[5] * a[0] - a[3] * a[2])),
|
1496
|
+
|
1497
|
+
d * ( a[7] * a[3] - a[6] * a[4]),
|
1498
|
+
d * (-(a[7] * a[0] - a[6] * a[1])),
|
1499
|
+
d * ( a[4] * a[0] - a[3] * a[1])
|
1500
|
+
);
|
1501
|
+
},
|
1502
|
+
|
1503
|
+
/**
|
1504
|
+
* Calculates the determinant of the current matrix
|
1505
|
+
* @param void
|
1506
|
+
* @return Number
|
1507
|
+
* @link http://www.dr-lex.be/random/matrix_inv.html
|
1508
|
+
*/
|
1509
|
+
determinant: function() {
|
1510
|
+
var a = this.elements;
|
1511
|
+
return a[0] * (a[8] * a[4] - a[7] * a[5]) - a[3] * (a[8] * a[1] - a[7] * a[2]) + a[6] * (a[5] * a[1] - a[4] * a[2]);
|
1512
|
+
}
|
1513
|
+
});
|
1514
|
+
|
1515
|
+
/** generic vector prototype */
|
1516
|
+
var Vector = {
|
1517
|
+
/**
|
1518
|
+
* Return a specific element from the vector
|
1519
|
+
* @param Number i where 1 is the 0th value
|
1520
|
+
* @return Number
|
1521
|
+
*/
|
1522
|
+
e: function(i) {
|
1523
|
+
return this.elements[i - 1];
|
1524
|
+
}
|
1525
|
+
};
|
1526
|
+
|
1527
|
+
/** Extend all of the vector types with the same prototype */
|
1528
|
+
$.extend($m.V2.prototype, Vector);
|
1529
|
+
$.extend($m.V3.prototype, Vector);
|
1530
|
+
})(jQuery, this, this.document);
|
1531
|
+
///////////////////////////////////////////////////////
|
1532
|
+
// Matrix Calculations
|
1533
|
+
///////////////////////////////////////////////////////
|
1534
|
+
(function($, window, document, undefined) {
|
1535
|
+
/**
|
1536
|
+
* Matrix object for creating matrices relevant for 2d Transformations
|
1537
|
+
* @var Object
|
1538
|
+
*/
|
1539
|
+
if (typeof($.matrix) == 'undefined') {
|
1540
|
+
$.extend({
|
1541
|
+
matrix: {}
|
1542
|
+
});
|
1543
|
+
}
|
1544
|
+
|
1545
|
+
$.extend( $.matrix, {
|
1546
|
+
/**
|
1547
|
+
* Class for calculating coordinates on a matrix
|
1548
|
+
* @param Matrix matrix
|
1549
|
+
* @param Number outerHeight
|
1550
|
+
* @param Number outerWidth
|
1551
|
+
* @constructor
|
1552
|
+
*/
|
1553
|
+
calc: function(matrix, outerHeight, outerWidth) {
|
1554
|
+
/**
|
1555
|
+
* @var Matrix
|
1556
|
+
*/
|
1557
|
+
this.matrix = matrix;
|
1558
|
+
|
1559
|
+
/**
|
1560
|
+
* @var Number
|
1561
|
+
*/
|
1562
|
+
this.outerHeight = outerHeight;
|
1563
|
+
|
1564
|
+
/**
|
1565
|
+
* @var Number
|
1566
|
+
*/
|
1567
|
+
this.outerWidth = outerWidth;
|
1568
|
+
}
|
1569
|
+
});
|
1570
|
+
|
1571
|
+
$.matrix.calc.prototype = {
|
1572
|
+
/**
|
1573
|
+
* Calculate a coord on the new object
|
1574
|
+
* @return Object
|
1575
|
+
*/
|
1576
|
+
coord: function(x, y, z) {
|
1577
|
+
//default z and w
|
1578
|
+
z = typeof(z) !== 'undefined' ? z : 0;
|
1579
|
+
|
1580
|
+
var matrix = this.matrix,
|
1581
|
+
vector;
|
1582
|
+
|
1583
|
+
switch (matrix.rows) {
|
1584
|
+
case 2:
|
1585
|
+
vector = matrix.x(new $.matrix.V2(x, y));
|
1586
|
+
break;
|
1587
|
+
case 3:
|
1588
|
+
vector = matrix.x(new $.matrix.V3(x, y, z));
|
1589
|
+
break;
|
1590
|
+
}
|
1591
|
+
|
1592
|
+
return vector;
|
1593
|
+
},
|
1594
|
+
|
1595
|
+
/**
|
1596
|
+
* Calculate the corners of the new object
|
1597
|
+
* @return Object
|
1598
|
+
*/
|
1599
|
+
corners: function(x, y) {
|
1600
|
+
// Try to save the corners if this is called a lot
|
1601
|
+
var save = !(typeof(x) !=='undefined' || typeof(y) !=='undefined'),
|
1602
|
+
c;
|
1603
|
+
if (!this.c || !save) {
|
1604
|
+
y = y || this.outerHeight;
|
1605
|
+
x = x || this.outerWidth;
|
1606
|
+
|
1607
|
+
c = {
|
1608
|
+
tl: this.coord(0, 0),
|
1609
|
+
bl: this.coord(0, y),
|
1610
|
+
tr: this.coord(x, 0),
|
1611
|
+
br: this.coord(x, y)
|
1612
|
+
};
|
1613
|
+
} else {
|
1614
|
+
c = this.c;
|
1615
|
+
}
|
1616
|
+
|
1617
|
+
if (save) {
|
1618
|
+
this.c = c;
|
1619
|
+
}
|
1620
|
+
return c;
|
1621
|
+
},
|
1622
|
+
|
1623
|
+
/**
|
1624
|
+
* Calculate the sides of the new object
|
1625
|
+
* @return Object
|
1626
|
+
*/
|
1627
|
+
sides: function(corners) {
|
1628
|
+
// The corners of the box
|
1629
|
+
var c = corners || this.corners();
|
1630
|
+
|
1631
|
+
return {
|
1632
|
+
top: Math.min(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
|
1633
|
+
bottom: Math.max(c.tl.e(2), c.tr.e(2), c.br.e(2), c.bl.e(2)),
|
1634
|
+
left: Math.min(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1)),
|
1635
|
+
right: Math.max(c.tl.e(1), c.tr.e(1), c.br.e(1), c.bl.e(1))
|
1636
|
+
};
|
1637
|
+
},
|
1638
|
+
|
1639
|
+
/**
|
1640
|
+
* Calculate the offset of the new object
|
1641
|
+
* @return Object
|
1642
|
+
*/
|
1643
|
+
offset: function(corners) {
|
1644
|
+
// The corners of the box
|
1645
|
+
var s = this.sides(corners);
|
1646
|
+
|
1647
|
+
// return size
|
1648
|
+
return {
|
1649
|
+
height: Math.abs(s.bottom - s.top),
|
1650
|
+
width: Math.abs(s.right - s.left)
|
1651
|
+
};
|
1652
|
+
},
|
1653
|
+
|
1654
|
+
/**
|
1655
|
+
* Calculate the area of the new object
|
1656
|
+
* @return Number
|
1657
|
+
* @link http://en.wikipedia.org/wiki/Quadrilateral#Area_of_a_convex_quadrilateral
|
1658
|
+
*/
|
1659
|
+
area: function(corners) {
|
1660
|
+
// The corners of the box
|
1661
|
+
var c = corners || this.corners();
|
1662
|
+
|
1663
|
+
// calculate the two diagonal vectors
|
1664
|
+
var v1 = {
|
1665
|
+
x: c.tr.e(1) - c.tl.e(1) + c.br.e(1) - c.bl.e(1),
|
1666
|
+
y: c.tr.e(2) - c.tl.e(2) + c.br.e(2) - c.bl.e(2)
|
1667
|
+
},
|
1668
|
+
v2 = {
|
1669
|
+
x: c.bl.e(1) - c.tl.e(1) + c.br.e(1) - c.tr.e(1),
|
1670
|
+
y: c.bl.e(2) - c.tl.e(2) + c.br.e(2) - c.tr.e(2)
|
1671
|
+
};
|
1672
|
+
|
1673
|
+
return 0.25 * Math.abs(v1.e(1) * v2.e(2) - v1.e(2) * v2.e(1));
|
1674
|
+
},
|
1675
|
+
|
1676
|
+
/**
|
1677
|
+
* Calculate the non-affinity of the new object
|
1678
|
+
* @return Number
|
1679
|
+
*/
|
1680
|
+
nonAffinity: function() {
|
1681
|
+
// The corners of the box
|
1682
|
+
var sides = this.sides(),
|
1683
|
+
xDiff = sides.top - sides.bottom,
|
1684
|
+
yDiff = sides.left - sides.right;
|
1685
|
+
|
1686
|
+
return parseFloat(parseFloat(Math.abs(
|
1687
|
+
(Math.pow(xDiff, 2) + Math.pow(yDiff, 2)) /
|
1688
|
+
(sides.top * sides.bottom + sides.left * sides.right)
|
1689
|
+
)).toFixed(8));
|
1690
|
+
},
|
1691
|
+
|
1692
|
+
/**
|
1693
|
+
* Calculate a proper top and left for IE
|
1694
|
+
* @param Object toOrigin
|
1695
|
+
* @param Object fromOrigin
|
1696
|
+
* @return Object
|
1697
|
+
*/
|
1698
|
+
originOffset: function(toOrigin, fromOrigin) {
|
1699
|
+
// the origin to translate to
|
1700
|
+
toOrigin = toOrigin ? toOrigin : new $.matrix.V2(
|
1701
|
+
this.outerWidth * 0.5,
|
1702
|
+
this.outerHeight * 0.5
|
1703
|
+
);
|
1704
|
+
|
1705
|
+
// the origin to translate from (IE has a fixed origin of 0, 0)
|
1706
|
+
fromOrigin = fromOrigin ? fromOrigin : new $.matrix.V2(
|
1707
|
+
0,
|
1708
|
+
0
|
1709
|
+
);
|
1710
|
+
|
1711
|
+
// transform the origins
|
1712
|
+
var toCenter = this.coord(toOrigin.e(1), toOrigin.e(2));
|
1713
|
+
var fromCenter = this.coord(fromOrigin.e(1), fromOrigin.e(2));
|
1714
|
+
|
1715
|
+
// return the offset
|
1716
|
+
return {
|
1717
|
+
top: (fromCenter.e(2) - fromOrigin.e(2)) - (toCenter.e(2) - toOrigin.e(2)),
|
1718
|
+
left: (fromCenter.e(1) - fromOrigin.e(1)) - (toCenter.e(1) - toOrigin.e(1))
|
1719
|
+
};
|
1720
|
+
}
|
1721
|
+
};
|
1722
|
+
})(jQuery, this, this.document);
|
1723
|
+
///////////////////////////////////////////////////////
|
1724
|
+
// 2d Matrix Functions
|
1725
|
+
///////////////////////////////////////////////////////
|
1726
|
+
(function($, window, document, undefined) {
|
1727
|
+
/**
|
1728
|
+
* Matrix object for creating matrices relevant for 2d Transformations
|
1729
|
+
* @var Object
|
1730
|
+
*/
|
1731
|
+
if (typeof($.matrix) == 'undefined') {
|
1732
|
+
$.extend({
|
1733
|
+
matrix: {}
|
1734
|
+
});
|
1735
|
+
}
|
1736
|
+
var $m = $.matrix,
|
1737
|
+
$m2x2 = $m.M2x2,
|
1738
|
+
$m3x3 = $m.M3x3;
|
1739
|
+
|
1740
|
+
$.extend( $m, {
|
1741
|
+
/**
|
1742
|
+
* Identity matrix
|
1743
|
+
* @param Number size
|
1744
|
+
* @return Matrix
|
1745
|
+
*/
|
1746
|
+
identity: function(size) {
|
1747
|
+
size = size || 2;
|
1748
|
+
var length = size * size,
|
1749
|
+
elements = new Array(length),
|
1750
|
+
mod = size + 1;
|
1751
|
+
for (var i = 0; i < length; i++) {
|
1752
|
+
elements[i] = (i % mod) === 0 ? 1 : 0;
|
1753
|
+
}
|
1754
|
+
return new $m['M'+size+'x'+size](elements);
|
1755
|
+
},
|
1756
|
+
|
1757
|
+
/**
|
1758
|
+
* Matrix
|
1759
|
+
* @return Matrix
|
1760
|
+
*/
|
1761
|
+
matrix: function() {
|
1762
|
+
var args = Array.prototype.slice.call(arguments);
|
1763
|
+
// arguments are in column-major order
|
1764
|
+
switch (arguments.length) {
|
1765
|
+
case 4:
|
1766
|
+
return new $m2x2(
|
1767
|
+
args[0], args[2],
|
1768
|
+
args[1], args[3]
|
1769
|
+
);
|
1770
|
+
case 6:
|
1771
|
+
return new $m3x3(
|
1772
|
+
args[0], args[2], args[4],
|
1773
|
+
args[1], args[3], args[5],
|
1774
|
+
0, 0, 1
|
1775
|
+
);
|
1776
|
+
}
|
1777
|
+
},
|
1778
|
+
|
1779
|
+
/**
|
1780
|
+
* Reflect (same as rotate(180))
|
1781
|
+
* @return Matrix
|
1782
|
+
*/
|
1783
|
+
reflect: function() {
|
1784
|
+
return new $m2x2(
|
1785
|
+
-1, 0,
|
1786
|
+
0, -1
|
1787
|
+
);
|
1788
|
+
},
|
1789
|
+
|
1790
|
+
/**
|
1791
|
+
* Reflect across the x-axis (mirrored upside down)
|
1792
|
+
* @return Matrix
|
1793
|
+
*/
|
1794
|
+
reflectX: function() {
|
1795
|
+
return new $m2x2(
|
1796
|
+
1, 0,
|
1797
|
+
0, -1
|
1798
|
+
);
|
1799
|
+
},
|
1800
|
+
|
1801
|
+
/**
|
1802
|
+
* Reflect by swapping x an y (same as reflectX + rotate(-90))
|
1803
|
+
* @return Matrix
|
1804
|
+
*/
|
1805
|
+
reflectXY: function() {
|
1806
|
+
return new $m2x2(
|
1807
|
+
0, 1,
|
1808
|
+
1, 0
|
1809
|
+
);
|
1810
|
+
},
|
1811
|
+
|
1812
|
+
/**
|
1813
|
+
* Reflect across the y-axis (mirrored)
|
1814
|
+
* @return Matrix
|
1815
|
+
*/
|
1816
|
+
reflectY: function() {
|
1817
|
+
return new $m2x2(
|
1818
|
+
-1, 0,
|
1819
|
+
0, 1
|
1820
|
+
);
|
1821
|
+
},
|
1822
|
+
|
1823
|
+
/**
|
1824
|
+
* Rotates around the origin
|
1825
|
+
* @param Number deg
|
1826
|
+
* @return Matrix
|
1827
|
+
* @link http://www.w3.org/TR/SVG/coords.html#RotationDefined
|
1828
|
+
*/
|
1829
|
+
rotate: function(deg) {
|
1830
|
+
//TODO: detect units
|
1831
|
+
var rad = $.angle.degreeToRadian(deg),
|
1832
|
+
costheta = Math.cos(rad),
|
1833
|
+
sintheta = Math.sin(rad);
|
1834
|
+
|
1835
|
+
var a = costheta,
|
1836
|
+
b = sintheta,
|
1837
|
+
c = -sintheta,
|
1838
|
+
d = costheta;
|
1839
|
+
|
1840
|
+
return new $m2x2(
|
1841
|
+
a, c,
|
1842
|
+
b, d
|
1843
|
+
);
|
1844
|
+
},
|
1845
|
+
|
1846
|
+
/**
|
1847
|
+
* Scale
|
1848
|
+
* @param Number sx
|
1849
|
+
* @param Number sy
|
1850
|
+
* @return Matrix
|
1851
|
+
* @link http://www.w3.org/TR/SVG/coords.html#ScalingDefined
|
1852
|
+
*/
|
1853
|
+
scale: function (sx, sy) {
|
1854
|
+
sx = sx || sx === 0 ? sx : 1;
|
1855
|
+
sy = sy || sy === 0 ? sy : sx;
|
1856
|
+
|
1857
|
+
return new $m2x2(
|
1858
|
+
sx, 0,
|
1859
|
+
0, sy
|
1860
|
+
);
|
1861
|
+
},
|
1862
|
+
|
1863
|
+
/**
|
1864
|
+
* Scale on the X-axis
|
1865
|
+
* @param Number sx
|
1866
|
+
* @return Matrix
|
1867
|
+
*/
|
1868
|
+
scaleX: function (sx) {
|
1869
|
+
return $m.scale(sx, 1);
|
1870
|
+
},
|
1871
|
+
|
1872
|
+
/**
|
1873
|
+
* Scale on the Y-axis
|
1874
|
+
* @param Number sy
|
1875
|
+
* @return Matrix
|
1876
|
+
*/
|
1877
|
+
scaleY: function (sy) {
|
1878
|
+
return $m.scale(1, sy);
|
1879
|
+
},
|
1880
|
+
|
1881
|
+
/**
|
1882
|
+
* Skews on the X-axis and Y-axis
|
1883
|
+
* @param Number degX
|
1884
|
+
* @param Number degY
|
1885
|
+
* @return Matrix
|
1886
|
+
*/
|
1887
|
+
skew: function (degX, degY) {
|
1888
|
+
degX = degX || 0;
|
1889
|
+
degY = degY || 0;
|
1890
|
+
|
1891
|
+
//TODO: detect units
|
1892
|
+
var radX = $.angle.degreeToRadian(degX),
|
1893
|
+
radY = $.angle.degreeToRadian(degY),
|
1894
|
+
x = Math.tan(radX),
|
1895
|
+
y = Math.tan(radY);
|
1896
|
+
|
1897
|
+
return new $m2x2(
|
1898
|
+
1, x,
|
1899
|
+
y, 1
|
1900
|
+
);
|
1901
|
+
},
|
1902
|
+
|
1903
|
+
/**
|
1904
|
+
* Skews on the X-axis
|
1905
|
+
* @param Number degX
|
1906
|
+
* @return Matrix
|
1907
|
+
* @link http://www.w3.org/TR/SVG/coords.html#SkewXDefined
|
1908
|
+
*/
|
1909
|
+
skewX: function (degX) {
|
1910
|
+
return $m.skew(degX);
|
1911
|
+
},
|
1912
|
+
|
1913
|
+
/**
|
1914
|
+
* Skews on the Y-axis
|
1915
|
+
* @param Number degY
|
1916
|
+
* @return Matrix
|
1917
|
+
* @link http://www.w3.org/TR/SVG/coords.html#SkewYDefined
|
1918
|
+
*/
|
1919
|
+
skewY: function (degY) {
|
1920
|
+
return $m.skew(0, degY);
|
1921
|
+
},
|
1922
|
+
|
1923
|
+
/**
|
1924
|
+
* Translate
|
1925
|
+
* @param Number tx
|
1926
|
+
* @param Number ty
|
1927
|
+
* @return Matrix
|
1928
|
+
* @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
|
1929
|
+
*/
|
1930
|
+
translate: function (tx, ty) {
|
1931
|
+
tx = tx || 0;
|
1932
|
+
ty = ty || 0;
|
1933
|
+
|
1934
|
+
return new $m3x3(
|
1935
|
+
1, 0, tx,
|
1936
|
+
0, 1, ty,
|
1937
|
+
0, 0, 1
|
1938
|
+
);
|
1939
|
+
},
|
1940
|
+
|
1941
|
+
/**
|
1942
|
+
* Translate on the X-axis
|
1943
|
+
* @param Number tx
|
1944
|
+
* @return Matrix
|
1945
|
+
* @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
|
1946
|
+
*/
|
1947
|
+
translateX: function (tx) {
|
1948
|
+
return $m.translate(tx);
|
1949
|
+
},
|
1950
|
+
|
1951
|
+
/**
|
1952
|
+
* Translate on the Y-axis
|
1953
|
+
* @param Number ty
|
1954
|
+
* @return Matrix
|
1955
|
+
* @link http://www.w3.org/TR/SVG/coords.html#TranslationDefined
|
1956
|
+
*/
|
1957
|
+
translateY: function (ty) {
|
1958
|
+
return $m.translate(0, ty);
|
1959
|
+
}
|
1960
|
+
});
|
1961
|
+
})(jQuery, this, this.document);
|