Javascript Animate Matching CSS Animation - javascript

I'm trying to get the Javascript animation to match exactly my css animation. I'm not sure why this is not working? I'm trying to use basic javascript. not jquery. The second div should be matching the animation of the first div
https://jsfiddle.net/JokerMartini/pf2nt4su/
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
let timing = {
duration: 2000,
iterations: Infinity
}
div.animate([
keyframes,
timing
]);
//elements += html;
content.append(div)
body {
background: #808080;
}
.base {
width: 180px;
height: 90px;
background: black;
}
.sample {
animation: play 2s steps(10) infinite;
}
#keyframes play {
0% {
background-color: green;
opacity: 0;
}
100% {
background-color: blue;
opacity: 1;
}
}
<div class='base sample'></div>
<div id="content"></div>

edit: Replace below (notice square brackets)
div.animate([
keyframes,
timing
]);
with:
document.getElementById("content").animate(
keyframes,
timing
);
Here working code snippet: (updated with steps in JS)
<style>
body {
background: #808080;
}
.base {
width: 180px;
height: 90px;
background: black;
}
.sample {
animation: play 2s steps(8) infinite;
}
#keyframes play {
0% {
background-color: green;
opacity: 0;
}
100% {
background-color: blue;
opacity: 1;
}
}
</style>
<div class='base sample'></div> <br>
<div id="content" class="base"></div>
<script>
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
var timing = {
duration: 2000,
easing: 'steps(8)',
iterations: Infinity
}
document.getElementById("content").animate(
keyframes,
timing
);
</script>

Move the content.append(div) before the animate call. Also, remove the [] from the animate.
I forked your JSFiddle. Here is a working version. https://jsfiddle.net/jrgiant/c5z7x2bu/.
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
let timing = {
duration: 2000,
iterations: Infinity
}
content.append(div)
div.animate(
keyframes,
timing
);
//elements += html;
body {
background: #808080;
}
.base {
width: 180px;
height: 90px;
background: black;
}
.sample {
animation: play 2s steps(10) infinite;
}
#keyframes play {
0% {
background-color: green;
opacity: 0;
}
100% {
background-color: blue;
opacity: 1;
}
}
<div class='base sample'></div>
<div id="content"></div>

Your exact problem is that you are applying the animation before appending the div, and passing the keyframes argument as a list of lists instead of a list of objects (as you defined it):
let content = document.getElementById("content");
html = `<div class="base"></div>`;
let doc = new DOMParser().parseFromString(html, 'text/html');
let div = doc.body.firstChild;
content.append(div)
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API/Using_the_Web_Animations_API
// keyframes
var keyframes = [{
backgroundColor: 'green',
opacity: 0
}, {
backgroundColor: 'blue',
opacity: 1
}];
// timing
let timing = {
duration: 200,
iterations: Infinity
}
div.animate(
keyframes,
timing
);

Related

How to save object position after animation in JavaScript?

I am trying to animate an object for a game in which the ball is supposed to move up, right, left and down on pressing user button. I am trying to achieve this by using .animate() function on the ball. But after every animation event, the ball resets to its initial position and does not continue moving from its "new" position. Is there any way to accomplish this?
Following is my condensed code snippet for simplicity:
/* Animation */
var item = document.getElementById('item');
var anim;
function myMoveLeft(){
anim=item.animate([
// keyframes
{ transform: 'translateX(0px)' },
{ transform: 'translateX(-60px)' }
], {
duration: 1000,
iterations: 1
});
}
function myMoveDown(){
anim=item.animate([
// keyframes
{ transform: 'translateY(0px)' },
{ transform: 'translateY(60px)' }
], {
duration: 1000,
iterations: 1
});
// anim.onfinish(()=>{console.log("onfinish ran")})
}
item.addEventListener('animationend', () => {
console.log('Animation ended');
});
button{
display:inline-block;
height:40px;
width:80px;
}
#myContainer {
width: 400px;
height: 400px;
position: relative;
background: lightgray ;
}
#item {
background: orange;
position: absolute;
right:30px;
top:30px;
height: 30px;
width: 30px;
border-radius:50%;
}
<p>
<button onclick="myMoveLeft()">Left</button>
<button onclick="myMoveDown()">Down</button>
</p>
<div id ="myContainer">
<div id="item"></div>
</div>
As seen, I have already tried using .onfinish() and Event Listener 'animationend' hoping I could update the new 'right' and 'top' position but it does not work. Not sure if that would be the right approach.
Could someone please suggest on how to save the element to a new position and animate it further from that new position?
PS: I am also open to suggestions/techniques if you feel there are other better ways to do this.
Thanks a lot in Advance!!
You can make the ball get the final transform value using the fill option, which is the same as animation-fill-mode in css animation.
For not override the transform when you do the next animation, you can save the x and y value as variables, and do any animation according to the current x and y state. (from x to x-60, instead from 0 to -60, etc.)
Example:
/* Animation */
var item = document.getElementById('item');
var anim;
var x=0, y=0;
function myMoveLeft(){
anim=item.animate([
// keyframes
{ transform: `translate(${x}px, ${y}px)` },
{ transform: `translate(${x-60}px, ${y}px)` }
], {
duration: 1000,
iterations: 1,
fill: 'forwards'
});
x -= 60;
}
function myMoveDown(){
anim=item.animate([
// keyframes
{ transform: `translate(${x}px, ${y}px)` },
{ transform: `translate(${x}px, ${y+60}px)` }
], {
duration: 1000,
iterations: 1,
fill: 'forwards'
});
y += 60;
// anim.onfinish(()=>{console.log("onfinish ran")})
}
item.addEventListener('animationend', () => {
console.log('Animation ended');
});
button{
display:inline-block;
height:40px;
width:80px;
}
#myContainer {
width: 400px;
height: 400px;
position: relative;
background: lightgray ;
}
#item {
background: orange;
position: absolute;
right:30px;
top:30px;
height: 30px;
width: 30px;
border-radius:50%;
}
<p>
<button onclick="myMoveLeft()">Left</button>
<button onclick="myMoveDown()">Down</button>
</p>
<div id ="myContainer">
<div id="item"></div>
</div>

How to pause interval on mouseover and resume when the mouse is no longer over

I created a page where the background colors of a div change every so often. I want to make it so that when the mouse is over(or hovers) the color changer pauses where it is, as long as the mouse hovers there. And when the mouse no longer hovers the div, the colors continue to change where it left off. The closest examples I ran into on this website used JQuery solutions. I am not looking for a JQuery solution. I am looking for a javascript solution. I appreciate any and all of your responses. Thank You!
var dammit = document.getElementById("muck");
var colorChange = document.getElementById("color-changer");
var colors = ["red", "blue", "green", "pink"];
var counter = 0;
function changer() {
if (counter >= colors.length) {
counter = 0;
};
colorChange.style.background = colors[counter];
counter++;
};
var myTimer = setInterval(changer, 3000);
body {
background: #FDCA40;
margin: 0;
padding: 0;
-webkit-transition: background 0.9s;
-moz-transition: background 0.9s;
transition: background 0.9s;
}
div#muck {
width: 100%;
height: 100vh;
}
<body id="color-changer">
<div id="muck"></div>
</body>
There is no way to pause a timer, but you can just stop the currently running one and then start a new one.
(FYI: All browsers that are within 5 years old at least support CSS transitions. No need to vendor prefix that.)
var source = document.getElementById("muck");
var colorChange = document.getElementById("color-changer");
var colors = ["red", "blue", "green", "pink"];
var counter = 0;
function changer(){
if (counter >= colors.length){
counter = 0;
};
colorChange.style.background = colors[counter];
counter++;
};
var myTimer = setInterval(changer, 1000);
// Stop the current timer when mouseover
source.addEventListener("mouseover", function(){ clearInterval(myTimer)});
// Start a new timer when mouse out
source.addEventListener("mouseout", function(){ myTimer = setInterval(changer, 1000);});
body{
background: #FDCA40;
margin: 0;
padding: 0;
transition: background 0.9s;
}
div#muck{
width: 100%;
height: 100vh;
}
<body id="color-changer">
<div id="muck"></div>
</body>
You can do this purely in CSS but you need to use animation. I also added some CSS variables so the animation is easier to change.
body {
background: #FDCA40;
margin: 0;
padding: 0;
}
/* Safari 4.0 - 8.0 */
#-webkit-keyframes example {
from {background-color: red;}
to {background-color: yellow;}
}
#keyframes example {
0% {background-color: red;}
20% {background-color: blue;}
40% {background-color: green;}
80% {background-color: pink;}
100% {background-color: red;}
}
div#muck {
--animation-transition-speed: 0.9s;
--number-of-colors: 4;
width: 100%;
height: 100vh;
-webkit-animation-name: example;
-webkit-animation-duration: calc(var(--animation-transition-speed) * var(--number-of-colors));
animation-name: example;
animation-duration: calc(var(--animation-transition-speed) * var(--number-of-colors));
animation-iteration-count: infinite;
}
div#muck:hover {
animation-play-state: paused;
}
<body id="color-changer">
<div id="muck"></div>
</body>
While this doesnt really pouse the interval it mimics what you need very closely..
You can use a flag.. something like this:
var output = document.getElementById('id')
var isPaused = false;
var counter = 0;
window.setInterval(function() {
if(!isPaused) {
counter++;
if (counter >= colors.length) {
counter = 0;
};
colorChange.style.background = colors[counter];
}
}, 1000);
document.getElementById('muck').addEventListener('mouseenter', function(e) {
isPaused = true;
});
document.getElementById('muck').addEvenetListener('mouseleave', function(e) {
isPaused = false;
});
from Javascript - Pausing setInterval()

How do I create a vertical jQuery or CSS slider for an inline element

So basically I saw this really cool CSS animation on code pen (https://codepen.io/yoannhel/pen/sJpDj) and I've been trying to replicate it so that it would work for me. I was able to replicate the animation on the brackets with CSS fairly easily, but I have absolutely no idea how to do the transition between changing text like they did. I want to replicate the way that new text slides down into the visible inline view frame and then slides out.
I would prefer if this had a CSS only solution but at this point I'll take anything.
This is the code I have so far
var users = ["bob", "john", "world", "everyone"];
counter = 0;
setInterval(function() {
//slide down off screen
//Change Value
if (counter >= (users.length - 1)) {
elUser.textContent = users[counter];
counter = 0;
} else {
elUser.textContent = users[counter];
counter += 1
}
//reset to top
$("#user").animate({
bottom: '-=120'
});
//slide down on screen
}, 2000);
#keyframes WelcomeBrackets {
0% {
color: rgba(242, 12, 54, 0);
}
50% {
color: rgba(242, 12, 54, 1);
}
100% {
color: rgba(242, 12, 54, 0);
}
}
#user {
display: inline;
overflow: hidden;
}
.bracket {
animation: WelcomeBrackets 2s;
animation-iteration-count: infinite;
color: #2603c1;
}
<h1><span class="bracket">[ </span> Welcome <span id="user">User</span>
<span class="bracket"> ]</span>
</h1>
You did not call the correct id. change your Div ID as elUser and it will work.
var users = ["bob", "john", "world", "everyone"];
counter = 0;
setInterval(function() {
//slide down off screen
//Change Value
if (counter >= (users.length - 1)) {
elUser.textContent = users[counter];
counter = 0;
} else {
elUser.textContent = users[counter];
counter += 1
}
//reset to top
$("#user").animate({
bottom: '-=120'
});
//slide down on screen
}, 2000);
#keyframes WelcomeBrackets {
0% {
color: rgba(242, 12, 54, 0);
}
50% {
color: rgba(242, 12, 54, 1);
}
100% {
color: rgba(242, 12, 54, 0);
}
}
#user {
display: inline;
overflow: hidden;
}
.bracket {
animation: WelcomeBrackets 2s;
animation-iteration-count: infinite;
color: #2603c1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1><span class="bracket">[ </span> Welcome <span id="elUser">User</span>
<span class="bracket"> ]</span>
</h1>
You can get the output using Slide Up and Slide Down animation.
To get the knowledge on that please refer the snippet below
#keyframes WelcomeBrackets {
0% {
color: rgba(242, 12, 54, 0);
}
50% {
color: rgba(242, 12, 54, 1);
}
100% {
color: rgba(242, 12, 54, 0);
}
}
#user {
display: inline;
overflow: hidden;
}
.bracket {
animation: WelcomeBrackets 2s;
animation-iteration-count: infinite;
color: #2603c1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1><span class="bracket">[ </span> Welcome <span id="elUser">User</span>
<span class="bracket"> ]</span>
</h1>
<script>
var users = ["bob", "john", "world", "everyone"];
counter = 0;
setInterval(function () {
$('#elUser').slideDown(1000);
if (counter >= (users.length - 1)) {
elUser.textContent = users[counter];
$('#elUserelUser').slideDown(1000);
counter = 0;
} else {
elUser.textContent = users[counter];
$('#elUser').slideUp(1000);
counter += 1;
}
}, 2000);
</script>

Making smooth transition from image placeholder to images when they are loaded

I am using swiper slider in my project, and I am wondering how can I have some smooth transition from image placeholders that I would replace with real images when they are loaded. So, in my case I have made a slider that looks like this:
<div class="swiper-slide">
<a href="/player/{{ $player->id }}/{{ $player->fullName }}">
<div class="mdc-card player-slider-card">
<img data-src="https://placeimg.com/250/300/any" class="player-images"/>
<div class="card-img-overlay">
<section class="mdc-card__media">
<i class="material-icons player-icon">person_outline</i>
<h3 class="mdc-card__title mdc-card__title--large">{{ $player->first_name }} {{ $player->last_name }}</h3>
</section>
<div class="mdc-card__primary">
<h4 class="mdc-card__subtitle">
{{ $player->nationality }}
#if($player->position != '')
| {{ $player->position }}
#endif
</h4>
</div>
</div>
</div>
</a>
</div>
I have made img tags with data-src attribute that I am later removing and adding the src attribute, when the images are loaded and I am at the same time removing the icon person_outline that I have as an image placeholder. This is the scss file:
app.scss
$white: #fff;
#mixin pulse {
-webkit-animation: pulse .65s infinite alternate;
animation: pulse .65s infinite alternate;
}
#keyframes pulse {
0%{opacity:.5}100%{opacity:1}
}
.slider-section {
position: relative;
.arrow-left, .arrow-right {
position: absolute;
top: 40%;
z-index: 10;
}
.arrow-left {
left: 5px;
}
.arrow-right {
right: 5px;
}
.swiper-slide {
a {
text-decoration: none;
}
}
.player-slider-card {
background: #E1E9EE;
color: $white;
width: 250px;
#include pulse;
h3, h4 {
#include pulse;
color: $white;
}
img {
opacity: 1;
transition: opacity 0.3s;
}
img[data-src] {
opacity: 0;
}
.mdc-card__media {
height: 300px;
}
.player-icon {
margin: auto;
font-size: 78px;
margin-bottom: 50px;
margin-top: 50px;
}
}
}
And this is the js file:
app.js
import Swiper from 'swiper';
const removePlaceholder = (item) => {
setTimeout(() => {
let slides = document.querySelectorAll(`.${item}-slider-card`);
let images = document.querySelectorAll(`.${item}-images`);
let placeholders = document.querySelectorAll(`.${item}-icon`);
slides.forEach(el => {
el.classList.remove(`${item}-slider-card`);
});
images.forEach(el => {
el.setAttribute('src', el.getAttribute('data-src'));
el.removeAttribute('data-src');
})
placeholders.forEach(el => {
el.remove();
})
}, 3000);
}
const sliderOptions = (nextEl, prevEl) => {
return {
direction: 'horizontal',
slidesPerView: 5,
simulateTouch: false,
spaceBetween: 1,
navigation: {
nextEl,
prevEl,
},
on: {
imagesReady:() => {
removePlaceholder('player');
},
},
breakpoints: {
1181: {
slidesPerView: 5
},
1180: {
slidesPerView: 4
},
1020: {
slidesPerView: 3
},
700: {
slidesPerView: 2
}
}
}
}
let videoOptions = sliderOptions('.js-arrow-videos-right', '.js-arrow-videos-left');
let playerOptions = sliderOptions('.js-arrow-players-right', '.js-arrow-players-left');
let swiperVideos = new Swiper('.js-videos-slider', videoOptions);
let swiperPlayers = new Swiper('.js-players-slider', playerOptions);
I have made a jsfiddle here. What I am wondering is how can I make a smooth transition when the images are being loaded. I thought I would maybe solve this with just a simple transition:
img {
opacity: 1;
transition: opacity 0.3s;
}
img[data-src] {
opacity: 0;
}
But, that didn't help, how can I achieve the similar effect to images on for example on themedium site or facebook.

Show element for a second, then hide it

I'm trying to show an element for a short amount of time, then hiding it with a CSS transition, on a button click.
Here's the outline of what I did.
elem has a property of opacity: 0.
Fire event when button gets selected.
The events function will add, then remove a class named show to elem.
CSS has the following property: transition: opacity 500ms ease 1000ms;.
#elem.show has a property of opacity: 1.
The problem is, nothing happens when the button gets clicked on. How can I make element get shown, without a transition effect, then, after 1s close with a transition?
JSFiddle
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.add('show');
elem.classList.remove('show');
});
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease 1000ms;
}
#elem.show {
opacity: 1;
transition: none;
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Using setTimeout is not tidy - it is better to listen to the animation end event and remove the show class. I have also used animation to show and hide the element successively - see demo below:
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.remove('show');
// this force-restarts the CSS animation
void elem.offsetWidth;
elem.classList.add('show');
});
elem.addEventListener("animationend", function(){
elem.classList.remove('show');
}, false);
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
}
#elem.show {
animation: anime 1s 1;
}
#keyframes anime {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Update
Listening to the animation-end event do not seem necessary actually - it works properly even without it. The gist here is the use of void elem.offsetWidth to forcefully restart the animation:
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.remove('show');
// this force-restarts the CSS animation
void elem.offsetWidth;
elem.classList.add('show');
});
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
}
#elem.show {
animation: anime 1s 1;
}
#keyframes anime {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<button id="btn">Press Me</button>
<div id="elem"></div>
just do this :
setTimeout(function() { elem.classList.remove('show'); }, 1000);
instead of writing :
elem.classList.remove('show');
To handle repeated clicks, do this ::
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
var timeOutFunc;
btn.addEventListener('click', function() {
elem.classList.add('show');
clearTimeout(timeOutFunc);
timeOutFunc = setTimeout(function() {elem.classList.remove('show') } , 1000);
});
This borrows from other answers, and addresses the multiple press "issue"
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', (function() {
var timer = null;
return function() {
elem.classList.add('show');
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(e => elem.classList.remove('show'), 1000);
};
})());
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease 500ms;
}
#elem.show {
opacity: 1;
transition: none;
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Try with this...i Hope its resolved your prblm
https://jsfiddle.net/b3en368p/5/
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.add('show');
setTimeout(function(text){
elem.classList.remove('show');
}, 1000);
});
Add css
#elem {
background-color: orange;
width: 100px;
height: 100px;
display: none;
}
#elem.show {
display: block;
}
Your listener should be like this-
btn.addEventListener('click', function() {
elem.classList.add('show');
setTimeout(function(){
elem.classList.remove('show');
}, 1000);
});

Categories