14

I've been given a cut down subset of the jQuery lib one of the key features I'm missing is the .effect functions. I do however have .animate. I was wondering if anyone would have any ideas how I could go about reproducing the animation functions.

I am particularly consious of making this only a few lines as I need to keep the code size down. Which is why the jquery lib is as small as it is and doesnt have the effects functions.

TLDR - I'm trying to replace

 $("#"+id_string).effect( "shake", {}, "fast" );

With something using .animate within jQuery.

karim79
  • 339,989
  • 67
  • 413
  • 406
wmitchell
  • 5,665
  • 10
  • 37
  • 62

10 Answers10

45

So far I have something like this ..

jQuery.fn.shake = function(intShakes, intDistance, intDuration) {
    this.each(function() {
        $(this).css("position","relative"); 
        for (var x=1; x<=intShakes; x++) {
        $(this).animate({left:(intDistance*-1)}, (((intDuration/intShakes)/4)))
    .animate({left:intDistance}, ((intDuration/intShakes)/2))
    .animate({left:0}, (((intDuration/intShakes)/4)));
    }
  });
return this;
};
wmitchell
  • 5,665
  • 10
  • 37
  • 62
16

I like @phpslightly solution so much, I keep using it. So here it is updated to basic jquery plugin form which will return your element

jQuery.fn.shake = function(interval,distance,times){
   interval = typeof interval == "undefined" ? 100 : interval;
   distance = typeof distance == "undefined" ? 10 : distance;
   times = typeof times == "undefined" ? 3 : times;
   var jTarget = $(this);
   jTarget.css('position','relative');
   for(var iter=0;iter<(times+1);iter++){
      jTarget.animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
   }
   return jTarget.animate({ left: 0},interval);
}

You would then use it like a regular plugin:

$("#your-element").shake(100,10,3);

Or use the default values (100, 10, 3):

$("#your-element").shake();
el producer
  • 321
  • 3
  • 9
  • Why not just put default value in the param like so ? `function (interval = 100, distance = 10, times = 1){` – Warface Feb 08 '19 at 13:40
9

It's actually already implemented this way under the covers, you can see exactly how in jquery.effects.shake.js, if you wanted to copy only that functionality you can.

Another approach to think about: if you're using multiple effects, I'd recommend downloading jQuery UI with only the effects you want. For this effect, without copying the functionality yourself, you would just need jquery.effects.core.js and jquery.effects.shake.js.

aleclarson
  • 18,087
  • 14
  • 64
  • 91
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • As I'm stuck in a severly cut down version of jquery I dont have access to the effects code at all. I had been playing with the following .. have to add it as answer as cant seem to format in replies. – wmitchell Dec 09 '10 at 14:40
  • @wmitchell - I linked you to the source code in the answer :) – Nick Craver Dec 09 '10 at 14:41
  • 5
    New links: [jquery.ui.effect.js](https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.effect.js) and [jquery.ui.effect.shake.js](https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.effect-shake.js) – Nicolas Cadilhac Sep 29 '12 at 15:07
  • 3
    New links again: [effect.js](https://github.com/jquery/jquery-ui/blob/master/ui/effect.js) and [effect-shake.js](https://github.com/jquery/jquery-ui/blob/master/ui/effect-shake.js) – Nicolas Cadilhac Apr 29 '14 at 15:05
  • or http://codingstuffsbykiran.blogspot.com/2014/06/jquery-shake-effect-part-2.html – kiran Jun 20 '14 at 16:04
  • 2
    new links again [effect.js](http://stackoverflow.com/questions/4399005/implementing-jquerys-shake-effect-with-animate) and [effect-shake.js](https://github.com/jquery/jquery-ui/blob/master/ui/effects/effect-shake.js) – Sahil Oct 17 '16 at 11:08
  • New links again: https://github.com/jquery/jquery-ui/blob/master/ui/effect.js and https://github.com/jquery/jquery-ui/blob/master/ui/effects/effect-shake.js – Ari Seyhun Jun 04 '17 at 06:53
6

This is probably irrelevant now but I've ported jQ UI's shake effect as a standalone jQuery plugin. All you need is jQuery and it will work exactly like the one provided in jQ UI.

For those who want to use the effect without actually bloating their project with unnecessary jQ UI core files.

$('#element').shake({...});

It can be found here with instruction: https://github.com/ninty9notout/jquery-shake

Thought I'd leave this here for future reference.

ninty9notout
  • 1,121
  • 8
  • 11
4

This is a more clean and smooth way to do the animation.

jQuery.fn.shake = function(shakes, distance, duration) {
    if(shakes > 0) {
        this.each(function() {
            var $el = $(this);
            var left = $el.css('left');
            $el.animate({left: "-=" + distance}, duration, function(){
                $el.animate({left: "+=" + distance * 2}, duration, function() {
                    $el.animate({left: left}, duration, function() {
                        $el.shake(shakes-1, distance, duration); });});
            });
        });
    }
    return this;
};
leek
  • 11,803
  • 8
  • 45
  • 61
Guilherme Oliveira
  • 2,132
  • 1
  • 14
  • 20
3

I don't understand all the complexity being thrown into reproducing the shake effect with solely animate. Here's my solution in just a couple lines.

function shake(div,interval=100,distance=10,times=4){
    $(div).css('position','relative');
    for(var iter=0;iter<(times+1);iter++){
        $(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
    }//for
    $(div).animate({ left: 0},interval);
}//shake

EDIT: Updated code to return element to original position. Still believe this is the lightest and best solution to the problem.

phpslightly
  • 304
  • 3
  • 6
2

I wrote some time ago a few simple jquery animations:

https://github.com/yckart/jquery-custom-animations

/**
 * @param {number} times - The number of shakes
 * @param {number} duration - The speed amount
 * @param {string} easing - The easing method
 * @param {function} complete - A callback function
 */
jQuery.fn.shake =
jQuery.fn.wiggle = function (times, duration, easing, complete) {
    var self = this;

    if (times > 0) {
        this.animate({
            marginLeft: times-- % 2 === 0 ? -15 : 15
        }, duration, easing, function () {
            self.wiggle(times, duration, easing, complete);
        });
    } else {
        this.animate({
            marginLeft: 0
        }, duration, easing, function () {
            if (jQuery.isFunction(complete)) {
                complete();
            }
        });
    }
    return this;
};
yckart
  • 32,460
  • 9
  • 122
  • 129
  • you may also try this http://codingstuffsbykiran.blogspot.com/2014/06/jquery-shake-effect-part-2.html – kiran Jul 01 '14 at 20:03
0

This is not perfect, but functional

    // Example: $('#<% =ButtonTest.ClientID %>').myshake(3, 120, 3, false);
    jQuery.fn.myshake = function (steps, duration, amount, vertical) {
        var s = steps || 3;
        var d = duration || 120;
        var a = amount || 3;
        var v = vertical || false;
        this.css('position', 'relative');
        var cur = parseInt(this.css(v ? "top" : "left"), 10);
        if (isNaN(cur))
            cur = 0;

        var ds = d / s;

        if (v) {
            for (i = 0; i < s; i++)
                this.animate({ "top": cur + a + "px" }, ds).animate({ "top": cur - a + "px" }, ds);
            this.animate({ "top": cur }, 20);
        }
        else {
            for (i = 0; i < s; i++)
                this.animate({ "left": cur + a }, ds).animate({ "left": cur - a + "px" }, ds);
            this.animate({ "left": cur }, 20);
        }

        return this;
    }
Steinwolfe
  • 81
  • 1
  • 4
0

Based on @el producer solution, I added some multiply logic and make it look like a random shake.

jQuery.fn.shake = function (interval, distance, times) {
    interval = typeof interval == "undefined" ? 100 : interval;
    distance = typeof distance == "undefined" ? 10 : distance;
    times = typeof times == "undefined" ? 3 : times;
    var jTarget = $(this);
    jTarget.css('position', 'relative');
    for (var iter = 0; iter < (times + 1) ; iter++) {
        jTarget.animate({ top: ((iter % 2 == 0 ? distance * Math.random() : distance * Math.random() * -1)), left: ((iter % 2 == 0 ? distance * Math.random() : distance * Math.random() * -1)) }, interval);
    }
    return jTarget.animate({ top: 0 , left: 0 }, interval);
}
Chen Wang
  • 33
  • 7
0

Position had to be absolute on my side, so I changed it to:

jQuery.fn.shake = function(interval, distance, times) {
  interval = typeof interval == "undefined" ? 100 : interval;
  distance = typeof distance == "undefined" ? 10 : distance;
  times = typeof times == "undefined" ? 3 : times;
  var jTarget = $(this);
  for (var iter=0;iter<(times+1);iter++) {
    jTarget.animate({ 'padding-left': ((iter%2==0 ? distance : distance*-1))}, interval);
  }
  return jTarget.animate({ 'padding-left': 0 } ,interval);
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31