Viktor D Viktor D - 7 months ago 35
Javascript Question

Getting right position of clicked button (ripple effect)

I have problem with finding the right position of click. I want to make google material design - ripple effect on clicked button. Circle need to be on button not somewhere else. So when you click on button white circle is showing somewhere else not above the wanted button. Where is the mistake i made?



$(function () {
var btnClick, bWidth, bHeight, x, y, posX, posY,d;
$(".btn").click(function (e) {
e.preventDefault();

posX = $(this).offset().left;
posY = $(this).offset().top;
bWidth = $(this).outerWidth();
bHeight = $(this).outerHeight();
d = Math.max(bWidth, bHeight);

$(".btn-over").remove();

if ($(this).find(".btn-over").length === 0) {
$(this).prepend("<span class='btn-over'></span>");
}

// btnClick = $(this).children(".btn-over");
// btnClick.removeClass("animation");
// if (!btnClick.height() && !btnClick.width()) {
// d = Math.max($(this).outerWidth(), $(this).outerHeight());
// btnClick.css({
// height: d,
// width: d
// });
// }

x = e.pageX - posX - bWidth / 2;
y = e.pageY - posY - bHeight /2;

$(".btn-over").css({
width: d,
height: d,
top: y + 'px',
left: x + 'px'
}).addClass("animation");
});
});

nav {
height: 3rem;
background-color: #424242;
color: #fff; }

.menu {
list-style: none;
float: right; }
.menu li {
display: inline-block; }

.btn-sigup {
box-shadow: none;
background-color: #4CAF50; }
.btn-sigup:hover {
background-color: #66BB6A;
box-shadow: none; }

.btn-login {
box-shadow: none;
background-color: transparent; }
.btn-login:hover {
box-shadow: none;
background-color: transparent; }

.btn-over {
display: inline-block;
position: absolute;
background: rgba(255, 255, 255, 0.3);
border-radius: 100%;
-webkit-transform: scale(0);
-moz-transform: scale(0);
-o-transform: scale(0);
transform: scale(0); }

.animation {
-webkit-animation: ripple 0.65s linear;
-moz-animation: ripple 0.65s linear;
-ms-animation: ripple 0.65s linear;
-o-animation: ripple 0.65s linear;
animation: ripple 0.65s linear; }

@-webkit-keyframes ripple {
100% {
opacity: 0;
-webkit-transform: scale(2.5); } }

@-moz-keyframes ripple {
100% {
opacity: 0;
-moz-transform: scale(2.5); } }

@-o-keyframes ripple {
100% {
opacity: 0;
-o-transform: scale(2.5); } }

@keyframes ripple {
100% {
opacity: 0;
transform: scale(2.5); } }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<header>
<nav>
<ul class="menu">
<li>
<button class="btn btn-login">LOG IN</button>
</li>
<li>
<button class="btn btn-sigup">SING UP</button>
</li>
</ul>
</nav>
</header>




Answer

There's nothing wrong with your JavaScript, you just need to set the position of the buttons to relative so that the positioning of the .btn-over span is contained within them. You should also consider setting the overflow of the buttons to hidden so that the "ripple" doesn't spill out of them.

$(function(){
  var btnClick,bWidth,bHeight,x,y,posX,posY,d;
  $(".btn").click(function(e){
    e.preventDefault();
    posX=$(this).offset().left;
    posY=$(this).offset().top;
    bWidth=$(this).outerWidth();
    bHeight=$(this).outerHeight();
    d=Math.max(bWidth,bHeight);
    $(".btn-over").remove();
    if($(this).find(".btn-over").length===0)
      $(this).prepend("<span class=\"btn-over\"></span>");
    x=e.pageX-posX-bWidth/2;
    y=e.pageY-posY-bHeight/2;
    $(".btn-over").css({
      width:d+"px",
      height:d+"px",
      top:y+"px",
      left:x+"px"
    }).addClass("animation");
  });
});
nav{
  background-color:#424242;
  color:#fff;
  height:3rem;
}
.menu{
  float:right;
  list-style:none;
}
.menu li{
  display:inline-block;
}
.btn-sigup{
  background-color:#4CAF50;
  overflow:hidden;
  position:relative;
}
.btn-sigup:hover{
  background-color:#66BB6A;
}
.btn-login{
  background-color:transparent;
  overflow:hidden;
  position:relative;
}
.btn-over{
  background:rgba(255, 255, 255, 0.3);
  border-radius:50%;
  display:inline-block;
  position:absolute;
  transform:scale(0);
}
.animation{
  animation:ripple .65s linear;
}
@keyframes ripple{
  to{
    opacity:0;
    transform:scale(2.5);
  }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
  <nav>
    <ul class="menu">
      <li>
        <button class="btn btn-login">LOG IN</button>
      </li>
      <li>
        <button class="btn btn-sigup">SING UP</button>
      </li>
    </ul>
  </nav>
</header>

And here' an alternative implementation that you can use on any element you wish. To implement it, you'll need to copy the JavaSript and the important stuff from the CSS and then you just give any element you want to apply this effect to a data-ripple attribute, which takes a value of any valid CSS color

(function(){
  if(document.querySelector("[data-ripple]")){
    var	span=document.createElement("span");
    span.dataset.type="ripple";
    document.addEventListener("click",function(event){
      var  target=event.target,
           parent=target.parentNode,
           color,node,style;
      if(target.dataset.type==="ripple")target=parent;
      if(color=target.dataset.ripple){
        target.appendChild(node=span.cloneNode(0));
        style=node.style;
        style.background=color;
        style.height=style.width=Math.min(target.offsetHeight,target.offsetWidth)+"px";
        style.left=event.pageX-target.offsetLeft+"px";
        style.top=event.pageY-target.offsetTop+"px";
        setTimeout(function(){target.removeChild(node);},2501);
      }
    },0);
  }
})();
/* Housekeeping */@import url(https://fonts.googleapis.com/css?family=Roboto:400,500);*{background-color:#fff;border:0;box-sizing:border-box;color:#000;font-family:Roboto,sans-serif;font-size:14px;-webkit-font-smoothing:antialiased;font-weight:400;margin:0;outline:0;padding:0;text-decoration:none;text-rendering:auto;}
/* The important stuff */
[data-ripple]{
  overflow:hidden;
  position:relative;
}
[data-ripple]>span{
  animation:ripple 2.5s;
  border-radius:50%;
  display:block;
  opacity:0;
  position:absolute;
  transform:translate(-50%,-50%);
}
@keyframes ripple{
  from{
    transform:scale(1);
    opacity:.5;
  }to{
    transform:scale(100);
    opacity:0;
  }
}
/* Snippet styles */
a,button{
  border-radius:2px;
  display:block;
  font-size:24px;
  font-weight:500;
  line-height:40px;
  margin:20px auto;
  padding:8px;
  text-align:center;
  width:200px;
}
a{
  background:#d32f2f;
  color:#fff;
}
button{
  background:#303f9f;
  color:#fff;
  font-size:24px;
  line-height:40px;
  padding:8px;
  text-align:center;
  text-transform:uppercase;
  width:200px;
}
p{
  line-height:20px;
  margin:0 8px;
  padding:8px;
}
<button data-ripple="#fff">Button</button>
<a data-ripple="#303f9f" href="#">Link</a>
<p data-ripple="#616161">Paragrpah</p>