Play new css animation seamlessly - javascript

I created a simple HTML game, which disappears under the screen when I click on a moving box.
However, the animation that disappears starts at the original location, not where it was clicked.
I think 0% of the remove #keyframes should have the location of the click, but I couldn't find a way
How shall I do it?
(function () {
const charactersGroup = document.querySelectorAll('.character');
const stage = document.querySelector('.stage')
const clickHandler = (e) => {
const target = e.target;
if (target.classList.contains('character')) {
target.classList.remove(`f${target.dataset.id}`);
target.classList.add('f0');
target.classList.add('remove');
setTimeout(() => { stage.removeChild(target) }, 2000);
}
}
stage.addEventListener('click', clickHandler);
}());
.stage {
overflow: hidden;
position: relative;
background: #eeeeaa;
width: 40vw;
height: 20vw;
}
#keyframes moving {
0% {
transform: translateX(0);
}
100% {
transform: translateX(30vw);
}
}
#keyframes remove {
0% {
transform: translate(0);
}
100% {
transform: translateY(60vw);
}
}
.character {
position: absolute;
width: 50px;
height: 50px;
background-repeat: no-repeat;
background-position: 50% 50%;
background-size: contain;
animation: moving infinite alternate;
}
.remove {
animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
}
.f0 {
background-color: black;
animation-duration: 2s;
}
.f1 {
left: 5%;
bottom: 5%;
animation-duration: 2s;
background-color: red;
}
<div class="stage">
<div class="character f1" data-id="1"></div>
</div>

Change the first animation to consider left instead of translate then append both of them to the element initially and you simply toggle the animation-play-state when adding the remove class
(function() {
const charactersGroup = document.querySelectorAll('.character');
const stage = document.querySelector('.stage')
const clickHandler = (e) => {
const target = e.target;
if (target.classList.contains('character')) {
target.classList.add('remove');
setTimeout(() => {
stage.removeChild(target)
}, 2000);
}
}
stage.addEventListener('click', clickHandler);
}());
.stage {
overflow: hidden;
position: relative;
background: #eeeeaa;
width: 40vw;
height: 20vw;
}
#keyframes moving {
100% {
left:calc(95% - 50px);
}
}
#keyframes remove {
50% {
transform: translateY(-30vh);
}
100% {
transform: translateY(60vw);
}
}
.character {
position: absolute;
width: 50px;
height: 50px;
background:red;
left: 5%;
bottom: 5%;
animation:
moving 2s infinite alternate,
remove 1s cubic-bezier(.68, -0.55, .27, 1.55) forwards paused;
}
.remove {
animation-play-state:paused,running;
background: black;
}
<div class="stage">
<div class="character f1" data-id="1"></div>
</div>

If your use case is to deal with a lot of such boxes and complexity, it's better to go with handling everything with pure JS but I tried to make this work with minimal changes in JS and CSS.
I have added comments to the new JS lines.
Also taken the liberty to have a separate class with name moving for animation moving so that we can remove it on click.
(function () {
const charactersGroup = document.querySelectorAll('.character');
const stage = document.querySelector('.stage')
const clickHandler = (e) => {
const target = e.target;
if (target.classList.contains('character')) {
target.classList.remove(`f${target.dataset.id}`);
target.classList.add('f0');
// remove the moving animation
target.classList.remove('moving');
// Get offsetWidth which is the half of width to substract later while calculating left for the target i.e our box.
const offsetWidth = parseInt(getComputedStyle(target).width)/2;
// e.clientX gives us the x coordinate of the mouse pointer
// target.getBoundingClientRect().left gives us left position of the bounding rectangle and acts as a good offset to get the accurate left for our box.
target.style.left = `${e.clientX -target.getBoundingClientRect().left - offsetWidth}px`;
target.classList.add('remove');
setTimeout(() => { stage.removeChild(target) }, 2000);
}
}
stage.addEventListener('click', clickHandler);
}());
.stage {
overflow: hidden;
position: relative;
background: #eeeeaa;
width: 40vw;
height: 20vw;
}
#keyframes moving {
0% {
transform: translateX(0);
}
100% {
transform: translateX(30vw);
}
}
#keyframes remove {
0% {
transform: translate(0vh);
}
100% {
transform: translateY(60vw);
}
}
.character {
position: absolute;
width: 50px;
height: 50px;
background-repeat: no-repeat;
background-position: 50% 50%;
background-size: contain;
}
.moving{
animation: moving infinite alternate;
}
.remove {
animation: remove 0.2s cubic-bezier(.68,-0.55,.27,1.55) forwards;
}
.f0 {
background-color: black;
animation-duration: 2s;
}
.f1 {
left: 5%;
bottom: 5%;
animation-duration: 2s;
background-color: red;
}
<div class="stage">
<div class="character moving f1" data-id="1"></div>
</div>

Related

How to make an image fade in and another fade out with one button click?

I'm trying to fade in the blue square with the first click of the button. And then on the second click, the blue square fades out and the red one fades in.
As you can see when you test it, it doesn't work that way. I don't know where I am wrong and If anyone can show me how to fix it I'd appreciate it.
var currentscene = 0;
function next() {
currentscene++;
if (currentscene = 1) {
var element = document.getElementById("blue");
element.classList.add("fade-in");
}
if (currentscene = 2) {
var element = document.getElementById("blue");
element.classList.add("fade-out");
var element = document.getElementById("red");
element.classList.add("fade-in");
}
}
.squareblue {
height: 50px;
width: 50px;
top: 50px;
background-color: blue;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
}
.squarered {
height: 50px;
width: 50px;
top: 100px;
background-color: red;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
}
.fade-out {
animation: fadeOut ease 2s
}
#keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fade-in {
animation: fadeIn ease 2s
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<div2 id="blue" class="squareblue"></div2>
<div2 id="red" class="squarered"></div2>
<button class="button" onclick="next()">next</button>
A few mistakes, and a few things to improve.
Inside your if conditionals, you were assigning the value of 1 and 2 to the variable currentscene instead of using the comparison operator ==. I added the remainder operator to be able to continue the loop indefinitely.
Instead of grabbing the element from the dom each loop, I just defined the elements at the top, and continued to reference the save variable.
instead of using a css keyframes animation, I used the css transition property to add animation to the changing of opacity.
If you have any questions, please ask 🚀
let currentscene = 0;
const blue = document.getElementById("blue");;
const red = document.getElementById("red");;
function next() {
currentscene++;
if (currentscene % 2 == 0) {
blue.classList.remove("opaque");
red.classList.add("opaque");
}
else if (currentscene % 2 == 1) {
red.classList.remove("opaque");
blue.classList.add("opaque");
}
}
.squareblue,
.squarered {
height: 50px;
width: 50px;
position: absolute;
opacity: 0;
animation-fill-mode: forwards;
transition: 1s;
}
.squareblue {
top: 50px;
background-color: blue;
}
.squarered {
top: 100px;
background-color: red;
}
.opaque {
opacity: 1;
}
button {user-select: none}
<div2 id="blue" class="squareblue"></div2>
<div2 id="red" class="squarered"></div2>
<button class="button" onclick="next()">next</button>

How to set keyframes 50% using jquery(or javascript)?

I'm making time(second) bar.
When opening page, bar's width should be (second/60)*100%.
I want to start from 50% instead of the beginning.
Using jquery or javascript.
Please tell me about.
#loader {
width: 50%;
height: 5px;
background-color: #fff;
animation-name: loadingBar;
animation-duration: 60s;
animation-timing-function: steps(60, end);
animation-direction: normal;
animation-play-state: running;
animation-iteration-count: infinite;
#keyframes loadingBar {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
Hi Could you try this overwrite the style existing.And also remove it if required to get old behavior
function setStyle() {
let st = document.createElement("style");
st.id="RemoveMeInFuture";
const stext=`#keyframes loadingBar {
50% {
width: 0%;
}
100% {
width: 100%;
}
}
.foo{background:red}`;
document.querySelector("head").appendChild(st);
if (st.styleSheet){
// This is required for IE8 and below.
st.styleSheet.cssText = stext;
} else {
st.appendChild(document.createTextNode(stext));
}
}

What is the JavaScript equivalent of the following jQuery code?

I want to make spinning wheel but instead of rotating wheel i want to rotate the pointer. I have the following jQuery code snippet which rotates a pointer but I don't know how to convert this jQuery snippet into JavaScript.
jQuery code:
$( document ).ready(function() {
var startJP = (164) + (360 * 3);
$('.jackpot-pointer').animate({ transform: startJP }, {
step: function(now,fx) {
$(this).css('-webkit-transform','rotate('+now+'deg)');
},
duration:6000
},'linear');
});
i want to do something like this
https://i.stack.imgur.com/0KArr.gif
Here is a simple example, that shows how you could solve it with vanilla JS and CSS by using CSS animations which can be toggled on and off via JS.
var stage = document.querySelector('#stage');
var rot = document.querySelector('#rotating');
stage.addEventListener('click', function () {
rot.classList.toggle('animated');
});
#stage {
position: relative;
height: 100px;
background-color: #000;
}
#rotating {
position: absolute;
top: calc(50% - 25px);
left: calc(50% - 25px);
width: 50px;
height: 50px;
background-color: #c00;
animation: rotate linear 6s;
animation-iteration-count: infinite;
animation-play-state: paused;
transform-origin: 50% 50%;
}
#rotating.animated {
animation-play-state: running;
}
#keyframes rotate {
0% {
transform: rotate(0deg) ;
}
100% {
transform: rotate(359deg) ;
}
}
<div id="stage">
<div id="rotating"></div>
</div>
Depending on which browsers you want/have to support, you might have to add vendor prefixes in the CSS code.

Bounce animation on a scaled object

What is the best way to have an object scale and then perform a bounce animation at that scale factor before going back to the original scale factor. I realize I could do something like scaling it to 2.2, then 1.8, then 2.0, but I'm looking for a way where you just have to perform the bounce animation on the scale factor because my scale factor will change.
Here is my example. Basically I want to combine the two to work like I said but as you can see the bounce animation performs based off the image size prior to scaling.
I need all sides of the image to bounce equally, like the example.
function myFunction() {
var image = document.getElementById('test');
image.style.WebkitTransform = ('scale(2,2)');
image.classList.remove('bounce');
image.offsetWidth = image.offsetWidth;
image.classList.add('bounce') ;
}
div#test {
position:relative;
display: block;
width: 50px;
height: 50px;
background-color: blue;
margin: 50px auto;
transition-duration: 1s;
}
.bounce {
animation: bounce 450ms;
animation-timing-function: linear;
}
#keyframes bounce{
25%{transform: scale(1.15);}
50%{transform: scale(0.9);}
75%{transform: scale(1.1);}
100%{transform: scale(1.0);}
}
<div id='test'> </div>
<button class = 'butt' onclick = 'myFunction()'>FIRST</button>
You can try the use of CSS variable in order to make the scale factor dynamic within the keyframe:
function myFunction(id,s) {
var image = document.querySelectorAll('.test')[id];
image.style.setProperty("--s", s);
image.classList.remove('bounce');
image.offsetWidth = image.offsetWidth;
image.classList.add('bounce');
}
div.test {
display: inline-block;
width: 50px;
height: 50px;
background-color: blue;
margin: 50px;
transform:scale(var(--s,1));
}
.bounce {
animation: bounce 450ms;
animation-timing-function: linear;
}
#keyframes bounce {
25% {
transform: scale(calc(var(--s,1) + 0.2));
}
50% {
transform: scale(calc(var(--s,1) - 0.1));
}
75% {
transform: scale(calc(var(--s,1) + 0.1));
}
100% {
transform: scale(var(--s,1));
}
}
<div class='test'> </div>
<div class='test'> </div>
<div class='test'> </div>
<div>
<button class='butt' onclick='myFunction(0,"2")'>first</button>
<button class='butt' onclick='myFunction(1,"3")'>Second</button>
<button class='butt' onclick='myFunction(2,"0.5")'>third</button>
<button class='butt' onclick='myFunction(1,"1")'>second again</button>
</div>
Dispatch each transform on a different wrapping element.
This way you can achieve several level of transforms, all relative to their parent wrapper.
Then you just need to set your animation to fire after a delay equal to the transition's duration:
btn.onclick = e => {
// in order to have two directions, we need to be a bit verbose in here...
const test = document.querySelector('.test');
const classList = test.classList;
const state = classList.contains('zoomed-in');
// first remove previous
classList.remove('zoomed-' + (state ? 'in' : 'out'));
// force reflow
test.offsetWidth;
// set new one
classList.add('zoomed-' + (state ? 'out' : 'in'));
};
div.test {
position: relative;
display: inline-block;
margin: 50px 50px;
}
div.test div{
width: 100%;
height: 100%;
transition: transform 1s;
}
div.test.zoomed-in .scaler {
transform: scale(2);
}
div.test.zoomed-in .bouncer,
div.test.zoomed-out .bouncer {
animation: bounce .25s 1s;/* transition's duration delay */
}
div.test .inner {
background-color: blue;
width: 50px;
height: 50px;
}
#keyframes bounce {
0% {
transform: scale(1.15);
}
33% {
transform: scale(0.9);
}
66% {
transform: scale(1.1);
}
100% {
transform: scale(1.0);
}
}
<div class="test">
<div class="scaler">
<div class="bouncer">
<div class="inner"></div>
</div>
</div>
</div>
<button id="btn">toggle zoom</button>

Trigger CSS Animations in JavaScript

I don't know how to use JQuery, so I need a method which could trigger an animation using JavaScript only.
I need to call/trigger CSS Animation when the user scrolls the page.
function start() {
document.getElementById('logo').style.animation = "anim 2s 2s forward";
document.getElementById('earthlogo').style.animation = "anim2 2s 2s forward";
}
* {
margin: 0px;
}
#logo {
position: fixed;
top: 200px;
height: 200px;
width: 1000px;
left: 5%;
z-index: 4;
opacity: 0.8;
}
#earthlogo {
position: fixed;
top: 200px;
height: 120px;
align-self: center;
left: 5%;
margin-left: 870px;
margin-top: 60px;
z-index: 4;
opacity: 0.9;
}
#keyframes anim {
50% {
filter: blur(10px);
transform: rotate(-15deg);
box-shadow: 0px 0px 10px 3px;
}
100% {
height: 100px;
width: 500px;
left: 10px;
top: 10px;
box-shadow: 0px 0px 15px 5px rgba(0, 0, 0, 0.7);
background-color: rgba(0, 0, 1, 0.3);
opacity: 0.7;
}
}
#keyframes anim2 {
50% {
filter: blur(40px);
transform: rotate(-15deg);
}
100% {
height: 60px;
width: 60px;
left: 10px;
top: 10px;
margin-left: 435px;
margin-top: 30px;
opacity: 0.8;
}
}
#backstar {
position: fixed;
width: 100%;
z-index: 1;
}
#earth {
position: absolute;
width: 100%;
z-index: 2;
top: 300px;
}
<img src="logo.png" id="logo" onclick="start();">
<img src="earthlogo.gif" id="earthlogo" onscroll="start();">
<img src="earth.png" id="earth">
<img src="stars.jpg" id="backstar">
The simplest method to trigger CSS animations is by adding or removing a class - how to do this with pure Javascript you can read here:
How do I add a class to a given element?
If you DO use jQuery (which should really be easy to learn in basic usage) you do it simply with addClass / removeClass.
All you have to do then is set a transition to a given element like this:
.el {
width:10px;
transition: all 2s;
}
And then change its state if the element has a class:
.el.addedclass {
width:20px;
}
Note: This example was with transition. But for animations its the same: Just add the animation on the element which has a class on it.
There is a similar question here: Trigger a CSS keyframe animation via scroll
This is how you can use vanilla JavaScript to change/trigger an animation associated with an HTML element.
First, you define your animations in CSS.
#keyframes spin1 { 100% { transform:rotate(360deg); } }
#keyframes spin2 { 100% { transform:rotate(-360deg); } }
#keyframes idle { 100% {} }
Then you use javascript to switch between animations.
document.getElementById('yourElement').style.animation="spin2 4s linear infinite";
Note: 'yourElement' is the target HTML element that you wish to
animate.
For example: <div id="yourElement"> ... </div>
Adding and removing the animation class does not work in a function. The delay is simply too little. As suggested by this article you can request the browser to reflow and then add the class. The delay isn't an issue in that case. Hence, you can use this code:
element.classList.remove("animation")
element.offsetWidth
element.classList.add("animation")
The best thing is, this works everywhere. All credit goes to the article.
A more idiomatic solution is to use the Web Animations API.
Here is the example from MDN:
document.getElementById("alice").animate(
[
{ transform: 'rotate(0) translate3D(-50%, -50%, 0)', color: '#000' },
{ color: '#431236', offset: 0.3 },
{ transform: 'rotate(360deg) translate3D(-50%, -50%, 0)', color: '#000' }
], {
duration: 3000,
iterations: Infinity
}
);
OP's example:
document.getElementById('logo').animate(
[
{},
{
filter: 'blur(10px)',
transform: 'rotate(-15deg)',
box-shadow: '0px 0px 10px 3px',
},
{
height: '100px',
width: '500px',
left: '10px',
top: '10px',
box-shadow: '0px 0px 15px 5px rgba(0, 0, 0, 0.7)',
background-color: 'rgba(0, 0, 1, 0.3)',
opacity: '0.7',
},
],
{
duration: 2000,
delay: 2000,
fill: 'forwards',
},
)
At the time of writing, it's supported in all major browsers except IE.
Supported browsers
I have a similar problem.
The best answer didn’t work for me, but when I added the delay it worked.
The following is my solution.
CSS
.circle_ani1,
.circle_ani2 {
animation-duration: 1s;
animation-iteration-count: 1;
}
.circle_ani1 {
animation-name: circle1;
}
.circle_ani2 {
animation-name: circle2;
}
JS
let temp_circle1 = $('.TimeCountdown_circle1').removeClass('circle_ani1');
let temp_circle2 = $('.TimeCountdown_circle2').removeClass('circle_ani2');
window.setTimeout(function() {
temp_circle1.addClass('circle_ani1');
temp_circle2.addClass('circle_ani2');
}, 50);
Vanilla JS version
document.getElementById('logo').classList.add("anim");
document.getElementById('earthlogo').classList.add("anim2");
You could use CSS to hide the image / animation and show when the user scrolls. This would work like this:
CSS:
div {
border: 1px solid black;
width: 200px;
height: 100px;
overflow: scroll;
}
#demo{
display: none;
}
HTML:
<div id="myDIV"> </div>
<div id="demo">
<img src="earthlogo.gif" id="earthlogo" alt="Thanks for scrolling. Now you see me">
</div>
Your javascript just needs to include an eventListener to call the function which triggers the display of your animation.
JS:
document.getElementById("myDIV").addEventListener("scroll", start);
function start() {
document.getElementById('demo').style.display='block';
}
You could use animation-play-state (Mdn docs) like this
element.style.animationPlayState = "paused/running"
Code snippet:
function play() {
document.getElementById("div").style.animationPlayState = "running";
}
function pause() {
document.getElementById("div").style.animationPlayState = "paused";
}
.animation {
width: 50px;
height: 50px;
background-color: red;
position: relative;
animation-name: example;
animation-duration: 2s;
animation-play-state: paused;
animation-iteration-count: infinite;
}
#keyframes example {
0% {
background-color: red;
left: 0px;
top: 0px;
}
25% {
background-color: yellow;
left: 50px;
top: 0px;
}
50% {
background-color: blue;
left: 50px;
top: 50px;
}
75% {
background-color: green;
left: 0px;
top: 50px;
}
100% {
background-color: red;
left: 0px;
top: 0px;
}
}
<button onclick="play()">Play</button>
<button onclick="pause()">Pause</button><br><br>
<div id="div" class="animation"></div>
Here's the main code:
HTML:
<img id="myImg">
CSS:
#myImg {
//properties
animation: animate 2s linear infinite //infinite is important!
}
#keyframes animate {
//animation base
}
JS:
document.getElementById("myImg").style.webkitAnimationPlayState = "paused";
window.addEventListener("scroll", function() {
document.getElementById("myImg").style.webkitAnimationPlayState = "running";
setTimeout(function() {
document.getElementById("myImg").style.webkitAnimationPlayState = "paused";
}, 2000);
});
If you want Animations i recommend you create a CSS class which you toggle on a Condition whit JS:
CSS
.animation {
animation: anim 2s ease infinite;
transition: .2s
}
JS
// Select your Element
$element.document.querySelector(".yourElement");
$element.addEventListner('click', () => {
$element.classList.toggle("animation")
})

Categories