How to repeat shake animation on every click of a button? Simple JS

Viewed 1270

I'm a complete beginner so I apologize in advance if my code doesn't make any sense! Looking at it would probably be a headache. I'm trying to do a magic 8 ball project, and right now I'm stuck on making the 8 ball image shake with every click of the button. The animation only executes once and then I have to refresh it again. I also connected another function to the button where it would give random answers and I don't have any issues with that. I want it to simultaneously shake and give an answer with every click. How can I do this?

HTML, CSS and JS:

.shakeutton {
  position: absolute;
  bottom: 70%;
  left: 570px;
  width: 7%;

}
.head {
  position: relative;
  margin: auto;
  text-align: center;
  margin-bottom: 500px;
}

.shake {
  animation: shake 0.5s;

  animation-iteration-count: 2;
}

@keyframes shake {
  0% { transform: translate(1px, 1px) rotate(0deg); }
  10% { transform: translate(-1px, -2px) rotate(-1deg); }
  20% { transform: translate(-3px, 0px) rotate(1deg); }
  30% { transform: translate(3px, 2px) rotate(0deg); }
  40% { transform: translate(1px, -1px) rotate(1deg); }
  50% { transform: translate(-1px, 2px) rotate(-1deg); }
  60% { transform: translate(-3px, 1px) rotate(0deg); }
  70% { transform: translate(3px, 1px) rotate(-1deg); }
  80% { transform: translate(-1px, -1px) rotate(1deg); }
  90% { transform: translate(1px, 2px) rotate(0deg); }
  100% { transform: translate(1px, -2px) rotate(-1deg); }
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Magic 8 Ball</title>
</head>

<body>
  <div style='position: absolute; bottom:20%'>
    <img id='imgSh' src='magic-8-ball-8-ball-pool-eight-ball-crystal-ball-8__1_-removebg-preview.png' width='350px'; height='350px';/>
  </div>
  <h2 class='head'>Ask Me Anything And Click Shake</h2>
  <button id='shakeButton' class='shakeutton'>Shake</button>
  <div  style='position: absolute; bottom:250px; left:500px'>
    <p id='answer'></p>
  </div>

  <input type='text' style='position:absolute; left:458px; bottom:80%; width:25%; height:5%'/>

<script>
    let x = document.getElementById('shakeButton')
    x.addEventListener('click', ff);
    x.addEventListener('click', ansAppear)
    x.addEventListener('click', ballSh)

    function ansAppear() {
      document.getElementById('answer').innerHTML = fortune[finalFortune];
    }

    let fortune = ['As I see it, yes.', 'Ask again later.', 'Better not tell you now.',
  'Cannot predict now.', 'Concentrate and ask again.', 'Don’t count on it.','It is certain.',
'It is decidedly so.', 'Most likely.', 'My reply is no.','My sources say no.',
'Outlook not so good.', 'Outlook good.', 'Reply hazy, try again.', 'Signs point to yes.',
'Very doubtful.', 'Without a doubt.', 'Yes.', 'Yes – definitely.', 'You may rely on it.']

  function ff() {
    globalThis.finalFortune = Math.floor(Math.random()*fortune.length)
    console.log(fortune[finalFortune])
  }
  console.log(ff())

  function ballSh() {
    document.getElementById('imgSh').classList.add("shake");
    }


</script>

2 Answers

You can make use of the animationend event on your imgSh element and just toggle the shake class on it.

Modified your ballSh function to toggle instead of add.

Certainly you can have separate handler too for removing the shake class (which you register with animationend event) and keep your ballSh function just for adding the shake class but that's upto you.

 
    let x = document.getElementById('shakeButton')
    let ballSHEle = document.getElementById('imgSh')
    x.addEventListener('click', ff);
    x.addEventListener('click', ansAppear)
    x.addEventListener('click', ballSh)
    ballSHEle.addEventListener('animationend',ballSh);

    function ansAppear() {
      document.getElementById('answer').innerHTML = fortune[finalFortune];
    }

    let fortune = ['As I see it, yes.', 'Ask again later.', 'Better not tell you now.',
  'Cannot predict now.', 'Concentrate and ask again.', 'Don’t count on it.','It is certain.',
'It is decidedly so.', 'Most likely.', 'My reply is no.','My sources say no.',
'Outlook not so good.', 'Outlook good.', 'Reply hazy, try again.', 'Signs point to yes.',
'Very doubtful.', 'Without a doubt.', 'Yes.', 'Yes – definitely.', 'You may rely on it.']

  function ff() {
    globalThis.finalFortune = Math.floor(Math.random()*fortune.length)
    console.log(fortune[finalFortune])
  }
  console.log(ff())

  function ballSh() {
    document.getElementById('imgSh').classList.toggle("shake");
    }
.shakeutton {
      position: absolute;
      bottom: 70%;
      left: 570px;
      width: 7%;

    }
    .head {
      position: relative;
      margin: auto;
      text-align: center;
      margin-bottom: 500px;
    }

    .shake {
  animation: shake 0.5s;

  animation-iteration-count: 2;
}

@keyframes shake {
  0% { transform: translate(1px, 1px) rotate(0deg); }
  10% { transform: translate(-1px, -2px) rotate(-1deg); }
  20% { transform: translate(-3px, 0px) rotate(1deg); }
  30% { transform: translate(3px, 2px) rotate(0deg); }
  40% { transform: translate(1px, -1px) rotate(1deg); }
  50% { transform: translate(-1px, 2px) rotate(-1deg); }
  60% { transform: translate(-3px, 1px) rotate(0deg); }
  70% { transform: translate(3px, 1px) rotate(-1deg); }
  80% { transform: translate(-1px, -1px) rotate(1deg); }
  90% { transform: translate(1px, 2px) rotate(0deg); }
  100% { transform: translate(1px, -2px) rotate(-1deg); }
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Magic 8 Ball</title>
</head>

<body>
  <div style='position: absolute; bottom:20%'>
    <img id='imgSh' src='magic-8-ball-8-ball-pool-eight-ball-crystal-ball-8__1_-removebg-preview.png' width='350px'; height='350px';/>
  </div>
  <h2 class='head'>Ask Me Anything And Click Shake</h2>
  <button id='shakeButton' class='shakeutton'>Shake</button>
  <div  style='position: absolute; bottom:250px; left:500px'>
    <p id='answer'></p>
  </div>

  <input type='text' style='position:absolute; left:458px; bottom:80%; width:25%; height:5%'/>

Removing and re-adding the class 'shake' might work.

function ballSh() {
  document.getElementById('imgSh').classList.remove("shake").add("shake");
}
Related