Fig. 4 | Material Design Ripple

In this example below you will see how to do a Fig. 4 | Material Design Ripple with some HTML / CSS and Javascript

For a blogpost: Material Design Ripple

Thumbnail
This awesome code was written by , you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright ⁣ ©
  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Fig. 4 | Material Design Ripple</title>
  
  
  <link rel='stylesheet prefetch' href='css/https___codepen_io_pixela.css'>

      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <span class="bound wire">Area</span><span class="bound wire">Area</span><span class="bound wire">Area</span><span class="bound wire">Area</span><span class="bound wire">Area</span>
  
  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/pixelass/fig-4-or-material-design-ripple-JdqWmQ */
body {
  margin: 50px;
  font-family: sans-serif;
  background: #424242;
}

.wire {
  display: inline-block;
  position: relative;
  width: 5em;
  height: 5em;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4), 0 -1px 3px rgba(0, 0, 0, 0.2);
  font-size: 20px;
  line-height: 5em;
  margin: 1em;
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
  text-align: center;
  border: 0;
  background: white;
  overflow: hidden;
  cursor: pointer;
}
.wire:nth-child(1) {
  background: #a3b9ff;
  color: black;
  height: 135px;
  line-height: 135px;
  width: 135px;
}
.wire:nth-child(1) .ripple {
  background: rgba(0, 0, 0, 0.1);
}
.wire:nth-child(2) {
  background: #f9fff0;
  color: black;
  height: 150px;
  line-height: 150px;
  width: 120px;
}
.wire:nth-child(2) .ripple {
  background: rgba(0, 0, 0, 0.1);
}
.wire:nth-child(3) {
  background: #d1a000;
  color: black;
  height: 90px;
  line-height: 90px;
  width: 150px;
}
.wire:nth-child(3) .ripple {
  background: rgba(0, 0, 0, 0.1);
}
.wire:nth-child(4) {
  background: #004b52;
  color: black;
  color: white;
  height: 90px;
  line-height: 90px;
  width: 165px;
}
.wire:nth-child(4) .ripple {
  background: rgba(0, 0, 0, 0.1);
}
.wire:nth-child(4) .ripple {
  background: rgba(255, 255, 255, 0.1);
}
.wire:nth-child(5) {
  background: #ffb3c8;
  color: black;
  height: 165px;
  line-height: 165px;
  width: 150px;
}
.wire:nth-child(5) .ripple {
  background: rgba(0, 0, 0, 0.1);
}

.ripple {
  position: absolute;
  border-radius: 100%;
  pointer-events: none;
  -webkit-transform: translate(-50%, -50%);
          transform: translate(-50%, -50%);
  -webkit-animation: scale-in .4s ease-in-out;
          animation: scale-in .4s ease-in-out;
  transition: opacity .4s .2s ease-out;
}

@-webkit-keyframes scale-in {
  from {
    -webkit-transform: translate(-50%, -50%) scale(0);
            transform: translate(-50%, -50%) scale(0);
  }
  to {
    -webkit-transform: translate(-50%, -50%) scale(1);
            transform: translate(-50%, -50%) scale(1);
  }
}

@keyframes scale-in {
  from {
    -webkit-transform: translate(-50%, -50%) scale(0);
            transform: translate(-50%, -50%) scale(0);
  }
  to {
    -webkit-transform: translate(-50%, -50%) scale(1);
            transform: translate(-50%, -50%) scale(1);
  }
}


/*Downloaded from https://www.codeseek.co/pixelass/fig-4-or-material-design-ripple-JdqWmQ */
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

/**
 * create instances of ripple containers
 */
var Ripples = function () {
  function Ripples(box) {
    _classCallCheck(this, Ripples);

    this.box = box;
    this.ripples = {};
    this.rippleIndex = 0;
    this.last = 0;
    this.down = false;
    this.appendRipple = this.appendRipple.bind(this);
    this.handleDown = this.handleDown.bind(this);
    this.handleUp = this.handleUp.bind(this);
    this.endIntro = this.endIntro.bind(this);
    this.startOutro = this.startOutro.bind(this);
    this.removeFromDOM = this.removeFromDOM.bind(this);
    box.addEventListener('mousedown', this.handleDown);
    box.addEventListener('mouseup', this.handleUp);
    box.addEventListener('mouseleave', this.handleUp);
  }

  /**
   * adds a ripple to the box
   * @prop {Object({x: Number,y: Number})} coordinates
   * @prop {Number}                        size
   */


  _createClass(Ripples, [{
    key: 'appendRipple',
    value: function appendRipple(coordinates, size) {
      // increase index
      ++this.rippleIndex;
      // create element
      var ripple = document.createElement('div');
      var style = '\n        top: ' + coordinates.y + 'px;\n        left: ' + coordinates.x + 'px;\n        height: ' + size + 'px;\n        width: ' + size + 'px;\n    ';
      ripple.setAttribute('style', style);
      ripple.classList.add('ripple');
      // cache index on ripple
      ripple.index = this.rippleIndex;
      // listen to animation
      ripple.addEventListener('animationend', this.endIntro);
      this.ripples[this.rippleIndex] = {
        element: ripple,
        animating: true
      };
      // appned the element
      this.box.appendChild(ripple);
    }

    /**
     * ends the intro animation
     */

  }, {
    key: 'endIntro',
    value: function endIntro(event) {
      this.ripples[event.target.index].animating = false;
      event.target.removeEventListener('animationend', this.endIntro);
    }

    /**
     * starts the outro animation
     * @prop {Event} event  The event that triggered the action
     */

  }, {
    key: 'startOutro',
    value: function startOutro(event) {
      // update last
      ++this.last;
      // if the trigger was an event we need to clear the listener
      if (event) {
        event.target.removeEventListener('animationend', this.startOutro);
      }
      this.ripples[this.last].element.style.opacity = 0;
      // add a new listener
      this.ripples[this.last].element.addEventListener('transitionend', this.removeFromDOM);
    }

    /**
     * removes the element from the DOM tree
     * @prop {Event} event  The event that triggered the action
     **/

  }, {
    key: 'removeFromDOM',
    value: function removeFromDOM(event) {
      // remove element and listeners
      event.target.removeEventListener('transitionend', this.removeFromDOM);
      delete this.ripples[event.target.index];
      event.target.remove();
    }

    /**
     * handles the up event inside the box
     * @prop {Event} event  The event that triggered the action
     */

  }, {
    key: 'handleUp',
    value: function handleUp(event) {

      // don't proceed if we didn't press
      if (!this.down) {
        return;
      }
      this.down = false;
      if (this.ripples[this.rippleIndex].animating) {
        // if the ripple is still animating we need to wait
        this.ripples[this.rippleIndex].element.addEventListener('animationend', this.startOutro);
      } else {
        // otherwise we can start removing the ripple
        this.startOutro();
      }
    }

    /**
     * handles the down event inside the box
     * @prop {Event} event  The event that triggered the action
     */

  }, {
    key: 'handleDown',
    value: function handleDown(event) {
      // get event coordinates
      this.down = true;
      var y = event.layerY;
      var x = event.layerX;
      // get event dimensions
      var w = event.target.offsetWidth;
      var h = event.target.offsetHeight;
      // get offset
      var offsetX = Math.abs(w / 2 - x);
      var offsetY = Math.abs(h / 2 - y);
      // get delta
      var deltaX = w / 2 + offsetX;
      var deltaY = h / 2 + offsetY;
      // calculate size
      var size = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2) - 2 * deltaX * deltaY * Math.cos(90 / 180 * Math.PI)) * 2;

      this.appendRipple({
        x: x,
        y: y
      }, size);
    }
  }]);

  return Ripples;
}();

// get all boxes


var boxes = document.querySelectorAll('.bound');

// call an instance for each box
Array.prototype.forEach.call(boxes, function (box) {
  var ripplesBox = new Ripples(box);
});

Comments