Created
April 8, 2015 18:18
-
-
Save mistic100/ec6017f7a20a4fb64d92 to your computer and use it in GitHub Desktop.
Creates a tile explosion effect over an image when the mouse cursor hovers it. It is also compatible with multi-touch screens.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* jQuery imageExplode 1.0 | |
* | |
* Copyright 2013, Damien "Mistic" Sorel | |
* http://www.strangeplanet.fr | |
* | |
* thanks to Ryan Florence for the main algorythm | |
* http://ryanflorence.com/cssanimation | |
* | |
* Dual licensed under the MIT or GPL Version 3 licenses. | |
* http://www.opensource.org/licenses/mit-license.php | |
* http://www.gnu.org/licenses/gpl.html | |
* | |
* Depends: | |
* jquery | |
* CSSAnimation | |
* CSSAnimation.jQuery | |
*/ | |
(function($) { | |
/** | |
* Plugin declaration | |
*/ | |
$.fn.imageExplode = function(options) { | |
// callable public methods | |
var callable = ['explode', 'disable', 'enable']; | |
var plugin = $(this).data('imageExplode'); | |
// already instantiated and trying to execute a method | |
if (plugin && typeof options === 'string') { | |
if ($.inArray(options,callable)!==-1) { | |
return plugin[options].apply(plugin, Array.prototype.slice.call(arguments, 1)); | |
} | |
else { | |
throw 'Method "' + options + '" does not exist in jQuery.imageExplode'; | |
} | |
} | |
// not instantiated and trying to pass options object (or nothing) | |
else if (!plugin && (typeof options === 'object' || !options)) { | |
if (!options) { | |
options = {}; | |
} | |
// extend defaults | |
options = $.extend({}, $.fn.imageExplode.defaults, options); | |
// for each element instantiate the plugin | |
return this.each(function() { | |
var plugin = $(this).data('imageExplode'); | |
// create new instance of the plugin if the plugin isn't initialised | |
if (!plugin) { | |
plugin = new $.imageExplode($(this), options); | |
plugin.init(); | |
$(this).data('imageExplode', plugin); | |
} | |
}); | |
} | |
} | |
/** | |
* Defaults | |
*/ | |
$.fn.imageExplode.defaults = { | |
effect: 'chaos', | |
tileWidth : 50, | |
preserveBackground : false, | |
image : null, | |
width : null, | |
height : null, | |
speed : 500, | |
flipAngle : { | |
y: 180 | |
}, | |
onBeforeMove: null, | |
onAfterMove: null | |
}; | |
/** | |
* Main plugin function | |
*/ | |
$.imageExplode = function(element, options) { | |
var __this = this; | |
this.options = options; | |
if (element instanceof jQuery) { | |
this.$container = element; | |
} | |
else { | |
this.$container = $(element); | |
} | |
this.$spans = $(); | |
/* | |
* init the plugin | |
* scope: private | |
*/ | |
this.init = function() { | |
if (this.options.width == null) { | |
this.options.width = this.$container.width(); | |
} | |
if (this.options.height == null) { | |
this.options.height = this.$container.height(); | |
} | |
if (this.options.image == null) { | |
this.options.image = this.$container.css('background-image'); | |
} | |
else if (this.options.image.substr(0, 3) != 'url') { | |
this.options.image = 'url(' + this.options.image + ')'; | |
} | |
this.options.nbCols = Math.floor(this.options.width / this.options.tileWidth); | |
this.options.nbRows = Math.floor(this.options.height / this.options.tileWidth); | |
this.options.realWidth = this.options.tileWidth * this.options.nbCols; | |
this.options.realHeight = this.options.tileWidth * this.options.nbRows; | |
this.$container.css({ | |
width : this.options.realWidth, | |
height : this.options.realHeight | |
}); | |
if (!this.options.preserveBackground) { | |
this.$container.css('background-image', 'none'); | |
} | |
this.generateTiles(); | |
this.bindEvents(); | |
} | |
/* | |
* generate spans | |
* scope: private | |
*/ | |
this.generateTiles = function() { | |
var html = ''; | |
for (x = 0; x < this.options.nbRows; x++) { | |
for (y = 0; y < this.options.nbCols; y++) { | |
html+= '<span style="background-position:-' + (this.options.tileWidth * y) + 'px -' + (this.options.tileWidth * x) + 'px;"></span>'; | |
} | |
} | |
this.$container.html(html); | |
this.$spans = this.$container.children('span'); | |
this.$spans.css({ | |
'background-image' : this.options.image, | |
'width' : this.options.tileWidth, | |
'height' : this.options.tileWidth, | |
'float' : 'left', | |
'display' : 'block', | |
'z-index' : 1 | |
}); | |
this.$spans.setTransition({ | |
'property': 'transform' | |
}); | |
this.reset3d(this.$spans); | |
} | |
/* | |
* add events handlers | |
* scope: private | |
*/ | |
this.bindEvents = function() { | |
var events = this.$container.data('imageExplodeEvents'); | |
if (typeof events != 'boolean' || events !== true) { | |
// touch support | |
this.$container.on('touchmove.imageExplode', function(e) { | |
$.each(e.originalEvent.touches, function(i, touch) { | |
var off = __this.$container.offset(); | |
var cell = { | |
col: Math.floor((touch.pageX - off.left) / __this.options.tileWidth), | |
row: Math.floor((touch.pageY - off.top) / __this.options.tileWidth) | |
}; | |
if (cell.col >= __this.options.nbCols || cell.row >= __this.options.nbRows || cell.col < 0 || cell.row < 0) { | |
return; | |
} | |
var $cell = __this.$spans.eq( cell.row * __this.options.nbCols + cell.col ); | |
__this.frighten($cell); | |
}); | |
e.preventDefault(); | |
}); | |
// mouse support | |
this.$spans.on('mouseenter.imageExplode', function() { | |
__this.frighten($(this)); | |
}); | |
this.$container.data('imageExplodeEvents', true); | |
} | |
} | |
/* | |
* remove event handlers | |
* scope: private | |
*/ | |
this.unbindEvents = function() { | |
this.$spans.off('mouseenter.imageExplode'); | |
this.$container.off('touchmove.imageExplode'); | |
this.$container.data('imageExplodeEvents', false); | |
} | |
/* | |
* generate a random number | |
* scope : private | |
*/ | |
this.nbRandom = function(min, max) { | |
return Math.floor(Math.random() * (max - min + 1) + min); | |
} | |
/* | |
* apply random 3D transforms | |
* scope : private | |
*/ | |
this.chaos3d = function($target) { | |
$target.translate({ | |
x: this.nbRandom(-1000, 1000), | |
y: this.nbRandom(-1000, 1000), | |
z: this.nbRandom(-1000, 1000) | |
}).rotate({ | |
x: this.nbRandom(-720, 720), | |
y: this.nbRandom(-720, 720), | |
z: this.nbRandom(-720, 720) | |
}); | |
} | |
this.flip3d = function($target) { | |
$target.rotate(this.options.flipAngle); | |
} | |
/* | |
* restore 3D state | |
* scope : private | |
*/ | |
this.reset3d = function($target) { | |
$target.translate({x:0, y:0, z:0}).rotate({x:0, y:0, z:0}); | |
} | |
/* | |
* animate random 3D transforms and restore after complete | |
* scope : private | |
*/ | |
this.frighten = function($target) { | |
$target.stop().css('z-index', 1000); | |
if (typeof this.options.onBeforeMove == 'function') { | |
this.options.onBeforeMove.call($target[0], this.options); | |
} | |
$target.setTransition({ | |
'duration': this.options.speed + 'ms', | |
'timing-function': 'ease-out' | |
}); | |
switch (this.options.effect) { | |
case 'chaos' : | |
this.chaos3d($target); | |
break; | |
case 'flip': | |
this.flip3d($target); | |
break; | |
} | |
setTimeout(function() { | |
$target.setTransition({ | |
'timing-function': 'ease-in-out' | |
}); | |
__this.reset3d($target); | |
}, this.options.speed); | |
setTimeout(function() { | |
$target.css('z-index', 1); | |
if (typeof __this.options.onAfterMove == 'function') { | |
__this.options.onAfterMove.call($target[0], __this.options); | |
} | |
}, this.options.speed*2); | |
} | |
/* | |
* explode the whole image | |
* scope : public | |
*/ | |
this.explode = function() { | |
this.$spans.each(function() { | |
__this.frighten($(this)); | |
}); | |
} | |
/* | |
* disable effect | |
* scope : public | |
*/ | |
this.disable = function() { | |
this.$spans.setTransition({ | |
'duration': '0ms' | |
}); | |
this.reset3d(this.$spans); | |
this.$spans.stop(); | |
this.unbindEvents(); | |
} | |
/* | |
* enable effect | |
* scope : public | |
*/ | |
this.enable = function() { | |
this.bindEvents(); | |
} | |
}; | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment