0

I have a task:

  1. Run animation on button click
  2. Run animation just once on holding a button
  3. Use just "onKeyDown" the only dom event that device supports

Here you can see the example how I did this:

let timer = null;
let isPressed = false;

const runAnimation = () => {
    div.classList.remove('run-animation');
    void div.offsetWidth;
    div.classList.add('run-animation');
}

const fillDiv = () => {
  if (!isPressed) {
    isPressed = true;
    runAnimation();
  }

  clearTimeout(timer);
  timer = setTimeout(() => {
    isPressed = false;
  }, 50);
};

document.onkeydown = function() {
  fillDiv();
}

Working example

But the problem here, that when you hold button, the animation plays twice

Is there some solution how to avoid second firing of run animation?

  • Your animation takes longer to run than your timeout.... maybe try a different approach. I change the timeout to 1501 to test and it fired only once, as expected. – Stuart Jun 08 '18 at 09:55
  • you can use keyup event https://stackoverflow.com/questions/6087959/prevent-javascript-keydown-event-from-being-handled-multiple-times-while-held-do – Vladu Ionut Jun 08 '18 at 10:00
  • @Stuart Yes, I can change the timeout, but appropriate one is "550ms", so it doesn't work for me because I need to fire animation second time if you re-click the button – Denis Efremov Jun 08 '18 at 10:13
  • @VladuIonut How I said, I cannot use it. The device doesn't support "onKeyUp" – Denis Efremov Jun 08 '18 at 10:15
  • 1
    how about [onanimationend](https://developer.mozilla.org/en-US/docs/Web/Events/animationend)? – Andrew Bone Jun 08 '18 at 10:16
  • @AndrewBone Imagine that you will click button 3 times in a row. Not all the time animation will be done and sometime you will need to re-run it. So I'm not sure how "onAnimationed" can help me – Denis Efremov Jun 08 '18 at 10:22

2 Answers2

0

You can use animationend event

const div = document.getElementById('test');
let timer = null;
let isPressed = false;
let isRunning = false

const runAnimation = () => {
    isRunning = true;
    div.classList.remove('run-animation');
    void div.offsetWidth;
    div.classList.add('run-animation');
}

const fillDiv = () => {
   if (!isPressed) runAnimation();  
};

document.onkeydown = function() {
  if (!isRunning) fillDiv();
    isPressed = true;
}
document.onkeyup = function() {
  isPressed = false;
}

 div.addEventListener("animationend", function(){
   console.log("animationend") 
   isRunning = false;
 });
@-webkit-keyframes runAnimation {
   from { background-color: green; }
     to { background-color: white; }
}

.run-animation {
  -webkit-animation: runAnimation 1.5s ease;
 -webkit-animation-fill-mode: forwards;
}

.center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

#test {
  padding: 10px 17px;
  display: inline-block;
  border-radius: 5px;
  margin: 0 auto;
}

.text {
  font-size: 26pt;
}
<div id="test" class="center">
  <div class="text">
    Text
  </div>
</div>
Vladu Ionut
  • 8,075
  • 1
  • 19
  • 30
  • When you click 3 - 5 times button, the animation runs with some delay or doesn't run at all. Also, when you click and hold button, animation fires just when you release button, not when you just clicked it. But for me, I need to show that button was clicked. Basically, animation should run just one user clicked the button. If user hold button, then I just run when he has clicked, and all other time it's on hold – Denis Efremov Jun 08 '18 at 10:25
  • Also with this approach, animation fires in a cycle when you hold a button – Denis Efremov Jun 08 '18 at 10:33
  • [How it looks like if I would have an "onKeyUp"](https://codepen.io/anon/pen/LrbObO?editors=1010) – Denis Efremov Jun 08 '18 at 10:37
  • I've updated the code maybe you don't need the animation running logic – Vladu Ionut Jun 08 '18 at 10:38
  • Guys I cannot use OnKeyUp! A device doesn't support it, so in JS I don't know about this event! – Denis Efremov Jun 08 '18 at 10:40
  • @DenisEfremov what device is it? – Andrew Bone Jun 08 '18 at 10:40
  • Unfortunately, I cannot name it. It's a device with the custom Android and remote which fires "onKeyDown" when user interacts with the device – Denis Efremov Jun 08 '18 at 10:44
  • @DenisEfremov testing this example in a desktop device shows none of the problems you are describing for me - so that would make me question first of all, does your mysterious device support animationend to begin with? Asking for solutions here that have to work under such restrictions, that we probably don’t even know the half of yet, seems rather not a good fit for this site IMHO. (Or you would have at least to provide us with a list of what it _does_ support first.) – CBroe Jun 08 '18 at 10:54
  • @CBroe I'm not sure that I can understand you. 1. I have said that you can use just "onkeydown" but in the example above "onkeyup" is used 2. All examples I have tested on PC and if it would work as I asked on PC it would work on the device. The device from the key event handle just onkeydown, that's all. All other events should triggers as expected (without mouseclicks because it doesn't have mouse) – Denis Efremov Jun 08 '18 at 11:08
0

OK, here is a way to look for if the key is being held down. The keydown event object contains a property called repeat.

true if a key has been depressed long enough to trigger key repetition; otherwise, false.

We can check this. If it's true we can just return without doing anything otherwise we can start the fillDiv function.

I've stipped out all the bits that are no longer needed like isPressed and timer

To make it work I had to pass e as an argument in your event listener, I used e to represent event.

const div = document.getElementById('test');

const runAnimation = () => {
  div.classList.remove('run-animation');
  void div.offsetWidth;
  div.classList.add('run-animation');
}

const fillDiv = () => {
  runAnimation();
};

document.onkeydown = (e) => {
  if (e.repeat) return;
  fillDiv();
}
@-webkit-keyframes runAnimation {
  from {
    background-color: green;
  }
  to {
    background-color: white;
  }
}

.run-animation {
  -webkit-animation: runAnimation 1.5s ease;
  -webkit-animation-fill-mode: forwards;
}

.center {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

#test {
  padding: 10px 17px;
  display: inline-block;
  border-radius: 5px;
  margin: 0 auto;
}

.text {
  font-size: 26pt;
}
<div id="test" class="center">
  <div class="text">
    Text
  </div>
</div>

I hope you find this helpful.

Andrew Bone
  • 7,092
  • 2
  • 18
  • 33