These are the natively supported easing functions, built into WebKit.
49 |
50 |
linear
51 |
ease
52 |
ease-in
53 |
ease-out
54 |
ease-in-out
55 |
56 |
Custom
57 |
These are custom easing functions (thanks to Robert Penner & Thomas Fuchs) that can produce much more interesting transitions.
58 |
59 |
Generated Animation CSS
60 |
Internally the custom easing function for the transition is faked using CSS animations. Here is the code that is produced on the fly for the most recent "transition".
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/js/modernizr.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Modernizr v2.0
3 | * http://www.modernizr.com
4 | *
5 | * Copyright (c) 2009-2011 Faruk Ates, Paul Irish, Alex Sexton
6 | * Dual-licensed under the BSD or MIT licenses: www.modernizr.com/license/
7 | */
8 |
9 | /*
10 | * Modernizr tests which native CSS3 and HTML5 features are available in
11 | * the current UA and makes the results available to you in two ways:
12 | * as properties on a global Modernizr object, and as classes on the
13 | * element. This information allows you to progressively enhance
14 | * your pages with a granular level of control over the experience.
15 | *
16 | * Modernizr has an optional (not included) conditional resource loader
17 | * called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
18 | * To get a build that includes Modernizr.load(), as well as choosing
19 | * which tests to include, go to www.modernizr.com/download/
20 | *
21 | * @author Faruk Ates
22 | * @author Paul Irish
23 | * @author Alex Sexton
24 | * @copyright (c) 2009-2011
25 | * @contributor Ben Alman
26 | */
27 |
28 | window.Modernizr = (function( window, document, undefined ) {
29 |
30 | var version = '2.0',
31 |
32 | Modernizr = {},
33 |
34 | // option for enabling the HTML classes to be added
35 | enableClasses = true,
36 |
37 | docElement = document.documentElement,
38 | docHead = document.head || document.getElementsByTagName('head')[0],
39 |
40 | /**
41 | * Create our "modernizr" element that we do most feature tests on.
42 | */
43 | mod = 'modernizr',
44 | modElem = document.createElement(mod),
45 | mStyle = modElem.style,
46 |
47 | /**
48 | * Create the input element for various Web Forms feature tests.
49 | */
50 | inputElem = document.createElement('input'),
51 |
52 | smile = ':)',
53 |
54 | toString = Object.prototype.toString,
55 |
56 | // List of property values to set for css tests. See ticket #21
57 | prefixes = ' -webkit- -moz- -o- -ms- -khtml- '.split(' '),
58 |
59 | // Following spec is to expose vendor-specific style properties as:
60 | // elem.style.WebkitBorderRadius
61 | // and the following would be incorrect:
62 | // elem.style.webkitBorderRadius
63 |
64 | // Webkit ghosts their properties in lowercase but Opera & Moz do not.
65 | // Microsoft foregoes prefixes entirely <= IE8, but appears to
66 | // use a lowercase `ms` instead of the correct `Ms` in IE9
67 |
68 | // More here: http://github.com/Modernizr/Modernizr/issues/issue/21
69 | domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
70 |
71 | ns = {'svg': 'http://www.w3.org/2000/svg'},
72 |
73 | tests = {},
74 | inputs = {},
75 | attrs = {},
76 |
77 | classes = [],
78 |
79 | featureName, // used in testing loop
80 |
81 |
82 | // Inject element with style element and some CSS rules
83 | injectElementWithStyles = function( rule, callback, nodes, testnames ) {
84 |
85 | var style, ret, node,
86 | div = document.createElement('div');
87 |
88 | if ( parseInt(nodes, 10) ) {
89 | // In order not to give false positives we create a node for each test
90 | // This also allows the method to scale for unspecified uses
91 | while ( nodes-- ) {
92 | node = document.createElement('div');
93 | node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
94 | div.appendChild(node);
95 | }
96 | }
97 |
98 | // '].join('');
103 | div.id = mod;
104 | div.innerHTML += style;
105 | docElement.appendChild(div);
106 |
107 | ret = callback(div, rule);
108 | div.parentNode.removeChild(div);
109 |
110 | return !!ret;
111 |
112 | },
113 |
114 |
115 | // adapted from matchMedia polyfill
116 | // by Scott Jehl and Paul Irish
117 | // gist.github.com/786768
118 | testMediaQuery = function( mq ) {
119 |
120 | if ( window.matchMedia ) {
121 | return matchMedia(mq).matches;
122 | }
123 |
124 | var bool;
125 |
126 | injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
127 | bool = (window.getComputedStyle ?
128 | getComputedStyle(node, null) :
129 | node.currentStyle)['position'] == 'absolute';
130 | });
131 |
132 | return bool;
133 |
134 | },
135 |
136 |
137 | /**
138 | * isEventSupported determines if a given element supports the given event
139 | * function from http://yura.thinkweb2.com/isEventSupported/
140 | */
141 | isEventSupported = (function() {
142 |
143 | var TAGNAMES = {
144 | 'select': 'input', 'change': 'input',
145 | 'submit': 'form', 'reset': 'form',
146 | 'error': 'img', 'load': 'img', 'abort': 'img'
147 | };
148 |
149 | function isEventSupported( eventName, element ) {
150 |
151 | element = element || document.createElement(TAGNAMES[eventName] || 'div');
152 | eventName = 'on' + eventName;
153 |
154 | // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
155 | var isSupported = eventName in element;
156 |
157 | if ( !isSupported ) {
158 | // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
159 | if ( !element.setAttribute ) {
160 | element = document.createElement('div');
161 | }
162 | if ( element.setAttribute && element.removeAttribute ) {
163 | element.setAttribute(eventName, '');
164 | isSupported = is(element[eventName], 'function');
165 |
166 | // If property was created, "remove it" (by setting value to `undefined`)
167 | if ( !is(element[eventName], undefined) ) {
168 | element[eventName] = undefined;
169 | }
170 | element.removeAttribute(eventName);
171 | }
172 | }
173 |
174 | element = null;
175 | return isSupported;
176 | }
177 | return isEventSupported;
178 | })();
179 |
180 | // hasOwnProperty shim by kangax needed for Safari 2.0 support
181 | var _hasOwnProperty = ({}).hasOwnProperty, hasOwnProperty;
182 | if ( !is(_hasOwnProperty, undefined) && !is(_hasOwnProperty.call, undefined) ) {
183 | hasOwnProperty = function (object, property) {
184 | return _hasOwnProperty.call(object, property);
185 | };
186 | }
187 | else {
188 | hasOwnProperty = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
189 | return ((property in object) && is(object.constructor.prototype[property], undefined));
190 | };
191 | }
192 |
193 | /**
194 | * setCss applies given styles to the Modernizr DOM node.
195 | */
196 | function setCss( str ) {
197 | mStyle.cssText = str;
198 | }
199 |
200 | /**
201 | * setCssAll extrapolates all vendor-specific css strings.
202 | */
203 | function setCssAll( str1, str2 ) {
204 | return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
205 | }
206 |
207 | /**
208 | * is returns a boolean for if typeof obj is exactly type.
209 | */
210 | function is( obj, type ) {
211 | return typeof obj === type;
212 | }
213 |
214 | /**
215 | * contains returns a boolean for if substr is found within str.
216 | */
217 | function contains( str, substr ) {
218 | return !!~('' + str).indexOf(substr);
219 | }
220 |
221 | /**
222 | * testProps is a generic CSS / DOM property test; if a browser supports
223 | * a certain property, it won't return undefined for it.
224 | * A supported CSS property returns empty string when its not yet set.
225 | */
226 | function testProps( props, prefixed ) {
227 | for ( var i in props ) {
228 | if ( mStyle[ props[i] ] !== undefined ) {
229 | return prefixed == 'pfx' ? props[i] : true;
230 | }
231 | }
232 | return false;
233 | }
234 |
235 | /**
236 | * testPropsAll tests a list of DOM properties we want to check against.
237 | * We specify literally ALL possible (known and/or likely) properties on
238 | * the element including the non-vendor prefixed one, for forward-
239 | * compatibility.
240 | */
241 | function testPropsAll( prop, prefixed ) {
242 |
243 | var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
244 | props = (prop + ' ' + domPrefixes.join(ucProp + ' ') + ucProp).split(' ');
245 |
246 | return testProps(props, prefixed);
247 | }
248 |
249 | /**
250 | * testBundle tests a list of CSS features that require element and style injection.
251 | * By bundling them together we can reduce the need to touch the DOM multiple times.
252 | */
253 | /*>>testBundle*/
254 | var testBundle = (function( styles, tests ) {
255 | var style = styles.join(''),
256 | len = tests.length;
257 |
258 | injectElementWithStyles(style, function( node, rule ) {
259 | var style = document.styleSheets[document.styleSheets.length - 1],
260 | cssText = style.cssText || style.cssRules[0].cssText,
261 | children = node.childNodes, hash = {};
262 |
263 | while ( len-- ) {
264 | hash[children[len].id] = children[len];
265 | }
266 |
267 | /*>>touch*/ Modernizr['touch'] = ('ontouchstart' in window) || hash['touch'].offsetTop === 9; /*>>touch*/
268 | /*>>csstransforms3d*/ Modernizr['csstransforms3d'] = hash['csstransforms3d'].offsetLeft === 9; /*>>csstransforms3d*/
269 | /*>>generatedcontent*/Modernizr['generatedcontent'] = hash['generatedcontent'].offsetHeight >= 1; /*>>generatedcontent*/
270 | /*>>fontface*/ Modernizr['fontface'] = /src/i.test(cssText) &&
271 | cssText.indexOf(rule.split(' ')[0]) === 0; /*>>fontface*/
272 | }, len, tests);
273 |
274 | })([
275 | // Pass in styles to be injected into document
276 | /*>>fontface*/ '@font-face {font-family:"font";src:url("//:")}' /*>>fontface*/
277 |
278 | /*>>touch*/ ,['@media (',prefixes.join('touch-enabled),('),mod,')',
279 | '{#touch{top:9px;position:absolute}}'].join('') /*>>touch*/
280 |
281 | /*>>csstransforms3d*/ ,['@media (',prefixes.join('transform-3d),('),mod,')',
282 | '{#csstransforms3d{left:9px;position:absolute}}'].join('')/*>>csstransforms3d*/
283 |
284 | /*>>generatedcontent*/,['#generatedcontent:after{content:"',smile,'"}'].join('') /*>>generatedcontent*/
285 | ],
286 | [
287 | /*>>fontface*/ 'fontface' /*>>fontface*/
288 | /*>>touch*/ ,'touch' /*>>touch*/
289 | /*>>csstransforms3d*/ ,'csstransforms3d' /*>>csstransforms3d*/
290 | /*>>generatedcontent*/,'generatedcontent' /*>>generatedcontent*/
291 |
292 | ]);/*>>testBundle*/
293 |
294 |
295 | /**
296 | * Tests
297 | * -----
298 | */
299 |
300 | tests['flexbox'] = function() {
301 | /**
302 | * setPrefixedValueCSS sets the property of a specified element
303 | * adding vendor prefixes to the VALUE of the property.
304 | * @param {Element} element
305 | * @param {string} property The property name. This will not be prefixed.
306 | * @param {string} value The value of the property. This WILL be prefixed.
307 | * @param {string=} extra Additional CSS to append unmodified to the end of
308 | * the CSS string.
309 | */
310 | function setPrefixedValueCSS( element, property, value, extra ) {
311 | property += ':';
312 | element.style.cssText = (property + prefixes.join(value + ';' + property)).slice(0, -property.length) + (extra || '');
313 | }
314 |
315 | /**
316 | * setPrefixedPropertyCSS sets the property of a specified element
317 | * adding vendor prefixes to the NAME of the property.
318 | * @param {Element} element
319 | * @param {string} property The property name. This WILL be prefixed.
320 | * @param {string} value The value of the property. This will not be prefixed.
321 | * @param {string=} extra Additional CSS to append unmodified to the end of
322 | * the CSS string.
323 | */
324 | function setPrefixedPropertyCSS( element, property, value, extra ) {
325 | element.style.cssText = prefixes.join(property + ':' + value + ';') + (extra || '');
326 | }
327 |
328 | var c = document.createElement('div'),
329 | elem = document.createElement('div');
330 |
331 | setPrefixedValueCSS(c, 'display', 'box', 'width:42px;padding:0;');
332 | setPrefixedPropertyCSS(elem, 'box-flex', '1', 'width:10px;');
333 |
334 | c.appendChild(elem);
335 | docElement.appendChild(c);
336 |
337 | var ret = elem.offsetWidth === 42;
338 |
339 | c.removeChild(elem);
340 | docElement.removeChild(c);
341 |
342 | return ret;
343 | };
344 |
345 | // On the S60 and BB Storm, getContext exists, but always returns undefined
346 | // http://github.com/Modernizr/Modernizr/issues/issue/97/
347 |
348 | tests['canvas'] = function() {
349 | var elem = document.createElement('canvas');
350 | return !!(elem.getContext && elem.getContext('2d'));
351 | };
352 |
353 | tests['canvastext'] = function() {
354 | return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
355 | };
356 |
357 | // This WebGL test may false positive.
358 | // But really it's quite impossible to know whether webgl will succeed until after you create the context.
359 | // You might have hardware that can support a 100x100 webgl canvas, but will not support a 1000x1000 webgl
360 | // canvas. So this feature inference is weak, but intentionally so.
361 |
362 | // It is known to false positive in FF4 with certain hardware and the iPad 2.
363 |
364 | tests['webgl'] = function() {
365 | return !!window.WebGLRenderingContext;
366 | };
367 |
368 | /*
369 | * The Modernizr.touch test only indicates if the browser supports
370 | * touch events, which does not necessarily reflect a touchscreen
371 | * device, as evidenced by tablets running Windows 7 or, alas,
372 | * the Palm Pre / WebOS (touch) phones.
373 | *
374 | * Additionally, Chrome (desktop) used to lie about its support on this,
375 | * but that has since been rectified: http://crbug.com/36415
376 | *
377 | * We also test for Firefox 4 Multitouch Support.
378 | *
379 | * For more info, see: http://modernizr.github.com/Modernizr/touch.html
380 | */
381 |
382 | tests['touch'] = function() {
383 | return Modernizr['touch'];
384 | };
385 |
386 |
387 | /**
388 | * geolocation tests for the new Geolocation API specification.
389 | * This test is a standards compliant-only test; for more complete
390 | * testing, including a Google Gears fallback, please see:
391 | * http://code.google.com/p/geo-location-javascript/
392 | * or view a fallback solution using google's geo API:
393 | * http://gist.github.com/366184
394 | */
395 | tests['geolocation'] = function() {
396 | return !!navigator.geolocation;
397 | };
398 |
399 | // Per 1.6:
400 | // This used to be Modernizr.crosswindowmessaging but the longer
401 | // name has been deprecated in favor of a shorter and property-matching one.
402 | // The old API is still available in 1.6, but as of 2.0 will throw a warning,
403 | // and in the first release thereafter disappear entirely.
404 | tests['postmessage'] = function() {
405 | return !!window.postMessage;
406 | };
407 |
408 | // Web SQL database detection is tricky:
409 |
410 | // In chrome incognito mode, openDatabase is truthy, but using it will
411 | // throw an exception: http://crbug.com/42380
412 | // We can create a dummy database, but there is no way to delete it afterwards.
413 |
414 | // Meanwhile, Safari users can get prompted on any database creation.
415 | // If they do, any page with Modernizr will give them a prompt:
416 | // http://github.com/Modernizr/Modernizr/issues/closed#issue/113
417 |
418 | // We have chosen to allow the Chrome incognito false positive, so that Modernizr
419 | // doesn't litter the web with these test databases. As a developer, you'll have
420 | // to account for this gotcha yourself.
421 | tests['websqldatabase'] = function() {
422 | var result = !!window.openDatabase;
423 | /* if (result){
424 | try {
425 | result = !!openDatabase( mod + "testdb", "1.0", mod + "testdb", 2e4);
426 | } catch(e) {
427 | }
428 | } */
429 | return result;
430 | };
431 |
432 | // Vendors had inconsistent prefixing with the experimental Indexed DB:
433 | // - Webkit's implementation is accessible through webkitIndexedDB
434 | // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
435 | // For speed, we don't test the legacy (and beta-only) indexedDB
436 | tests['indexedDB'] = function() {
437 | for ( var i = -1, len = domPrefixes.length; ++i < len; ){
438 | if ( window[domPrefixes[i].toLowerCase() + 'IndexedDB'] ){
439 | return true;
440 | }
441 | }
442 | return !!window.indexedDB;
443 | };
444 |
445 | // documentMode logic from YUI to filter out IE8 Compat Mode
446 | // which false positives.
447 | tests['hashchange'] = function() {
448 | return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
449 | };
450 |
451 | // Per 1.6:
452 | // This used to be Modernizr.historymanagement but the longer
453 | // name has been deprecated in favor of a shorter and property-matching one.
454 | // The old API is still available in 1.6, but as of 2.0 will throw a warning,
455 | // and in the first release thereafter disappear entirely.
456 | tests['history'] = function() {
457 | return !!(window.history && history.pushState);
458 | };
459 |
460 | tests['draganddrop'] = function() {
461 | return isEventSupported('dragstart') && isEventSupported('drop');
462 | };
463 |
464 | // Mozilla is targeting to land MozWebSocket for FF6
465 | // bugzil.la/659324
466 | tests['websockets'] = function() {
467 | for ( var i = -1, len = domPrefixes.length; ++i < len; ){
468 | if ( window[domPrefixes[i] + 'WebSocket'] ){
469 | return true;
470 | }
471 | }
472 | return 'WebSocket' in window;
473 | };
474 |
475 |
476 | // http://css-tricks.com/rgba-browser-support/
477 | tests['rgba'] = function() {
478 | // Set an rgba() color and check the returned value
479 |
480 | setCss('background-color:rgba(150,255,150,.5)');
481 |
482 | return contains(mStyle.backgroundColor, 'rgba');
483 | };
484 |
485 | tests['hsla'] = function() {
486 | // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
487 | // except IE9 who retains it as hsla
488 |
489 | setCss('background-color:hsla(120,40%,100%,.5)');
490 |
491 | return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
492 | };
493 |
494 | tests['multiplebgs'] = function() {
495 | // Setting multiple images AND a color on the background shorthand property
496 | // and then querying the style.background property value for the number of
497 | // occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
498 |
499 | setCss('background:url(//:),url(//:),red url(//:)');
500 |
501 | // If the UA supports multiple backgrounds, there should be three occurrences
502 | // of the string "url(" in the return value for elemStyle.background
503 |
504 | return /(url\s*\(.*?){3}/.test(mStyle.background);
505 | };
506 |
507 |
508 | // In testing support for a given CSS property, it's legit to test:
509 | // `elem.style[styleName] !== undefined`
510 | // If the property is supported it will return an empty string,
511 | // if unsupported it will return undefined.
512 |
513 | // We'll take advantage of this quick test and skip setting a style
514 | // on our modernizr element, but instead just testing undefined vs
515 | // empty string.
516 |
517 |
518 | tests['backgroundsize'] = function() {
519 | return testPropsAll('backgroundSize');
520 | };
521 |
522 | tests['borderimage'] = function() {
523 | return testPropsAll('borderImage');
524 | };
525 |
526 |
527 | // Super comprehensive table about all the unique implementations of
528 | // border-radius: http://muddledramblings.com/table-of-css3-border-radius-compliance
529 |
530 | tests['borderradius'] = function() {
531 | return testPropsAll('borderRadius');
532 | };
533 |
534 | // WebOS unfortunately false positives on this test.
535 | tests['boxshadow'] = function() {
536 | return testPropsAll('boxShadow');
537 | };
538 |
539 | // FF3.0 will false positive on this test
540 | tests['textshadow'] = function() {
541 | return document.createElement('div').style.textShadow === '';
542 | };
543 |
544 |
545 | tests['opacity'] = function() {
546 | // Browsers that actually have CSS Opacity implemented have done so
547 | // according to spec, which means their return values are within the
548 | // range of [0.0,1.0] - including the leading zero.
549 |
550 | setCssAll('opacity:.55');
551 |
552 | // The non-literal . in this regex is intentional:
553 | // German Chrome returns this value as 0,55
554 | // https://github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
555 | return /^0.55$/.test(mStyle.opacity);
556 | };
557 |
558 |
559 | tests['cssanimations'] = function() {
560 | return testPropsAll('animationName');
561 | };
562 |
563 |
564 | tests['csscolumns'] = function() {
565 | return testPropsAll('columnCount');
566 | };
567 |
568 |
569 | tests['cssgradients'] = function() {
570 | /**
571 | * For CSS Gradients syntax, please see:
572 | * http://webkit.org/blog/175/introducing-css-gradients/
573 | * https://developer.mozilla.org/en/CSS/-moz-linear-gradient
574 | * https://developer.mozilla.org/en/CSS/-moz-radial-gradient
575 | * http://dev.w3.org/csswg/css3-images/#gradients-
576 | */
577 |
578 | var str1 = 'background-image:',
579 | str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
580 | str3 = 'linear-gradient(left top,#9f9, white);';
581 |
582 | setCss(
583 | (str1 + prefixes.join(str2 + str1) + prefixes.join(str3 + str1)).slice(0, -str1.length)
584 | );
585 |
586 | return contains(mStyle.backgroundImage, 'gradient');
587 | };
588 |
589 |
590 | tests['cssreflections'] = function() {
591 | return testPropsAll('boxReflect');
592 | };
593 |
594 |
595 | tests['csstransforms'] = function() {
596 | return !!testProps(['transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform']);
597 | };
598 |
599 |
600 | tests['csstransforms3d'] = function() {
601 |
602 | var ret = !!testProps(['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']);
603 |
604 | // Webkit’s 3D transforms are passed off to the browser's own graphics renderer.
605 | // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
606 | // some conditions. As a result, Webkit typically recognizes the syntax but
607 | // will sometimes throw a false positive, thus we must do a more thorough check:
608 | if ( ret && 'webkitPerspective' in docElement.style ) {
609 |
610 | // Webkit allows this media query to succeed only if the feature is enabled.
611 | // `@media (transform-3d),(-o-transform-3d),(-moz-transform-3d),(-ms-transform-3d),(-webkit-transform-3d),(modernizr){ ... }`
612 | ret = Modernizr['csstransforms3d'];
613 | }
614 | return ret;
615 | };
616 |
617 |
618 | tests['csstransitions'] = function() {
619 | return testPropsAll('transitionProperty');
620 | };
621 |
622 |
623 | /*>>fontface*/
624 | // @font-face detection routine by Diego Perini
625 | // http://javascript.nwbox.com/CSSSupport/
626 | tests['fontface'] = function() {
627 | return Modernizr['fontface'];
628 | };
629 | /*>>fontface*/
630 |
631 | // CSS generated content detection
632 | tests['generatedcontent'] = function() {
633 | return Modernizr['generatedcontent'];
634 | };
635 |
636 |
637 |
638 | // These tests evaluate support of the video/audio elements, as well as
639 | // testing what types of content they support.
640 | //
641 | // We're using the Boolean constructor here, so that we can extend the value
642 | // e.g. Modernizr.video // true
643 | // Modernizr.video.ogg // 'probably'
644 | //
645 | // Codec values from : http://github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
646 | // thx to NielsLeenheer and zcorpan
647 |
648 | // Note: in FF 3.5.1 and 3.5.0, "no" was a return value instead of empty string.
649 | // Modernizr does not normalize for that.
650 |
651 | tests['video'] = function() {
652 | var elem = document.createElement('video'),
653 | bool = false;
654 |
655 | // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
656 | try {
657 | if ( bool = !!elem.canPlayType ) {
658 | bool = new Boolean(bool);
659 | bool.ogg = elem.canPlayType('video/ogg; codecs="theora"');
660 |
661 | // Workaround required for IE9, which doesn't report video support without audio codec specified.
662 | // bug 599718 @ msft connect
663 | var h264 = 'video/mp4; codecs="avc1.42E01E';
664 | bool.h264 = elem.canPlayType(h264 + '"') || elem.canPlayType(h264 + ', mp4a.40.2"');
665 |
666 | bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"');
667 | }
668 |
669 | } catch(e) { }
670 |
671 | return bool;
672 | };
673 |
674 | tests['audio'] = function() {
675 | var elem = document.createElement('audio'),
676 | bool = false;
677 |
678 | try {
679 | if ( bool = !!elem.canPlayType ) {
680 | bool = new Boolean(bool);
681 | bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"');
682 | bool.mp3 = elem.canPlayType('audio/mpeg;');
683 |
684 | // Mimetypes accepted:
685 | // https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
686 | // http://bit.ly/iphoneoscodecs
687 | bool.wav = elem.canPlayType('audio/wav; codecs="1"');
688 | bool.m4a = elem.canPlayType('audio/x-m4a;') || elem.canPlayType('audio/aac;');
689 | }
690 | } catch(e) { }
691 |
692 | return bool;
693 | };
694 |
695 |
696 | // Firefox has made these tests rather unfun.
697 |
698 | // In FF4, if disabled, window.localStorage should === null.
699 |
700 | // Normally, we could not test that directly and need to do a
701 | // `('localStorage' in window) && ` test first because otherwise Firefox will
702 | // throw http://bugzil.la/365772 if cookies are disabled
703 |
704 | // However, in Firefox 4 betas, if dom.storage.enabled == false, just mentioning
705 | // the property will throw an exception. http://bugzil.la/599479
706 | // This looks to be fixed for FF4 Final.
707 |
708 | // Because we are forced to try/catch this, we'll go aggressive.
709 |
710 | // FWIW: IE8 Compat mode supports these features completely:
711 | // http://www.quirksmode.org/dom/html5.html
712 | // But IE8 doesn't support either with local files
713 |
714 | tests['localstorage'] = function() {
715 | try {
716 | return !!localStorage.getItem;
717 | } catch(e) {
718 | return false;
719 | }
720 | };
721 |
722 | tests['sessionstorage'] = function() {
723 | try {
724 | return !!sessionStorage.getItem;
725 | } catch(e){
726 | return false;
727 | }
728 | };
729 |
730 |
731 | tests['webworkers'] = function() {
732 | return !!window.Worker;
733 | };
734 |
735 |
736 | tests['applicationcache'] = function() {
737 | return !!window.applicationCache;
738 | };
739 |
740 |
741 | // Thanks to Erik Dahlstrom
742 | tests['svg'] = function() {
743 | return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
744 | };
745 |
746 | // specifically for SVG inline in HTML, not within XHTML
747 | // test page: paulirish.com/demo/inline-svg
748 | tests['inlinesvg'] = function() {
749 | var div = document.createElement('div');
750 | div.innerHTML = '';
751 | return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
752 | };
753 |
754 | // Thanks to F1lt3r and lucideer, ticket #35
755 | tests['smil'] = function() {
756 | return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
757 | };
758 |
759 | tests['svgclippaths'] = function() {
760 | // Possibly returns a false positive in Safari 3.2?
761 | return !!document.createElementNS && /SVG/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
762 | };
763 |
764 | // input features and input types go directly onto the ret object, bypassing the tests loop.
765 | // Hold this guy to execute in a moment.
766 | function webforms() {
767 | // Run through HTML5's new input attributes to see if the UA understands any.
768 | // We're using f which is the element created early on
769 | // Mike Taylr has created a comprehensive resource for testing these attributes
770 | // when applied to all input types:
771 | // http://miketaylr.com/code/input-type-attr.html
772 | // spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
773 |
774 | // Only input placeholder is tested while textarea's placeholder is not.
775 | // Currently Safari 4 and Opera 11 have support only for the input placeholder
776 | // Both tests are available in feature-detects/forms-placeholder.js
777 | Modernizr['input'] = (function( props ) {
778 | for ( var i = 0, len = props.length; i < len; i++ ) {
779 | attrs[ props[i] ] = !!(props[i] in inputElem);
780 | }
781 | return attrs;
782 | })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
783 |
784 | // Run through HTML5's new input types to see if the UA understands any.
785 | // This is put behind the tests runloop because it doesn't return a
786 | // true/false like all the other tests; instead, it returns an object
787 | // containing each input type with its corresponding true/false value
788 |
789 | // Big thanks to @miketaylr for the html5 forms expertise. http://miketaylr.com/
790 | Modernizr['inputtypes'] = (function(props) {
791 |
792 | for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
793 |
794 | inputElem.setAttribute('type', inputElemType = props[i]);
795 | bool = inputElem.type !== 'text';
796 |
797 | // We first check to see if the type we give it sticks..
798 | // If the type does, we feed it a textual value, which shouldn't be valid.
799 | // If the value doesn't stick, we know there's input sanitization which infers a custom UI
800 | if ( bool ) {
801 |
802 | inputElem.value = smile;
803 | inputElem.style.cssText = 'position:absolute;visibility:hidden;';
804 |
805 | if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
806 |
807 | docElement.appendChild(inputElem);
808 | defaultView = document.defaultView;
809 |
810 | // Safari 2-4 allows the smiley as a value, despite making a slider
811 | bool = defaultView.getComputedStyle &&
812 | defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
813 | // Mobile android web browser has false positive, so must
814 | // check the height to see if the widget is actually there.
815 | (inputElem.offsetHeight !== 0);
816 |
817 | docElement.removeChild(inputElem);
818 |
819 | } else if ( /^(search|tel)$/.test(inputElemType) ){
820 | // Spec doesnt define any special parsing or detectable UI
821 | // behaviors so we pass these through as true
822 |
823 | // Interestingly, opera fails the earlier test, so it doesn't
824 | // even make it here.
825 |
826 | } else if ( /^(url|email)$/.test(inputElemType) ) {
827 | // Real url and email support comes with prebaked validation.
828 | bool = inputElem.checkValidity && inputElem.checkValidity() === false;
829 |
830 | } else if ( /^color$/.test(inputElemType) ) {
831 | // chuck into DOM and force reflow for Opera bug in 11.00
832 | // github.com/Modernizr/Modernizr/issues#issue/159
833 | docElement.appendChild(inputElem);
834 | docElement.offsetWidth;
835 | bool = inputElem.value != smile;
836 | docElement.removeChild(inputElem);
837 |
838 | } else {
839 | // If the upgraded input compontent rejects the :) text, we got a winner
840 | bool = inputElem.value != smile;
841 | }
842 | }
843 |
844 | inputs[ props[i] ] = !!bool;
845 | }
846 | return inputs;
847 | })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
848 | }
849 |
850 |
851 | // End of test definitions
852 | // -----------------------
853 |
854 |
855 |
856 | // Run through all tests and detect their support in the current UA.
857 | // todo: hypothetically we could be doing an array of tests and use a basic loop here.
858 | for ( var feature in tests ) {
859 | if ( hasOwnProperty(tests, feature) ) {
860 | // run the test, throw the return value into the Modernizr,
861 | // then based on that boolean, define an appropriate className
862 | // and push it into an array of classes we'll join later.
863 | featureName = feature.toLowerCase();
864 | Modernizr[featureName] = tests[feature]();
865 |
866 | classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
867 | }
868 | }
869 |
870 | // input tests need to run.
871 | Modernizr.input || webforms();
872 |
873 |
874 | /**
875 | * addTest allows the user to define their own feature tests
876 | * the result will be added onto the Modernizr object,
877 | * as well as an appropriate className set on the html element
878 | *
879 | * @param feature - String naming the feature
880 | * @param test - Function returning true if feature is supported, false if not
881 | */
882 | Modernizr.addTest = function ( feature, test ) {
883 | if ( typeof feature == "object" ) {
884 | for ( var key in feature ) {
885 | if ( hasOwnProperty( feature, key ) ) {
886 | Modernizr.addTest( key, feature[ key ] );
887 | }
888 | }
889 | } else {
890 |
891 | feature = feature.toLowerCase();
892 |
893 | if ( Modernizr[feature] !== undefined ) {
894 | // we're going to quit if you're trying to overwrite an existing test
895 | // if we were to allow it, we'd do this:
896 | // var re = new RegExp("\\b(no-)?" + feature + "\\b");
897 | // docElement.className = docElement.className.replace( re, '' );
898 | // but, no rly, stuff 'em.
899 | return;
900 | }
901 |
902 | test = typeof test == "boolean" ? test : !!test();
903 |
904 | docElement.className += ' ' + (test ? '' : 'no-') + feature;
905 | Modernizr[feature] = test;
906 |
907 | }
908 |
909 | return Modernizr; // allow chaining.
910 | };
911 |
912 |
913 | // Reset modElem.cssText to nothing to reduce memory footprint.
914 | setCss('');
915 | modElem = inputElem = null;
916 |
917 | //>>BEGIN IEPP
918 | // Enable HTML 5 elements for styling (and printing) in IE.
919 | if ( window.attachEvent && (function(){ var elem = document.createElement('div');
920 | elem.innerHTML = '';
921 | return elem.childNodes.length !== 1; })() ) {
922 |
923 | // iepp v2 by @jon_neal & afarkas : github.com/aFarkas/iepp/
924 | (function(win, doc) {
925 | win.iepp = win.iepp || {};
926 | var iepp = win.iepp,
927 | elems = iepp.html5elements || 'abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video',
928 | elemsArr = elems.split('|'),
929 | elemsArrLen = elemsArr.length,
930 | elemRegExp = new RegExp('(^|\\s)('+elems+')', 'gi'),
931 | tagRegExp = new RegExp('<(\/*)('+elems+')', 'gi'),
932 | filterReg = /^\s*[\{\}]\s*$/,
933 | ruleRegExp = new RegExp('(^|[^\\n]*?\\s)('+elems+')([^\\n]*)({[\\n\\w\\W]*?})', 'gi'),
934 | docFrag = doc.createDocumentFragment(),
935 | html = doc.documentElement,
936 | head = html.firstChild,
937 | bodyElem = doc.createElement('body'),
938 | styleElem = doc.createElement('style'),
939 | printMedias = /print|all/,
940 | body;
941 | function shim(doc) {
942 | var a = -1;
943 | while (++a < elemsArrLen)
944 | // Use createElement so IE allows HTML5-named elements in a document
945 | doc.createElement(elemsArr[a]);
946 | }
947 |
948 | iepp.getCSS = function(styleSheetList, mediaType) {
949 | if(styleSheetList+'' === undefined){return '';}
950 | var a = -1,
951 | len = styleSheetList.length,
952 | styleSheet,
953 | cssTextArr = [];
954 | while (++a < len) {
955 | styleSheet = styleSheetList[a];
956 | //currently no test for disabled/alternate stylesheets
957 | if(styleSheet.disabled){continue;}
958 | mediaType = styleSheet.media || mediaType;
959 | // Get css from all non-screen stylesheets and their imports
960 | if (printMedias.test(mediaType)) cssTextArr.push(iepp.getCSS(styleSheet.imports, mediaType), styleSheet.cssText);
961 | //reset mediaType to all with every new *not imported* stylesheet
962 | mediaType = 'all';
963 | }
964 | return cssTextArr.join('');
965 | };
966 |
967 | iepp.parseCSS = function(cssText) {
968 | var cssTextArr = [],
969 | rule;
970 | while ((rule = ruleRegExp.exec(cssText)) != null){
971 | // Replace all html5 element references with iepp substitute classnames
972 | cssTextArr.push(( (filterReg.exec(rule[1]) ? '\n' : rule[1]) +rule[2]+rule[3]).replace(elemRegExp, '$1.iepp_$2')+rule[4]);
973 | }
974 | return cssTextArr.join('\n');
975 | };
976 |
977 | iepp.writeHTML = function() {
978 | var a = -1;
979 | body = body || doc.body;
980 | while (++a < elemsArrLen) {
981 | var nodeList = doc.getElementsByTagName(elemsArr[a]),
982 | nodeListLen = nodeList.length,
983 | b = -1;
984 | while (++b < nodeListLen)
985 | if (nodeList[b].className.indexOf('iepp_') < 0)
986 | // Append iepp substitute classnames to all html5 elements
987 | nodeList[b].className += ' iepp_'+elemsArr[a];
988 | }
989 | docFrag.appendChild(body);
990 | html.appendChild(bodyElem);
991 | // Write iepp substitute print-safe document
992 | bodyElem.className = body.className;
993 | bodyElem.id = body.id;
994 | // Replace HTML5 elements with which is print-safe and shouldn't conflict since it isn't part of html5
995 | bodyElem.innerHTML = body.innerHTML.replace(tagRegExp, '<$1font');
996 | };
997 |
998 |
999 | iepp._beforePrint = function() {
1000 | // Write iepp custom print CSS
1001 | styleElem.styleSheet.cssText = iepp.parseCSS(iepp.getCSS(doc.styleSheets, 'all'));
1002 | iepp.writeHTML();
1003 | };
1004 |
1005 | iepp.restoreHTML = function(){
1006 | // Undo everything done in onbeforeprint
1007 | bodyElem.innerHTML = '';
1008 | html.removeChild(bodyElem);
1009 | html.appendChild(body);
1010 | };
1011 |
1012 | iepp._afterPrint = function(){
1013 | // Undo everything done in onbeforeprint
1014 | iepp.restoreHTML();
1015 | styleElem.styleSheet.cssText = '';
1016 | };
1017 |
1018 |
1019 |
1020 | // Shim the document and iepp fragment
1021 | shim(doc);
1022 | shim(docFrag);
1023 |
1024 | //
1025 | if(iepp.disablePP){return;}
1026 |
1027 | // Add iepp custom print style element
1028 | head.insertBefore(styleElem, head.firstChild);
1029 | styleElem.media = 'print';
1030 | styleElem.className = 'iepp-printshim';
1031 | win.attachEvent(
1032 | 'onbeforeprint',
1033 | iepp._beforePrint
1034 | );
1035 | win.attachEvent(
1036 | 'onafterprint',
1037 | iepp._afterPrint
1038 | );
1039 | })(window, document);
1040 | }
1041 | //>>END IEPP
1042 |
1043 | // Assign private properties to the return object with prefix
1044 | Modernizr._version = version;
1045 |
1046 | // expose these for the plugin API. Look in the source for how to join() them against your input
1047 | Modernizr._prefixes = prefixes;
1048 | Modernizr._domPrefixes = domPrefixes;
1049 |
1050 | // Modernizr.mq tests a given media query, live against the current state of the window
1051 | // A few important notes:
1052 | // * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
1053 | // * A max-width or orientation query will be evaluated against the current state, which may change later.
1054 | // * You must specify values. Eg. If you are testing support for the min-width media query use:
1055 | // Modernizr.mq('(min-width:0)')
1056 | // usage:
1057 | // Modernizr.mq('only screen and (max-width:768)')
1058 | Modernizr.mq = testMediaQuery;
1059 |
1060 | // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
1061 | // Modernizr.hasEvent('gesturestart', elem)
1062 | Modernizr.hasEvent = isEventSupported;
1063 |
1064 | // Modernizr.testProp() investigates whether a given style property is recognized
1065 | // Note that the property names must be provided in the camelCase variant.
1066 | // Modernizr.testProp('pointerEvents')
1067 | Modernizr.testProp = function(prop){
1068 | return testProps([prop]);
1069 | };
1070 |
1071 | // Modernizr.testAllProps() investigates whether a given style property,
1072 | // or any of its vendor-prefixed variants, is recognized
1073 | // Note that the property names must be provided in the camelCase variant.
1074 | // Modernizr.testAllProps('boxSizing')
1075 | Modernizr.testAllProps = testPropsAll;
1076 |
1077 |
1078 |
1079 | // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
1080 | // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
1081 | Modernizr.testStyles = injectElementWithStyles;
1082 |
1083 |
1084 | // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
1085 | // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
1086 |
1087 | // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
1088 | // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
1089 | //
1090 | // str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
1091 |
1092 | // If you're trying to ascertain which transition end event to bind to, you might do something like...
1093 | //
1094 | // var transEndEventNames = {
1095 | // 'WebkitTransition' : 'webkitTransitionEnd',
1096 | // 'MozTransition' : 'transitionend',
1097 | // 'OTransition' : 'oTransitionEnd',
1098 | // 'msTransition' : 'msTransitionEnd', // maybe?
1099 | // 'transition' : 'transitionEnd'
1100 | // },
1101 | // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
1102 |
1103 | Modernizr.prefixed = function(prop){
1104 | return testPropsAll(prop, 'pfx');
1105 | };
1106 |
1107 |
1108 |
1109 | // Remove "no-js" class from element, if it exists:
1110 | docElement.className = docElement.className.replace(/\bno-js\b/, '')
1111 |
1112 | // Add the new classes to the element.
1113 | + (enableClasses ? ' js ' + classes.join(' ') : '');
1114 |
1115 | return Modernizr;
1116 |
1117 | })(this, this.document);
--------------------------------------------------------------------------------
/js/morf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve Morf v0.1.5
3 | * http://www.joelambert.co.uk/morf
4 | *
5 | * Copyright 2011, Joe Lambert.
6 | * Free to use under the MIT license.
7 | * http://www.opensource.org/licenses/mit-license.php
8 | */
9 |
10 | var Morf = function(elem, css, opts) {
11 | var from = {}, to = {},
12 |
13 | fromElem = document.createElement('div'),
14 | toElem = document.createElement('div'),
15 |
16 | options = {
17 | timingFunction: 'ease',
18 | duration: null,
19 | increment: 0.01,
20 | debug: false,
21 | optimise: true, // Whether the outputted CSS should be optimised
22 | decimalPlaces: 5 // How many decimal places to optimise the WebKitCSSMatrix output to
23 | },
24 |
25 | // Define all other var's used in the function
26 | i = rule = ruleName = camel = m1 = m2 = progress = frame = rule = transEvent = val = null, cacheKey = '',
27 |
28 | // Setup a scoped reference to ourselves
29 | _this = this,
30 |
31 | keyframes = {},
32 |
33 | // Create a unique name for this animation
34 | animName = 'anim'+(new Date().getTime()),
35 |
36 |
37 | /* --- Helper Functions ------------------------------------------------------------------- */
38 |
39 | // Event listener for the webkitAnimationEnd Event
40 | animationEndListener = function(event){
41 | elem.removeEventListener('webkitAnimationEnd', animationEndListener, true);
42 |
43 | // Dispatch a faux webkitTransitionEnd event to complete the appearance of this being a transition rather than an animation
44 | // TODO: Should we throw an event for each property changed? (event.propertyName = 'opacity' etc)
45 | transEvent = document.createEvent("Event");
46 | transEvent.initEvent("webkitTransitionEnd", true, true);
47 | elem.dispatchEvent(transEvent);
48 |
49 | // Reset transition effects after use
50 | elem.style.webkitTransitionTimingFunction = null;
51 | elem.style.webkitTransitionDuration = 0;
52 |
53 | if (options.callback) {
54 | options.callback(elem);
55 | }
56 | },
57 |
58 | // Adds the CSS to the current page
59 | addKeyframeRule = function(rule) {
60 | if (document.styleSheets && document.styleSheets.length)
61 | document.styleSheets[0].insertRule(rule, 0);
62 | else
63 | {
64 | var style = document.createElement('style');
65 | style.innerHTML = rule;
66 | document.head.appendChild(style);
67 | }
68 | },
69 |
70 | // Produces a CSS string representation of the Keyframes
71 | createAnimationCSS = function(kf, name) {
72 | var str = '@-webkit-keyframes '+name+' {\n', f = pos = rule = null, fStr = '';
73 |
74 | for(pos in kf)
75 | {
76 | f = kf[pos];
77 | fStr = '\t'+pos+' {\n';
78 |
79 | for(rule in f)
80 | fStr += '\t\t'+_this.util.toDash(rule)+': '+f[rule]+';\n';
81 |
82 | fStr += "\t}\n\n";
83 |
84 | str += fStr;
85 | }
86 |
87 | return options.optimise ? optimiseCSS(str+' }') : str+' }';
88 | },
89 |
90 | // Replaces scale(0) with 0.0001 to get around the inability to these decompose matrix
91 | sanityCheckTransformString = function(str) {
92 | var scale = str.match(/scale[Y|X|Z]*\([0-9, ]*0[,0-9 ]*\)/g),
93 | i = 0;
94 |
95 | if(scale)
96 | {
97 | // There might be multiple scale() properties in the string
98 | for(i = 0; i < scale.length; i++)
99 | str = str.replace(scale[i], scale[i].replace(/([^0-9])0([^0.9])/g, "$10.0001$2"));
100 | }
101 |
102 | return str;
103 | },
104 |
105 | // WebKitCSSMatrix toString() ALWAYS outputs numbers to 5 decimal places - this helps optimise the string
106 | optimiseCSS = function(str, decimalPlaces) {
107 | decimalPlaces = typeof options.decimalPlaces == 'number' ? options.decimalPlaces : 5;
108 | var matches = str.match(/[0-9\.]+/gm),
109 | i = 0;
110 |
111 | if(matches)
112 | {
113 | for(i = 0; i < matches.length; i++)
114 | str = str.replace(matches[i], parseFloat( parseFloat(matches[i]).toFixed(decimalPlaces)));
115 | }
116 |
117 | return str;
118 | };
119 |
120 | /* --- Helper Functions End --------------------------------------------------------------- */
121 |
122 |
123 | // Import the options
124 | for(i in opts)
125 | options[i] = opts[i];
126 |
127 |
128 | // If timingFunction is a natively supported function then just trigger normal transition
129 | if( options.timingFunction === 'ease' ||
130 | options.timingFunction === 'linear' ||
131 | options.timingFunction === 'ease-in' ||
132 | options.timingFunction === 'ease-out' ||
133 | options.timingFunction === 'ease-in-out' ||
134 | /^cubic-bezier/.test(options.timingFunction)) {
135 |
136 | elem.style.webkitTransitionDuration = options.duration;
137 | elem.style.webkitTransitionTimingFunction = options.timingFunction;
138 |
139 | // Listen for the transitionEnd event to fire the callback if needed
140 | var transitionEndListener = function(event) {
141 | elem.removeEventListener('webkitTransitionEnd', transitionEndListener, true);
142 |
143 | // Clean up after ourself
144 | elem.style.webkitTransitionDuration = 0;
145 | elem.style.webkitTransitionTimingFunction = null;
146 |
147 | if (options.callback) {
148 | // Delay execution to ensure the clean up CSS has taken effect
149 | setTimeout(function() {
150 | options.callback(elem);
151 | }, 10);
152 | }
153 | };
154 |
155 | elem.addEventListener('webkitTransitionEnd', transitionEndListener, true);
156 |
157 | setTimeout(function() {
158 | for(rule in css) {
159 | camel = _this.util.toCamel(rule);
160 | elem.style[camel] = css[rule];
161 | }
162 | }, 10);
163 |
164 | this.css = '';
165 |
166 | return;
167 | }
168 | else
169 | {
170 | // Reset transition properties for this element
171 | elem.style.webkitTransitionTimingFunction = null;
172 | elem.style.webkitTransitionDuration = 0;
173 | }
174 |
175 | // Create the key used to cache this animation
176 | cacheKey += options.timingFunction;
177 |
178 | // Setup the start and end CSS state
179 | for(rule in css)
180 | {
181 | camel = this.util.toCamel(rule);
182 |
183 | toElem.style[camel] = css[rule];
184 |
185 | // Set the from/start state
186 | from[rule] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix( sanityCheckTransformString( window.getComputedStyle(elem)['-webkit-transform'] ) ) : window.getComputedStyle(elem)[rule];
187 |
188 | // Set the to/end state
189 | to[rule] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix( sanityCheckTransformString( toElem.style.WebkitTransform ) ) : toElem.style[camel];
190 |
191 | // Shifty requires numeric values to be a number rather than a string (e.g. for opacity)
192 | from[rule] = from[rule] == (val = parseInt(from[rule], 10)) ? val : from[rule];
193 | to[rule] = to[rule] == (val = parseInt(from[rule], 10)) ? val : to[rule];
194 |
195 | // Update the cacheKey
196 | cacheKey += ';' + rule + ':' + from[rule] + '->' + to[rule];
197 | }
198 |
199 | // Check the cache to save expensive calculations
200 | if(Morf.cache[cacheKey])
201 | {
202 | this.css = Morf.cache[cacheKey].css;
203 | animName = Morf.cache[cacheKey].name;
204 | }
205 | else
206 | {
207 | // Produce decompositions of matrices here so we don't have to redo it on each iteration
208 | // Decomposing the matrix is expensive so we need to minimise these requests
209 | if(from['-webkit-transform'])
210 | {
211 | m1 = from['-webkit-transform'].decompose();
212 | m2 = to['-webkit-transform'].decompose();
213 | }
214 |
215 | // Produce style keyframes
216 | for(progress = 0; progress <= 1; progress += options.increment) {
217 | // Use Shifty.js to work out the interpolated CSS state
218 | frame = Tweenable.util.interpolate(from, to, progress, options.timingFunction);
219 |
220 | // Work out the interpolated matrix transformation
221 | if(m1 !== null && m2 !== null)
222 | frame['-webkit-transform'] = m1.tween(m2, progress, Tweenable.prototype.formula[options.timingFunction]);
223 |
224 | keyframes[parseInt(progress*100, 10)+'%'] = frame;
225 | }
226 |
227 | // Ensure the last frame has been added
228 | keyframes['100%'] = to;
229 |
230 | // Add the new animation to the document
231 | this.css = createAnimationCSS(keyframes, animName);
232 | addKeyframeRule(this.css);
233 |
234 | Morf.cache[cacheKey] = {css: this.css, name: animName};
235 | }
236 |
237 | // Set the final position state as this should be a transition not an animation & the element should end in the 'to' state
238 | for(rule in to)
239 | elem.style[this.util.toCamel(rule)] = to[rule];
240 |
241 | // Trigger the animation
242 | elem.addEventListener('webkitAnimationEnd', animationEndListener, true);
243 | elem.style.webkitAnimationDuration = options.duration;
244 | elem.style.webkitAnimationTimingFunction = 'linear';
245 | elem.style.webkitAnimationName = animName;
246 |
247 | // Print the animation to the console if the debug switch is given
248 | if(options.debug && window.console && window.console.log)
249 | console.log(this.css);
250 | };
251 |
252 |
253 | /**
254 | * Convenience function for triggering a transition
255 | * @param {HTMLDom} elem The element to apply the transition to
256 | * @param {Object} css Key value pair of CSS properties
257 | * @param {Object} opts Additional configuration options
258 | *
259 | * Configuration options
260 | * - timingFunction: {String} Name of the easing function to perform
261 | * - duration: {integer} Duration in ms
262 | * - increment: {float} How frequently to generate keyframes (Defaults to 0.01, which is every 1%)
263 | * - debug: {Boolean} Should the generated CSS Animation be printed to the console
264 | *
265 | * @returns {Morf} An instance of the Morf object
266 | */
267 |
268 | Morf.transition = function(elem, css, opts){
269 | return new Morf(elem, css, opts);
270 | };
271 |
272 | /**
273 | * Object to cache generated animations
274 | */
275 | Morf.cache = {};
276 |
277 | /**
278 | * Current version
279 | */
280 | Morf.version = '0.1.5';
281 |
282 | // Utilities Placeholder
283 | Morf.prototype.util = {};
284 |
285 |
286 | /**
287 | * Converts a DOM style string to CSS property name
288 | * @param {String} str A DOM style string
289 | * @returns {String} CSS property name
290 | */
291 |
292 | Morf.prototype.util.toDash = function(str){
293 | str = str.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();});
294 | return /^webkit/.test(str) ? '-'+str : str;
295 | };
296 |
297 |
298 | /**
299 | * Converts a CSS property name to DOM style string
300 | * @param {String} str A CSS property name
301 | * @returns {String} DOM style string
302 | */
303 |
304 | Morf.prototype.util.toCamel = function(str){
305 | return str.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase().replace('-','');});
306 | };
307 |
308 | /**
309 | * WebKitCSSMatrix Extensions
310 | *
311 | * Copyright 2011, Joe Lambert (http://www.joelambert.co.uk)
312 | * Free to use under the MIT license.
313 | * http://joelambert.mit-license.org/
314 | */
315 |
316 | // Wrap this functionality up to prevent poluting the global namespace
317 | (function(){
318 |
319 |
320 | /**
321 | * A 4 dimensional vector
322 | * @author Joe Lambert
323 | * @constructor
324 | */
325 |
326 | var Vector4 = function(x, y, z, w)
327 | {
328 | this.x = x ? x : 0;
329 | this.y = y ? y : 0;
330 | this.z = z ? z : 0;
331 | this.w = w ? w : 0;
332 |
333 |
334 | /**
335 | * Ensure that values are not undefined
336 | * @author Joe Lambert
337 | * @returns null
338 | */
339 |
340 | this.checkValues = function() {
341 | this.x = this.x ? this.x : 0;
342 | this.y = this.y ? this.y : 0;
343 | this.z = this.z ? this.z : 0;
344 | this.w = this.w ? this.w : 0;
345 | };
346 |
347 |
348 | /**
349 | * Get the length of the vector
350 | * @author Joe Lambert
351 | * @returns {float}
352 | */
353 |
354 | this.length = function() {
355 | this.checkValues();
356 | return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
357 | };
358 |
359 |
360 | /**
361 | * Get a normalised representation of the vector
362 | * @author Joe Lambert
363 | * @returns {Vector4}
364 | */
365 |
366 | this.normalise = function() {
367 | var len = this.length(),
368 | v = new Vector4(this.x / len, this.y / len, this.z / len);
369 |
370 | return v;
371 | };
372 |
373 |
374 | /**
375 | * Vector Dot-Product
376 | * @param {Vector4} v The second vector to apply the product to
377 | * @author Joe Lambert
378 | * @returns {float} The Dot-Product of this and v.
379 | */
380 |
381 | this.dot = function(v) {
382 | return this.x*v.x + this.y*v.y + this.z*v.z + this.w*v.w;
383 | };
384 |
385 |
386 | /**
387 | * Vector Cross-Product
388 | * @param {Vector4} v The second vector to apply the product to
389 | * @author Joe Lambert
390 | * @returns {Vector4} The Cross-Product of this and v.
391 | */
392 |
393 | this.cross = function(v) {
394 | return new Vector4(this.y*v.z - this.z*v.y, this.z*v.x - this.x*v.z, this.x*v.y - this.y*v.x);
395 | };
396 |
397 |
398 | /**
399 | * Helper function required for matrix decomposition
400 | * A Javascript implementation of pseudo code available from http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition
401 | * @param {Vector4} aPoint A 3D point
402 | * @param {float} ascl
403 | * @param {float} bscl
404 | * @author Joe Lambert
405 | * @returns {Vector4}
406 | */
407 |
408 | this.combine = function(aPoint, ascl, bscl) {
409 | return new Vector4( (ascl * this.x) + (bscl * aPoint.x),
410 | (ascl * this.y) + (bscl * aPoint.y),
411 | (ascl * this.z) + (bscl * aPoint.z) );
412 | }
413 | };
414 |
415 |
416 | /**
417 | * Object containing the decomposed components of a matrix
418 | * @author Joe Lambert
419 | * @constructor
420 | */
421 |
422 | var CSSMatrixDecomposed = function(obj) {
423 | obj === undefined ? obj = {} : null;
424 | var components = {perspective: null, translate: null, skew: null, scale: null, rotate: null};
425 |
426 | for(var i in components)
427 | this[i] = obj[i] ? obj[i] : new Vector4();
428 |
429 | /**
430 | * Tween between two decomposed matrices
431 | * @param {CSSMatrixDecomposed} dm The destination decomposed matrix
432 | * @param {float} progress A float value between 0-1, representing the percentage of completion
433 | * @param {function} fn An easing function following the prototype function(pos){}
434 | * @author Joe Lambert
435 | * @returns {WebKitCSSMatrix} A new matrix for the tweened state
436 | */
437 |
438 | this.tween = function(dm, progress, fn) {
439 | if(fn === undefined)
440 | fn = function(pos) {return pos;}; // Default to a linear easing
441 |
442 | if(!dm)
443 | dm = new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose());
444 |
445 | var r = new CSSMatrixDecomposed(),
446 | i = index = null,
447 | trans = '';
448 |
449 | progress = fn(progress);
450 |
451 | for(index in components)
452 | for(i in {x:'x', y:'y', z:'z', w:'w'})
453 | r[index][i] = (this[index][i] + (dm[index][i] - this[index][i]) * progress ).toFixed(5);
454 |
455 | trans = 'matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, '+r.perspective.x+', '+r.perspective.y+', '+r.perspective.z+', '+r.perspective.w+') ' +
456 | 'translate3d('+r.translate.x+'px, '+r.translate.y+'px, '+r.translate.z+'px) ' +
457 | 'rotateX('+r.rotate.x+'rad) rotateY('+r.rotate.y+'rad) rotateZ('+r.rotate.z+'rad) ' +
458 | 'matrix3d(1,0,0,0, 0,1,0,0, 0,'+r.skew.z+',1,0, 0,0,0,1) ' +
459 | 'matrix3d(1,0,0,0, 0,1,0,0, '+r.skew.y+',0,1,0, 0,0,0,1) ' +
460 | 'matrix3d(1,0,0,0, '+r.skew.x+',1,0,0, 0,0,1,0, 0,0,0,1) ' +
461 | 'scale3d('+r.scale.x+', '+r.scale.y+', '+r.scale.z+')';
462 |
463 | try { r = new WebKitCSSMatrix(trans); return r; }
464 | catch(e) { console.error('Invalid matrix string: '+trans); return '' };
465 | };
466 | };
467 |
468 |
469 | /**
470 | * Tween between two matrices
471 | * @param {WebKitCSSMatrix} matrix The destination matrix
472 | * @param {float} progress A float value between 0-1, representing the percentage of completion
473 | * @param {function} fn An easing function following the prototype function(pos){}
474 | * @author Joe Lambert
475 | * @returns {WebKitCSSMatrix} A new matrix for the tweened state
476 | */
477 |
478 | WebKitCSSMatrix.prototype.tween = function(matrix, progress, fn) {
479 | if(fn === undefined)
480 | fn = function(pos) {return pos;}; // Default to a linear easing
481 |
482 | var m = new WebKitCSSMatrix,
483 | m1 = this.decompose(),
484 | m2 = matrix.decompose(),
485 | r = m.decompose()
486 | trans = '',
487 | index = i = null;
488 |
489 | // Tween between the two decompositions
490 | return m1.tween(m2, progress, fn);
491 | };
492 |
493 |
494 | /**
495 | * Transform a Vector4 object using the current matrix
496 | * @param {Vector4} v The vector to transform
497 | * @author Joe Lambert
498 | * @returns {Vector4} The transformed vector
499 | */
500 |
501 | WebKitCSSMatrix.prototype.transformVector = function(v) {
502 | // TODO: Do we need to mod this for Vector4?
503 | return new Vector4( this.m11*v.x + this.m12*v.y + this.m13*v.z,
504 | this.m21*v.x + this.m22*v.y + this.m23*v.z,
505 | this.m31*v.x + this.m32*v.y + this.m33*v.z );
506 | };
507 |
508 |
509 | /**
510 | * Transposes the matrix
511 | * @author Joe Lambert
512 | * @returns {WebKitCSSMatrix} The transposed matrix
513 | */
514 |
515 | WebKitCSSMatrix.prototype.transpose = function() {
516 | var matrix = new WebKitCSSMatrix(), n = m = 0;
517 |
518 | for (n = 0; n <= 4-2; n++)
519 | {
520 | for (m = n + 1; m <= 4-1; m++)
521 | {
522 | matrix['m'+(n+1)+(m+1)] = this['m'+(m+1)+(n+1)];
523 | matrix['m'+(m+1)+(n+1)] = this['m'+(n+1)+(m+1)];
524 | }
525 | }
526 |
527 | return matrix;
528 | };
529 |
530 |
531 | /**
532 | * Calculates the determinant
533 | * @author Joe Lambert
534 | * @returns {float} The determinant of the matrix
535 | */
536 |
537 | WebKitCSSMatrix.prototype.determinant = function() {
538 | return this.m14 * this.m23 * this.m32 * this.m41-this.m13 * this.m24 * this.m32 * this.m41 -
539 | this.m14 * this.m22 * this.m33 * this.m41+this.m12 * this.m24 * this.m33 * this.m41 +
540 | this.m13 * this.m22 * this.m34 * this.m41-this.m12 * this.m23 * this.m34 * this.m41 -
541 | this.m14 * this.m23 * this.m31 * this.m42+this.m13 * this.m24 * this.m31 * this.m42 +
542 | this.m14 * this.m21 * this.m33 * this.m42-this.m11 * this.m24 * this.m33 * this.m42 -
543 | this.m13 * this.m21 * this.m34 * this.m42+this.m11 * this.m23 * this.m34 * this.m42 +
544 | this.m14 * this.m22 * this.m31 * this.m43-this.m12 * this.m24 * this.m31 * this.m43 -
545 | this.m14 * this.m21 * this.m32 * this.m43+this.m11 * this.m24 * this.m32 * this.m43 +
546 | this.m12 * this.m21 * this.m34 * this.m43-this.m11 * this.m22 * this.m34 * this.m43 -
547 | this.m13 * this.m22 * this.m31 * this.m44+this.m12 * this.m23 * this.m31 * this.m44 +
548 | this.m13 * this.m21 * this.m32 * this.m44-this.m11 * this.m23 * this.m32 * this.m44 -
549 | this.m12 * this.m21 * this.m33 * this.m44+this.m11 * this.m22 * this.m33 * this.m44;
550 | };
551 |
552 |
553 | /**
554 | * Decomposes the matrix into its component parts.
555 | * A Javascript implementation of the pseudo code available from http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition
556 | * @author Joe Lambert
557 | * @returns {Object} An object with each of the components of the matrix (perspective, translate, skew, scale, rotate) or identity matrix on failure
558 | */
559 |
560 | WebKitCSSMatrix.prototype.decompose = function() {
561 | var matrix = new WebKitCSSMatrix(this.toString()),
562 | perspectiveMatrix = rightHandSide = inversePerspectiveMatrix = transposedInversePerspectiveMatrix =
563 | perspective = translate = row = i = scale = skew = pdum3 = rotate = null;
564 |
565 | if (matrix.m33 == 0)
566 | return new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose()); // Return the identity matrix
567 |
568 | // Normalize the matrix.
569 | for (i = 1; i <= 4; i++)
570 | for (j = 1; j <= 4; j++)
571 | matrix['m'+i+j] /= matrix.m44;
572 |
573 | // perspectiveMatrix is used to solve for perspective, but it also provides
574 | // an easy way to test for singularity of the upper 3x3 component.
575 | perspectiveMatrix = matrix;
576 |
577 | for (i = 1; i <= 3; i++)
578 | perspectiveMatrix['m'+i+'4'] = 0;
579 |
580 | perspectiveMatrix.m44 = 1;
581 |
582 | if (perspectiveMatrix.determinant() == 0)
583 | return new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose()); // Return the identity matrix
584 |
585 | // First, isolate perspective.
586 | if (matrix.m14 != 0 || matrix.m24 != 0 || matrix.m34 != 0)
587 | {
588 | // rightHandSide is the right hand side of the equation.
589 | rightHandSide = new Vector4(matrix.m14, matrix.m24, matrix.m34, matrix.m44);
590 |
591 | // Solve the equation by inverting perspectiveMatrix and multiplying
592 | // rightHandSide by the inverse.
593 | inversePerspectiveMatrix = perspectiveMatrix.inverse();
594 | transposedInversePerspectiveMatrix = inversePerspectiveMatrix.transpose();
595 | perspective = transposedInversePerspectiveMatrix.transformVector(rightHandSide);
596 |
597 | // Clear the perspective partition
598 | matrix.m14 = matrix.m24 = matrix.m34 = 0;
599 | matrix.m44 = 1;
600 | }
601 | else
602 | {
603 | // No perspective.
604 | perspective = new Vector4(0,0,0,1);
605 | }
606 |
607 | // Next take care of translation
608 | translate = new Vector4(matrix.m41, matrix.m42, matrix.m43);
609 |
610 | matrix.m41 = 0;
611 | matrix.m42 = 0;
612 | matrix.m43 = 0;
613 |
614 | // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
615 | row = [
616 | new Vector4(), new Vector4(), new Vector4()
617 | ];
618 |
619 | for (i = 1; i <= 3; i++)
620 | {
621 | row[i-1].x = matrix['m'+i+'1'];
622 | row[i-1].y = matrix['m'+i+'2'];
623 | row[i-1].z = matrix['m'+i+'3'];
624 | }
625 |
626 | // Compute X scale factor and normalize first row.
627 | scale = new Vector4();
628 | skew = new Vector4();
629 |
630 | scale.x = row[0].length();
631 | row[0] = row[0].normalise();
632 |
633 | // Compute XY shear factor and make 2nd row orthogonal to 1st.
634 | skew.x = row[0].dot(row[1]);
635 | row[1] = row[1].combine(row[0], 1.0, -skew.x);
636 |
637 | // Now, compute Y scale and normalize 2nd row.
638 | scale.y = row[1].length();
639 | row[1] = row[1].normalise();
640 | skew.x /= scale.y;
641 |
642 | // Compute XZ and YZ shears, orthogonalize 3rd row
643 | skew.y = row[0].dot(row[2]);
644 | row[2] = row[2].combine(row[0], 1.0, -skew.y);
645 | skew.z = row[1].dot(row[2]);
646 | row[2] = row[2].combine(row[1], 1.0, -skew.z);
647 |
648 | // Next, get Z scale and normalize 3rd row.
649 | scale.z = row[2].length();
650 | row[2] = row[2].normalise();
651 | skew.y /= scale.z;
652 | skew.y /= scale.z;
653 |
654 | // At this point, the matrix (in rows) is orthonormal.
655 | // Check for a coordinate system flip. If the determinant
656 | // is -1, then negate the matrix and the scaling factors.
657 | pdum3 = row[1].cross(row[2])
658 | if (row[0].dot(pdum3) < 0)
659 | {
660 | for (i = 0; i < 3; i++)
661 | {
662 | scale.x *= -1;
663 | row[i].x *= -1;
664 | row[i].y *= -1;
665 | row[i].z *= -1;
666 | }
667 | }
668 |
669 | // Now, get the rotations out
670 | rotate = new Vector4();
671 | rotate.y = Math.asin(-row[0].z);
672 | if (Math.cos(rotate.y) != 0)
673 | {
674 | rotate.x = Math.atan2(row[1].z, row[2].z);
675 | rotate.z = Math.atan2(row[0].y, row[0].x);
676 | }
677 | else
678 | {
679 | rotate.x = Math.atan2(-row[2].x, row[1].y);
680 | rotate.z = 0;
681 | }
682 |
683 | return new CSSMatrixDecomposed({
684 | perspective: perspective,
685 | translate: translate,
686 | skew: skew,
687 | scale: scale,
688 | rotate: rotate
689 | });
690 | };
691 |
692 |
693 | })();
694 |
695 |
696 | /**
697 | Mifty - A custom build of Shifty for use with Morf.js.
698 | By Jeremy Kahn - jeremyckahn@gmail.com
699 | v0.4.1
700 |
701 | For instructions on how to use Shifty, please consult the README: https://github.com/jeremyckahn/shifty/blob/master/README.md
702 |
703 | MIT Lincense. This code free to use, modify, distribute and enjoy.
704 |
705 | */
706 |
707 | (function(e){function a(){return+new Date}function b(a,c){for(var j in a)a.hasOwnProperty(j)&&c(a,j)}function h(a,c){b(c,function(c,f){a[f]=c[f]});return a}function k(a,c){b(c,function(c,f){typeof a[f]==="undefined"&&(a[f]=c[f])});return a}function i(a,c,j){var f,a=(a-c.timestamp)/c.duration;for(f in j.current)j.current.hasOwnProperty(f)&&c.to.hasOwnProperty(f)&&(j.current[f]=c.originalState[f]+(c.to[f]-c.originalState[f])*c.easingFunc(a));return j.current}function n(a,c,j,f){var b;for(b=0;b=0;b++)this._hook[a][b]===c&&this._hook[a].splice(b,1);else this._hook[a]=[]};g.prototype.filter={};g.util={now:a,each:b,tweenProps:i,applyFilter:l,simpleCopy:h};g.prototype.formula={linear:function(a){return a}};e.Tweenable=g})(this);
714 | (function(e){e.Tweenable.util.simpleCopy(e.Tweenable.prototype.formula,{easeInQuad:function(a){return Math.pow(a,2)},easeOutQuad:function(a){return-(Math.pow(a-1,2)-1)},easeInOutQuad:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,2);return-0.5*((a-=2)*a-2)},easeInCubic:function(a){return Math.pow(a,3)},easeOutCubic:function(a){return Math.pow(a-1,3)+1},easeInOutCubic:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,3);return 0.5*(Math.pow(a-2,3)+2)},easeInQuart:function(a){return Math.pow(a,4)},easeOutQuart:function(a){return-(Math.pow(a-
715 | 1,4)-1)},easeInOutQuart:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,4);return-0.5*((a-=2)*Math.pow(a,3)-2)},easeInQuint:function(a){return Math.pow(a,5)},easeOutQuint:function(a){return Math.pow(a-1,5)+1},easeInOutQuint:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,5);return 0.5*(Math.pow(a-2,5)+2)},easeInSine:function(a){return-Math.cos(a*(Math.PI/2))+1},easeOutSine:function(a){return Math.sin(a*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a)-1)},easeInExpo:function(a){return a==
716 | 0?0:Math.pow(2,10*(a-1))},easeOutExpo:function(a){return a==1?1:-Math.pow(2,-10*a)+1},easeInOutExpo:function(a){if(a==0)return 0;if(a==1)return 1;if((a/=0.5)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return-(Math.sqrt(1-a*a)-1)},easeOutCirc:function(a){return Math.sqrt(1-Math.pow(a-1,2))},easeInOutCirc:function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeOutBounce:function(a){return a<1/2.75?7.5625*
717 | a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},easeInBack:function(a){return a*a*(2.70158*a-1.70158)},easeOutBack:function(a){return(a-=1)*a*(2.70158*a+1.70158)+1},easeInOutBack:function(a){var b=1.70158;if((a/=0.5)<1)return 0.5*a*a*(((b*=1.525)+1)*a-b);return 0.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},elastic:function(a){return-1*Math.pow(4,-8*a)*Math.sin((a*6-1)*2*Math.PI/2)+1},swingFromTo:function(a){var b=1.70158;return(a/=0.5)<
718 | 1?0.5*a*a*(((b*=1.525)+1)*a-b):0.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},swingFrom:function(a){return a*a*(2.70158*a-1.70158)},swingTo:function(a){return(a-=1)*a*(2.70158*a+1.70158)+1},bounce:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},bouncePast:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?2-(7.5625*(a-=1.5/2.75)*a+0.75):a<2.5/2.75?2-(7.5625*(a-=2.25/2.75)*a+0.9375):2-(7.5625*(a-=2.625/2.75)*
719 | a+0.984375)},easeFromTo:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,4);return-0.5*((a-=2)*Math.pow(a,3)-2)},easeFrom:function(a){return Math.pow(a,4)},easeTo:function(a){return Math.pow(a,0.25)}})})(this);
720 | (function(e){if(e.Tweenable)e.Tweenable.util.interpolate=function(a,b,h,k){var i;if(a&&a.from)b=a.to,h=a.position,k=a.easing,a=a.from;i=e.Tweenable.util.simpleCopy({},a);e.Tweenable.util.applyFilter("tweenCreated",i,[i,a,b]);e.Tweenable.util.applyFilter("beforeTween",i,[i,a,b]);h=e.Tweenable.util.tweenProps(h,{originalState:a,to:b,timestamp:0,duration:1,easingFunc:e.Tweenable.prototype.formula[k]||e.Tweenable.prototype.formula.linear},{current:i});e.Tweenable.util.applyFilter("afterTween",h,[h,a,
721 | b]);return h},e.Tweenable.prototype.interpolate=function(a,b,h){a=e.Tweenable.util.interpolate(this.get(),a,b,h);this.set(a);return a}})(this);
722 |
723 | /**
724 | * @preserve
725 | * Extra easing functions borrowed from scripty2 (c) 2005-2010 Thomas Fuchs (MIT Licence)
726 | * https://raw.github.com/madrobby/scripty2/master/src/effects/transitions/transitions.js
727 | */
728 |
729 | (function(){
730 | var scripty2 = {
731 | spring: function(pos) {
732 | return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
733 | },
734 |
735 | sinusoidal: function(pos) {
736 | return (-Math.cos(pos*Math.PI)/2) + 0.5;
737 | }
738 | };
739 |
740 | // Load the Scripty2 functions
741 | for(var t in scripty2)
742 | Tweenable.prototype.formula[t] = scripty2[t];
743 | })();
744 |
745 |
746 |
--------------------------------------------------------------------------------
/js/morf.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | Morf v0.1.5
3 | http://www.joelambert.co.uk/morf
4 |
5 | Copyright 2011, Joe Lambert.
6 | Free to use under the MIT license.
7 | http://www.opensource.org/licenses/mit-license.php
8 |
9 | Extra easing functions borrowed from scripty2 (c) 2005-2010 Thomas Fuchs (MIT Licence)
10 | https://raw.github.com/madrobby/scripty2/master/src/effects/transitions/transitions.js
11 | */
12 | var Morf=function(d,a,c){var f={},l={};document.createElement("div");var o=document.createElement("div"),e={timingFunction:"ease",duration:null,increment:0.01,debug:false,optimise:true,decimalPlaces:5},q=rule=ruleName=camel=m1=m2=progress=frame=rule=transEvent=val=null,k="",p=this,b={},g="anim"+(new Date).getTime(),h=function(){d.removeEventListener("webkitAnimationEnd",h,true);transEvent=document.createEvent("Event");transEvent.initEvent("webkitTransitionEnd",true,true);d.dispatchEvent(transEvent);
13 | d.style.webkitTransitionTimingFunction=null;d.style.webkitTransitionDuration=0;e.callback&&e.callback(d)},n=function(t){if(document.styleSheets&&document.styleSheets.length)document.styleSheets[0].insertRule(t,0);else{var u=document.createElement("style");u.innerHTML=t;document.head.appendChild(u)}},s=function(t,u){var r="@-webkit-keyframes "+u+" {\n",w=pos=rule=null,v="";for(pos in t){w=t[pos];v="\t"+pos+" {\n";for(rule in w)v+="\t\t"+p.util.toDash(rule)+": "+w[rule]+";\n";v+="\t}\n\n";r+=v}if(e.optimise){r=
14 | r+" }";w=void 0;w=typeof e.decimalPlaces=="number"?e.decimalPlaces:5;v=r.match(/[0-9\.]+/gm);var x=0;if(v)for(x=0;x"+l[rule]}if(Morf.cache[k]){this.css=Morf.cache[k].css;g=Morf.cache[k].name}else{if(f["-webkit-transform"]){m1=f["-webkit-transform"].decompose();m2=l["-webkit-transform"].decompose()}for(progress=0;progress<=1;progress+=e.increment){frame=Tweenable.util.interpolate(f,l,progress,e.timingFunction);if(m1!==null&&m2!==null)frame["-webkit-transform"]=m1.tween(m2,progress,Tweenable.prototype.formula[e.timingFunction]);b[parseInt(progress*
18 | 100,10)+"%"]=frame}b["100%"]=l;this.css=s(b,g);n(this.css);Morf.cache[k]={css:this.css,name:g}}for(rule in l)d.style[this.util.toCamel(rule)]=l[rule];d.addEventListener("webkitAnimationEnd",h,true);d.style.webkitAnimationDuration=e.duration;d.style.webkitAnimationTimingFunction="linear";d.style.webkitAnimationName=g;e.debug&&window.console&&window.console.log&&console.log(this.css)}};Morf.transition=function(d,a,c){return new Morf(d,a,c)};Morf.cache={};Morf.version="0.1.5";Morf.prototype.util={};
19 | Morf.prototype.util.toDash=function(d){d=d.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()});return/^webkit/.test(d)?"-"+d:d};Morf.prototype.util.toCamel=function(d){return d.replace(/(\-[a-z])/g,function(a){return a.toUpperCase().replace("-","")})};
20 | (function(){var d=function(c,f,l,o){this.x=c?c:0;this.y=f?f:0;this.z=l?l:0;this.w=o?o:0;this.checkValues=function(){this.x=this.x?this.x:0;this.y=this.y?this.y:0;this.z=this.z?this.z:0;this.w=this.w?this.w:0};this.length=function(){this.checkValues();return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)};this.normalise=function(){var e=this.length();return new d(this.x/e,this.y/e,this.z/e)};this.dot=function(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.w};this.cross=function(e){return new d(this.y*
21 | e.z-this.z*e.y,this.z*e.x-this.x*e.z,this.x*e.y-this.y*e.x)};this.combine=function(e,q,k){return new d(q*this.x+k*e.x,q*this.y+k*e.y,q*this.z+k*e.z)}},a=function(c){c===undefined&&(c={});var f={perspective:null,translate:null,skew:null,scale:null,rotate:null},l;for(l in f)this[l]=c[l]?c[l]:new d;this.tween=function(o,e,q){if(q===undefined)q=function(h){return h};o||(o=new a((new WebKitCSSMatrix).decompose()));var k=new a,p=index=null,b="";e=q(e);for(index in f)for(p in{x:"x",y:"y",z:"z",w:"w"})k[index][p]=
22 | (this[index][p]+(o[index][p]-this[index][p])*e).toFixed(5);b="matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, "+k.perspective.x+", "+k.perspective.y+", "+k.perspective.z+", "+k.perspective.w+") translate3d("+k.translate.x+"px, "+k.translate.y+"px, "+k.translate.z+"px) rotateX("+k.rotate.x+"rad) rotateY("+k.rotate.y+"rad) rotateZ("+k.rotate.z+"rad) matrix3d(1,0,0,0, 0,1,0,0, 0,"+k.skew.z+",1,0, 0,0,0,1) matrix3d(1,0,0,0, 0,1,0,0, "+k.skew.y+",0,1,0, 0,0,0,1) matrix3d(1,0,0,0, "+k.skew.x+",1,0,0, 0,0,1,0, 0,0,0,1) scale3d("+
23 | k.scale.x+", "+k.scale.y+", "+k.scale.z+")";try{return k=new WebKitCSSMatrix(b)}catch(g){console.error("Invalid matrix string: "+b);return""}}};WebKitCSSMatrix.prototype.tween=function(c,f,l){if(l===undefined)l=function(q){return q};var o=new WebKitCSSMatrix,e=this.decompose();c=c.decompose();o.decompose();trans="";index=i=null;return e.tween(c,f,l)};WebKitCSSMatrix.prototype.transformVector=function(c){return new d(this.m11*c.x+this.m12*c.y+this.m13*c.z,this.m21*c.x+this.m22*c.y+this.m23*c.z,this.m31*
24 | c.x+this.m32*c.y+this.m33*c.z)};WebKitCSSMatrix.prototype.transpose=function(){var c=new WebKitCSSMatrix,f=m=0;for(f=0;f<=2;f++)for(m=f+1;m<=3;m++){c["m"+(f+1)+(m+1)]=this["m"+(m+1)+(f+1)];c["m"+(m+1)+(f+1)]=this["m"+(f+1)+(m+1)]}return c};WebKitCSSMatrix.prototype.determinant=function(){return this.m14*this.m23*this.m32*this.m41-this.m13*this.m24*this.m32*this.m41-this.m14*this.m22*this.m33*this.m41+this.m12*this.m24*this.m33*this.m41+this.m13*this.m22*this.m34*this.m41-this.m12*this.m23*this.m34*
25 | this.m41-this.m14*this.m23*this.m31*this.m42+this.m13*this.m24*this.m31*this.m42+this.m14*this.m21*this.m33*this.m42-this.m11*this.m24*this.m33*this.m42-this.m13*this.m21*this.m34*this.m42+this.m11*this.m23*this.m34*this.m42+this.m14*this.m22*this.m31*this.m43-this.m12*this.m24*this.m31*this.m43-this.m14*this.m21*this.m32*this.m43+this.m11*this.m24*this.m32*this.m43+this.m12*this.m21*this.m34*this.m43-this.m11*this.m22*this.m34*this.m43-this.m13*this.m22*this.m31*this.m44+this.m12*this.m23*this.m31*
26 | this.m44+this.m13*this.m21*this.m32*this.m44-this.m11*this.m23*this.m32*this.m44-this.m12*this.m21*this.m33*this.m44+this.m11*this.m22*this.m33*this.m44};WebKitCSSMatrix.prototype.decompose=function(){var c=new WebKitCSSMatrix(this.toString()),f=rightHandSide=inversePerspectiveMatrix=transposedInversePerspectiveMatrix=perspective=translate=row=i=scale=skew=pdum3=rotate=null;if(c.m33==0)return new a((new WebKitCSSMatrix).decompose());for(i=1;i<=4;i++)for(j=1;j<=4;j++)c["m"+i+j]/=c.m44;f=c;for(i=1;i<=
27 | 3;i++)f["m"+i+"4"]=0;f.m44=1;if(f.determinant()==0)return new a((new WebKitCSSMatrix).decompose());if(c.m14!=0||c.m24!=0||c.m34!=0){rightHandSide=new d(c.m14,c.m24,c.m34,c.m44);inversePerspectiveMatrix=f.inverse();transposedInversePerspectiveMatrix=inversePerspectiveMatrix.transpose();perspective=transposedInversePerspectiveMatrix.transformVector(rightHandSide);c.m14=c.m24=c.m34=0;c.m44=1}else perspective=new d(0,0,0,1);translate=new d(c.m41,c.m42,c.m43);c.m41=0;c.m42=0;c.m43=0;row=[new d,new d,new d];
28 | for(i=1;i<=3;i++){row[i-1].x=c["m"+i+"1"];row[i-1].y=c["m"+i+"2"];row[i-1].z=c["m"+i+"3"]}scale=new d;skew=new d;scale.x=row[0].length();row[0]=row[0].normalise();skew.x=row[0].dot(row[1]);row[1]=row[1].combine(row[0],1,-skew.x);scale.y=row[1].length();row[1]=row[1].normalise();skew.x/=scale.y;skew.y=row[0].dot(row[2]);row[2]=row[2].combine(row[0],1,-skew.y);skew.z=row[1].dot(row[2]);row[2]=row[2].combine(row[1],1,-skew.z);scale.z=row[2].length();row[2]=row[2].normalise();skew.y/=scale.z;skew.y/=
29 | scale.z;pdum3=row[1].cross(row[2]);if(row[0].dot(pdum3)<0)for(i=0;i<3;i++){scale.x*=-1;row[i].x*=-1;row[i].y*=-1;row[i].z*=-1}rotate=new d;rotate.y=Math.asin(-row[0].z);if(Math.cos(rotate.y)!=0){rotate.x=Math.atan2(row[1].z,row[2].z);rotate.z=Math.atan2(row[0].y,row[0].x)}else{rotate.x=Math.atan2(-row[2].x,row[1].y);rotate.z=0}return new a({perspective:perspective,translate:translate,skew:skew,scale:scale,rotate:rotate})}})();
30 | (function(d){function a(){return+new Date}function c(b,g){for(var h in b)b.hasOwnProperty(h)&&g(b,h)}function f(b,g){c(g,function(h,n){b[n]=h[n]});return b}function l(b,g){c(g,function(h,n){typeof b[n]==="undefined"&&(b[n]=h[n])});return b}function o(b,g,h){var n;b=(b-g.timestamp)/g.duration;for(n in h.current)h.current.hasOwnProperty(n)&&g.to.hasOwnProperty(n)&&(h.current[n]=g.originalState[n]+(g.to[n]-g.originalState[n])*g.easingFunc(b));return h.current}function e(b,g,h,n){var s;for(s=0;s=0;h++)this._hook[b][h]===g&&this._hook[b].splice(h,1);else this._hook[b]=[]};p.prototype.filter={};p.util={now:a,each:c,tweenProps:o,applyFilter:q,simpleCopy:f};p.prototype.formula={linear:function(b){return b}};d.Tweenable=p})(this);
37 | (function(d){d.Tweenable.util.simpleCopy(d.Tweenable.prototype.formula,{easeInQuad:function(a){return Math.pow(a,2)},easeOutQuad:function(a){return-(Math.pow(a-1,2)-1)},easeInOutQuad:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,2);return-0.5*((a-=2)*a-2)},easeInCubic:function(a){return Math.pow(a,3)},easeOutCubic:function(a){return Math.pow(a-1,3)+1},easeInOutCubic:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,3);return 0.5*(Math.pow(a-2,3)+2)},easeInQuart:function(a){return Math.pow(a,4)},easeOutQuart:function(a){return-(Math.pow(a-
38 | 1,4)-1)},easeInOutQuart:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,4);return-0.5*((a-=2)*Math.pow(a,3)-2)},easeInQuint:function(a){return Math.pow(a,5)},easeOutQuint:function(a){return Math.pow(a-1,5)+1},easeInOutQuint:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,5);return 0.5*(Math.pow(a-2,5)+2)},easeInSine:function(a){return-Math.cos(a*(Math.PI/2))+1},easeOutSine:function(a){return Math.sin(a*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a)-1)},easeInExpo:function(a){return a==
39 | 0?0:Math.pow(2,10*(a-1))},easeOutExpo:function(a){return a==1?1:-Math.pow(2,-10*a)+1},easeInOutExpo:function(a){if(a==0)return 0;if(a==1)return 1;if((a/=0.5)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return-(Math.sqrt(1-a*a)-1)},easeOutCirc:function(a){return Math.sqrt(1-Math.pow(a-1,2))},easeInOutCirc:function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeOutBounce:function(a){return a<1/2.75?7.5625*
40 | a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},easeInBack:function(a){return a*a*(2.70158*a-1.70158)},easeOutBack:function(a){return(a-=1)*a*(2.70158*a+1.70158)+1},easeInOutBack:function(a){var c=1.70158;if((a/=0.5)<1)return 0.5*a*a*(((c*=1.525)+1)*a-c);return 0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},elastic:function(a){return-1*Math.pow(4,-8*a)*Math.sin((a*6-1)*2*Math.PI/2)+1},swingFromTo:function(a){var c=1.70158;return(a/=0.5)<
41 | 1?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},swingFrom:function(a){return a*a*(2.70158*a-1.70158)},swingTo:function(a){return(a-=1)*a*(2.70158*a+1.70158)+1},bounce:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},bouncePast:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?2-(7.5625*(a-=1.5/2.75)*a+0.75):a<2.5/2.75?2-(7.5625*(a-=2.25/2.75)*a+0.9375):2-(7.5625*(a-=2.625/2.75)*
42 | a+0.984375)},easeFromTo:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,4);return-0.5*((a-=2)*Math.pow(a,3)-2)},easeFrom:function(a){return Math.pow(a,4)},easeTo:function(a){return Math.pow(a,0.25)}})})(this);
43 | (function(d){if(d.Tweenable){d.Tweenable.util.interpolate=function(a,c,f,l){var o;if(a&&a.from){c=a.to;f=a.position;l=a.easing;a=a.from}o=d.Tweenable.util.simpleCopy({},a);d.Tweenable.util.applyFilter("tweenCreated",o,[o,a,c]);d.Tweenable.util.applyFilter("beforeTween",o,[o,a,c]);f=d.Tweenable.util.tweenProps(f,{originalState:a,to:c,timestamp:0,duration:1,easingFunc:d.Tweenable.prototype.formula[l]||d.Tweenable.prototype.formula.linear},{current:o});d.Tweenable.util.applyFilter("afterTween",f,[f,
44 | a,c]);return f};d.Tweenable.prototype.interpolate=function(a,c,f){a=d.Tweenable.util.interpolate(this.get(),a,c,f);this.set(a);return a}}})(this);(function(){var d={spring:function(c){return 1-Math.cos(c*4.5*Math.PI)*Math.exp(-c*6)},sinusoidal:function(c){return-Math.cos(c*Math.PI)/2+0.5}},a;for(a in d)Tweenable.prototype.formula[a]=d[a]})();
45 |
--------------------------------------------------------------------------------
/js/morf.noshifty.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve Morf v0.1.5
3 | * http://www.joelambert.co.uk/morf
4 | *
5 | * Copyright 2011, Joe Lambert.
6 | * Free to use under the MIT license.
7 | * http://www.opensource.org/licenses/mit-license.php
8 | */
9 |
10 | var Morf = function(elem, css, opts) {
11 | var from = {}, to = {},
12 |
13 | fromElem = document.createElement('div'),
14 | toElem = document.createElement('div'),
15 |
16 | options = {
17 | timingFunction: 'ease',
18 | duration: null,
19 | increment: 0.01,
20 | debug: false,
21 | optimise: true, // Whether the outputted CSS should be optimised
22 | decimalPlaces: 5 // How many decimal places to optimise the WebKitCSSMatrix output to
23 | },
24 |
25 | // Define all other var's used in the function
26 | i = rule = ruleName = camel = m1 = m2 = progress = frame = rule = transEvent = val = null, cacheKey = '',
27 |
28 | // Setup a scoped reference to ourselves
29 | _this = this,
30 |
31 | keyframes = {},
32 |
33 | // Create a unique name for this animation
34 | animName = 'anim'+(new Date().getTime()),
35 |
36 |
37 | /* --- Helper Functions ------------------------------------------------------------------- */
38 |
39 | // Event listener for the webkitAnimationEnd Event
40 | animationEndListener = function(event){
41 | elem.removeEventListener('webkitAnimationEnd', animationEndListener, true);
42 |
43 | // Dispatch a faux webkitTransitionEnd event to complete the appearance of this being a transition rather than an animation
44 | // TODO: Should we throw an event for each property changed? (event.propertyName = 'opacity' etc)
45 | transEvent = document.createEvent("Event");
46 | transEvent.initEvent("webkitTransitionEnd", true, true);
47 | elem.dispatchEvent(transEvent);
48 |
49 | // Reset transition effects after use
50 | elem.style.webkitTransitionTimingFunction = null;
51 | elem.style.webkitTransitionDuration = 0;
52 |
53 | if (options.callback) {
54 | options.callback(elem);
55 | }
56 | },
57 |
58 | // Adds the CSS to the current page
59 | addKeyframeRule = function(rule) {
60 | if (document.styleSheets && document.styleSheets.length)
61 | document.styleSheets[0].insertRule(rule, 0);
62 | else
63 | {
64 | var style = document.createElement('style');
65 | style.innerHTML = rule;
66 | document.head.appendChild(style);
67 | }
68 | },
69 |
70 | // Produces a CSS string representation of the Keyframes
71 | createAnimationCSS = function(kf, name) {
72 | var str = '@-webkit-keyframes '+name+' {\n', f = pos = rule = null, fStr = '';
73 |
74 | for(pos in kf)
75 | {
76 | f = kf[pos];
77 | fStr = '\t'+pos+' {\n';
78 |
79 | for(rule in f)
80 | fStr += '\t\t'+_this.util.toDash(rule)+': '+f[rule]+';\n';
81 |
82 | fStr += "\t}\n\n";
83 |
84 | str += fStr;
85 | }
86 |
87 | return options.optimise ? optimiseCSS(str+' }') : str+' }';
88 | },
89 |
90 | // Replaces scale(0) with 0.0001 to get around the inability to these decompose matrix
91 | sanityCheckTransformString = function(str) {
92 | var scale = str.match(/scale[Y|X|Z]*\([0-9, ]*0[,0-9 ]*\)/g),
93 | i = 0;
94 |
95 | if(scale)
96 | {
97 | // There might be multiple scale() properties in the string
98 | for(i = 0; i < scale.length; i++)
99 | str = str.replace(scale[i], scale[i].replace(/([^0-9])0([^0.9])/g, "$10.0001$2"));
100 | }
101 |
102 | return str;
103 | },
104 |
105 | // WebKitCSSMatrix toString() ALWAYS outputs numbers to 5 decimal places - this helps optimise the string
106 | optimiseCSS = function(str, decimalPlaces) {
107 | decimalPlaces = typeof options.decimalPlaces == 'number' ? options.decimalPlaces : 5;
108 | var matches = str.match(/[0-9\.]+/gm),
109 | i = 0;
110 |
111 | if(matches)
112 | {
113 | for(i = 0; i < matches.length; i++)
114 | str = str.replace(matches[i], parseFloat( parseFloat(matches[i]).toFixed(decimalPlaces)));
115 | }
116 |
117 | return str;
118 | };
119 |
120 | /* --- Helper Functions End --------------------------------------------------------------- */
121 |
122 |
123 | // Import the options
124 | for(i in opts)
125 | options[i] = opts[i];
126 |
127 |
128 | // If timingFunction is a natively supported function then just trigger normal transition
129 | if( options.timingFunction === 'ease' ||
130 | options.timingFunction === 'linear' ||
131 | options.timingFunction === 'ease-in' ||
132 | options.timingFunction === 'ease-out' ||
133 | options.timingFunction === 'ease-in-out' ||
134 | /^cubic-bezier/.test(options.timingFunction)) {
135 |
136 | elem.style.webkitTransitionDuration = options.duration;
137 | elem.style.webkitTransitionTimingFunction = options.timingFunction;
138 |
139 | // Listen for the transitionEnd event to fire the callback if needed
140 | var transitionEndListener = function(event) {
141 | elem.removeEventListener('webkitTransitionEnd', transitionEndListener, true);
142 |
143 | // Clean up after ourself
144 | elem.style.webkitTransitionDuration = 0;
145 | elem.style.webkitTransitionTimingFunction = null;
146 |
147 | if (options.callback) {
148 | // Delay execution to ensure the clean up CSS has taken effect
149 | setTimeout(function() {
150 | options.callback(elem);
151 | }, 10);
152 | }
153 | };
154 |
155 | elem.addEventListener('webkitTransitionEnd', transitionEndListener, true);
156 |
157 | setTimeout(function() {
158 | for(rule in css) {
159 | camel = _this.util.toCamel(rule);
160 | elem.style[camel] = css[rule];
161 | }
162 | }, 10);
163 |
164 | this.css = '';
165 |
166 | return;
167 | }
168 | else
169 | {
170 | // Reset transition properties for this element
171 | elem.style.webkitTransitionTimingFunction = null;
172 | elem.style.webkitTransitionDuration = 0;
173 | }
174 |
175 | // Create the key used to cache this animation
176 | cacheKey += options.timingFunction;
177 |
178 | // Setup the start and end CSS state
179 | for(rule in css)
180 | {
181 | camel = this.util.toCamel(rule);
182 |
183 | toElem.style[camel] = css[rule];
184 |
185 | // Set the from/start state
186 | from[rule] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix( sanityCheckTransformString( window.getComputedStyle(elem)['-webkit-transform'] ) ) : window.getComputedStyle(elem)[rule];
187 |
188 | // Set the to/end state
189 | to[rule] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix( sanityCheckTransformString( toElem.style.WebkitTransform ) ) : toElem.style[camel];
190 |
191 | // Shifty requires numeric values to be a number rather than a string (e.g. for opacity)
192 | from[rule] = from[rule] == (val = parseInt(from[rule], 10)) ? val : from[rule];
193 | to[rule] = to[rule] == (val = parseInt(from[rule], 10)) ? val : to[rule];
194 |
195 | // Update the cacheKey
196 | cacheKey += ';' + rule + ':' + from[rule] + '->' + to[rule];
197 | }
198 |
199 | // Check the cache to save expensive calculations
200 | if(Morf.cache[cacheKey])
201 | {
202 | this.css = Morf.cache[cacheKey].css;
203 | animName = Morf.cache[cacheKey].name;
204 | }
205 | else
206 | {
207 | // Produce decompositions of matrices here so we don't have to redo it on each iteration
208 | // Decomposing the matrix is expensive so we need to minimise these requests
209 | if(from['-webkit-transform'])
210 | {
211 | m1 = from['-webkit-transform'].decompose();
212 | m2 = to['-webkit-transform'].decompose();
213 | }
214 |
215 | // Produce style keyframes
216 | for(progress = 0; progress <= 1; progress += options.increment) {
217 | // Use Shifty.js to work out the interpolated CSS state
218 | frame = Tweenable.util.interpolate(from, to, progress, options.timingFunction);
219 |
220 | // Work out the interpolated matrix transformation
221 | if(m1 !== null && m2 !== null)
222 | frame['-webkit-transform'] = m1.tween(m2, progress, Tweenable.prototype.formula[options.timingFunction]);
223 |
224 | keyframes[parseInt(progress*100, 10)+'%'] = frame;
225 | }
226 |
227 | // Ensure the last frame has been added
228 | keyframes['100%'] = to;
229 |
230 | // Add the new animation to the document
231 | this.css = createAnimationCSS(keyframes, animName);
232 | addKeyframeRule(this.css);
233 |
234 | Morf.cache[cacheKey] = {css: this.css, name: animName};
235 | }
236 |
237 | // Set the final position state as this should be a transition not an animation & the element should end in the 'to' state
238 | for(rule in to)
239 | elem.style[this.util.toCamel(rule)] = to[rule];
240 |
241 | // Trigger the animation
242 | elem.addEventListener('webkitAnimationEnd', animationEndListener, true);
243 | elem.style.webkitAnimationDuration = options.duration;
244 | elem.style.webkitAnimationTimingFunction = 'linear';
245 | elem.style.webkitAnimationName = animName;
246 |
247 | // Print the animation to the console if the debug switch is given
248 | if(options.debug && window.console && window.console.log)
249 | console.log(this.css);
250 | };
251 |
252 |
253 | /**
254 | * Convenience function for triggering a transition
255 | * @param {HTMLDom} elem The element to apply the transition to
256 | * @param {Object} css Key value pair of CSS properties
257 | * @param {Object} opts Additional configuration options
258 | *
259 | * Configuration options
260 | * - timingFunction: {String} Name of the easing function to perform
261 | * - duration: {integer} Duration in ms
262 | * - increment: {float} How frequently to generate keyframes (Defaults to 0.01, which is every 1%)
263 | * - debug: {Boolean} Should the generated CSS Animation be printed to the console
264 | *
265 | * @returns {Morf} An instance of the Morf object
266 | */
267 |
268 | Morf.transition = function(elem, css, opts){
269 | return new Morf(elem, css, opts);
270 | };
271 |
272 | /**
273 | * Object to cache generated animations
274 | */
275 | Morf.cache = {};
276 |
277 | /**
278 | * Current version
279 | */
280 | Morf.version = '0.1.5';
281 |
282 | // Utilities Placeholder
283 | Morf.prototype.util = {};
284 |
285 |
286 | /**
287 | * Converts a DOM style string to CSS property name
288 | * @param {String} str A DOM style string
289 | * @returns {String} CSS property name
290 | */
291 |
292 | Morf.prototype.util.toDash = function(str){
293 | str = str.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();});
294 | return /^webkit/.test(str) ? '-'+str : str;
295 | };
296 |
297 |
298 | /**
299 | * Converts a CSS property name to DOM style string
300 | * @param {String} str A CSS property name
301 | * @returns {String} DOM style string
302 | */
303 |
304 | Morf.prototype.util.toCamel = function(str){
305 | return str.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase().replace('-','');});
306 | };
307 |
308 | /**
309 | * WebKitCSSMatrix Extensions
310 | *
311 | * Copyright 2011, Joe Lambert (http://www.joelambert.co.uk)
312 | * Free to use under the MIT license.
313 | * http://joelambert.mit-license.org/
314 | */
315 |
316 | // Wrap this functionality up to prevent poluting the global namespace
317 | (function(){
318 |
319 |
320 | /**
321 | * A 4 dimensional vector
322 | * @author Joe Lambert
323 | * @constructor
324 | */
325 |
326 | var Vector4 = function(x, y, z, w)
327 | {
328 | this.x = x ? x : 0;
329 | this.y = y ? y : 0;
330 | this.z = z ? z : 0;
331 | this.w = w ? w : 0;
332 |
333 |
334 | /**
335 | * Ensure that values are not undefined
336 | * @author Joe Lambert
337 | * @returns null
338 | */
339 |
340 | this.checkValues = function() {
341 | this.x = this.x ? this.x : 0;
342 | this.y = this.y ? this.y : 0;
343 | this.z = this.z ? this.z : 0;
344 | this.w = this.w ? this.w : 0;
345 | };
346 |
347 |
348 | /**
349 | * Get the length of the vector
350 | * @author Joe Lambert
351 | * @returns {float}
352 | */
353 |
354 | this.length = function() {
355 | this.checkValues();
356 | return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
357 | };
358 |
359 |
360 | /**
361 | * Get a normalised representation of the vector
362 | * @author Joe Lambert
363 | * @returns {Vector4}
364 | */
365 |
366 | this.normalise = function() {
367 | var len = this.length(),
368 | v = new Vector4(this.x / len, this.y / len, this.z / len);
369 |
370 | return v;
371 | };
372 |
373 |
374 | /**
375 | * Vector Dot-Product
376 | * @param {Vector4} v The second vector to apply the product to
377 | * @author Joe Lambert
378 | * @returns {float} The Dot-Product of this and v.
379 | */
380 |
381 | this.dot = function(v) {
382 | return this.x*v.x + this.y*v.y + this.z*v.z + this.w*v.w;
383 | };
384 |
385 |
386 | /**
387 | * Vector Cross-Product
388 | * @param {Vector4} v The second vector to apply the product to
389 | * @author Joe Lambert
390 | * @returns {Vector4} The Cross-Product of this and v.
391 | */
392 |
393 | this.cross = function(v) {
394 | return new Vector4(this.y*v.z - this.z*v.y, this.z*v.x - this.x*v.z, this.x*v.y - this.y*v.x);
395 | };
396 |
397 |
398 | /**
399 | * Helper function required for matrix decomposition
400 | * A Javascript implementation of pseudo code available from http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition
401 | * @param {Vector4} aPoint A 3D point
402 | * @param {float} ascl
403 | * @param {float} bscl
404 | * @author Joe Lambert
405 | * @returns {Vector4}
406 | */
407 |
408 | this.combine = function(aPoint, ascl, bscl) {
409 | return new Vector4( (ascl * this.x) + (bscl * aPoint.x),
410 | (ascl * this.y) + (bscl * aPoint.y),
411 | (ascl * this.z) + (bscl * aPoint.z) );
412 | }
413 | };
414 |
415 |
416 | /**
417 | * Object containing the decomposed components of a matrix
418 | * @author Joe Lambert
419 | * @constructor
420 | */
421 |
422 | var CSSMatrixDecomposed = function(obj) {
423 | obj === undefined ? obj = {} : null;
424 | var components = {perspective: null, translate: null, skew: null, scale: null, rotate: null};
425 |
426 | for(var i in components)
427 | this[i] = obj[i] ? obj[i] : new Vector4();
428 |
429 | /**
430 | * Tween between two decomposed matrices
431 | * @param {CSSMatrixDecomposed} dm The destination decomposed matrix
432 | * @param {float} progress A float value between 0-1, representing the percentage of completion
433 | * @param {function} fn An easing function following the prototype function(pos){}
434 | * @author Joe Lambert
435 | * @returns {WebKitCSSMatrix} A new matrix for the tweened state
436 | */
437 |
438 | this.tween = function(dm, progress, fn) {
439 | if(fn === undefined)
440 | fn = function(pos) {return pos;}; // Default to a linear easing
441 |
442 | if(!dm)
443 | dm = new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose());
444 |
445 | var r = new CSSMatrixDecomposed(),
446 | i = index = null,
447 | trans = '';
448 |
449 | progress = fn(progress);
450 |
451 | for(index in components)
452 | for(i in {x:'x', y:'y', z:'z', w:'w'})
453 | r[index][i] = (this[index][i] + (dm[index][i] - this[index][i]) * progress ).toFixed(5);
454 |
455 | trans = 'matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, '+r.perspective.x+', '+r.perspective.y+', '+r.perspective.z+', '+r.perspective.w+') ' +
456 | 'translate3d('+r.translate.x+'px, '+r.translate.y+'px, '+r.translate.z+'px) ' +
457 | 'rotateX('+r.rotate.x+'rad) rotateY('+r.rotate.y+'rad) rotateZ('+r.rotate.z+'rad) ' +
458 | 'matrix3d(1,0,0,0, 0,1,0,0, 0,'+r.skew.z+',1,0, 0,0,0,1) ' +
459 | 'matrix3d(1,0,0,0, 0,1,0,0, '+r.skew.y+',0,1,0, 0,0,0,1) ' +
460 | 'matrix3d(1,0,0,0, '+r.skew.x+',1,0,0, 0,0,1,0, 0,0,0,1) ' +
461 | 'scale3d('+r.scale.x+', '+r.scale.y+', '+r.scale.z+')';
462 |
463 | try { r = new WebKitCSSMatrix(trans); return r; }
464 | catch(e) { console.error('Invalid matrix string: '+trans); return '' };
465 | };
466 | };
467 |
468 |
469 | /**
470 | * Tween between two matrices
471 | * @param {WebKitCSSMatrix} matrix The destination matrix
472 | * @param {float} progress A float value between 0-1, representing the percentage of completion
473 | * @param {function} fn An easing function following the prototype function(pos){}
474 | * @author Joe Lambert
475 | * @returns {WebKitCSSMatrix} A new matrix for the tweened state
476 | */
477 |
478 | WebKitCSSMatrix.prototype.tween = function(matrix, progress, fn) {
479 | if(fn === undefined)
480 | fn = function(pos) {return pos;}; // Default to a linear easing
481 |
482 | var m = new WebKitCSSMatrix,
483 | m1 = this.decompose(),
484 | m2 = matrix.decompose(),
485 | r = m.decompose()
486 | trans = '',
487 | index = i = null;
488 |
489 | // Tween between the two decompositions
490 | return m1.tween(m2, progress, fn);
491 | };
492 |
493 |
494 | /**
495 | * Transform a Vector4 object using the current matrix
496 | * @param {Vector4} v The vector to transform
497 | * @author Joe Lambert
498 | * @returns {Vector4} The transformed vector
499 | */
500 |
501 | WebKitCSSMatrix.prototype.transformVector = function(v) {
502 | // TODO: Do we need to mod this for Vector4?
503 | return new Vector4( this.m11*v.x + this.m12*v.y + this.m13*v.z,
504 | this.m21*v.x + this.m22*v.y + this.m23*v.z,
505 | this.m31*v.x + this.m32*v.y + this.m33*v.z );
506 | };
507 |
508 |
509 | /**
510 | * Transposes the matrix
511 | * @author Joe Lambert
512 | * @returns {WebKitCSSMatrix} The transposed matrix
513 | */
514 |
515 | WebKitCSSMatrix.prototype.transpose = function() {
516 | var matrix = new WebKitCSSMatrix(), n = m = 0;
517 |
518 | for (n = 0; n <= 4-2; n++)
519 | {
520 | for (m = n + 1; m <= 4-1; m++)
521 | {
522 | matrix['m'+(n+1)+(m+1)] = this['m'+(m+1)+(n+1)];
523 | matrix['m'+(m+1)+(n+1)] = this['m'+(n+1)+(m+1)];
524 | }
525 | }
526 |
527 | return matrix;
528 | };
529 |
530 |
531 | /**
532 | * Calculates the determinant
533 | * @author Joe Lambert
534 | * @returns {float} The determinant of the matrix
535 | */
536 |
537 | WebKitCSSMatrix.prototype.determinant = function() {
538 | return this.m14 * this.m23 * this.m32 * this.m41-this.m13 * this.m24 * this.m32 * this.m41 -
539 | this.m14 * this.m22 * this.m33 * this.m41+this.m12 * this.m24 * this.m33 * this.m41 +
540 | this.m13 * this.m22 * this.m34 * this.m41-this.m12 * this.m23 * this.m34 * this.m41 -
541 | this.m14 * this.m23 * this.m31 * this.m42+this.m13 * this.m24 * this.m31 * this.m42 +
542 | this.m14 * this.m21 * this.m33 * this.m42-this.m11 * this.m24 * this.m33 * this.m42 -
543 | this.m13 * this.m21 * this.m34 * this.m42+this.m11 * this.m23 * this.m34 * this.m42 +
544 | this.m14 * this.m22 * this.m31 * this.m43-this.m12 * this.m24 * this.m31 * this.m43 -
545 | this.m14 * this.m21 * this.m32 * this.m43+this.m11 * this.m24 * this.m32 * this.m43 +
546 | this.m12 * this.m21 * this.m34 * this.m43-this.m11 * this.m22 * this.m34 * this.m43 -
547 | this.m13 * this.m22 * this.m31 * this.m44+this.m12 * this.m23 * this.m31 * this.m44 +
548 | this.m13 * this.m21 * this.m32 * this.m44-this.m11 * this.m23 * this.m32 * this.m44 -
549 | this.m12 * this.m21 * this.m33 * this.m44+this.m11 * this.m22 * this.m33 * this.m44;
550 | };
551 |
552 |
553 | /**
554 | * Decomposes the matrix into its component parts.
555 | * A Javascript implementation of the pseudo code available from http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition
556 | * @author Joe Lambert
557 | * @returns {Object} An object with each of the components of the matrix (perspective, translate, skew, scale, rotate) or identity matrix on failure
558 | */
559 |
560 | WebKitCSSMatrix.prototype.decompose = function() {
561 | var matrix = new WebKitCSSMatrix(this.toString()),
562 | perspectiveMatrix = rightHandSide = inversePerspectiveMatrix = transposedInversePerspectiveMatrix =
563 | perspective = translate = row = i = scale = skew = pdum3 = rotate = null;
564 |
565 | if (matrix.m33 == 0)
566 | return new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose()); // Return the identity matrix
567 |
568 | // Normalize the matrix.
569 | for (i = 1; i <= 4; i++)
570 | for (j = 1; j <= 4; j++)
571 | matrix['m'+i+j] /= matrix.m44;
572 |
573 | // perspectiveMatrix is used to solve for perspective, but it also provides
574 | // an easy way to test for singularity of the upper 3x3 component.
575 | perspectiveMatrix = matrix;
576 |
577 | for (i = 1; i <= 3; i++)
578 | perspectiveMatrix['m'+i+'4'] = 0;
579 |
580 | perspectiveMatrix.m44 = 1;
581 |
582 | if (perspectiveMatrix.determinant() == 0)
583 | return new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose()); // Return the identity matrix
584 |
585 | // First, isolate perspective.
586 | if (matrix.m14 != 0 || matrix.m24 != 0 || matrix.m34 != 0)
587 | {
588 | // rightHandSide is the right hand side of the equation.
589 | rightHandSide = new Vector4(matrix.m14, matrix.m24, matrix.m34, matrix.m44);
590 |
591 | // Solve the equation by inverting perspectiveMatrix and multiplying
592 | // rightHandSide by the inverse.
593 | inversePerspectiveMatrix = perspectiveMatrix.inverse();
594 | transposedInversePerspectiveMatrix = inversePerspectiveMatrix.transpose();
595 | perspective = transposedInversePerspectiveMatrix.transformVector(rightHandSide);
596 |
597 | // Clear the perspective partition
598 | matrix.m14 = matrix.m24 = matrix.m34 = 0;
599 | matrix.m44 = 1;
600 | }
601 | else
602 | {
603 | // No perspective.
604 | perspective = new Vector4(0,0,0,1);
605 | }
606 |
607 | // Next take care of translation
608 | translate = new Vector4(matrix.m41, matrix.m42, matrix.m43);
609 |
610 | matrix.m41 = 0;
611 | matrix.m42 = 0;
612 | matrix.m43 = 0;
613 |
614 | // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
615 | row = [
616 | new Vector4(), new Vector4(), new Vector4()
617 | ];
618 |
619 | for (i = 1; i <= 3; i++)
620 | {
621 | row[i-1].x = matrix['m'+i+'1'];
622 | row[i-1].y = matrix['m'+i+'2'];
623 | row[i-1].z = matrix['m'+i+'3'];
624 | }
625 |
626 | // Compute X scale factor and normalize first row.
627 | scale = new Vector4();
628 | skew = new Vector4();
629 |
630 | scale.x = row[0].length();
631 | row[0] = row[0].normalise();
632 |
633 | // Compute XY shear factor and make 2nd row orthogonal to 1st.
634 | skew.x = row[0].dot(row[1]);
635 | row[1] = row[1].combine(row[0], 1.0, -skew.x);
636 |
637 | // Now, compute Y scale and normalize 2nd row.
638 | scale.y = row[1].length();
639 | row[1] = row[1].normalise();
640 | skew.x /= scale.y;
641 |
642 | // Compute XZ and YZ shears, orthogonalize 3rd row
643 | skew.y = row[0].dot(row[2]);
644 | row[2] = row[2].combine(row[0], 1.0, -skew.y);
645 | skew.z = row[1].dot(row[2]);
646 | row[2] = row[2].combine(row[1], 1.0, -skew.z);
647 |
648 | // Next, get Z scale and normalize 3rd row.
649 | scale.z = row[2].length();
650 | row[2] = row[2].normalise();
651 | skew.y /= scale.z;
652 | skew.y /= scale.z;
653 |
654 | // At this point, the matrix (in rows) is orthonormal.
655 | // Check for a coordinate system flip. If the determinant
656 | // is -1, then negate the matrix and the scaling factors.
657 | pdum3 = row[1].cross(row[2])
658 | if (row[0].dot(pdum3) < 0)
659 | {
660 | for (i = 0; i < 3; i++)
661 | {
662 | scale.x *= -1;
663 | row[i].x *= -1;
664 | row[i].y *= -1;
665 | row[i].z *= -1;
666 | }
667 | }
668 |
669 | // Now, get the rotations out
670 | rotate = new Vector4();
671 | rotate.y = Math.asin(-row[0].z);
672 | if (Math.cos(rotate.y) != 0)
673 | {
674 | rotate.x = Math.atan2(row[1].z, row[2].z);
675 | rotate.z = Math.atan2(row[0].y, row[0].x);
676 | }
677 | else
678 | {
679 | rotate.x = Math.atan2(-row[2].x, row[1].y);
680 | rotate.z = 0;
681 | }
682 |
683 | return new CSSMatrixDecomposed({
684 | perspective: perspective,
685 | translate: translate,
686 | skew: skew,
687 | scale: scale,
688 | rotate: rotate
689 | });
690 | };
691 |
692 |
693 | })();
694 |
695 |
696 | /**
697 | * @preserve
698 | * Extra easing functions borrowed from scripty2 (c) 2005-2010 Thomas Fuchs (MIT Licence)
699 | * https://raw.github.com/madrobby/scripty2/master/src/effects/transitions/transitions.js
700 | */
701 |
702 | (function(){
703 | var scripty2 = {
704 | spring: function(pos) {
705 | return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
706 | },
707 |
708 | sinusoidal: function(pos) {
709 | return (-Math.cos(pos*Math.PI)/2) + 0.5;
710 | }
711 | };
712 |
713 | // Load the Scripty2 functions
714 | for(var t in scripty2)
715 | Tweenable.prototype.formula[t] = scripty2[t];
716 | })();
717 |
718 |
719 |
--------------------------------------------------------------------------------
/js/morf.noshifty.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | Morf v0.1.5
3 | http://www.joelambert.co.uk/morf
4 |
5 | Copyright 2011, Joe Lambert.
6 | Free to use under the MIT license.
7 | http://www.opensource.org/licenses/mit-license.php
8 |
9 | Extra easing functions borrowed from scripty2 (c) 2005-2010 Thomas Fuchs (MIT Licence)
10 | https://raw.github.com/madrobby/scripty2/master/src/effects/transitions/transitions.js
11 | */
12 | var Morf=function(b,g,a){var d={},f={};document.createElement("div");var l=document.createElement("div"),c={timingFunction:"ease",duration:null,increment:0.01,debug:false,optimise:true,decimalPlaces:5},k=rule=ruleName=camel=m1=m2=progress=frame=rule=transEvent=val=null,e="",q=this,r={},t="anim"+(new Date).getTime(),v=function(){b.removeEventListener("webkitAnimationEnd",v,true);transEvent=document.createEvent("Event");transEvent.initEvent("webkitTransitionEnd",true,true);b.dispatchEvent(transEvent);
13 | b.style.webkitTransitionTimingFunction=null;b.style.webkitTransitionDuration=0;c.callback&&c.callback(b)},y=function(n){if(document.styleSheets&&document.styleSheets.length)document.styleSheets[0].insertRule(n,0);else{var o=document.createElement("style");o.innerHTML=n;document.head.appendChild(o)}},z=function(n,o){var h="@-webkit-keyframes "+o+" {\n",s=pos=rule=null,p="";for(pos in n){s=n[pos];p="\t"+pos+" {\n";for(rule in s)p+="\t\t"+q.util.toDash(rule)+": "+s[rule]+";\n";p+="\t}\n\n";h+=p}if(c.optimise){h=
14 | h+" }";s=void 0;s=typeof c.decimalPlaces=="number"?c.decimalPlaces:5;p=h.match(/[0-9\.]+/gm);var u=0;if(p)for(u=0;u"+f[rule]}if(Morf.cache[e]){this.css=Morf.cache[e].css;t=Morf.cache[e].name}else{if(d["-webkit-transform"]){m1=d["-webkit-transform"].decompose();m2=f["-webkit-transform"].decompose()}for(progress=0;progress<=1;progress+=c.increment){frame=Tweenable.util.interpolate(d,f,progress,c.timingFunction);if(m1!==null&&m2!==null)frame["-webkit-transform"]=m1.tween(m2,progress,Tweenable.prototype.formula[c.timingFunction]);r[parseInt(progress*
18 | 100,10)+"%"]=frame}r["100%"]=f;this.css=z(r,t);y(this.css);Morf.cache[e]={css:this.css,name:t}}for(rule in f)b.style[this.util.toCamel(rule)]=f[rule];b.addEventListener("webkitAnimationEnd",v,true);b.style.webkitAnimationDuration=c.duration;b.style.webkitAnimationTimingFunction="linear";b.style.webkitAnimationName=t;c.debug&&window.console&&window.console.log&&console.log(this.css)}};Morf.transition=function(b,g,a){return new Morf(b,g,a)};Morf.cache={};Morf.version="0.1.5";Morf.prototype.util={};
19 | Morf.prototype.util.toDash=function(b){b=b.replace(/([A-Z])/g,function(g){return"-"+g.toLowerCase()});return/^webkit/.test(b)?"-"+b:b};Morf.prototype.util.toCamel=function(b){return b.replace(/(\-[a-z])/g,function(g){return g.toUpperCase().replace("-","")})};
20 | (function(){var b=function(a,d,f,l){this.x=a?a:0;this.y=d?d:0;this.z=f?f:0;this.w=l?l:0;this.checkValues=function(){this.x=this.x?this.x:0;this.y=this.y?this.y:0;this.z=this.z?this.z:0;this.w=this.w?this.w:0};this.length=function(){this.checkValues();return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)};this.normalise=function(){var c=this.length();return new b(this.x/c,this.y/c,this.z/c)};this.dot=function(c){return this.x*c.x+this.y*c.y+this.z*c.z+this.w*c.w};this.cross=function(c){return new b(this.y*
21 | c.z-this.z*c.y,this.z*c.x-this.x*c.z,this.x*c.y-this.y*c.x)};this.combine=function(c,k,e){return new b(k*this.x+e*c.x,k*this.y+e*c.y,k*this.z+e*c.z)}},g=function(a){a===undefined&&(a={});var d={perspective:null,translate:null,skew:null,scale:null,rotate:null},f;for(f in d)this[f]=a[f]?a[f]:new b;this.tween=function(l,c,k){if(k===undefined)k=function(v){return v};l||(l=new g((new WebKitCSSMatrix).decompose()));var e=new g,q=index=null,r="";c=k(c);for(index in d)for(q in{x:"x",y:"y",z:"z",w:"w"})e[index][q]=
22 | (this[index][q]+(l[index][q]-this[index][q])*c).toFixed(5);r="matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, "+e.perspective.x+", "+e.perspective.y+", "+e.perspective.z+", "+e.perspective.w+") translate3d("+e.translate.x+"px, "+e.translate.y+"px, "+e.translate.z+"px) rotateX("+e.rotate.x+"rad) rotateY("+e.rotate.y+"rad) rotateZ("+e.rotate.z+"rad) matrix3d(1,0,0,0, 0,1,0,0, 0,"+e.skew.z+",1,0, 0,0,0,1) matrix3d(1,0,0,0, 0,1,0,0, "+e.skew.y+",0,1,0, 0,0,0,1) matrix3d(1,0,0,0, "+e.skew.x+",1,0,0, 0,0,1,0, 0,0,0,1) scale3d("+
23 | e.scale.x+", "+e.scale.y+", "+e.scale.z+")";try{return e=new WebKitCSSMatrix(r)}catch(t){console.error("Invalid matrix string: "+r);return""}}};WebKitCSSMatrix.prototype.tween=function(a,d,f){if(f===undefined)f=function(k){return k};var l=new WebKitCSSMatrix,c=this.decompose();a=a.decompose();l.decompose();trans="";index=i=null;return c.tween(a,d,f)};WebKitCSSMatrix.prototype.transformVector=function(a){return new b(this.m11*a.x+this.m12*a.y+this.m13*a.z,this.m21*a.x+this.m22*a.y+this.m23*a.z,this.m31*
24 | a.x+this.m32*a.y+this.m33*a.z)};WebKitCSSMatrix.prototype.transpose=function(){var a=new WebKitCSSMatrix,d=m=0;for(d=0;d<=2;d++)for(m=d+1;m<=3;m++){a["m"+(d+1)+(m+1)]=this["m"+(m+1)+(d+1)];a["m"+(m+1)+(d+1)]=this["m"+(d+1)+(m+1)]}return a};WebKitCSSMatrix.prototype.determinant=function(){return this.m14*this.m23*this.m32*this.m41-this.m13*this.m24*this.m32*this.m41-this.m14*this.m22*this.m33*this.m41+this.m12*this.m24*this.m33*this.m41+this.m13*this.m22*this.m34*this.m41-this.m12*this.m23*this.m34*
25 | this.m41-this.m14*this.m23*this.m31*this.m42+this.m13*this.m24*this.m31*this.m42+this.m14*this.m21*this.m33*this.m42-this.m11*this.m24*this.m33*this.m42-this.m13*this.m21*this.m34*this.m42+this.m11*this.m23*this.m34*this.m42+this.m14*this.m22*this.m31*this.m43-this.m12*this.m24*this.m31*this.m43-this.m14*this.m21*this.m32*this.m43+this.m11*this.m24*this.m32*this.m43+this.m12*this.m21*this.m34*this.m43-this.m11*this.m22*this.m34*this.m43-this.m13*this.m22*this.m31*this.m44+this.m12*this.m23*this.m31*
26 | this.m44+this.m13*this.m21*this.m32*this.m44-this.m11*this.m23*this.m32*this.m44-this.m12*this.m21*this.m33*this.m44+this.m11*this.m22*this.m33*this.m44};WebKitCSSMatrix.prototype.decompose=function(){var a=new WebKitCSSMatrix(this.toString()),d=rightHandSide=inversePerspectiveMatrix=transposedInversePerspectiveMatrix=perspective=translate=row=i=scale=skew=pdum3=rotate=null;if(a.m33==0)return new g((new WebKitCSSMatrix).decompose());for(i=1;i<=4;i++)for(j=1;j<=4;j++)a["m"+i+j]/=a.m44;d=a;for(i=1;i<=
27 | 3;i++)d["m"+i+"4"]=0;d.m44=1;if(d.determinant()==0)return new g((new WebKitCSSMatrix).decompose());if(a.m14!=0||a.m24!=0||a.m34!=0){rightHandSide=new b(a.m14,a.m24,a.m34,a.m44);inversePerspectiveMatrix=d.inverse();transposedInversePerspectiveMatrix=inversePerspectiveMatrix.transpose();perspective=transposedInversePerspectiveMatrix.transformVector(rightHandSide);a.m14=a.m24=a.m34=0;a.m44=1}else perspective=new b(0,0,0,1);translate=new b(a.m41,a.m42,a.m43);a.m41=0;a.m42=0;a.m43=0;row=[new b,new b,new b];
28 | for(i=1;i<=3;i++){row[i-1].x=a["m"+i+"1"];row[i-1].y=a["m"+i+"2"];row[i-1].z=a["m"+i+"3"]}scale=new b;skew=new b;scale.x=row[0].length();row[0]=row[0].normalise();skew.x=row[0].dot(row[1]);row[1]=row[1].combine(row[0],1,-skew.x);scale.y=row[1].length();row[1]=row[1].normalise();skew.x/=scale.y;skew.y=row[0].dot(row[2]);row[2]=row[2].combine(row[0],1,-skew.y);skew.z=row[1].dot(row[2]);row[2]=row[2].combine(row[1],1,-skew.z);scale.z=row[2].length();row[2]=row[2].normalise();skew.y/=scale.z;skew.y/=
29 | scale.z;pdum3=row[1].cross(row[2]);if(row[0].dot(pdum3)<0)for(i=0;i<3;i++){scale.x*=-1;row[i].x*=-1;row[i].y*=-1;row[i].z*=-1}rotate=new b;rotate.y=Math.asin(-row[0].z);if(Math.cos(rotate.y)!=0){rotate.x=Math.atan2(row[1].z,row[2].z);rotate.z=Math.atan2(row[0].y,row[0].x)}else{rotate.x=Math.atan2(-row[2].x,row[1].y);rotate.z=0}return new g({perspective:perspective,translate:translate,skew:skew,scale:scale,rotate:rotate})}})();
30 | (function(){var b={spring:function(a){return 1-Math.cos(a*4.5*Math.PI)*Math.exp(-a*6)},sinusoidal:function(a){return-Math.cos(a*Math.PI)/2+0.5}},g;for(g in b)Tweenable.prototype.formula[g]=b[g]})();
31 |
--------------------------------------------------------------------------------
/js/shifty.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | Mifty - A custom build of Shifty for use with Morf.js.
3 | By Jeremy Kahn - jeremyckahn@gmail.com
4 | v0.4.1
5 |
6 | For instructions on how to use Shifty, please consult the README: https://github.com/jeremyckahn/shifty/blob/master/README.md
7 |
8 | MIT Lincense. This code free to use, modify, distribute and enjoy.
9 |
10 | */
11 |
12 | (function(e){function a(){return+new Date}function b(a,c){for(var j in a)a.hasOwnProperty(j)&&c(a,j)}function h(a,c){b(c,function(c,f){a[f]=c[f]});return a}function k(a,c){b(c,function(c,f){typeof a[f]==="undefined"&&(a[f]=c[f])});return a}function i(a,c,j){var f,a=(a-c.timestamp)/c.duration;for(f in j.current)j.current.hasOwnProperty(f)&&c.to.hasOwnProperty(f)&&(j.current[f]=c.originalState[f]+(c.to[f]-c.originalState[f])*c.easingFunc(a));return j.current}function n(a,c,j,f){var b;for(b=0;b=0;b++)this._hook[a][b]===c&&this._hook[a].splice(b,1);else this._hook[a]=[]};g.prototype.filter={};g.util={now:a,each:b,tweenProps:i,applyFilter:l,simpleCopy:h};g.prototype.formula={linear:function(a){return a}};e.Tweenable=g})(this);
19 | (function(e){e.Tweenable.util.simpleCopy(e.Tweenable.prototype.formula,{easeInQuad:function(a){return Math.pow(a,2)},easeOutQuad:function(a){return-(Math.pow(a-1,2)-1)},easeInOutQuad:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,2);return-0.5*((a-=2)*a-2)},easeInCubic:function(a){return Math.pow(a,3)},easeOutCubic:function(a){return Math.pow(a-1,3)+1},easeInOutCubic:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,3);return 0.5*(Math.pow(a-2,3)+2)},easeInQuart:function(a){return Math.pow(a,4)},easeOutQuart:function(a){return-(Math.pow(a-
20 | 1,4)-1)},easeInOutQuart:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,4);return-0.5*((a-=2)*Math.pow(a,3)-2)},easeInQuint:function(a){return Math.pow(a,5)},easeOutQuint:function(a){return Math.pow(a-1,5)+1},easeInOutQuint:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,5);return 0.5*(Math.pow(a-2,5)+2)},easeInSine:function(a){return-Math.cos(a*(Math.PI/2))+1},easeOutSine:function(a){return Math.sin(a*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a)-1)},easeInExpo:function(a){return a==
21 | 0?0:Math.pow(2,10*(a-1))},easeOutExpo:function(a){return a==1?1:-Math.pow(2,-10*a)+1},easeInOutExpo:function(a){if(a==0)return 0;if(a==1)return 1;if((a/=0.5)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return-(Math.sqrt(1-a*a)-1)},easeOutCirc:function(a){return Math.sqrt(1-Math.pow(a-1,2))},easeInOutCirc:function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeOutBounce:function(a){return a<1/2.75?7.5625*
22 | a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},easeInBack:function(a){return a*a*(2.70158*a-1.70158)},easeOutBack:function(a){return(a-=1)*a*(2.70158*a+1.70158)+1},easeInOutBack:function(a){var b=1.70158;if((a/=0.5)<1)return 0.5*a*a*(((b*=1.525)+1)*a-b);return 0.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},elastic:function(a){return-1*Math.pow(4,-8*a)*Math.sin((a*6-1)*2*Math.PI/2)+1},swingFromTo:function(a){var b=1.70158;return(a/=0.5)<
23 | 1?0.5*a*a*(((b*=1.525)+1)*a-b):0.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},swingFrom:function(a){return a*a*(2.70158*a-1.70158)},swingTo:function(a){return(a-=1)*a*(2.70158*a+1.70158)+1},bounce:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375},bouncePast:function(a){return a<1/2.75?7.5625*a*a:a<2/2.75?2-(7.5625*(a-=1.5/2.75)*a+0.75):a<2.5/2.75?2-(7.5625*(a-=2.25/2.75)*a+0.9375):2-(7.5625*(a-=2.625/2.75)*
24 | a+0.984375)},easeFromTo:function(a){if((a/=0.5)<1)return 0.5*Math.pow(a,4);return-0.5*((a-=2)*Math.pow(a,3)-2)},easeFrom:function(a){return Math.pow(a,4)},easeTo:function(a){return Math.pow(a,0.25)}})})(this);
25 | (function(e){if(e.Tweenable)e.Tweenable.util.interpolate=function(a,b,h,k){var i;if(a&&a.from)b=a.to,h=a.position,k=a.easing,a=a.from;i=e.Tweenable.util.simpleCopy({},a);e.Tweenable.util.applyFilter("tweenCreated",i,[i,a,b]);e.Tweenable.util.applyFilter("beforeTween",i,[i,a,b]);h=e.Tweenable.util.tweenProps(h,{originalState:a,to:b,timestamp:0,duration:1,easingFunc:e.Tweenable.prototype.formula[k]||e.Tweenable.prototype.formula.linear},{current:i});e.Tweenable.util.applyFilter("afterTween",h,[h,a,
26 | b]);return h},e.Tweenable.prototype.interpolate=function(a,b,h){a=e.Tweenable.util.interpolate(this.get(),a,b,h);this.set(a);return a}})(this);
--------------------------------------------------------------------------------
/js/src/WebkitCSSMatrix.ext.js:
--------------------------------------------------------------------------------
1 | /**
2 | * WebKitCSSMatrix Extensions
3 | *
4 | * Copyright 2011, Joe Lambert (http://www.joelambert.co.uk)
5 | * Free to use under the MIT license.
6 | * http://joelambert.mit-license.org/
7 | */
8 |
9 | // Wrap this functionality up to prevent poluting the global namespace
10 | (function(){
11 |
12 |
13 | /**
14 | * A 4 dimensional vector
15 | * @author Joe Lambert
16 | * @constructor
17 | */
18 |
19 | var Vector4 = function(x, y, z, w)
20 | {
21 | this.x = x ? x : 0;
22 | this.y = y ? y : 0;
23 | this.z = z ? z : 0;
24 | this.w = w ? w : 0;
25 |
26 |
27 | /**
28 | * Ensure that values are not undefined
29 | * @author Joe Lambert
30 | * @returns null
31 | */
32 |
33 | this.checkValues = function() {
34 | this.x = this.x ? this.x : 0;
35 | this.y = this.y ? this.y : 0;
36 | this.z = this.z ? this.z : 0;
37 | this.w = this.w ? this.w : 0;
38 | };
39 |
40 |
41 | /**
42 | * Get the length of the vector
43 | * @author Joe Lambert
44 | * @returns {float}
45 | */
46 |
47 | this.length = function() {
48 | this.checkValues();
49 | return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
50 | };
51 |
52 |
53 | /**
54 | * Get a normalised representation of the vector
55 | * @author Joe Lambert
56 | * @returns {Vector4}
57 | */
58 |
59 | this.normalise = function() {
60 | var len = this.length(),
61 | v = new Vector4(this.x / len, this.y / len, this.z / len);
62 |
63 | return v;
64 | };
65 |
66 |
67 | /**
68 | * Vector Dot-Product
69 | * @param {Vector4} v The second vector to apply the product to
70 | * @author Joe Lambert
71 | * @returns {float} The Dot-Product of this and v.
72 | */
73 |
74 | this.dot = function(v) {
75 | return this.x*v.x + this.y*v.y + this.z*v.z + this.w*v.w;
76 | };
77 |
78 |
79 | /**
80 | * Vector Cross-Product
81 | * @param {Vector4} v The second vector to apply the product to
82 | * @author Joe Lambert
83 | * @returns {Vector4} The Cross-Product of this and v.
84 | */
85 |
86 | this.cross = function(v) {
87 | return new Vector4(this.y*v.z - this.z*v.y, this.z*v.x - this.x*v.z, this.x*v.y - this.y*v.x);
88 | };
89 |
90 |
91 | /**
92 | * Helper function required for matrix decomposition
93 | * A Javascript implementation of pseudo code available from http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition
94 | * @param {Vector4} aPoint A 3D point
95 | * @param {float} ascl
96 | * @param {float} bscl
97 | * @author Joe Lambert
98 | * @returns {Vector4}
99 | */
100 |
101 | this.combine = function(aPoint, ascl, bscl) {
102 | return new Vector4( (ascl * this.x) + (bscl * aPoint.x),
103 | (ascl * this.y) + (bscl * aPoint.y),
104 | (ascl * this.z) + (bscl * aPoint.z) );
105 | }
106 | };
107 |
108 |
109 | /**
110 | * Object containing the decomposed components of a matrix
111 | * @author Joe Lambert
112 | * @constructor
113 | */
114 |
115 | var CSSMatrixDecomposed = function(obj) {
116 | obj === undefined ? obj = {} : null;
117 | var components = {perspective: null, translate: null, skew: null, scale: null, rotate: null};
118 |
119 | for(var i in components)
120 | this[i] = obj[i] ? obj[i] : new Vector4();
121 |
122 | /**
123 | * Tween between two decomposed matrices
124 | * @param {CSSMatrixDecomposed} dm The destination decomposed matrix
125 | * @param {float} progress A float value between 0-1, representing the percentage of completion
126 | * @param {function} fn An easing function following the prototype function(pos){}
127 | * @author Joe Lambert
128 | * @returns {WebKitCSSMatrix} A new matrix for the tweened state
129 | */
130 |
131 | this.tween = function(dm, progress, fn) {
132 | if(fn === undefined)
133 | fn = function(pos) {return pos;}; // Default to a linear easing
134 |
135 | if(!dm)
136 | dm = new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose());
137 |
138 | var r = new CSSMatrixDecomposed(),
139 | i = index = null,
140 | trans = '';
141 |
142 | progress = fn(progress);
143 |
144 | for(index in components)
145 | for(i in {x:'x', y:'y', z:'z', w:'w'})
146 | r[index][i] = (this[index][i] + (dm[index][i] - this[index][i]) * progress ).toFixed(5);
147 |
148 | trans = 'matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, '+r.perspective.x+', '+r.perspective.y+', '+r.perspective.z+', '+r.perspective.w+') ' +
149 | 'translate3d('+r.translate.x+'px, '+r.translate.y+'px, '+r.translate.z+'px) ' +
150 | 'rotateX('+r.rotate.x+'rad) rotateY('+r.rotate.y+'rad) rotateZ('+r.rotate.z+'rad) ' +
151 | 'matrix3d(1,0,0,0, 0,1,0,0, 0,'+r.skew.z+',1,0, 0,0,0,1) ' +
152 | 'matrix3d(1,0,0,0, 0,1,0,0, '+r.skew.y+',0,1,0, 0,0,0,1) ' +
153 | 'matrix3d(1,0,0,0, '+r.skew.x+',1,0,0, 0,0,1,0, 0,0,0,1) ' +
154 | 'scale3d('+r.scale.x+', '+r.scale.y+', '+r.scale.z+')';
155 |
156 | try { r = new WebKitCSSMatrix(trans); return r; }
157 | catch(e) { console.error('Invalid matrix string: '+trans); return '' };
158 | };
159 | };
160 |
161 |
162 | /**
163 | * Tween between two matrices
164 | * @param {WebKitCSSMatrix} matrix The destination matrix
165 | * @param {float} progress A float value between 0-1, representing the percentage of completion
166 | * @param {function} fn An easing function following the prototype function(pos){}
167 | * @author Joe Lambert
168 | * @returns {WebKitCSSMatrix} A new matrix for the tweened state
169 | */
170 |
171 | WebKitCSSMatrix.prototype.tween = function(matrix, progress, fn) {
172 | if(fn === undefined)
173 | fn = function(pos) {return pos;}; // Default to a linear easing
174 |
175 | var m = new WebKitCSSMatrix,
176 | m1 = this.decompose(),
177 | m2 = matrix.decompose(),
178 | r = m.decompose()
179 | trans = '',
180 | index = i = null;
181 |
182 | // Tween between the two decompositions
183 | return m1.tween(m2, progress, fn);
184 | };
185 |
186 |
187 | /**
188 | * Transform a Vector4 object using the current matrix
189 | * @param {Vector4} v The vector to transform
190 | * @author Joe Lambert
191 | * @returns {Vector4} The transformed vector
192 | */
193 |
194 | WebKitCSSMatrix.prototype.transformVector = function(v) {
195 | // TODO: Do we need to mod this for Vector4?
196 | return new Vector4( this.m11*v.x + this.m12*v.y + this.m13*v.z,
197 | this.m21*v.x + this.m22*v.y + this.m23*v.z,
198 | this.m31*v.x + this.m32*v.y + this.m33*v.z );
199 | };
200 |
201 |
202 | /**
203 | * Transposes the matrix
204 | * @author Joe Lambert
205 | * @returns {WebKitCSSMatrix} The transposed matrix
206 | */
207 |
208 | WebKitCSSMatrix.prototype.transpose = function() {
209 | var matrix = new WebKitCSSMatrix(), n = m = 0;
210 |
211 | for (n = 0; n <= 4-2; n++)
212 | {
213 | for (m = n + 1; m <= 4-1; m++)
214 | {
215 | matrix['m'+(n+1)+(m+1)] = this['m'+(m+1)+(n+1)];
216 | matrix['m'+(m+1)+(n+1)] = this['m'+(n+1)+(m+1)];
217 | }
218 | }
219 |
220 | return matrix;
221 | };
222 |
223 |
224 | /**
225 | * Calculates the determinant
226 | * @author Joe Lambert
227 | * @returns {float} The determinant of the matrix
228 | */
229 |
230 | WebKitCSSMatrix.prototype.determinant = function() {
231 | return this.m14 * this.m23 * this.m32 * this.m41-this.m13 * this.m24 * this.m32 * this.m41 -
232 | this.m14 * this.m22 * this.m33 * this.m41+this.m12 * this.m24 * this.m33 * this.m41 +
233 | this.m13 * this.m22 * this.m34 * this.m41-this.m12 * this.m23 * this.m34 * this.m41 -
234 | this.m14 * this.m23 * this.m31 * this.m42+this.m13 * this.m24 * this.m31 * this.m42 +
235 | this.m14 * this.m21 * this.m33 * this.m42-this.m11 * this.m24 * this.m33 * this.m42 -
236 | this.m13 * this.m21 * this.m34 * this.m42+this.m11 * this.m23 * this.m34 * this.m42 +
237 | this.m14 * this.m22 * this.m31 * this.m43-this.m12 * this.m24 * this.m31 * this.m43 -
238 | this.m14 * this.m21 * this.m32 * this.m43+this.m11 * this.m24 * this.m32 * this.m43 +
239 | this.m12 * this.m21 * this.m34 * this.m43-this.m11 * this.m22 * this.m34 * this.m43 -
240 | this.m13 * this.m22 * this.m31 * this.m44+this.m12 * this.m23 * this.m31 * this.m44 +
241 | this.m13 * this.m21 * this.m32 * this.m44-this.m11 * this.m23 * this.m32 * this.m44 -
242 | this.m12 * this.m21 * this.m33 * this.m44+this.m11 * this.m22 * this.m33 * this.m44;
243 | };
244 |
245 |
246 | /**
247 | * Decomposes the matrix into its component parts.
248 | * A Javascript implementation of the pseudo code available from http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition
249 | * @author Joe Lambert
250 | * @returns {Object} An object with each of the components of the matrix (perspective, translate, skew, scale, rotate) or identity matrix on failure
251 | */
252 |
253 | WebKitCSSMatrix.prototype.decompose = function() {
254 | var matrix = new WebKitCSSMatrix(this.toString()),
255 | perspectiveMatrix = rightHandSide = inversePerspectiveMatrix = transposedInversePerspectiveMatrix =
256 | perspective = translate = row = i = scale = skew = pdum3 = rotate = null;
257 |
258 | if (matrix.m33 == 0)
259 | return new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose()); // Return the identity matrix
260 |
261 | // Normalize the matrix.
262 | for (i = 1; i <= 4; i++)
263 | for (j = 1; j <= 4; j++)
264 | matrix['m'+i+j] /= matrix.m44;
265 |
266 | // perspectiveMatrix is used to solve for perspective, but it also provides
267 | // an easy way to test for singularity of the upper 3x3 component.
268 | perspectiveMatrix = matrix;
269 |
270 | for (i = 1; i <= 3; i++)
271 | perspectiveMatrix['m'+i+'4'] = 0;
272 |
273 | perspectiveMatrix.m44 = 1;
274 |
275 | if (perspectiveMatrix.determinant() == 0)
276 | return new CSSMatrixDecomposed(new WebKitCSSMatrix().decompose()); // Return the identity matrix
277 |
278 | // First, isolate perspective.
279 | if (matrix.m14 != 0 || matrix.m24 != 0 || matrix.m34 != 0)
280 | {
281 | // rightHandSide is the right hand side of the equation.
282 | rightHandSide = new Vector4(matrix.m14, matrix.m24, matrix.m34, matrix.m44);
283 |
284 | // Solve the equation by inverting perspectiveMatrix and multiplying
285 | // rightHandSide by the inverse.
286 | inversePerspectiveMatrix = perspectiveMatrix.inverse();
287 | transposedInversePerspectiveMatrix = inversePerspectiveMatrix.transpose();
288 | perspective = transposedInversePerspectiveMatrix.transformVector(rightHandSide);
289 |
290 | // Clear the perspective partition
291 | matrix.m14 = matrix.m24 = matrix.m34 = 0;
292 | matrix.m44 = 1;
293 | }
294 | else
295 | {
296 | // No perspective.
297 | perspective = new Vector4(0,0,0,1);
298 | }
299 |
300 | // Next take care of translation
301 | translate = new Vector4(matrix.m41, matrix.m42, matrix.m43);
302 |
303 | matrix.m41 = 0;
304 | matrix.m42 = 0;
305 | matrix.m43 = 0;
306 |
307 | // Now get scale and shear. 'row' is a 3 element array of 3 component vectors
308 | row = [
309 | new Vector4(), new Vector4(), new Vector4()
310 | ];
311 |
312 | for (i = 1; i <= 3; i++)
313 | {
314 | row[i-1].x = matrix['m'+i+'1'];
315 | row[i-1].y = matrix['m'+i+'2'];
316 | row[i-1].z = matrix['m'+i+'3'];
317 | }
318 |
319 | // Compute X scale factor and normalize first row.
320 | scale = new Vector4();
321 | skew = new Vector4();
322 |
323 | scale.x = row[0].length();
324 | row[0] = row[0].normalise();
325 |
326 | // Compute XY shear factor and make 2nd row orthogonal to 1st.
327 | skew.x = row[0].dot(row[1]);
328 | row[1] = row[1].combine(row[0], 1.0, -skew.x);
329 |
330 | // Now, compute Y scale and normalize 2nd row.
331 | scale.y = row[1].length();
332 | row[1] = row[1].normalise();
333 | skew.x /= scale.y;
334 |
335 | // Compute XZ and YZ shears, orthogonalize 3rd row
336 | skew.y = row[0].dot(row[2]);
337 | row[2] = row[2].combine(row[0], 1.0, -skew.y);
338 | skew.z = row[1].dot(row[2]);
339 | row[2] = row[2].combine(row[1], 1.0, -skew.z);
340 |
341 | // Next, get Z scale and normalize 3rd row.
342 | scale.z = row[2].length();
343 | row[2] = row[2].normalise();
344 | skew.y /= scale.z;
345 | skew.y /= scale.z;
346 |
347 | // At this point, the matrix (in rows) is orthonormal.
348 | // Check for a coordinate system flip. If the determinant
349 | // is -1, then negate the matrix and the scaling factors.
350 | pdum3 = row[1].cross(row[2])
351 | if (row[0].dot(pdum3) < 0)
352 | {
353 | for (i = 0; i < 3; i++)
354 | {
355 | scale.x *= -1;
356 | row[i].x *= -1;
357 | row[i].y *= -1;
358 | row[i].z *= -1;
359 | }
360 | }
361 |
362 | // Now, get the rotations out
363 | rotate = new Vector4();
364 | rotate.y = Math.asin(-row[0].z);
365 | if (Math.cos(rotate.y) != 0)
366 | {
367 | rotate.x = Math.atan2(row[1].z, row[2].z);
368 | rotate.z = Math.atan2(row[0].y, row[0].x);
369 | }
370 | else
371 | {
372 | rotate.x = Math.atan2(-row[2].x, row[1].y);
373 | rotate.z = 0;
374 | }
375 |
376 | return new CSSMatrixDecomposed({
377 | perspective: perspective,
378 | translate: translate,
379 | skew: skew,
380 | scale: scale,
381 | rotate: rotate
382 | });
383 | };
384 |
385 |
386 | })();
387 |
--------------------------------------------------------------------------------
/js/src/morf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve Morf v@VERSION
3 | * http://www.joelambert.co.uk/morf
4 | *
5 | * Copyright 2011, Joe Lambert.
6 | * Free to use under the MIT license.
7 | * http://www.opensource.org/licenses/mit-license.php
8 | */
9 |
10 | var Morf = function(elem, css, opts) {
11 | var from = {}, to = {},
12 |
13 | fromElem = document.createElement('div'),
14 | toElem = document.createElement('div'),
15 |
16 | options = {
17 | timingFunction: 'ease',
18 | duration: null,
19 | increment: 0.01,
20 | debug: false,
21 | optimise: true, // Whether the outputted CSS should be optimised
22 | decimalPlaces: 5 // How many decimal places to optimise the WebKitCSSMatrix output to
23 | },
24 |
25 | // Define all other var's used in the function
26 | i = rule = ruleName = camel = m1 = m2 = progress = frame = rule = transEvent = val = null, cacheKey = '',
27 |
28 | // Setup a scoped reference to ourselves
29 | _this = this,
30 |
31 | keyframes = {},
32 |
33 | // Create a unique name for this animation
34 | animName = 'anim'+(new Date().getTime()),
35 |
36 |
37 | /* --- Helper Functions ------------------------------------------------------------------- */
38 |
39 | // Event listener for the webkitAnimationEnd Event
40 | animationEndListener = function(event){
41 | elem.removeEventListener('webkitAnimationEnd', animationEndListener, true);
42 |
43 | // Dispatch a faux webkitTransitionEnd event to complete the appearance of this being a transition rather than an animation
44 | // TODO: Should we throw an event for each property changed? (event.propertyName = 'opacity' etc)
45 | transEvent = document.createEvent("Event");
46 | transEvent.initEvent("webkitTransitionEnd", true, true);
47 | elem.dispatchEvent(transEvent);
48 |
49 | // Reset transition effects after use
50 | elem.style.webkitTransitionTimingFunction = null;
51 | elem.style.webkitTransitionDuration = 0;
52 |
53 | if (options.callback) {
54 | options.callback(elem);
55 | }
56 | },
57 |
58 | // Adds the CSS to the current page
59 | addKeyframeRule = function(rule) {
60 | if (document.styleSheets && document.styleSheets.length)
61 | document.styleSheets[0].insertRule(rule, 0);
62 | else
63 | {
64 | var style = document.createElement('style');
65 | style.innerHTML = rule;
66 | document.head.appendChild(style);
67 | }
68 | },
69 |
70 | // Produces a CSS string representation of the Keyframes
71 | createAnimationCSS = function(kf, name) {
72 | var str = '@-webkit-keyframes '+name+' {\n', f = pos = rule = null, fStr = '';
73 |
74 | for(pos in kf)
75 | {
76 | f = kf[pos];
77 | fStr = '\t'+pos+' {\n';
78 |
79 | for(rule in f)
80 | fStr += '\t\t'+_this.util.toDash(rule)+': '+f[rule]+';\n';
81 |
82 | fStr += "\t}\n\n";
83 |
84 | str += fStr;
85 | }
86 |
87 | return options.optimise ? optimiseCSS(str+' }') : str+' }';
88 | },
89 |
90 | // Replaces scale(0) with 0.0001 to get around the inability to these decompose matrix
91 | sanityCheckTransformString = function(str) {
92 | var scale = str.match(/scale[Y|X|Z]*\([0-9, ]*0[,0-9 ]*\)/g),
93 | i = 0;
94 |
95 | if(scale)
96 | {
97 | // There might be multiple scale() properties in the string
98 | for(i = 0; i < scale.length; i++)
99 | str = str.replace(scale[i], scale[i].replace(/([^0-9])0([^0.9])/g, "$10.0001$2"));
100 | }
101 |
102 | return str;
103 | },
104 |
105 | // WebKitCSSMatrix toString() ALWAYS outputs numbers to 5 decimal places - this helps optimise the string
106 | optimiseCSS = function(str, decimalPlaces) {
107 | decimalPlaces = typeof options.decimalPlaces == 'number' ? options.decimalPlaces : 5;
108 | var matches = str.match(/[0-9\.]+/gm),
109 | i = 0;
110 |
111 | if(matches)
112 | {
113 | for(i = 0; i < matches.length; i++)
114 | str = str.replace(matches[i], parseFloat( parseFloat(matches[i]).toFixed(decimalPlaces)));
115 | }
116 |
117 | return str;
118 | };
119 |
120 | /* --- Helper Functions End --------------------------------------------------------------- */
121 |
122 |
123 | // Import the options
124 | for(i in opts)
125 | options[i] = opts[i];
126 |
127 |
128 | // If timingFunction is a natively supported function then just trigger normal transition
129 | if( options.timingFunction === 'ease' ||
130 | options.timingFunction === 'linear' ||
131 | options.timingFunction === 'ease-in' ||
132 | options.timingFunction === 'ease-out' ||
133 | options.timingFunction === 'ease-in-out' ||
134 | /^cubic-bezier/.test(options.timingFunction)) {
135 |
136 | elem.style.webkitTransitionDuration = options.duration;
137 | elem.style.webkitTransitionTimingFunction = options.timingFunction;
138 |
139 | // Listen for the transitionEnd event to fire the callback if needed
140 | var transitionEndListener = function(event) {
141 | elem.removeEventListener('webkitTransitionEnd', transitionEndListener, true);
142 |
143 | // Clean up after ourself
144 | elem.style.webkitTransitionDuration = 0;
145 | elem.style.webkitTransitionTimingFunction = null;
146 |
147 | if (options.callback) {
148 | // Delay execution to ensure the clean up CSS has taken effect
149 | setTimeout(function() {
150 | options.callback(elem);
151 | }, 10);
152 | }
153 | };
154 |
155 | elem.addEventListener('webkitTransitionEnd', transitionEndListener, true);
156 |
157 | setTimeout(function() {
158 | for(rule in css) {
159 | camel = _this.util.toCamel(rule);
160 | elem.style[camel] = css[rule];
161 | }
162 | }, 10);
163 |
164 | this.css = '';
165 |
166 | return;
167 | }
168 | else
169 | {
170 | // Reset transition properties for this element
171 | elem.style.webkitTransitionTimingFunction = null;
172 | elem.style.webkitTransitionDuration = 0;
173 | }
174 |
175 | // Create the key used to cache this animation
176 | cacheKey += options.timingFunction;
177 |
178 | // Setup the start and end CSS state
179 | for(rule in css)
180 | {
181 | camel = this.util.toCamel(rule);
182 |
183 | toElem.style[camel] = css[rule];
184 |
185 | // Set the from/start state
186 | from[rule] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix( sanityCheckTransformString( window.getComputedStyle(elem)['-webkit-transform'] ) ) : window.getComputedStyle(elem)[rule];
187 |
188 | // Set the to/end state
189 | to[rule] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix( sanityCheckTransformString( toElem.style.WebkitTransform ) ) : toElem.style[camel];
190 |
191 | // Shifty requires numeric values to be a number rather than a string (e.g. for opacity)
192 | from[rule] = from[rule] == (val = parseInt(from[rule], 10)) ? val : from[rule];
193 | to[rule] = to[rule] == (val = parseInt(from[rule], 10)) ? val : to[rule];
194 |
195 | // Update the cacheKey
196 | cacheKey += ';' + rule + ':' + from[rule] + '->' + to[rule];
197 | }
198 |
199 | // Check the cache to save expensive calculations
200 | if(Morf.cache[cacheKey])
201 | {
202 | this.css = Morf.cache[cacheKey].css;
203 | animName = Morf.cache[cacheKey].name;
204 | }
205 | else
206 | {
207 | // Produce decompositions of matrices here so we don't have to redo it on each iteration
208 | // Decomposing the matrix is expensive so we need to minimise these requests
209 | if(from['-webkit-transform'])
210 | {
211 | m1 = from['-webkit-transform'].decompose();
212 | m2 = to['-webkit-transform'].decompose();
213 | }
214 |
215 | // Produce style keyframes
216 | for(progress = 0; progress <= 1; progress += options.increment) {
217 | // Use Shifty.js to work out the interpolated CSS state
218 | frame = Tweenable.util.interpolate(from, to, progress, options.timingFunction);
219 |
220 | // Work out the interpolated matrix transformation
221 | if(m1 !== null && m2 !== null)
222 | frame['-webkit-transform'] = m1.tween(m2, progress, Tweenable.prototype.formula[options.timingFunction]);
223 |
224 | keyframes[parseInt(progress*100, 10)+'%'] = frame;
225 | }
226 |
227 | // Ensure the last frame has been added
228 | keyframes['100%'] = to;
229 |
230 | // Add the new animation to the document
231 | this.css = createAnimationCSS(keyframes, animName);
232 | addKeyframeRule(this.css);
233 |
234 | Morf.cache[cacheKey] = {css: this.css, name: animName};
235 | }
236 |
237 | // Set the final position state as this should be a transition not an animation & the element should end in the 'to' state
238 | for(rule in to)
239 | elem.style[this.util.toCamel(rule)] = to[rule];
240 |
241 | // Trigger the animation
242 | elem.addEventListener('webkitAnimationEnd', animationEndListener, true);
243 | elem.style.webkitAnimationDuration = options.duration;
244 | elem.style.webkitAnimationTimingFunction = 'linear';
245 | elem.style.webkitAnimationName = animName;
246 |
247 | // Print the animation to the console if the debug switch is given
248 | if(options.debug && window.console && window.console.log)
249 | console.log(this.css);
250 | };
251 |
252 |
253 | /**
254 | * Convenience function for triggering a transition
255 | * @param {HTMLDom} elem The element to apply the transition to
256 | * @param {Object} css Key value pair of CSS properties
257 | * @param {Object} opts Additional configuration options
258 | *
259 | * Configuration options
260 | * - timingFunction: {String} Name of the easing function to perform
261 | * - duration: {integer} Duration in ms
262 | * - increment: {float} How frequently to generate keyframes (Defaults to 0.01, which is every 1%)
263 | * - debug: {Boolean} Should the generated CSS Animation be printed to the console
264 | *
265 | * @returns {Morf} An instance of the Morf object
266 | */
267 |
268 | Morf.transition = function(elem, css, opts){
269 | return new Morf(elem, css, opts);
270 | };
271 |
272 | /**
273 | * Object to cache generated animations
274 | */
275 | Morf.cache = {};
276 |
277 | /**
278 | * Current version
279 | */
280 | Morf.version = '@VERSION';
--------------------------------------------------------------------------------
/js/src/morf.utils.js:
--------------------------------------------------------------------------------
1 | // Utilities Placeholder
2 | Morf.prototype.util = {};
3 |
4 |
5 | /**
6 | * Converts a DOM style string to CSS property name
7 | * @param {String} str A DOM style string
8 | * @returns {String} CSS property name
9 | */
10 |
11 | Morf.prototype.util.toDash = function(str){
12 | str = str.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();});
13 | return /^webkit/.test(str) ? '-'+str : str;
14 | };
15 |
16 |
17 | /**
18 | * Converts a CSS property name to DOM style string
19 | * @param {String} str A CSS property name
20 | * @returns {String} DOM style string
21 | */
22 |
23 | Morf.prototype.util.toCamel = function(str){
24 | return str.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase().replace('-','');});
25 | };
--------------------------------------------------------------------------------
/js/src/shifty.fn.scripty2.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve
3 | * Extra easing functions borrowed from scripty2 (c) 2005-2010 Thomas Fuchs (MIT Licence)
4 | * https://raw.github.com/madrobby/scripty2/master/src/effects/transitions/transitions.js
5 | */
6 |
7 | (function(){
8 | var scripty2 = {
9 | spring: function(pos) {
10 | return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
11 | },
12 |
13 | sinusoidal: function(pos) {
14 | return (-Math.cos(pos*Math.PI)/2) + 0.5;
15 | }
16 | };
17 |
18 | // Load the Scripty2 functions
19 | for(var t in scripty2)
20 | Tweenable.prototype.formula[t] = scripty2[t];
21 | })();
22 |
--------------------------------------------------------------------------------