Trigger keyframes with click function in JS - javascript

So I'm trying to create a rock paper scissors game with UI using html, css and JS and I got stuck on a problem, whenever the user chooses the rock by clicking the rock button, the rock div that contains the image with a fist should start to move on the screen but in my case it doesn't do anything.
The html:
<div class="game-screen-elements">
<h2 class="choice">Make your choice</h2>
<div class="fist-container">
<div class="fist-left"></div>
<div class="fist-right"></div>
</div>
<div class="pick">
<button class="rock" onclick="click()">rock</button>
<button class="paper">paper</button>
<button class="scissor">scissors</button>
</div>
</div>
</div>
The css:
.fist-container{
display: flex;
width: 100%;
justify-content: space-around;
}
.fist-right, .fist-left{
background-image: url(assets/rock.png);
width: 300px;
height: 300px;
background-size: cover;
}
.fist-left{
transform: rotateY(180deg);
}
#keyframes fistLeft {
0% {
transform: rotateY(180deg) translateY(0px);
}
15% {
transform: rotateY(180deg) translateY(-50px);
}
/*25% {
transform: rotateY(180deg) translateY(0px);
} */
35% {
transform: rotateY(180deg) translateY(-50px);
}
50% {
transform: rotateY(180deg) translateY(0px);
}
65% {
transform: rotateY(180deg) translateY(-50px);
}
75% {
transform: rotateY(180deg) translateY(0px);
}
85% {
transform: rotateY(180deg) translateY(-50px);
}
100% {
transform: rotateY(180deg) translateY(0px);
}
}
#keyframes fistRight {
0% {
transform: translateY(0px);
}
15% {
transform: translateY(-50px);
}
/*25% {
transform: translateY(0px);
} */
35% {
transform: translateY(-50px);
}
50% {
transform: translateY(0px);
}
65% {
transform: translateY(-50px);
}
75% {
transform: translateY(0px);
}
85% {
transform: translateY(-50px);
}
100% {
transform: translateY(0px);
}
}
The JS:
const playerHand = document.querySelector('.fist-left');
const rockChoice = document.querySelector('rock');
click = function(){
rockChoice.addEventListener('click', function(){
playerHand.style.animation = 'fistLeft 2s ease';
});
};

Here is your working Javascript code:
const playerHand = document.querySelector('.fist-left');
const rockChoice = document.querySelector('.rock');
rockChoice.addEventListener('click', click);
function click(){
playerHand.style.animation = 'fistLeft 2s ease';
}
Explanation: What your click function does is simply registering the event-listener and not necessarily executing the animation code, hence the event is not triggered. The separated click function now actually runs the code responsible for animation since it has been registered for any click events on your element with .rock class. Also make sure you are placing the JS code at the bottom of the body tag(inside closing body tag) if you are using it as external script.

Related

Using jQuery to trigger CSS shake animation, works every OTHER time ... why?

I have a rather simple fiddle here: http://jsfiddle.net/7aotzqmL/2/ that is supposed to shake a div with CSS animation upon clicking a link. It works, but only every other time (every second time). I'm stumped - can anybody help?
Other answers I've looked at mentioned how when using onmouseover you also need to attach onmouseout... but this is just a click so I'm not sure that's relevant. I just want the div to shake on every click rather than every other.
jsFiddle: https://jsfiddle.net/7aotzqmL/2/
CSS code:
$(function() {
$('a').click(function(ev) {
$('div').toggleClass('shaker');
ev.preventDefault();
});
});
div.shaker {
animation: shake 0.3s;
/* When the animation is finished, start again */
animation-iteration-count: 1; //single shake
}
#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);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
asd
<div>shake</div>
Try this will work
$(function(){
$('a').click(function(ev){
$('div').addClass('shaker');
setTimeout(function(){
$('div').removeClass('shaker');
},300);
ev.preventDefault();
});
});
Below code is removing class on even time click, and you animation working on adding class
$('div').toggleClass('shaker');
in above solution, div class will be removed after 0.3secs animation, it will add 'shaker' class every time you click and animation will happen
You are toggling the class so the first click adds it and the second removes it. Instead you could add the class on click and set a single use event listener to listen for the animation end and then remove the class.
$(function() {
const div = $('.container')
$('a').click(function(ev) {
div.addClass('shaker')
div.one('animationend', () => {
div.removeClass('shaker')
})
ev.preventDefault();
});
});
.container {
opacity: 1;
width: 100px;
height: 100px;
background: red;
}
.container.shaker {
/* Start the shake animation and make the animation last for 0.5 seconds */
animation: shake 0.3s;
/* When the animation is finished, start again */
animation-iteration-count: 1; //single shake
}
#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);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
asd
<div class="container"></div>
Well, for one, you're TOGGLING the class. so one click means "add" the next one means "remove". Also, "preventdefault" should appear first in order to prevent the default behavior of the anchor tag before you try to add or remove classes.
$(function(){
$('a').click(function(ev){
ev.preventDefault();
$('div').addClass('shaker');
setTimeout(()=> {
$('div').removeClass('shaker');
},300)
});
});
$(function(){
$('a').click(function(ev){
$('div').addClass('shaker');
setTimeout(()=>{
$('div').removeClass('shaker');
},300)
ev.preventDefault();
});
});
Use the above code. You were removing the shaker class alternatively.

Animate each transform property separately on click event using CSS

I want that whenever I click on the div, it first translate, then rotate and, finally scale. Further, I want to reverse it back in the same way when I click again
I have the following code:
$(() => {
$('div').on('click', () => {
$('div').toggleClass('clicked');
});
});
div.normal {
height: 20px;
width: 100px;
background: black;
transition: 2s all;
}
div.clicked {
transform: translate(100px, 100px) rotate(45deg) scale(2);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='normal'></div>
As you can see, all the transformations are occurring at the same time. But, I want them to occur separately. How do I achieve this?
Thanks in advance!
Decompose your animation using keyframes. Here is a minimally edited version of your code:
var $el = $('#to-animate')
var firstClick = true
$el.click(() => {
$el.toggleClass('clicked')
if (!firstClick) {
$el.toggleClass('unclicked')
}
firstClick = false
})
div.normal {
height: 20px;
width: 100px;
background: black;
}
div.clicked {
animation: transforms 2s forwards;
}
div.unclicked {
animation: transforms-2 2s reverse;
}
#keyframes transforms {
33% {
transform: translate(100px, 100px);
}
66% {
transform: translate(100px, 100px) rotate(45deg);
}
100% {
transform: translate(100px, 100px) rotate(45deg) scale(2);
}
}
#keyframes transforms-2 {
33% {
transform: translate(100px, 100px);
}
66% {
transform: translate(100px, 100px) rotate(45deg);
}
100% {
transform: translate(100px, 100px) rotate(45deg) scale(2);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="to-animate" class='normal'></div>
Edit updated to include ability to reverse the animation (making the code edit less minimal)
An idea is to rely on other properties to achieve the same effect and be able to apply different transition
$(() => {
$('div').on('click', () => {
$('div').toggleClass('clicked');
});
});
div.normal {
height: calc(20px * var(--s,1));
width: calc(100px * var(--s,1));
background: black;
position:relative;
top:0;
left:0;
transition: 2s top 4s,2s left 4s,2s width 2s,2s height 2s,2s transform;
}
div.clicked {
top:100px;
left:100px;
--s:2;
transform:rotate(45deg);
transition: 2s top,2s left,2s width 2s,2s height 2s,2s transform 4s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='normal'></div>

Css3 animation jumps to last keyframe on mobile without animating

I am trying to build a simple animation of a beaker tipping over. Everything is working great on desktop, but both iOS Safari and chrome, when the animation starts it jumps immediately to the last key frame (100%). So this tells me the animation is firing, but for some reason it just doesn't want to well... animate.
Here is my scss code. I have an auto-prefixer, I've checked and double checked, it doesn't seem to be anything to do with -webkit. Any help would be awesome!!
/** Our Process Area Edits **/
&.our-process-title {
#our-process-svg {
width: rem-calc(150);
height: rem-calc(150);
margin: 50px auto;
transform: translateZ(0);
animation-name: beakerShake;
animation-duration: 4s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-play-state: paused;
&.running {
animation-play-state: running;
}
#-webkit-keyframes beakerShake {
0% { -webkit-transform: rotateZ(0deg);}
5% { -webkit-transform: rotateZ(20deg); }
15% { -webkit-transform: rotateZ(-25deg); }
20% { -webkit-transform: rotateZ(0deg);}
40% { -webkit-transform: rotateZ(0deg);}
50% { -webkit-transform: rotateZ(5deg); }
55% { -webkit-transform: rotateZ(-10deg); }
58% { -webkit-transform: rotateZ(15deg); }
60% { -webkit-transform: rotateZ(0deg);}
65% { -webkit-transform: rotateZ(0deg);}
72% { -webkit-transform: rotateZ(30deg); }
78% { -webkit-transform: rotateZ(-35deg); }
85% { -webkit-transform: rotateZ(0deg);}
95% { -webkit-transform: rotateZ(0deg);}
100% { -webkit-transform: rotateZ(105deg);}
}
#keyframes beakerShake {
0% { transform: rotateZ(0deg);}
5% { transform: rotateZ(20deg); }
15% { transform: rotateZ(-25deg); }
20% { transform: rotateZ(0deg);}
40% { transform: rotateZ(0deg);}
50% { transform: rotateZ(5deg); }
55% { transform: rotateZ(-10deg); }
58% { transform: rotateZ(15deg); }
60% { transform: rotateZ(0deg);}
65% { transform: rotateZ(0deg);}
72% { transform: rotateZ(30deg); }
78% { transform: rotateZ(-35deg); }
85% { transform: rotateZ(0deg);}
95% { transform: rotateZ(0deg);}
100% { transform: rotateZ(105deg);}
}
EDIT:
After trying one last thing, of course I found the culprit. I am drawing this particular svg's path, and then when it's done drawing, changing the animation play state to running. Here is my js :
setTimeout(function(){
svg.style.animationPlayState = svg.style.WebkitAnimationPlayState = 'running';
}, 4500);
Once i removed that functionality it all worked fine. I really need this the animation to fire after the svg is drawn (for obvious reasons). Any help would be awesome.
Turns out this is an issue with how iOS and the mobile broswers handle the animation play state... Essentially they don't.
The solution was to add the class
.no-animation {
animation: none !important;
}
to the element, and remove that class with js when the time is right. Feels kind of like a hack, but its the only thing I could find to work on both mobile and desktop. If anyone has better suggestions, I'd love to hear them!

This infinite loop of css3 animation using javascript is not working properly and running with a delay ?

I made this animation here. I have to load the text part of this animation from and external file data.txt. which should be in following format.
#3 de cada 10 personas mayores de 60 años
*navega por Internet
#58% de los mayores de 60 años
*tiene facebook
#4 de 10 Jovenes Adultos
*quiere trabajar fuera del país
#Add top line with pound sign
*and bottom line with star sign
i wrote this javascript code to read files from data.txt
var languages;
var topLine = new Array();
var bottomLine = new Array();
var j = 1;
$.get('data.txt', function(data) {
languages = data.split("\n")
divide(languages);
document.getElementsByClassName("top")[0].innerHTML = topLine[0];
document.getElementsByClassName("bottom")[0].innerHTML= bottomLine[0];
var interval1Id = setInterval(function(){
if(j < topLine.length){
change(topLine[j],bottomLine[j]);
}
else if (j = topLine.length){
j=0;
change(topLine[j],bottomLine[j]);
}
j= j+1;
},5000);
});
function divide(data){
for (var i = 0; i < data.length; i++) {
if (data[i].charAt(0)=="#"){
data[i] = data[i].replace("#","")
topLine.push(data[i]);
}
else if(data[i].charAt(0)=="*"){
data[i] = data[i].replace("*","")
bottomLine.push(data[i]);
}
}
}
function change(top,bottom) {
document.getElementsByClassName("top")[0].innerHTML = top;
document.getElementsByClassName("bottom")[0].innerHTML= bottom;
}
and the css i added to the html div with respective classes is:
.top{
animation: slideIntop 5s infinite both;
}
.bottom{
animation: slideInbottom 5s infinite both;
}
#-webkit-keyframes slideIntop {
0% {
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
30% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
70% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
}
#keyframes slideIntop {
0% {
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
30% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
70% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
}
#-webkit-keyframes slideInbottom {
0% {
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
30% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
70% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
#keyframes slideInbottom {
0% {
-webkit-transform: translateX(2000px);
-ms-transform: translateX(2000px);
transform: translateX(2000px);
}
30% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
70% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
it should work properly but there is some delay in the animation as you see in the provide above and i don't know what i missed here
i tried to start the animation inside the success function by adding a class :
https://stackoverflow.com/a/5771504/3168107
It's working now.
It had to do with timing (and loading).

CSS animation NOT executing in Mozilla using mozAnimationName

<style>
#keyframes shake {
0% {
-moz-transform:scale(0);opacity:0;
}
25% {
-moz-transform:scale(1.3);opacity:1;
}
50% {
-moz-transform:scale(0.7);opacity:1;
}
75% {
-moz-transform:scale(2);opacity:1;
}
100% {
-moz-transform:scale(1);opacity:1;-moz-transform:rotate(45deg);
}
}
</style>
<div style="-moz-animation-duration:2s;" onclick='this.style.mozAnimationName="shake";'>TEST</div>
It works fine in Google Chrome with its respective -webkit prefix, but with Firefox (-moz), it doesn't function properly.
Is there a solution for this, or is this simply a dumb mistake on my part? Furthermore, I do not want to utilize jQuery for my solution.
It doesn't work because Firefox no longer requires the vendor prefixes in more recent versions (starting from Firefox 16), so just drop those:
http://jsfiddle.net/nsca73oo/2/
<style>
#keyframes shake {
0% {
transform: scale(0);
opacity:0;
}
25% {
transform: scale(1.3);
opacity: 1;
}
50% {
transform: scale(0.7);
opacity: 1;
}
75% {
transform: scale(2);
opacity: 1;
}
100% {
transform: scale(1);
opacity: 1;
transform: rotate(45deg);
}
}
</style>
<div style="animation-duration: 2s;" onclick='this.style.animationName = "shake";'>TEST</div>

Categories