animateRipple(x, y, isTouch) {
        if (this.rippleShouldTrigger(isTouch)) {
          const { top, left, width } = this.getDescriptor(x, y);
          const noRipplesActive = Object.keys(this.state.ripples).length === 0;
          const key = (this.props.rippleMultiple || noRipplesActive)
            ? this.getNextKey()
            : this.getLastKey();
          const endRipple = this.addRippleDeactivateEventListener(isTouch, key);
          const initialState = {
            active: false, restarting: true, top, left, width, endRipple,
          };
          const runningState = { active: true, restarting: false };

          this.setState(state => ({
            ripples: { ...state.ripples, [key]: initialState },
          }), () => {
            if (this.rippleNodes[key]) this.rippleNodes[key].offsetWidth; // eslint-disable-line

            this.setState(state => ({
              ripples: {
                ...state.ripples,
                [key]: Object.assign({}, state.ripples[key], runningState),
              },
            }));
          });
        }
      }
Start a ripple animation on an specific point with touch or mouse events. First
decides if the animation should trigger. If the ripple is multiple or there is no
ripple present, it creates a new key. If it's a simple ripple and already exists,
it just restarts the current ripple. The animation happens in two state changes
to allow triggering via css.

@param {Number} x Coordinate X on the screen where animation should start
@param {Number} y Coordinate Y on the screen where animation should start
@param {Boolean} isTouch Use events from touch or mouse.