0

I've looked around for the answer and have found that I should use position: relative; to remedy my situation. However, it does not appear to work in my case. I am using JQuery and AnimeJS. Essentially, what I am trying to accomplish is the Google ripple effect on their buttons with AnimeJS.

Thanks in advance if I do not respond immediately.

function ripple(event) {
  //Find cursor position
  var x = event.pageX,
    y = event.pageY;
  if ($(".ripple").length > 0) { //If there is already a div for the ripple
    //Remove previous ripple
    $(".ripple").remove();

    $("div.btn").append("<div class='ripple'></div>"); //Append a div with the class ripple
    $(".ripple").css({
      "top": y - 20,
      "left": x - 20
    }); //Position the div so that it is on the cursor
    var ripple = anime({ //Ripple Animation
      targets: ".ripple",
      opacity: {
        value: [1, 0],
        duration: 2000
      },
      scale: {
        value: 10,
        duration: 3000
      },
    });
    $(".ripple").delay(2000).queue(function() {
      $(this).remove();
    }); //Delete div at the end of the animation
  } else {
    $("div.btn").append("<div class='ripple'></div>"); //Append a div with the class ripple
    $(".ripple").css({
      "top": y - 20,
      "left": x - 20
    }); //Position the div so that it is on the cursor
    var ripple = anime({ //Ripple Animation
      targets: ".ripple",
      opacity: {
        value: [1, 0],
        duration: 2000
      },
      scale: {
        value: 10,
        duration: 3000
      },
    });
    $(".ripple").delay(3000).queue(function() {
      $(this).remove();
    }); //Delete div at the end of the animation
  }
}
html {
  background: #d6d7d8;
  height: 100%;
  width: 100%;
}

body {
  height: 100%;
  width: 100%;
  display: grid;
  grid-template-columns: 2fr 1fr 2fr;
  grid-template-rows: 2fr 1fr 2fr;
}

.btn {
  grid-column-start: 2;
  grid-column-end: 2;
  grid-row-start: 2;
  grid-row-end: 2;
  background: #ff5722;
  border-radius: 10px;
  box-shadow: 0 10px 20px 4px #aaaaaa;
  cursor: pointer;
  overflow: hidden;
  outline: none;
  border: none;
  position: relative;
}

.ripple {
  pointer-events: none;
  position: absolute;
  border-radius: 50%;
  height: 40px;
  width: 40px;
  background: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<div class="btn" onclick="ripple(event)"></div>
Pedram
  • 15,766
  • 10
  • 44
  • 73

1 Answers1

0

If I'm understanding the problem correctly, by setting the x & y to just the event.pageX / pageY doesn't take into account the position of the parent button. So, if pageX = 200 what is happening is you are setting the CSS to left: 200px relative to the parent. The parent is only like 80px wide, so it will be out of the parent container.

In order to account for the parent you can subtract the offsetLeft and offsetTop of the parent button from the event.pageX and pageY, respectively:

  var x = event.pageX - $btn.offsetLeft,
      y = event.pageY - $btn.offsetTop;

I did some clean up on your original JS. In general, you don't want to repeat yourself and it looked like all the code in the else statement wasn't necessary.

To debug problems like this in the future it might be easier to step through piece by piece and see if everything is where you expect before adding the animation. For example, by removing the animation and just looking at where the .ripple element was I could quickly see it was outside of where it needed to be.

function ripple(event) {
  var $btn = $("div.btn");
  var $ripple = $(".ripple");

  //Find cursor position
  var x = event.pageX - $btn.offsetLeft,
    y = event.pageY - $btn.offsetTop;

  //If there is already a div for the ripple
  if ($ripple.length > 0) {
    //Remove previous ripple
    $ripple.remove();
  }

  //Append a div with the class ripple
  $ripple = $('<div class="ripple"></div>');
  $btn.append($ripple);

  //Position the div so that it is on the cursor
  $ripple.css({
    "top": y,
    "left": x
  });

  //Ripple Animation
  var ripple = anime({
    targets: ".ripple",
    opacity: {
      value: [1, 0],
      duration: 2000
    },
    scale: {
      value: 10,
      duration: 3000
    },
  });

  //Delete div at the end of the animation
  $ripple.delay(2000).queue(function() {
    $(this).remove();
  });
}
html {
  background: #d6d7d8;
  height: 100%;
  width: 100%;
}

body {
  height: 100%;
  width: 100%;
  display: grid;
  grid-template-columns: 2fr 1fr 2fr;
  grid-template-rows: 2fr 1fr 2fr;
}

.btn {
  grid-column-start: 2;
  grid-column-end: 2;
  grid-row-start: 2;
  grid-row-end: 2;
  background: #ff5722;
  border-radius: 10px;
  box-shadow: 0 10px 20px 4px #aaaaaa;
  cursor: pointer;
  overflow: hidden;
  outline: none;
  border: none;
  position: relative;
}

.ripple {
  pointer-events: none;
  position: absolute;
  border-radius: 50%;
  height: 40px;
  width: 40px;
  background: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<div class="btn" onclick="ripple(event)"></div>
Pango
  • 663
  • 5
  • 10
  • I ran the code snippet and it appears that the ripple does not move to where the cursor is in the button. However, the effect you created is what I'm trying to do with the clipping. – Nicholas Kooman Feb 19 '18 at 17:26
  • Update: I ran it myself and found that the variables x and y return NaN when I click onscreen. – Nicholas Kooman Feb 19 '18 at 17:42