Search code examples
javascriptgsap

TweenMax reuse function for all element ID's


I'm using a Tweenmax script I found to create a ripple effect on some buttons. I have HTML as follows:

<label for="slider_1" id="js-ripple-btn" class="button styl-material">
Home
<svg class="ripple-obj" id="js-ripple"><use height="100" width="100" xlink:href="#ripply-scott" class="js-ripple"></use></svg>
</label>

<label for="slider_2" id="js-ripple-btn2" class="button styl-material">
Catalogue
<svg class="ripple-obj" id="js-ripple2"><use height="100" width="100" xlink:href="#ripply-scott" class="js-ripple2"></use></svg>
</label>

...

I'm a bit lost on how to have the script listen for any of the ID's that have the js-ripple class rather than specify just one. The following code only targets the first element ID but I need it to target whichever element ID is clicked.

var ripplyScott = (function() {
var circle = document.getElementById('js-ripple'),
  ripple = document.querySelectorAll('.js-ripple');

function rippleAnimation(event, timing) {
var tl           = new TimelineMax();
    x            = event.offsetX,
    y            = event.offsetY,
    w            = event.target.offsetWidth,
    h            = event.target.offsetHeight,
    offsetX      = Math.abs( (w / 2) - x ),
    offsetY      = Math.abs( (h / 2) - y ),
    deltaX       = (w / 2) + offsetX,
    deltaY       = (h / 2) + offsetY,
    scale_ratio  = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));

console.log('x is:' + x);
console.log('y is:' + y);
console.log('offsetX is:' + offsetX);
console.log('offsetY is:' + offsetY);
console.log('deltaX is:' + deltaX);
console.log('deltaY is:' + deltaY);
console.log('width is:' + w);
console.log('height is:' + h);
console.log('scale ratio is:' + scale_ratio);

tl.fromTo(ripple, timing, {
  x: x,
  y: y,
  transformOrigin: '50% 50%',
  scale: 0,
  opacity: 1,
  ease: Linear.easeIn
},{
  scale: scale_ratio,
  opacity: 0
});

return tl;
}

return {
init: function(target, timing) {
  var button = document.getElementById(target);

  button.addEventListener('click', function(event) {
    rippleAnimation.call(this, event, timing);
  });
}
};
})();

ripplyScott.init('js-ripple-btn', 0.75);

I can obviously duplicate the script changing the element ID to each button but that means, I'm sure, ridiculous repeating of code when there must be a way of targeting all with a slight modification. Help/guidance is appreciated thanks!

** Update ** Here is a fiddle so you can sort of see my issue. Thanks.


Solution

  • I have made an attempt on solving your problem based on my understanding. Take a look at this jsFiddle.

    Here is the explanation:

    • IDs should always be unique to elements.
    • Your js-ripple-btn ID has been changed to class.
    • We needed a way to get a reference to the button that has been clicked so that we can play respective animation.
    • We solved that by using an index variable from buttons passing them all the way down to your animations.

    Snippet:

    var ripplyScott = (function() {
      var circle = document.getElementById('js-ripple');
      var ripple = document.querySelectorAll('.js-ripple');
    
      function rippleAnimation(event, timing, index) {
        var tl = new TimelineMax();
        var x = event.offsetX;
        var y = event.offsetY;
        var w = event.target.offsetWidth;
        var h = event.target.offsetHeight;
        var offsetX = Math.abs((w / 2) - x);
        var offsetY = Math.abs((h / 2) - y);
        var deltaX = (w / 2) + offsetX;
        var deltaY = (h / 2) + offsetY;
        var scale_ratio = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
    
        tl.fromTo(ripple[index], timing, {
          x: x,
          y: y,
          transformOrigin: '50% 50%',
          scale: 0,
          opacity: 1,
          ease: Linear.easeIn
        }, {
          scale: scale_ratio,
          opacity: 0
        });
    
        return tl;
      }
    
      return {
        init: function(target, timing) {
          var buttons = document.getElementsByClassName(target);
          var numButtons = buttons.length;
          for (var i = 0; i < numButtons; i += 1) {
            (function(index) {
              buttons[index].addEventListener('click', function(event) {
                rippleAnimation.call(this, event, timing, index);
              });
            }(i));
          }
        }
      };
    })();
    
    ripplyScott.init('js-ripple-btn', 0.75);
    label {
      border-radius: 0;
      display: block;
      background: #ccc;
      margin: 5px 0;
      cursor: pointer;
      color: #333;
      width: 200px;
      padding: 0;
      font-size: 15px;
      border: 1px solid #333;
      text-align: center;
      height: 70px;
      line-height: 70px;
      overflow: hidden;
    }
    .button {
      padding: 1.5em 3em;
      margin: 0;
      position: relative;
      display: inline-block;
      overflow: hidden;
    }
    .button.styl-material {
      transition: 200ms background cubic-bezier(0.4, 0, 0.2, 1);
    }
    .button.styl-material:hover,
    .button.styl-material:focus {
      outline: none;
    }
    .ripple-obj,
    .ripple-obj2 {
      height: 100%;
      pointer-events: none;
      position: absolute;
      top: 0;
      left: 0;
      z-index: 0;
      width: 100%;
      fill: #AD1457;
    }
    .ripple-obj use,
    .ripple-obj2 use {
      opacity: 0;
    }
    <script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.2/TweenMax.min.js"></script>
    <label class="button styl-material js-ripple-btn" for="slider_1">Home
      <svg class="ripple-obj" id="js-ripple">
        <use class="js-ripple" height="100" width="100" xlink:href="#ripply-scott">
        </use>
      </svg>
    </label>
    <label class="button styl-material js-ripple-btn" for="slider_2">Catalogue
      <svg class="ripple-obj" id="js-ripple2">
        <use class="js-ripple" height="100" width="100" xlink:href="#ripply-scott">
        </use>
      </svg>
    </label>
    
    <!-- Firefox Button Fix -->
    <div aria-hidden="true" style="height: 0; width: 0; position: absolute; visibility: hidden;">
      <svg version="1.1" xmlns="http://www.w3.org/2000/svg">
        <defs>
          <radialgradient id="gradient">
            <stop offset="0" stop-color="#0868BB"></stop>
            <stop offset="0.25" stop-color="#0075D8"></stop>
            <stop offset="0.35" stop-color="#0868BB"></stop>
            <stop offset="0.5" stop-color="#0075D8"></stop>
            <stop offset="0.6" stop-color="#0868BB"></stop>
            <stop offset="0.85" stop-color="#0075D8"></stop>
            <stop offset="1" stop-color="#0868BB"></stop>
          </radialgradient>
        </defs>
        <symbol id="ripply-scott" viewbox="0 0 100 100">
          <circle cx="1" cy="1" fill="url(#gradient)" id="ripple-shape" r="1"></circle>
        </symbol>
      </svg>
    </div>
    <!-- / FF button fix -->

    Hope this helps.