How can I start or stop an animation by simply pressing and releasing any key?

I'm struggling to make this cool "rotating ball" animation start and stop based on any key being held down. The animation should only play while a key is actively pressed.

I've done some research, but I keep coming across jQuery solutions that I'm not familiar with. I feel like I might be missing something in my JavaScript code, but as you can tell, I'm pretty new to all of this and still trying to figure it out.

(I know I've assigned the keypress event to "Q", but ideally, I'd like the animation to begin as soon as any key is pressed and pause when the key is released. Additionally, I want the animation to repeat multiple times rather than stopping after just one loop.)

const start = document.querySelector("#ball");
const rot = document.querySelector("#roter");

window.addEventListener("keydown", move)
function move(event) {

    if (event.key !== "") {
        ball.style.animation = "roll 4s linear running";
        roter.style.animation = "rotate 4s linear running";
    } else {
        ball.style.animation = "roll 4s linear paused";
        roter.style.animation = "rotate 4s linear paused";
    }
};
.line{
        width: 1000px;
        height: 500px;

    }

    #ball{
        position: relative;
        top: 40px;
        left: 0;
        width: 100px;
        height: 100px;
        background-color: rgb(114, 240, 214);
        border-radius: 50%;
        animation-play-state: paused;
        text-align: center;
        line-height: 100px;
    }

   /* .ball:hover{
        animation-play-state: paused;
    }

    -#roter:hover{
        animation-play-state: paused;
    } */

    @keyframes roll {
        0%{
            top: 40px;
            left: 0;
            transform: rotate(0deg);
        }
        12.5%{
            top: 40px;
            left: 50px;
            transform: rotate(45deg);
        }
        25%{
            top: 40px;
            left: 100px;
            transform: rotate(90deg);
        }
        37.5%{
            top: 40px;
            left: 150px;
            transform: rotate(135deg);
        }
        50%{
            top: 40px;
            left: 200px;
            transform: rotate(180deg);
        }
        62.5%{
            top: 40px;
            left: 250;
            transform: rotate(225deg);
        }
        75%{
            top: 40px;
            left: 300px;
            transform: rotate(270deg);
        }
        87.5%{
            top: 40px;
            left: 350px;
            transform: rotate(315deg);
        }
        100%{
            top: 40px;
            left: 250px;
            transform: rotate(360deg);
        }
    }

    #roter{
        animation-name: roter;
        animation-play-state: paused;
    }

    @keyframes roter {
        0%{

        }
        25%{
            transform: rotate(90deg);
        }
        50%{
            transform: rotate(180deg);
        }
        75%{
            transform: rotate(270deg);
        }
        100%{
            transform: rotate(360deg);
        }
    }
<div class="line">
    <div id="ball">
        <p id="roter">161519</p>
    </div>

</div> 

Answer №1

Do you like what you see? Press the button to preview. Unfortunately, your css animation is not as smooth as it could be. I won't be able to fix it for you right now, but the code below should do the trick.

Note the javascript code included here. The animation in the css is already set up with the play state initially set to paused, so it won't run when the page loads. When a key is pressed (keydown event), the play state changes to running, and on key release (keyup event), it goes back to paused.

As for the other issue you mentioned about running the css animation indefinitely, you can achieve this by setting

animation-iteration-count: infinite
or using the shorthand
animation: spin 4s infinite linear;
like I've done in the code snippet. Pay attention to the keyword infinite.

const start = document.querySelector("#ball");
const rot = document.querySelector("#roter");

window.addEventListener("keydown", () => {
    ball.style.animationPlayState = "running";
    roter.style.animationPlayState = "running";
})

window.addEventListener("keyup", () => {
    ball.style.animationPlayState = "paused";
    roter.style.animationPlayState = "paused";
})
.line{
        width: 1000px;
        height: 500px;

    }

#ball{
    position: relative;
    top: 40px;
    left: 0;
    width: 100px;
    height: 100px;
    background-color: rgb(114, 240, 214);
    border-radius: 50%;
    animation: spin 4s infinite linear;
    animation-play-state: paused;
    text-align: center;
    line-height: 100px;
}

@keyframes spin {
    0%{
        top: 40px;
        left: 0;
        transform: rotate(0deg);
    }
    12.5%{
        top: 40px;
        left: 50px;
        transform: rotate(45deg);
    }
    25%{
        top: 40px;
        left: 100px;
        transform: rotate(90deg);
    }
    37.5%{
        top: 40px;
        left: 150px;
        transform: rotate(135deg);
    }
    50%{
        top: 40px;
        left: 200px;
        transform: rotate(180deg);
    }
    62.5%{
        top: 40px;
        left: 250;
        transform: rotate(225deg);
    }
    75%{
        top: 40px;
        left: 300px;
        transform: rotate(270deg);
    }
    87.5%{
        top: 40px;
        left: 350px;
        transform: rotate(315deg);
    }
    100%{
        top: 40px;
        left: 250px;
        transform: rotate(360deg);
    }
}

#roter{
    animation: spinner 4s linear infinite;
    animation-play-state: paused;
}

@keyframes spinner {
    0%{

    }
    25%{
        transform: rotate(90deg);
    }
    50%{
        transform: rotate(180deg);
    }
    75%{
        transform: rotate(270deg);
    }
    100%{
        transform: rotate(360deg);
    }
}
<div class="line">
    <div id="ball">
        <p id="spinner">161519</p>
    </div>
</div> 

Answer №2

To release the animation, you must monitor the "keyup" event. Remember, just because event.key == "q" doesn't necessarily imply that the Event.type was a "keyup".

Here is a more straightforward CSS and an improved JavaScript method.
Simply toggle the element's style animationPlayState value using JS. Ensure the code does not activate during a long press by checking evt.repeat:

const elBall = document.querySelector("#ball");

const toggleRoll = (evt) => {
  if (evt.key !== "q" || evt.repeat) return;
  elBall.style.animationPlayState = evt.type === "keydown" ? "running" : "paused";
};

addEventListener("keydown", toggleRoll);
addEventListener("keyup", toggleRoll);
#ball {
  --size: 100px;
  position: relative;
  top: 40px;
  width: var(--size);
  height: var(--size);
  line-height: var(--size);
  border-radius: var(--size);
  text-align: center;
  background-color: rgb(114, 240, 214);
  
  animation: roll 3s linear infinite alternate;
  animation-play-state: paused;
}

@keyframes roll {
  0% { transform: translateX(0px) rotate(0deg); }
  100% { transform: translateX(300px) rotate(360deg); }
}
Click here to focus, then press key "q" to animate!
<div id="ball">161519</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Invoking an *.aspx method from an external HTML file

Greetings, I am a newcomer to the world of web application development. I have successfully created an *aspx page that communicates with a webservice through a method returning a string. My next goal is to invoke this aspx method from a remote HTML 5 page ...

What is the best way to cluster related data points and display them together?

In order to efficiently manage the data I receive, it is necessary to group it based on specific criteria and display these groups in the user interface. "ServiceRequest": [ {"Status": "Re-Open", },{ "Status": "Open", ...

Tips on eliminating the header section in SlickGrid?

Is there a way to remove the header row in SlickGrid using CSS? I know there isn't an API for it, but maybe some CSS tricks can do the job. Any suggestions? Check out this example: Calling all CSS experts! I'm looking for assistance in modifyin ...

Hide overflow for images with unique shapes

Here are the two image layers: https://i.sstatic.net/lUUQC.jpg One shows a hand holding a phone, and the other is a black hole. This is how you can achieve it using HTML markup: <div class="wrapper"> <img class="wrapper__image" src="path/to/ ...

Why is it that every time I try to save values, I keep encountering a 405 error?

Recently delving into the world of factories, my main goal is to store the current settings from page load into the database. I aim to update these settings whenever I click somewhere on the page. Unfortunately, I am encountering an error that says POST ht ...

Learning to implement a sliding effect on tab bar button click using Angular

When a user clicks on any tab button, I am using the transition effect "slide" to display the content. I have successfully implemented this in jQuery Mobile and you can see it in action in this fiddle: http://jsfiddle.net/ezanker/o9foej5L/1/. Now, I tried ...

Utilizing Mantine dropzone in conjunction with React Hook Form within a Javascript environment

Can Mantine dropzone be used with React hook form in JavaScript? I am currently working on a modal Upload using Tailwind components like this import { useForm } from 'react-hook-form'; import { Group, Text, useMantineTheme } from '@mantine/c ...

Tips for adjusting row height in a fluid table design using div elements

I'm having trouble making a responsive table (a keyboard) where only the cells are resizing instead of the whole keyboard fitting on the screen without any scrolling required. Here is the code I have so far: https://jsfiddle.net/723ar2f5/2/embedded/r ...

Having difficulty executing the command 'npm install -g expo-cli'

When attempting to execute npm install - g expo-cli on a Windows 10 machine, I am encountering issues. An error message keeps popping up and preventing me from proceeding. I'm in desperate need of assistance! npm WARN deprecated <a href="/cdn-cgi/ ...

Connecting Vue component data to external state sources

I am facing a challenge with integrating a Vue component into a large legacy system that is not based on Vue. This component retrieves data through AJAX requests and displays information based on an array of database record IDs, typically passed at page lo ...

Tips for concealing a div when the mouse is moved off it?

My goal is to create a simple hover effect where hovering over an image within a view filled with images displays an additional div. This part works as expected. However, I'm facing issues when trying to hide the same div when the user moves out of t ...

How does the single-threaded nature of Node.js handle an abundance of concurrent requests?

I'm currently delving into the world of nodejs, trying to wrap my head around its single-threaded nature. Here's a pondering I have: Let's say I implement a non-blocking method and we have 20000 concurrent requests flowing in. If one request ...

Leveraging the callback function to display information from a JSON file

Attempting to retrieve JSON data from a PHP file and display it. Managed to successfully request the data via AJAX and log it to the console. (At least one part is working). Tried implementing a callback to ensure that the script waits for the data befor ...

How can we have a div stay at the top of the screen when scrolling down, but return to its original position when scrolling back up?

By utilizing this code, a div with position: absolute (top: 46px) on a page will become fixed to the top of the page (top: 0px) once the user scrolls to a certain point (the distance from the div to the top of the page). $(window).scroll(function (e) { ...

What is the best way to trigger a mouseup event in Vue when the mouse is released outside of a specific element?

To capture the mousedown event on the element, you can simply add @mousedown. If the cursor is lifted inside the element, using @mouseup will capture the event. However, if the mouse goes up outside of the element (even outside of the browser window), the ...

What is the best way to use jQuery to select a group of table rows based on the value of a

My current issue involves using a jQuery selector to move table rows "UP" and "Down." Here is the Table structure in HTML: jQuery Portion : $(".up,.down").click(function() { var row = $(this).parents("tr:first"); if ($(this).is(".up")) { ...

Error encountered while using AngularJS and Node.js with the 'phantom' node module. The application is throwing an injection error as AngularJS attempts to load a directive with a suffix

Upon loading an AngularJS page, everything proceeds smoothly with no console errors and the content displays as expected. However, encountering a different scenario where attempting to load the same page from another application using the Node module &apo ...

container dimensions for images

Is there a way to make an image adjust its size according to the container? For example, if the container is 100x100 pixels and the image within it is 90x80 pixels, can we make sure that the smaller property of the image (height in this case) adjusts to f ...

Successfully updating a document with Mongoose findByIdAndUpdate results in an error being returned

findByIdAndUpdate() function in my code successfully updates a document, but unexpectedly returns an error that I am having trouble understanding. Below is the schema that I am working with: const userSchema = mongoose.Schema({ phone: String, pas ...

Using NextJS to pass a string from an input field to getStaticProps via context

I am a beginner in NextJS and React, so please forgive my lack of knowledge. I am trying to figure out how to pass the text input by users from an input field (inside Header) to the getStaticProps function of a specific page using the React context API. I ...