1

First question, so please let me know if I could/should be asking this more succinctly/clearly...

I'm working on an experimental script that vibrates objects with a given class with increasing intensity over time. I'm working with jRumble as a base. My script needs to get the initial CSS position of objects to be vibrated and then add the modifying var. I set this up like so at first:

$this.animate({
    'left': parseFloat($this.css( "left" )) + rx + 'px',

which works great in Chrome, but Safari and iOS return different values. This explained the problem: jquery $('selector').css('top') returns different values for IE, firefox and Chrome, so I switched to using .offset:

offset = $(".offreg").offset();

...

'left': offset.left + rx + 'px', 

but this is problematic because the script iterates-- .offset returns the current position each time instead of the initial one. I tried placing the var outside of the iterating section, but this (obviously) doesn't work because it is no longer associated with the "this" of the rumble script. The var is then set at the value of the first element with class .offreg.

The page itself is here: http://sallymaier.github.io/off-register/ I'm going to revert to the last version that worked in Chrome. My github is public, so you can see my mess-making there I think.

Full script as it works in Chrome below:

var offRegister = function() {

    if (!($ = window.jQuery)) { // see if jQuery is already called, if not, calling script
      script = document.createElement( 'script' );
      script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js'; 
      script.onload=runRumbler;
      document.body.appendChild(script);
    } 
    else {
      runRumbler();
    }

    function runRumbler() {      
        $(document).ready(function(){

            var count = 0;

            $(function addone(){
                count = count+1;

                (function($) {
                  $.fn.jrumble = function(options){  // jRumble by Jack Rugile. http://jackrugile.com/jrumble/

                    /*========================================================*/
                    /* Options
                    /*========================================================*/
                    var defaults = {
                      x: count/5,
                      y: count/5,
                      rotation: 0,
                      speed: 200,
                      opacity: false,
                      opacityMin: .5
                    },
                    opt = $.extend(defaults, options);  

                    return this.each(function(){

                      /*========================================================*/
                      /* Variables
                      /*========================================================*/
                      var $this = $(this),        
                        x = opt.x*2,
                        y = opt.y*2,
                        rot = opt.rotation*2,
                        speed = (opt.speed === 0) ? 1 : opt.speed,      
                        opac = opt.opacity,
                        opacm = opt.opacityMin,
                        inline,
                        interval;

                      /*========================================================*/
                      /* Rumble Function
                      /*========================================================*/    
                      var rumbler = function(){       
                        var rx = Math.floor(Math.random() * (x+1)) -x/2,
                            ry = Math.floor(Math.random() * (y+1)) -y/2,
                            rrot = Math.floor(Math.random() * (rot+1)) -rot/2,
                            ropac = opac ? Math.random() + opacm : 1;

                        /*========================================================*/
                        /* Ensure Movement From Original Position
                        /*========================================================*/        
                        rx = (rx === 0 && x !== 0) ? ((Math.random() < .5) ? 1 : -1) : rx;
                        ry = (ry === 0 && y !== 0) ? ((Math.random() < .5) ? 1 : -1) : ry;  

                        /*========================================================*/
                        /* Check Inline
                        /*========================================================*/
                        if($this.css('display') === 'inline'){
                          inline = true;
                          $this.css('display', 'inline-block');
                        }

                        /*========================================================*/
                        /* Rumble Element
                        /*========================================================*/      
                        $this.animate({
                          'left': parseFloat($this.css( "left" )) + rx + 'px', // move from declared position
                          'top': parseFloat($this.css( "top" )) + ry+'px',
                          '-ms-filter':'progid:DXImageTransform.Microsoft.Alpha(Opacity='+ropac*100+')',
                          'filter':'alpha(opacity='+ropac*100+')',          
                          '-moz-opacity':ropac,         
                          '-khtml-opacity':ropac,         
                          'opacity':ropac,
                          '-webkit-transform':'rotate('+rrot+'deg)', 
                          '-moz-transform':'rotate('+rrot+'deg)', 
                          '-ms-transform':'rotate('+rrot+'deg)',
                          '-o-transform':'rotate('+rrot+'deg)', 
                          'transform':'rotate('+rrot+'deg)'
                        });

                      }; /* close rumble function */

                      /*========================================================*/
                      /* Rumble CSS Reset
                      /*========================================================*/
                      var reset = {
                        'left':0,
                        'top':0,
                        '-ms-filter':'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)',
                        'filter':'alpha(opacity=100)',          
                        '-moz-opacity':1,         
                        '-khtml-opacity':1,         
                        'opacity':1,
                        '-webkit-transform':'rotate(0deg)',
                        '-moz-transform':'rotate(0deg)',
                        '-ms-transform':'rotate(0deg)',
                        '-o-transform':'rotate(0deg)',
                        'transform':'rotate(0deg)'
                      };

                      /*========================================================*/
                      /* Rumble Start/Stop Trigger
                      /*========================================================*/
                        $this.bind({
                        'startRumble': function(e){
                          e.stopPropagation();
                          clearInterval(interval);
                          interval = setInterval(rumbler, speed)
                        },
                        'stopRumble': function(e){
                          e.stopPropagation();
                          clearInterval(interval);
                          if(inline){
                            $this.css('display', 'inline');
                          }
                          $this.css(reset);
                        }
                      });   

                    });// End return this.each
                  };// End $.fn.jrumble

                })(jQuery);

                /*===============================================================*/
                /* Specify selector to vibrate below. 
                /* For bookmarklet, 'div' will vibrate all elements, 
                /* in plugin this can be specifically targeted to a class or id.
                /*===============================================================*/

                $('.offreg').jrumble();    
                $('.offreg').trigger('startRumble');

             setTimeout(addone, 1000); // how many seconds to wait before adding to count, increasing vibration

            }); // end addone()

         });
    };
  };

offRegister();
Community
  • 1
  • 1

2 Answers2

1

I've been playing around with this source code the last couple minutes, and it seems to me the problem stems from the use of position: absolute on the rumbling elements themselves. In the jRumble docs http://jackrugile.com/jrumble/#documentation it says that 'For rumble elements that are position fixed/absolute, they should instead be wrapped in an element that is fixed/absolute'.

So if you set your container element to position: absolute and then position all the interior divs relative to the container, you'll no longer need to alter the jRumble source code and redefine the plugin every iteration to change the default position or compute the offset of each element - all you'll have to do is increment the x and y values in the jRumble call itself.

The code below is UNTESTED, but I think you want something closer to this (again, this all hinges on the .offreg elements being position: relative):

$(document).ready(function(){
  var count = 0;

  function addone(){
    count++;
    $('.offreg').jrumble({
      x: count,
      y: count,
      rotation: 1
    });
    $('.offreg').trigger('startRumble');

    setTimeout(addone, 1000);
  }
});
Sean
  • 372
  • 2
  • 13
  • Here's a proof of concept http://codepen.io/seans887/pen/jEVXwB I removed the other elements and made it as simple as possible, but it illustrates that you don't need to alter the plugin itself to get the effect you want. Ultimately it's a CSS problem to just get all those divs lined up correctly without the use of `position: absolute` – Sean Jan 06 '15 at 04:33
  • yes, this makes a lot of sense. I've gotten so into figuring out the jquery that I've forgotten to consider the simple solution first (and reread the documentation! ;)). I'm going to give this a try now! – Sally Maier Jan 06 '15 at 22:24
  • Thanks again, @Sean. Got it working, looks good on mobile too! – Sally Maier Jan 07 '15 at 08:43
1

I like Sean's answer of sidestepping the need for adding code to override $.fn.jrumble, which creates a brittle maintenance point and makes $.fn.jrumble unusable outside this code block (since it depends on the variable "count").

For the immediate issue of the variable scope, if you still need to solve that problem, I'd suggest moving the redefinition of $.fn.jrumble out of addone(), and then scoping a variable, "offset", outside of said redefinition. Then refer to that variable in your call to $this.animate(). Code is below, but again, Sean's answer should make this unnecessary.

var offRegister = function() {
    if (!($ = window.jQuery)) { // see if jQuery is already called, if not, calling script
        script = document.createElement( 'script' );
        script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js'; 
        script.onload=runRumbler;
        document.body.appendChild(script);
    } 
    else {
        runRumbler();
    }
};
function runRumbler() {
    $(document).ready(function(){
        var count = 0;
        var offset;
        function addone() {
            ...
            $('.offreg').jrumble();    
            $('.offreg').trigger('startRumble');
            offset = $('.offreg').offset();
            setTimeout(addone, 1000); // how many seconds to wait before adding to 
        }
        (function($){
            $.fn.jrumble = function(options){
                ...
                $this.animate({
                      'left': parseFloat(offset) + rx + 'px',
                      ...
                });
                ...
            };
        )(jQuery);
        ...

}
offRegister();

Another suggestion: make the whole thing an anonymous function. Instead of:

var offRegister = function() {
    ...
}
offRegister();

Try:

(function(){
    ...
})();

That way you don't stick a variable "offRegister" in the global namespace. In this case, doing so isn't a problem, but in general code that you want to reuse elsewhere is cleaner if it doesn't introduce new globals.

dfrishberg
  • 111
  • 1
  • 4
  • Thanks, @dfrishberg! This is really helpful for me figuring out how to solve problems like this one in the future--but for this specific instance, I agree that Sean's solution is the best--might as well fix it in the CSS instead of fixing a problem I made myself in the script. – Sally Maier Jan 07 '15 at 08:41