UNPKG

jquery-flapper

Version:

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

289 lines (226 loc) 8.91 kB
(function($) { var Flapper = function($ele, options) { var _this = this; this.id = Math.floor(Math.random() * 1000) + 1; this.$ele = $ele; this.options = $.extend({}, this.defaults, options); // is transform loaded? this.options.transform = this.options.transform && $.transform; this.$div = $('<div></div>'); this.$div.attr('class', 'flapper ' + this.$ele.attr('class')); this.$ele.hide().after(this.$div); this.$ele.bind('change.flapper', function(){ _this.update(); }); this.init(); } Flapper.prototype = { defaults: { width: 6, format: null, align: 'right', padding: ' ', chars: null, chars_preset: 'num', timing: 250, min_timing: 10, threshhold: 100, transform: true, on_anim_start: null, on_anim_end: null, cycleInterval: null, }, init: function() { var _this = this; this.digits = []; for (i=0; i<this.options.width; i++) { this.digits[i] = new FlapDigit(null, this.options); this.$div.append(this.digits[i].$ele); } this.$div.on('digitAnimEnd', function(e){ _this.onDigitAnimEnd(e); }); if (this.options.on_anim_start) { this.$div.on('animStart', this.options.on_anim_start); } if (this.options.on_anim_end) { this.$div.on('animEnd', this.options.on_anim_end); } this.update(); if (this.options.cycleInterval) { this.startCycle(); } }, update: function() { var value = this.$ele.val().replace(/[\s|\u00a0]/g, ' '); var digits = this.getDigits(value); this.digitsFinished = 0; this.$div.trigger('animStart'); for (var i=0; i<this.digits.length; i++) { this.digits[i].goToChar(digits[i]); } }, onDigitAnimEnd: function(e) { this.digitsFinished++; if (this.digitsFinished == this.options.width) { this.$div.trigger('animEnd'); } }, getDigits: function(val, length) { var strval = val + ''; if (this.options.format) { strval = $.formatNumber(val, this.options.format); } var digits = strval.split(''); if (digits.length < this.options.width) { while (digits.length < this.options.width) { if (this.options.align == 'left') { digits.push(this.options.padding); } else { digits.unshift(this.options.padding); } } } else if (digits.length > this.options.width) { var overage = digits.length - this.options.width; if (this.options.align == 'left') { digits.splice(-1, overage); } else { digits.splice(0, overage); } } return digits; }, startCycle: function() { var self = this; setInterval(function() { for (var i=0; i<self.digits.length; i++) { self.digits[i].goToNextPosition(); } }, this.options.cycleInterval); }, } FlapDigit = function($ele, opts) { this.options = opts; if (!this.options.chars) { this.options.chars = this.presets[this.options.chars_preset]; } this.pos = 0; this.timeout; if (!$ele) { this.$ele = $(this.htmlTemplate); } else { this.$ele = $ele; } this.$prev = this.$ele.find('.front.top, .back.bottom'); this.$next = this.$ele.find('.back.top, .front.bottom'); this.$back_top = this.$ele.find('.back.top'); this.$back_bottom = this.$ele.find('.back.bottom'); this.$front_top = this.$ele.find('.front.top'); this.$front_bottom = this.$ele.find('.front.bottom'); this.initialize(); } FlapDigit.prototype = { presets: { num: [' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], hexnum: [' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '0'], alpha: [' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'], alphanum: [' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'], }, initialize: function() { this.$prev.html(this.options.chars[0]); this.$next.html(this.options.chars[0]); }, htmlTemplate: '<div class="digit"><div class="back top">&nbsp;</div>' + '<div class="back bottom">&nbsp;</div>' + '<div class="front top">&nbsp;</div>' + '<div class="front bottom">&nbsp;</div></div>', increment: function(speed) { var next = this.pos + 1; if (next >= this.options.chars.length) { next = 0; } this.$prev.html(this.options.chars[this.pos]).show(); this.$front_bottom.hide(); this.$next.html(this.options.chars[next]); var speed1 = Math.floor(Math.random() * speed * .4 + speed * .3); var speed2 = Math.floor(Math.random() * speed * .1 + speed * .2); if (speed >= this.options.threshhold) { if (this.options.transform) { this.animateSlow(speed1, speed2); } else { this.animateFast(speed1, speed2); } } this.pos = next; }, animateSlow: function(speed1, speed2) { var _this = this; this.$back_top.show(); this.$front_bottom.transform({ scaleY: 0.0 }); this.$front_top.transform({ scaleY: 1.0 }).stop().show().animate({ scaleY: 0.0 }, speed1, 'swing', function(){ _this.$front_bottom.stop().show().animate({ scaleY: 1.0 }, speed2, 'linear'); _this.$front_top.hide().transform({ scaleY: 1.0 }); }); }, animateFast: function(speed1, speed2) { var _this = this; if (this.timeout) { clearTimeout(this.timeout); } this.timeout = setTimeout(function(){ _this.$front_top.hide(); _this.timeout = setTimeout(function(){ _this.$front_bottom.show(); }, speed2); }, speed1); }, goToPosition: function(pos) { var _this = this; var frameFunc = function() { if (_this.timing_timer) { clearInterval(_this.timing_timer); _this.timing_timer = null; } var distance = pos - _this.pos; if (distance <0) { distance += _this.options.chars.length; } if (_this.pos == pos) { clearInterval(_this.timing_timer); _this.timing_timer = null; _this.$ele.trigger("digitAnimEnd"); } else { var duration = Math.floor( (_this.options.timing - _this.options.min_timing) / distance + _this.options.min_timing ); _this.increment(duration); _this.timing_timer = setTimeout(frameFunc, duration); } } frameFunc(); }, goToNextPosition: function() { var next = this.pos + 1; if (next >= this.options.chars.length) { next = 0; } this.goToPosition(next); }, goToChar: function(c) { var pos = $.inArray(c, this.options.chars); if (pos == -1) { this.options.chars.push(c); pos = this.options.chars.length - 1; } this.goToPosition(pos); } }; $.fn.flapper = function(options) { this.each(function(){ new Flapper($(this), options); }); return this; } })(jQuery);