Skip to content

Instantly share code, notes, and snippets.

@mistic100
Created April 8, 2015 18:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mistic100/ec6017f7a20a4fb64d92 to your computer and use it in GitHub Desktop.
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.
/*!
* 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