Skip to content

Instantly share code, notes, and snippets.

@diomed
Created August 4, 2019 16:31
Show Gist options
  • Save diomed/4d73da8d9ed77608c78d692326c3d7cc to your computer and use it in GitHub Desktop.
Save diomed/4d73da8d9ed77608c78d692326c3d7cc to your computer and use it in GitHub Desktop.
jQuery split flap
/* Split Flap Display for jQuery / Maxime Cousinou */
(function ($) {
'use strict';
/***************************************************************************
* Tools
**************************************************************************/
// Date.now Polyfill
Date.now = (Date.now || function () {
return (new Date()).getTime();
});
// requestAnimationFrame polyfill by Erik Möller, fixes from Paul Irish and Tino Zijdel
(function () {
var lastTime = 0;
var vendors = [ 'ms', 'moz', 'webkit', 'o' ];
for ( var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x ) {
window.requestAnimationFrame = window[ vendors[ x ] + 'RequestAnimationFrame' ];
window.cancelAnimationFrame = window[ vendors[ x ] + 'CancelAnimationFrame' ] || window[ vendors[ x ] + 'CancelRequestAnimationFrame' ];
}
if ( window.requestAnimationFrame === undefined ) {
window.requestAnimationFrame = function (callback, element) {
var currTime = Date.now(), timeToCall = Math.max(0, 16 - ( currTime - lastTime ));
var id = window.setTimeout(function () {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
window.cancelAnimationFrame = window.cancelAnimationFrame || function (id) {
window.clearTimeout(id);
};
}());
// Bind
var bind = function (method, instance) {
return function () {
return method.apply(instance, arguments);
};
};
/***************************************************************************
* Letter
**************************************************************************/
/**
* Letter Constructor
*
* @param settings
* @constructor
*/
function Letter(settings) {
this.settings = settings;
this.domObject = document.createElement('div');
$(this.domObject)
.css({
'-webkit-transform-style': 'preserve-3d',
'-moz-transform-style': 'preserve-3d',
'-ms-transform-style': 'preserve-3d',
'transform-style': 'preserve-3d'
})
.addClass("char");
this.upperObject = document.createElement('div');
this.lowerObject = document.createElement('div');
this.flippingObject = document.createElement('div');
var c = {
'background-image': 'url(' + this.settings.image + ')'
};
if ( this.settings.imageSize != '' ) {
c[ 'background-size' ] = this.settings.imageSize;
}
$(this.upperObject)
.width(this.settings.charWidth)
.height(this.settings.charHeight >> 1)
.css(c)
.addClass("upper");
$(this.lowerObject)
.width(this.settings.charWidth)
.height(this.settings.charHeight >> 1)
.css(c)
.addClass("lower");
$(this.flippingObject)
.width(this.settings.charWidth)
.height(this.settings.charHeight >> 1)
.css($.extend(c, {
'position': 'absolute',
'left': 0,
'top': 0
}))
.hide()
.addClass("flipping");
$(this.domObject).append(this.upperObject);
$(this.domObject).append(this.lowerObject);
$(this.domObject).append(this.flippingObject);
}
var lp = Letter.prototype;
/**
* Return DOM Object
*
* @returns {HTMLElement|*}
*/
lp.getDOMObject = function () {
return this.domObject;
}
lp.getCharOffset = function (char) {
return Math.max(0, this.settings.charsMap.indexOf(char));
}
/**
* Set Letter character
* @param char
* @param charFrom
* @param ratio
*/
lp.setChar = function (char, charFrom, ratio) {
if ( typeof ratio == 'undefined' ) {
ratio = 1;
}
var offset = this.getCharOffset(char);
$(this.upperObject).css({
'background-position': '-' + (offset * this.settings.charWidth) + 'px 0px'
});
if ( ratio >= 1 ) {
$(this.lowerObject).css({
'background-position': '-' + (offset * this.settings.charWidth) + 'px -' + (this.settings.charHeight >> 1) + 'px'
});
$(this.flippingObject).hide();
}
else if ( ratio <= 0 ) {
var offsetFrom = this.getCharOffset(charFrom);
$(this.upperObject).css({
'background-position': '-' + (offsetFrom * this.settings.charWidth) + 'px 0px'
});
$(this.lowerObject).css({
'background-position': '-' + (offsetFrom * this.settings.charWidth) + 'px -' + (this.settings.charHeight >> 1) + 'px'
});
$(this.flippingObject).hide();
}
else {
var offsetFrom = this.getCharOffset(charFrom);
$(this.lowerObject).css({
'background-position': '-' + (offsetFrom * this.settings.charWidth) + 'px -' + (this.settings.charHeight >> 1) + 'px'
});
var d;
if ( ratio < 0.5 ) {
d = (90 * 2 * ratio);
$(this.flippingObject)
.css({
'top': 0,
'z-index': Math.round(d),
'-webkit-transform': 'rotateX(-' + d + 'deg)',
'-moz-transform': 'rotateX(-' + d + 'deg)',
'-ms-transform': 'rotateX(-' + d + 'deg)',
'transform': 'rotateX(-' + d + 'deg)',
'-webkit-transform-origin': 'bottom center 0',
'-moz-transform-origin': 'bottom center 0',
'-ms-transform-origin': 'bottom center 0',
'transform-origin': 'bottom center 0',
'background-position': '-' + (offsetFrom * this.settings.charWidth) + 'px 0px'
});
}
else {
d = (90 * 2 * (1 - ratio));
$(this.flippingObject)
.css({
'top': (this.settings.charHeight >> 1) + 'px',
'z-index': Math.round(d),
'-webkit-transform': 'rotateX(' + d + 'deg)',
'-moz-transform': 'rotateX(' + d + 'deg)',
'-ms-transform': 'rotateX(' + d + 'deg)',
'transform': 'rotateX(' + d + 'deg)',
'-webkit-transform-origin': 'top center 0',
'-moz-transform-origin': 'top center 0',
'-ms-transform-origin': 'top center 0',
'transform-origin': 'top center 0',
'background-position': '-' + (offset * this.settings.charWidth) + 'px -' + (this.settings.charHeight >> 1) + 'px'
});
}
$(this.flippingObject).show();
}
}
/***************************************************************************
* SplitFlap
**************************************************************************/
function SplitFlap(settings) {
this.settings = settings;
this.domObject = document.createElement('div');
this.letters = new Array();
$(this.domObject).addClass("splitflap");
}
var sp = SplitFlap.prototype;
sp.getDOMObject = function () {
return this.domObject;
}
sp.build = function (size) {
$(this.domObject)
.css({
position: 'relative'
})
.width(size * this.settings.charWidth)
.height(this.settings.charHeight);
for ( var i = 0; i < size; i++ ) {
var letter = new Letter(this.settings);
var o = letter.getDOMObject();
$(o).css({
position: 'absolute',
left: i * this.settings.charWidth,
top: 0
});
$(this.domObject).append(o);
this.letters[ i ] = letter;
}
}
sp.setText = function (text, textFrom) {
var animated;
if ( typeof textFrom == 'undefined' ) {
textFrom = text;
animated = false;
}
else {
animated = true;
}
// Normalize text
while ( textFrom.length < this.letters.length ) {
if ( this.settings.padDir == 'left' ) {
textFrom = textFrom + this.settings.padChar;
}
else {
textFrom = this.settings.padChar + textFrom;
}
}
// Initialise display
var charsFrom = (new String(textFrom)).split("");
for ( var i = 0, l = this.letters.length; i < l; i++ ) {
var letter = this.letters[ i ];
letter.setChar(charsFrom[ i ]);
}
// Animation
if ( animated ) {
// Normalize text
while ( text.length < this.letters.length ) {
if ( this.settings.padDir == 'left' ) {
text = text + this.settings.padChar;
}
else {
text = this.settings.padChar + text;
}
}
var chars = (new String(text)).split("");
this.animation = {
letters: new Array()
};
for ( var i = 0, l = this.letters.length; i < l; i++ ) {
var al = {
ratio: 0,
speed: this.settings.speed + Math.random() * this.settings.speedVariation,
letters: new Array(charsFrom[ i ])
};
var index = this.letters[ i ].getCharOffset(charsFrom[ i ]);
while ( this.settings.charsMap.charAt(index) != chars[ i ] ) {
index = (index + 1) % this.settings.charsMap.length;
al.letters.push(this.settings.charsMap.charAt(index));
}
this.animation.letters[ i ] = al;
}
if ( this.settings.autoplay ) {
this.animate();
}
}
}
sp.animate = function () {
var t = new Date().getTime();
if ( typeof this.animation.time == 'undefined' ) {
this.animation.time = t;
}
var dt = 0.001 * (t - this.animation.time);
var n = 0;
for ( var i = 0, l = this.animation.letters.length; i < l; i++ ) {
var letter = this.letters[ i ];
var al = this.animation.letters[ i ];
if ( al.letters.length > 1 ) {
al.ratio += al.speed * dt;
if ( (al.ratio > 1) && (al.letters.length > 1) ) {
al.ratio = 0;
al.letters.shift();
}
}
if ( al.letters.length > 1 ) {
letter.setChar(al.letters[ 1 ], al.letters[ 0 ], al.ratio);
n++;
}
else {
letter.setChar(al.letters[ 0 ]);
}
}
this.animation.time = t;
if ( n > 0 ) {
requestAnimationFrame(bind(this.animate, this));
}
else {
this.settings.onComplete(this);
}
}
/***************************************************************************
* jQuery
**************************************************************************/
$.fn.splitFlap = function (options) {
if ( options == 'splitflap' ) {
if ( this.length < 0 ) {
return false;
}
var o = this.get(0);
if ( typeof o.splitflap == 'undefined' ) {
return false;
}
return o.splitflap;
}
var settings = $.extend({
image: 'images/chars.png',
imageSize: '',
charsMap: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789.,!?#@()+-=',
charWidth: 50,
charHeight: 100,
charSubstitute: ' ',
padDir: 'left',
padChar: ' ',
speed: 3,
speedVariation: 2,
text: '',
textInit: '',
autoplay: true,
onComplete: function () {}
}, options);
return this.each(function () {
var text = (new String(settings.text)).toUpperCase();
if ( text == '' ) {
text = (new String($(this).html())).toUpperCase();
}
// Verify chars
for ( var i = 0, l = text.length; i < l; i++ ) {
var c = text.charAt(i);
if ( settings.charsMap.indexOf(c) < 0 ) {
text = text.replace(c, settings.charSubstitute);
}
}
var textInit = settings.textInit.toUpperCase().substr(0, text.length);
// Verify chars
for ( var i = 0, l = textInit.length; i < l; i++ ) {
var c = textInit.charAt(i);
if ( settings.charsMap.indexOf(c) < 0 ) {
textInit = textInit.replace(c, settings.charSubstitute);
}
}
while ( textInit.length < text.length ) {
textInit = textInit + settings.charsMap.charAt(Math.floor(settings.charsMap.length * Math.random()));
}
this.splitflap = new SplitFlap(settings);
this.splitflap.build(text.length);
$(this).empty().append(this.splitflap.getDOMObject());
this.splitflap.setText(text, textInit);
});
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment