diff --git a/Gruntfile.js b/Gruntfile.js index bdaafb6..38e4ba5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -85,6 +85,6 @@ module.exports = function(grunt) { grunt.registerTask('default', ['jshint', 'qunit', 'clean', 'concat', 'uglify']); // Travis CI task. - grunt.registerTask('travis', ['jshint', 'qunit']); + grunt.registerTask('travis', ['jshint', 'qunit', 'clean', 'concat', 'uglify']); }; diff --git a/README.md b/README.md index 16ddbbf..fc68fac 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,22 @@ Set spin animation time Pass an int as miliseconds to make the machine auto rotate repeat: false + +### randomize + +Pass a function to select your own random element. This function must return an integer between 0 (first element) and max number of elements. + + randomize: function(activeElementIndex){} //activeElementIndex = current selected index + +Example (this machine always shows first element): + +```javascript +$('#foo').slotMachine({ + randomize : function(activeElementIndex){ + return 0; + } +}); +``` ## Authors diff --git a/dist/jquery.slotmachine.js b/dist/jquery.slotmachine.js new file mode 100644 index 0000000..19a8adc --- /dev/null +++ b/dist/jquery.slotmachine.js @@ -0,0 +1,585 @@ +/*! SlotMachine - v1.0.0 - 2014-06-23 +* https://github.com/josex2r/jQuery-SlotMachine +* Copyright (c) 2014 Jose Luis Represa; Licensed MIT */ +;(function($, window, document, undefined){ + + //Set required styles, filters and masks + + $(document).ready(function(){ + + //Fast blur + if( $("filter#slotMachineBlurSVG").length<=0 ){ + $("body").append(''+ + ''+ + ''+ + ''+ + ''); + } + + //Medium blur + if( $("filter#slotMachineBlurSVG").length<=0 ){ + $("body").append(''+ + ''+ + ''+ + ''+ + ''); + } + + //Slow blur + if( $("filter#slotMachineBlurSVG").length<=0 ){ + $("body").append(''+ + ''+ + ''+ + ''+ + ''); + } + + //Fade mask + if( $("mask#slotMachineFadeSVG").length<=0 ){ + $("body").append(''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''); + } + + //CSS classes + $("body").append(""); + + }); + + //Required easing functions + if( typeof $.easing.easeOutBounce!=="function" ){ + //From jQuery easing, extend jQuery animations functions + $.extend( $.easing, { + easeOutBounce: function (x, t, b, c, d) { + if ((t/=d) < (1/2.75)) { + return c*(7.5625*t*t) + b; + } else if (t < (2/2.75)) { + return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b; + } else if (t < (2.5/2.75)) { + return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b; + } else { + return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b; + } + }, + }); + } + + /** + * @desc PUBLIC - Makes Slot Machine animation effect + * @param object settings - Plugin configuration params + * @return jQuery node - Returns jQuery selector with some new functions (shuffle, stop, next, auto, active) + */ + $.fn.slotMachine = function(settings){ + + var defaults = { + active : 0, //Active element [int] + delay : 200, //Animation time [int] + repeat : false, //Repeat delay [false||int] + randomize : null //Randomize function, must return an integer with the selected position + }; + + settings = $.extend(defaults, settings); //Plugin settings + + var $slot = $(this), //jQuery selector + $titles = $slot.children(), //Slot Machine elements + $container, //Container to wrap $titles + _maxTop, //Max marginTop offset + _timer = null, //Timeout recursive function to handle auto (settings.repeat) + _currentAnim = null, //Current playing jQuery animation + _forceStop = false, //Force execution for some functions + _oncompleteShuffling = null, //Callback function + _isRunning = false, //Machine is running? + _active = { //Current active element + index : settings.active, + el : $titles.get( settings.active ) + }; + + /** + * @desc PRIVATE - Get element offset top + * @param int index - Element position + * @return int - Negative offset in px + */ + function _getOffset( index ){ + var offset = 0; + for(var i=0; i=0 ); + + //Choose element + var choosen = { + index : rnd, + el : $titles.get( rnd ) + }; + return choosen; + } + + /** + * @desc PRIVATE - Get the randomize setting function element + * @return int - Element index and HTML node + */ + function _getCustom(){ + var choosen = {}; + if( settings.randomize!==null && typeof settings.randomize==='function' ){ + var index = settings.randomize(_active.index); + if( index<0 || index>=$titles.length ){ + index = 0; + } + choosen = { + index : index, + el : $titles.get( index ) + }; + }else{ + choosen = _getRandom(); + } + return choosen; + } + + /** + * @desc PRIVATE - Get the previous element + * @return int - Element index and HTML node + */ + function _getPrev(){ + var prevIndex = _active.index-1<0 ? $titles.length-1 : _active.index-1; + var prevObj = { + index : prevIndex, + el : $titles.get(prevIndex) + }; + return prevObj; + } + + /** + * @desc PRIVATE - Get the next element + * @return int - Element index and HTML node + */ + function _getNext(){ + var nextIndex = _active.index+1<$titles.length ? _active.index+1 : 0; + var nextObj = { + index : nextIndex, + el : $titles.get(nextIndex) + }; + return nextObj; + } + + /** + * @desc PRIVATE - Get currently active element + * @return object elWithIndex - Element index and HTML node + */ + function _getActive(){ + //Update last choosen element index + return _active; + } + + /** + * @desc PRIVATE - Set currently showing element and makes active + * @param object elWithIndex - Element index and HTML node + */ + function _setActive( elWithIndex ){ + //Update last choosen element index + _active = elWithIndex; + } + + /** + * @desc PRIVATE - Set CSS classes to make speed effect + * @param string speed - Element speed [fast||medium||slow] + * @param string||boolean fade - Set fade gradient effect + */ + function _setAnimationFX(speed, fade){ + $slot.add($titles).removeClass("slotMachineBlurFast slotMachineBlurMedium slotMachineBlurSlow"); + switch( speed ){ + case 'fast': + $titles.addClass("slotMachineBlurFast"); + break; + case 'medium': + $titles.addClass("slotMachineBlurMedium"); + break; + case 'slow': + $titles.addClass("slotMachineBlurSlow"); + break; + } + + if( fade!==true || speed==="stop" ){ + $slot.add($titles).removeClass("slotMachineGradient"); + }else{ + $slot.add($titles).addClass("slotMachineGradient"); + } + } + + /** + * @desc PRIVATE - Reset active element position + */ + function _resetPosition(){ + $container.css("margin-top", _getOffset(_active.index)); + } + + /** + * @desc PRIVATE - Starts shuffling the elements + * @param int count - Number of shuffles (undefined to make infinite animation + */ + function _shuffle( count ){ + + _isRunning = true; + + var delay = settings.delay; + + //Infinite animation + if( count===undefined ){ + + //Set animation effects + _setAnimationFX("fast", true); + + delay /= 2; + + if( _isVisible() ){ + + //Perform animation + _currentAnim = $container.animate({ + marginTop : _maxTop + }, delay, function(){ + + //Remove animation var + _currentAnim = null; + + //Reset top position + $container.css("margin-top", 0); + + }); + + }else{ + + _setAnimationFX("stop"); + + _resetPosition(); + + } + + //Oncomplete animation + setTimeout(function(){ + + if( _forceStop===false ){ + + //Repeat animation + _shuffle(); + + } + + }, delay + 25); + + //Stop animation after {count} repeats + }else{ + + //Perform fast animation + if( count>=1 ){ + + if( count>1 ){ + + //Set animation effects + _setAnimationFX("fast", true); + + delay /= 2; + + }else{ + + //Set animation effects + _setAnimationFX("medium", true); + + } + + if( _isVisible() ){ + + //Perform animation + _currentAnim = $container.animate({ + marginTop : _maxTop + }, delay, function(){ + + //Remove animation var + _currentAnim = null; + + //Reset top position + $container.css("margin-top", 0); + + }); + + }else{ + + _setAnimationFX("stop"); + + _resetPosition(); + + } + + //Oncomplete animation + setTimeout(function(){ + + //Repeat animation + _shuffle( count-1 ); + + }, delay + 25); + + }else{ + + //Stop NOW! + _stop(true); + + } + + } + + } + + /** + * @desc PRIVATE - Perform Shuffling calback + */ + function completeCallback(){ + + if( typeof _oncompleteShuffling==="function" ){ + + _oncompleteShuffling($slot, _active); + + _oncompleteShuffling = null; + + } + + } + + /** + * @desc PRIVATE - Stop shuffling the elements + * @param int||boolean nowOrRepeations - Number of repeations to stop (true to stop NOW) + */ + function _stop( nowOrRepeations, getElementFn ){ + + //Stop animation + if( _currentAnim!==null ){ + _currentAnim.stop(); + } + + //Get element + var rnd; + if( typeof getElementFn==="function" ){ + + rnd = getElementFn(); + + }else{ + if( settings.randomize!==null && typeof settings.randomize==='function' ){ + rnd = _getCustom(); + }else if( settings.repeat ){ + rnd = _getNext(); + }else{ + rnd = _getRandom(); + } + + } + + //Stop animation NOW!!!!!!! + if( nowOrRepeations===true || nowOrRepeations<=1 ){ + + _setAnimationFX("slow", true); + + //get random element offset + var offset = _getOffset(rnd.index); + + //Exception: first element + if( rnd.index===0 ){ + $container.css("margin-top", -$( rnd.el ).height() / 2 ); + } + + var delay = 75 * $titles.length - rnd.index; + + if( _isVisible() ){ + + _setActive( rnd ); + + //Perform animation + $container.animate({ + marginTop : offset + }, delay, "easeOutBounce", completeCallback); + + }else{ + + _setAnimationFX("stop"); + + _resetPosition(); + + } + + //Oncomplete animation + setTimeout(function(){ + + _setAnimationFX("stop"); + + _isRunning = false; + + }, delay + 25); + + //Stop animation sloooooooowly + }else{ + + _shuffle(nowOrRepeations || 3); + + } + + } + + /** + * @desc PRIVATE - Checks if the machine is on the screen + * @return int - Returns true if machine is on the screen + */ + function _isVisible(){ + //Stop animation if element is [above||below] screen, best for performance + var above = $slot.offset().top > $(window).scrollTop() + $(window).height(), + below = $(window).scrollTop() > $slot.height() + $slot.offset().top; + + return !above && !below; + } + + /** + * @desc PRIVATE - Start auto shufflings, animation stops each 3 repeations. Then restart animation recursively + */ + function _auto( delay ){ + + if( _forceStop===false ){ + + delay = delay===undefined ? 1 : settings.repeat + 1000; + + _timer = setTimeout(function(){ + + if( _forceStop===false ){ + + _shuffle(3); + + } + + _timer = _auto( delay ); + + }, delay); + + } + + } + + $slot.css("overflow", "hidden"); + + //Wrap elements inside $container + $titles.wrapAll("
"); + $container = $slot.find(".slotMachineContainer"); + + //Set max top offset + _maxTop = - $container.height(); + + //Show active element + $container.css("margin-top", _getOffset(settings.active) ); + + //Start auto animation + if( settings.repeat!==false ){ + + _auto(); + + } + + + //Public methods + + + /** + * @desc PUBLIC - Starts shuffling the elements + * @param int count - Number of shuffles (undefined to make infinite animation + */ + $slot.shuffle = function( count, oncomplete ){ + + _forceStop = false; + + _oncompleteShuffling = oncomplete; + + _shuffle(count); + + }; + + /** + * @desc PUBLIC - Stop shuffling the elements + * @param int||boolean nowOrRepeations - Number of repeations to stop (true to stop NOW) + */ + $slot.stop = function( nowOrRepeations ){ + + _forceStop = true; + + if( settings.repeat!==false && _timer!==null ){ + + clearTimeout(_timer); + + } + + _stop(nowOrRepeations); + + }; + + /** + * @desc PUBLIC - SELECT previous element relative to the current active element + */ + $slot.prev = function(){ + + _stop(true, _getPrev); + + }; + + /** + * @desc PUBLIC - SELECT next element relative to the current active element + */ + $slot.next = function(){ + + _stop(true, _getNext); + + }; + + /** + * @desc PUBLIC - Get selected element + * @return object - Element index and HTML node + */ + $slot.active = function(){ + return _getActive(); + }; + + /** + * @desc PUBLIC - Check if the machine is doing stuff + * @return boolean - Machine is shuffling + */ + $slot.isRunning = function(){ + return _isRunning; + }; + + /** + * @desc PUBLIC - Start auto shufflings, animation stops each 3 repeations. Then restart animation recursively + */ + $slot.auto = _auto; + + return $slot; + + }; + +})( jQuery, window, document ); \ No newline at end of file diff --git a/dist/jquery.slotmachine.min.js b/dist/jquery.slotmachine.min.js new file mode 100644 index 0000000..1a9f169 --- /dev/null +++ b/dist/jquery.slotmachine.min.js @@ -0,0 +1,4 @@ +/*! SlotMachine - v1.0.0 - 2014-06-23 +* https://github.com/josex2r/jQuery-SlotMachine +* Copyright (c) 2014 Jose Luis Represa; Licensed MIT */ +!function(a,b,c,d){a(c).ready(function(){a("filter#slotMachineBlurSVG").length<=0&&a("body").append(''),a("filter#slotMachineBlurSVG").length<=0&&a("body").append(''),a("filter#slotMachineBlurSVG").length<=0&&a("body").append(''),a("mask#slotMachineFadeSVG").length<=0&&a("body").append(''),a("body").append("")}),"function"!=typeof a.easing.easeOutBounce&&a.extend(a.easing,{easeOutBounce:function(a,b,c,d,e){return(b/=e)<1/2.75?7.5625*d*b*b+c:2/2.75>b?d*(7.5625*(b-=1.5/2.75)*b+.75)+c:2.5/2.75>b?d*(7.5625*(b-=2.25/2.75)*b+.9375)+c:d*(7.5625*(b-=2.625/2.75)*b+.984375)+c}}),a.fn.slotMachine=function(c){function e(b){for(var c=0,d=0;b>d;d++)c+=a(w.get(d)).outerHeight();return-c}function f(){var a;do a=Math.floor(Math.random()*w.length);while(a===C.index&&a>=0);var b={index:a,el:w.get(a)};return b}function g(){var a={};if(null!==c.randomize&&"function"==typeof c.randomize){var b=c.randomize(C.index);(0>b||b>=w.length)&&(b=0),a={index:b,el:w.get(b)}}else a=f();return a}function h(){var a=C.index-1<0?w.length-1:C.index-1,b={index:a,el:w.get(a)};return b}function i(){var a=C.index+1=1?(a>1?(l("fast",!0),b/=2):l("medium",!0),q()?y=t.animate({marginTop:u},b,function(){y=null,t.css("margin-top",0)}):(l("stop"),m()),setTimeout(function(){n(a-1)},b+25)):p(!0)}function o(){"function"==typeof A&&(A(v,C),A=null)}function p(b,d){null!==y&&y.stop();var h;if(h="function"==typeof d?d():null!==c.randomize&&"function"==typeof c.randomize?g():c.repeat?i():f(),b===!0||1>=b){l("slow",!0);var j=e(h.index);0===h.index&&t.css("margin-top",-a(h.el).height()/2);var p=75*w.length-h.index;q()?(k(h),t.animate({marginTop:j},p,"easeOutBounce",o)):(l("stop"),m()),setTimeout(function(){l("stop"),B=!1},p+25)}else n(b||3)}function q(){var c=v.offset().top>a(b).scrollTop()+a(b).height(),d=a(b).scrollTop()>v.height()+v.offset().top;return!c&&!d}function r(a){z===!1&&(a=a===d?1:c.repeat+1e3,x=setTimeout(function(){z===!1&&n(3),x=r(a)},a))}var s={active:0,delay:200,repeat:!1,randomize:null};c=a.extend(s,c);var t,u,v=a(this),w=v.children(),x=null,y=null,z=!1,A=null,B=!1,C={index:c.active,el:w.get(c.active)};return v.css("overflow","hidden"),w.wrapAll("
"),t=v.find(".slotMachineContainer"),u=-t.height(),t.css("margin-top",e(c.active)),c.repeat!==!1&&r(),v.shuffle=function(a,b){z=!1,A=b,n(a)},v.stop=function(a){z=!0,c.repeat!==!1&&null!==x&&clearTimeout(x),p(a)},v.prev=function(){p(!0,h)},v.next=function(){p(!0,i)},v.active=function(){return j()},v.isRunning=function(){return B},v.auto=r,v}}(jQuery,window,document); \ No newline at end of file diff --git a/index.html b/index.html index aa0b6b9..8560fe8 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,7 @@ - + @@ -146,6 +146,81 @@
+ +
+ +
+ +
+

Trick your results:

+
+ +
+
+
+
+
+
+
+
+
+ +
GO!
+ + +
+
+
+
+
+
+
+
+ + +
+ +
+
Index: 0
+
+
+ +
+
+ +
diff --git a/src/jquery.slotmachine.js b/src/jquery.slotmachine.js index f163202..81d37a3 100644 --- a/src/jquery.slotmachine.js +++ b/src/jquery.slotmachine.js @@ -5,7 +5,7 @@ * Copyright 2014 Jose Luis Represa * Released under the MIT license */ -(function($) { +;(function($, window, document, undefined){ //Set required styles, filters and masks @@ -94,7 +94,8 @@ var defaults = { active : 0, //Active element [int] delay : 200, //Animation time [int] - repeat : false //Repeat delay [false||int] + repeat : false, //Repeat delay [false||int] + randomize : null //Randomize function, must return an integer with the selected position }; settings = $.extend(defaults, settings); //Plugin settings @@ -145,21 +146,24 @@ } /** - * @desc PRIVATE - Get currently active element - * @return object elWithIndex - Element index and HTML node - */ - function _getActive(){ - //Update last choosen element index - return _active; - } - - /** - * @desc PRIVATE - Set currently showing element and makes active - * @param object elWithIndex - Element index and HTML node - */ - function _setActive( elWithIndex ){ - //Update last choosen element index - _active = elWithIndex; + * @desc PRIVATE - Get the randomize setting function element + * @return int - Element index and HTML node + */ + function _getCustom(){ + var choosen = {}; + if( settings.randomize!==null && typeof settings.randomize==='function' ){ + var index = settings.randomize(_active.index); + if( index<0 || index>=$titles.length ){ + index = 0; + } + choosen = { + index : index, + el : $titles.get( index ) + }; + }else{ + choosen = _getRandom(); + } + return choosen; } /** @@ -188,6 +192,24 @@ return nextObj; } + /** + * @desc PRIVATE - Get currently active element + * @return object elWithIndex - Element index and HTML node + */ + function _getActive(){ + //Update last choosen element index + return _active; + } + + /** + * @desc PRIVATE - Set currently showing element and makes active + * @param object elWithIndex - Element index and HTML node + */ + function _setActive( elWithIndex ){ + //Update last choosen element index + _active = elWithIndex; + } + /** * @desc PRIVATE - Set CSS classes to make speed effect * @param string speed - Element speed [fast||medium||slow] @@ -369,11 +391,14 @@ rnd = getElementFn(); }else{ - if( settings.repeat ){ + if( settings.randomize!==null && typeof settings.randomize==='function' ){ + rnd = _getCustom(); + }else if( settings.repeat ){ rnd = _getNext(); }else{ rnd = _getRandom(); } + } //Stop animation NOW!!!!!!! @@ -445,7 +470,7 @@ if( _forceStop===false ){ - delay = delay===undefined ? 1 : settings.repeat + 1725; + delay = delay===undefined ? 1 : settings.repeat + 1000; _timer = setTimeout(function(){ @@ -561,4 +586,4 @@ }; -})(jQuery); +})( jQuery, window, document ); \ No newline at end of file