UNPKG

jquery-flapper

Version:

A split-flap (Solari) display for numbers and words using jQuery

305 lines (264 loc) 9.3 kB
/////////////////////////////////////////////////////// // Animation /////////////////////////////////////////////////////// (function($, window, document, undefined) { /** * @var Regex looks for units on a string */ var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/; /** * Doctors prop values in the event that they contain spaces * @param Object prop * @param String speed * @param String easing * @param Function callback * @return bool */ var _animate = $.fn.animate; $.fn.animate = function( prop, speed, easing, callback ) { var optall = $.speed(speed, easing, callback), mv = $.cssMultipleValues; // Speed always creates a complete function that must be reset optall.complete = optall.old; // Capture multiple values if (!$.isEmptyObject(prop)) { if (typeof optall.original === 'undefined') { optall.original = {}; } $.each( prop, function( name, val ) { if (mv[name] || $.cssAngle[name] || (!$.cssNumber[name] && $.inArray(name, $.transform.funcs) !== -1)) { // Handle special easing var specialEasing = null; if (jQuery.isArray(prop[name])) { var mvlen = 1, len = val.length; if (mv[name]) { mvlen = (typeof mv[name].length === 'undefined' ? mv[name] : mv[name].length); } if ( len > mvlen || (len < mvlen && len == 2) || (len == 2 && mvlen == 2 && isNaN(parseFloat(val[len - 1])))) { specialEasing = val[len - 1]; val.splice(len - 1, 1); } } // Store the original values onto the optall optall.original[name] = val.toString(); // reduce to a unitless number (to trick animate) prop[name] = parseFloat(val); } } ); } //NOTE: we edited prop above to trick animate //NOTE: we pre-convert to an optall so we can doctor it return _animate.apply(this, [arguments[0], optall]); }; var prop = 'paddingBottom'; function cur(elem, prop) { if ( elem[prop] != null && (!elem.style || elem.style[prop] == null) ) { //return elem[ prop ]; } var r = parseFloat( $.css( elem, prop ) ); return r && r > -10000 ? r : 0; } var _custom = $.fx.prototype.custom; $.fx.prototype.custom = function(from, to, unit) { var multiple = $.cssMultipleValues[this.prop], angle = $.cssAngle[this.prop]; //TODO: simply check for the existence of CSS Hooks? if (multiple || (!$.cssNumber[this.prop] && $.inArray(this.prop, $.transform.funcs) !== -1)) { this.values = []; if (!multiple) { multiple = 1; } // Pull out the known values var values = this.options.original[this.prop], currentValues = $(this.elem).css(this.prop), defaultValues = $.cssDefault[this.prop] || 0; // make sure the current css value is an array if (!$.isArray(currentValues)) { currentValues = [currentValues]; } // make sure the new values are an array if (!$.isArray(values)) { if ($.type(values) === 'string') { values = values.split(','); } else { values = [values]; } } // make sure we have enough new values var length = multiple.length || multiple, i = 0; while (values.length < length) { values.push(multiple.duplicate ? values[0] : defaultValues[i] || 0); i++; } // calculate a start, end and unit for each new value var start, parts, end, //unit, fx = this, transform = fx.elem.transform; orig = $.style(fx.elem, prop); $.each(values, function(i, val) { // find a sensible start value if (currentValues[i]) { start = currentValues[i]; } else if (defaultValues[i] && !multiple.duplicate) { start = defaultValues[i]; } else if (multiple.duplicate) { start = currentValues[0]; } else { start = 0; } // Force the correct unit on the start if (angle) { start = $.angle.toDegree(start); } else if (!$.cssNumber[fx.prop]) { parts = rfxnum.exec($.trim(start)); if (parts[3] && parts[3] !== 'px') { if (parts[3] === '%') { start = parseFloat( parts[2] ) / 100 * transform['safeOuter' + (i ? 'Height' : 'Width')](); } else { $.style( fx.elem, prop, start); start = cur(fx.elem, prop); $.style( fx.elem, prop, orig); } } } start = parseFloat(start); // parse the value with a regex parts = rfxnum.exec($.trim(val)); if (parts) { // we found a sensible value and unit end = parseFloat( parts[2] ); unit = parts[3] || "px"; //TODO: change to an appropriate default unit if (angle) { end = $.angle.toDegree(end + unit); unit = 'deg'; } else if (!$.cssNumber[fx.prop] && unit === '%') { start = (start / transform['safeOuter' + (i ? 'Height' : 'Width')]()) * 100; } else if (!$.cssNumber[fx.prop] && unit !== 'px') { $.style( fx.elem, prop, (end || 1) + unit); start = ((end || 1) / cur(fx.elem, prop)) * start; $.style( fx.elem, prop, orig); } // If a +=/-= token was provided, we're doing a relative animation if (parts[1]) { end = ((parts[1] === "-=" ? -1 : 1) * end) + start; } } else { // I don't know when this would happen end = val; unit = ''; } // Save the values fx.values.push({ start: start, end: end, unit: unit }); }); } return _custom.apply(this, arguments); }; /** * Animates a multi value attribute * @param Object fx * @return null */ $.fx.multipleValueStep = { _default: function(fx) { $.each(fx.values, function(i, val) { fx.values[i].now = val.start + ((val.end - val.start) * fx.pos); }); } }; $.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) { $.fx.multipleValueStep[func] = function(fx) { var d = fx.decomposed, $m = $.matrix; m = $m.identity(); d.now = {}; // increment each part of the decomposition and recompose it $.each(d.start, function(k) { // calculate the current value d.now[k] = parseFloat(d.start[k]) + ((parseFloat(d.end[k]) - parseFloat(d.start[k])) * fx.pos); // skip functions that won't affect the transform if (((k === 'scaleX' || k === 'scaleY') && d.now[k] === 1) || (k !== 'scaleX' && k !== 'scaleY' && d.now[k] === 0)) { return true; } // calculating m = m.x($m[k](d.now[k])); }); // save the correct matrix values for the value of now var val; $.each(fx.values, function(i) { switch (i) { case 0: val = parseFloat(m.e(1, 1).toFixed(6)); break; case 1: val = parseFloat(m.e(2, 1).toFixed(6)); break; case 2: val = parseFloat(m.e(1, 2).toFixed(6)); break; case 3: val = parseFloat(m.e(2, 2).toFixed(6)); break; case 4: val = parseFloat(m.e(1, 3).toFixed(6)); break; case 5: val = parseFloat(m.e(2, 3).toFixed(6)); break; } fx.values[i].now = val; }); }; }); /** * Step for animating tranformations */ $.each($.transform.funcs, function(i, func) { $.fx.step[func] = function(fx) { var transform = fx.elem.transform || new $.transform(fx.elem), funcs = {}; if ($.cssMultipleValues[func] || (!$.cssNumber[func] && $.inArray(func, $.transform.funcs) !== -1)) { ($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx); funcs[fx.prop] = []; $.each(fx.values, function(i, val) { funcs[fx.prop].push(val.now + ($.cssNumber[fx.prop] ? '' : val.unit)); }); } else { funcs[fx.prop] = fx.now + ($.cssNumber[fx.prop] ? '' : fx.unit); } transform.exec(funcs, {preserve: true}); }; }); // Support matrix animation $.each(['matrix', 'reflect', 'reflectX', 'reflectXY', 'reflectY'], function(i, func) { $.fx.step[func] = function(fx) { var transform = fx.elem.transform || new $.transform(fx.elem), funcs = {}; if (!fx.initialized) { fx.initialized = true; // Reflections need a sensible end value set if (func !== 'matrix') { var values = $.matrix[func]().elements; var val; $.each(fx.values, function(i) { switch (i) { case 0: val = values[0]; break; case 1: val = values[2]; break; case 2: val = values[1]; break; case 3: val = values[3]; break; default: val = 0; } fx.values[i].end = val; }); } // Decompose the start and end fx.decomposed = {}; var v = fx.values; fx.decomposed.start = $.matrix.matrix(v[0].start, v[1].start, v[2].start, v[3].start, v[4].start, v[5].start).decompose(); fx.decomposed.end = $.matrix.matrix(v[0].end, v[1].end, v[2].end, v[3].end, v[4].end, v[5].end).decompose(); } ($.fx.multipleValueStep[fx.prop] || $.fx.multipleValueStep._default)(fx); funcs.matrix = []; $.each(fx.values, function(i, val) { funcs.matrix.push(val.now); }); transform.exec(funcs, {preserve: true}); }; }); })(jQuery, this, this.document);