letops
4/21/2017 - 1:54 AM

Stack.html

<!-- https://tympanus.net/codrops/2017/03/15/stack-motion-hover-effects/ -->

<style>
  .stack {
    position: relative;
    width: 100%;
    height: 200px;
    transform-style: preserve-3d;
  }

  .stack__deco {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: currentColor;
    transform-origin: 50% 100%;
  }

  .stack__deco:first-child {
    opacity: 0.2;
  }

  .stack__deco:nth-child(2) {
    opacity: 0.4;
  }

  .stack__deco:nth-child(3) {
    opacity: 0.6;
  }

  .stack__deco:nth-child(4) {
    opacity: 0.8;
  }

  .stack__figure {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
    width: 100%;
    height: 100%;
    cursor: pointer;
    transform-origin: 50% 100%;
  }

  .stack__img {
    position: relative;
    display: block;
    flex: none;
  }
</style>




<div class='wrapper'>
  <div class='stack'>
    <div class='stack__deco'></div>
    <div class='stack__deco'></div>
    <div class='stack__deco'></div>
    <div class='stack__deco'></div>
    <div class='stack__figure'>
      <img class='stack__img' alt="Image"/>
    </div>
  </div>
</div>



<script>
  ;(function(window) {

    'use strict';

    /**
     * StackFx: The parent class.
     */
    function StackFx(el) {
      this.DOM = {};
      this.DOM.el = el;
      this.DOM.stack = this.DOM.el.querySelector('.stack');
      this.DOM.stackItems = [].slice.call(this.DOM.stack.children);
      this.totalItems = this.DOM.stackItems.length;
      this.DOM.img = this.DOM.stack.querySelector('.stack__figure > .stack__img');
    }

    StackFx.prototype._removeAnimeTargets = function() {
      anime.remove(this.DOM.stackItems);
      anime.remove(this.DOM.img);
    };


    /************************************************************************
     * HamalFx.
     ************************************************************************/
    function HamalFx(el) {
      StackFx.call(this, el);
      this._initEvents();
    }

    HamalFx.prototype = Object.create(StackFx.prototype);
    HamalFx.prototype.constructor = HamalFx;

    HamalFx.prototype._initEvents = function() {
      var self = this;
      this._mouseenterFn = function() {
        self._removeAnimeTargets();
        self._in();
      };
      this._mouseleaveFn = function() {
        self._removeAnimeTargets();
        self._out();
      };
      this.DOM.stack.addEventListener('mouseenter', this._mouseenterFn);
      this.DOM.stack.addEventListener('mouseleave', this._mouseleaveFn);
    };

    HamalFx.prototype._in = function() {
      var self = this;

      this.DOM.stackItems.map(function(e, i) {
        e.style.opacity = i !== self.totalItems - 1 ? 0.2*i+0.2 : 1
      });

      anime({
        targets: this.DOM.stackItems,
        duration: 1000,
        easing: 'easeOutExpo',
        translateY: function(target, index) {
          return -1*index*5;
        },
        rotate: function(target, index, cnt) {
          if( index === cnt - 1 ) {
            return 0;
          }
          else {
            return index%2 ? (cnt-index)*1 : -1*(cnt-index)*1;
          }
        },
        scale: function(target, index, cnt) {
          if( index === cnt - 1 ) {
            return 1;
          }
          else {
            return 1.05;
          }
        },
        delay: function(target, index, cnt) {
          return (cnt-index-1)*30
        }
      });
      
      anime({
        targets: this.DOM.img,
        duration: 1000,
        easing: 'easeOutExpo',
        scale: 0.7
      });
  
    };

    HamalFx.prototype._out = function() {
      var self = this;

      anime({
        targets: this.DOM.stackItems,
        duration: 500,
        easing: 'easeOutExpo',
        translateY: 0,
        rotate: 0,
        scale: 1,
        opacity: function(target, index, cnt) {
          return index !== cnt - 1 ? 0 : 1
        }
      });

      anime({
        targets: this.DOM.img,
        duration: 1000,
        easing: 'easeOutElastic',
        scale: 1
      });
    };

    window.HamalFx = HamalFx;
  })(window);

  
  (function() {
    [].slice.call(document.querySelectorAll('.wrapper')).forEach(function(stackEl) {
      new HamalFx(stackEl);
    });
  })();
</script>