React how to reset GIF upon project refresh? - javascript

Given :
function App() {
return (
<div className="container">
<span>
</span>
</div>
);
}
ReactDOM.render(<App />, document.querySelector("#app"));
.container {
background-color: black;
width: 100vw;
height:100px;
display: flex;
position: relative;
}
.container::before {
background: url('https://s9.gifyu.com/images/chain.gif');
background-size:cover;
content: '';
width: 100px;
height:100px;
right:35px;
bottom:-10px;
position:absolute;
z-index: 999 !important;
}
.container::after {
background: url('https://s9.gifyu.com/images/chain.gif');
background-size:cover;
content: '';
width: 100px;
height:100px;
right:80px;
bottom:-15px;
position:absolute;
rotate: -10deg;
z-index: 999 !important;
}
.container > span:before {
content: '';
background-color: rgb(231, 231, 231);
width: 75px;
height:40px;
right:80px;
bottom:-55px;
rotate: -7deg;
border: 3px solid rgb(126, 126, 126);
border-radius: 10px 10px 10px 10px;
position:absolute;
z-index: 999 !important;
/* transform: rotate(1deg) translate(279px, 28px);
animation: T-animation 3s linear infinite alternate-reverse; */
animation: animationFrames linear 6.25s;
animation-iteration-count: infinite;
transform-origin: 100% 0%;
animation-fill-mode:forwards; /*when the spec is finished*/
-webkit-animation: animationFrames linear 6.25s;
-webkit-animation-iteration-count: infinite;
-webkit-transform-origin: 100% 0%;
-webkit-animation-fill-mode:forwards; /*Chrome 16+, Safari 4+*/
}
#keyframes animationFrames{
0% {
transform: translate(35px,-2px) rotate(-3deg) ;
}
20% {
transform: translate(-14px,-8px) rotate(-3deg) ;
}
29% {
transform: translate(-14px,-8px) rotate(-3deg) ;
}
51% {
transform: translate(35px,-2px) rotate(-3deg) ;
}
72% {
transform: translate(65px,-1px) rotate(7deg) ;
}
79% {
transform: translate(65px,-1px) rotate(7deg) ;
}
100% {
transform: translate(35px,-2px) rotate(-3deg) ;
}
}
#-webkit-keyframes animationFrames {
0% {
-webkit-transform: translate(35px,-2px) rotate(-3deg) ;
}
20% {
-webkit-transform: translate(-14px,-8px) rotate(-3deg) ;
}
29% {
-webkit-transform: translate(-14px,-8px) rotate(-3deg) ;
}
51% {
-webkit-transform: translate(35px,-2px) rotate(-3deg) ;
}
72% {
-webkit-transform: translate(65px,-1px) rotate(7deg) ;
}
79% {
-webkit-transform: translate(65px,-1px) rotate(7deg) ;
}
100% {
-webkit-transform: translate(35px,-2px) rotate(-3deg) ;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
with JSFiddle link here,
I want to find a way to run the background gifs and the animations at the same time upon refresh or something similar. Currently, if you click run code snippet they are probably synchronized, but if the page is refreshed the gifs keep playing in the background whilst the animation is reloaded.
For instance if the run code snippet is clicked multiple times, the gif just keeps playing continuously while the animation restarts.
It is tedious for me to design this animation if every time I restart my program the gif and the animation are unsynchronized.
Things I have tried
I have tried changing <div className="container" /> to <div />, refresh, then change back, but that doesn't seem to fix it. I have also tried to change my App.js to
const [loaded,setState] = React.useState("container");
const reloadGif = () => {
React.setState({loaded: ''})
setTimeout(() => {
React.setState({loaded: "container"})
}, 0)
}
return (
<div className={loaded}>
<button onClick={reloadGif}>Reset</button>
<span>
</span>
</div>
);
}
ReactDOM.render(, document.querySelector("#app"));
but clicking on the replay button doesn't reset the gif and animation at all.
Does anyone know how I can solve this problem ?

Related

CSS chain multiple animations from different classes

I am developing a ReactJs app, I need to animate a bus in a visual path.
The bus should make stops. So the bus first go from A -> B , then when the user click a button it goes from B -> C , ect..
I have already made the animations and the logic
.bus_0 {
animation: move 3s linear forwards;
}
.bus_1 {
animation: move2nd 3s linear forwards;
}
#keyframes move {
20% {
transform: translate(50px, 0px);
}
40% {
transform: translate(50px, 0px) rotate(-90deg);
}
80% {
transform: translate(50px, -130px) rotate(-90deg);
}
100% {
transform: translate(50px, -125px) rotate(0deg);
}
}
#keyframes move2nd {
20% {
transform: translate(100px, 0px);
}
40% {
transform: translate(100px, 0px) rotate(-90deg);
}
100% {
transform: translate(100px, -50px) rotate(-90deg);
}
}
Here I add classNames based on an index
let bus = document.getElementById('bus');
bus && bus.classList.add(`bus_${data.selectedIndex}`);
The problem is when the first animation starts, the bus reachs point B , but for the second animation , it starts from point A.
Example the bus first position (0, 0), after the first animation (100, 100), when the second animation plays it start from (0, 0) but i need it the start from the last position reached.
There must be a better way probably but that is what i got and i think it will solve your problem
So i collect boxes x and y coordinates when animation button clicks and after the animationend event, i collect both x and y coordinates again and calculate difference of them and add to box style.
const firstButton = document.querySelectorAll('button')[0];
const secondButton = document.querySelectorAll('button')[1];
const myBox = document.querySelector('div')
let rectBefore;
let rectAfter;
let positionBeforeX;
let positionBeforeY;
let positionAfterX;
let positionAfterY;
let differenceX;
let differenceY;
firstButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;
myBox.classList.toggle('first');
})
secondButton.addEventListener('click', () => {
rectBefore = myBox.getBoundingClientRect();
positionBeforeX = rectBefore.left;
positionBeforeY = rectBefore.top;
myBox.classList.toggle('second');
})
myBox.addEventListener('animationend', (event) =>{
rectAfter = myBox.getBoundingClientRect();
positionAfterX = rectAfter.left;
positionAfterY = rectAfter.top;
differenceX = positionAfterX - positionBeforeX;
differenceY = positionAfterY - positionBeforeY;
if(myBox.style.left !== ""){
myBox.style.left = `${parseInt(myBox.style.left.split('px')) + differenceX}px`;
myBox.style.top = `${parseInt(myBox.style.top.split('px')) + differenceY}px`;
}
else{
myBox.style.left = `${differenceX}px`;
myBox.style.top = `${differenceY}px`;
}
myBox.classList.remove(`${event.animationName}`);
})
*,
*::before,
*::after {
box-sizing: border-box;
}
body{
min-height: 100vh;
position: relative;
display: grid;
place-content: center;
}
button{
position: absolute;
background-color: greenyellow;
width: 5rem;
height: 5rem;
}
button:nth-of-type(1){
top:5rem;
right: 10rem;
margin-right: 1rem;
}
button:nth-of-type(2){
top:5rem;
right: 5rem;
}
.box{
position:relative;
width: 100px;
height: 100px;
background-color: blue;
}
.first {
animation: first 3.0s linear forwards;
}
.second {
animation: second 3.0s linear forwards;
}
#keyframes first {
20% {
transform: translate(50px, 0px);
}
40% {
transform: translate(50px, 0px) rotate(-90deg);
}
80% {
transform: translate(50px, -130px) rotate(-90deg);
}
100% {
transform: translate(50px, -125px) rotate(0deg);
}
}
#keyframes second {
20% {
transform: translate(100px, 0px);
}
40% {
transform: translate(100px, 0px) rotate(-90deg);
}
100% {
transform: translate(100px, -50px) rotate(-90deg);
}
}
<div class="box"></div>
<button>First Animation</button>
<button>Second Animation</button>

Why does the drawer not animate on the way out?

I want my drawer to animate on the way in, and on the way out and when the animation ends, to turn to display: none but when the drawer is closed, it disappears and doesn't animate out.
const Drawer = ({ closeDrawer, isDrawerOpen }) => {
const [isAnimating, setIsAnimating] = useState()
let drawerClassName
if (isDrawerOpen) {
drawerClassName = "drawer-in"
} else if (!isDrawerOpen && isAnimating) {
drawerClassName = "drawer-animating"
} else if (!isDrawerOpen && !isAnimating) {
drawerClassName = "drawer-out"
}
return (
<>
<div
className={`drawer ${drawerClassName}`}
onAnimationStart={() => setIsAnimating(true)}
onAnimationEnd={() => setIsAnimating(false)}
></div>
<div onClick={closeDrawer}></div>
</>
)
}
CSS:
.drawer {
height: 100%;
width: 60%;
background-color: #fff;
position: absolute;
right: 0;
top: 0;
opacity: 1;
z-index: 3;
transform: translateX(100%);
}
.drawer-in {
animation: 0.7s drawerIn;
transform: translateX(0);
display: block;
}
.drawer-animating {
animation: 0.7s drawerOut;
display: block;
}
.drawer-out {
animation: 0.7s drawerOut;
display: none;
}
#keyframes drawerIn {
0% {
transform: translateX(100%);
}
1% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
#keyframes drawerOut {
0% {
transform: translateX(0);
}
99% {
transform: translateX(100%);
}
100% {
transform: translateX(100%);
}
}
it's because when you set the drawer-out class to the element display: none; is activated immediately and you don't see the animation.
One solution is to run a setTimeout function within your JavaScript to wait for the animation to finish, then change the elements display property to none. This will allow your 'closing animation' to complete before removing the element. See my snippet below for working example.
Basically what's happening in my example snippet is I'm triggering the closing animation by adding a class associated with the animation. Then I'm setting a time out function that waits for the animation to complete (set time out in milliseconds to match your animation time within your CSS). Once the timeout is complete, the animation class is removed and the element's data attribute is set to closed which will trigger the display none. Hope this helps.
const menu = document.querySelector('.menu');
const menuToggle = document.querySelector('.menu_toggle');
menuToggle.checked=false
menuToggle.addEventListener('change',(e)=>{
menuToggle.disabled=true
let menuState = menu.dataset.menuState
if(menuState==='closed'){
menu.dataset.menuState='opened'
setTimeout(() => {
menuToggle.disabled=false
}, 500);
}else{
menu.classList.add('animate_close')
setTimeout(() => {
menu.classList.remove('animate_close')
menu.dataset.menuState='closed'
menuToggle.disabled=false
}, 500);
}
})
body {
background-color: rgb(235, 235, 235);
}
.menu {
background-color: black;
color: white;
width: fit-content;
}
.menu {
transition: all .5s ease-in-out;
}
.menu[data-menu-state="closed"] {
background-color: red;
display: none;
}
.menu[data-menu-state="opened"] {
animation: openMenu .5s ease-in-out;
transform: translateX(100%);
background-color: green;
}
.menu.animate_close{
background-color: rgb(0, 30, 128);
animation: closeMenu .5s ease-in-out;
opacity: 0;
}
#keyframes openMenu {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100%);
}
}
#keyframes closeMenu {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
<body>
<label for="menu_toggle">Menu Toggle</label>
<input id="menu_toggle" type="checkbox" class="menu_toggle">
<div class="menu_container">
<div class="menu" data-menu-state="closed">
<ul>
<li>Item1</li>
<li>Item2</li>
<li>Item3</li>
</ul>
</div>
</div>
<script src="main.js"></script>
</body>

How to rotate an image with CSS or JavaScript with pause in between every rotation? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have a picture that I want to rotate from 0 to 90 stop 2s then continue from 90 to 180 then stop 2s to the 360 degrees any ideas thanks.
You can do that with CSS animations:
div {
width: 80px;
height: 80px;
background: linear-gradient(#e66465, #9198e5);;
animation: rotate-stop 10s infinite linear;
transform: rotate();
}
#keyframes rotate-stop{
0%{
transform: rotate(0deg);
}
5%, 25%{
transform: rotate(90deg);
}
30%, 50%{
transform: rotate(180deg);
}
55%, 75%{
transform: rotate(270deg);
}
80%, 100%{
transform: rotate(360deg);
}
}
<div></div>
You could use setTimeout and setInterval appropriately:
const rotate = (image, degrees) => {
image.style.transform = `rotate(${+degrees}deg)`;
}
const img = document.getElementById('js-logo');
const oneLoop = () => {
setTimeout(() => rotate(img, 90), 2000);
setTimeout(() => rotate(img, 180), 4000);
setTimeout(() => rotate(img, 360), 6000);
}
oneLoop();
setInterval(() => oneLoop(), 6000);
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/JavaScript-logo.png/240px-JavaScript-logo.png" alt="JS Logo" width="120" height="120" id="js-logo">
An example for javascript.
window.onload = function() {
var box = document.querySelector('.box');
setInterval(function() {
box.classList.toggle('rotate');
}, 2000);
}
.box {
width: 200px;
height: 200px;
background-color: green;
}
.rotate {
animation: rotate 1s;
}
#keyframes rotate {
from {
transform: rotate(0);
}
to {
transform: rotate(90deg);
}
}
<div class="box"></div>
Here is pure css example using animation keyframes.
If you calculate the time for each rotation animation, and each pause time, you can use css animate keyframe percentages to perform a sequence of desired css.
Here is an example below, see comments in css...
/* any kind of html elem, img, div etc */
DIV {
background: magenta;
color: white;
position: absolute;
top: 50%;
left: 50%;
padding: .5rem .75rem;
transform: translate(-50%);
transform-origin: center;
/* 4 rotations */
/* 4 2sec pauses */
/* 8 keyframes total */
/* 2sec rotation time example */
/* 8*2sec is 16s for complete sequence */
animation: rotate-pause 16s infinite;
}
/* rotate and pause key frames */
#keyframes rotate-pause {
/* 0 seconds */
0% {
transform: translate(-50%) rotate(0deg);
}
/* 2 seconds */
12.5% {
transform: translate(-50%) rotate(90deg);
}
/* 4 seconds */
25% {
transform: translate(-50%) rotate(90deg);
}
/* 6 seconds */
37.5% {
transform: translate(-50%) rotate(180deg);
}
/* 8 seconds */
50% {
transform: translate(-50%) rotate(180deg);
}
/* 10 seconds */
62.5% {
transform: translate(-50%) rotate(270deg);
}
/* 12 seconds */
75% {
transform: translate(-50%) rotate(270deg);
}
/* 14 seconds */
87.5% {
transform: translate(-50%) rotate(360deg);
}
/* 16 seconds */
100% {
transform: translate(-50%) rotate(360deg);
}
/* reloop if animate set to infinite */
}
/* demo reset css */
HTML {
width: 100%;
height: 100%;
min-height: 100%;
}
BODY {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
min-height: 100%;
overflow: hidden;
position: relative;
}
<div>Any kind of html elem: img, div...</div>

Vue: CSS animations on class change

I am creating a hamburger menu component in Vue but for some reason the animations do not work. It gets to what should be the end result of the animation, but there is no animation.
I trigger the animation through a class change.
I've read up some on Vue transitions but to me it seems like those are mostly used when actually removing or adding elements, which I am not doing, just changing styling in an element.
I include the whole component below, if it is of any help.
<template>
<div id="hamburgerWrapper" #click="changeClass()">
<div id="hamburger1" :class="classObject"></div>
<div id="hamburger2"></div>
<div id="hamburger3" :class="classObject"></div>
</div>
</template>
<script>
export default {
name: "hamburger",
data() {
return {
active: false
};
},
computed: {
classObject: function(){
return {
in: this.active,
out: !this.active
}
}
},
methods: {
changeClass(){
this.active = !this.active
}
}
};
</script>
<style lang="scss">
$height: 300px;
$width: $height;
#hamburgerWrapper{
margin-top: 30px;
margin-left: 30px;
width: $width;
height: $height;
background-color: rgb(192, 192, 192);
position: relative;
cursor: pointer;
#hamburger1,#hamburger2,#hamburger3{
position: absolute;
height: $height * 0.2;
width: $width;
background-color: blue;
border-radius: $height * 0.1;
}
#hamburger1{
top: 0;
//transform: translateY(($height/2)-($height * 0.1));
&.in{
animation: topIn 1s ease forwards;
}
&.out{
animation: topIn 1s ease reverse forwards;
}
}
#hamburger2{
top: 50%;
transform: translateY(-50%);
}
#hamburger3{
bottom: 0;
&.in{
animation: botIn 1s ease forwards;
}
&.out{
animation: botIn 1s ease reverse forwards;
}
}
}
#keyframes topIn {
0% {transform: translateY(0) rotate(0deg)}
50% {transform: translateY(($height/2)-($height * 0.1)) rotate(0deg)}
100% {transform: translateY(($height/2)-($height * 0.1)) rotate(45deg)}
}
#keyframes botIn {
0% {transform: translateY(0) rotate(0deg)}
50% {transform: translateY(-(($height/2)-($height * 0.1))) rotate(0deg)}
100% {transform: translateY(-(($height/2)-($height * 0.1))) rotate(-45deg)}
}
</style>
I changed the "out"-animation to not do the reversed "in"-animation, but instead just an own animation. That somehow worked.

CSS Animation, move element in front

I have 2 elements that overlap each other, on hover I want to animate the bottom element out to the right and then move back left but on top of the other element, on mouseleave I then want it to animate back to its default state. I've got something working only the opacity issue is making it quite buggy and not as smooth as I'd have liked...
https://codepen.io/liamgallagher/pen/vWrYOe?editors=1100
CSS
body {
background:#cacaca;
}
.sector-card {
position:relative;
width:50%;
.sector-panel {
width:50%;
display:block;
height:300px;
&__information {
background:#fff;
z-index:1;
position:relative;
}
&__study {
background-size:cover;
z-index:0;
position:absolute;
top:15%;
right:25%;
}
}
&:hover {
.sector-panel__study {
animation:moveFront 2s forwards;
}
}
}
#keyframes moveFront {
0% { right:25%; }
50% {z-index:3; right:0;}
100% { opacity: 1; right:25%;}
}
HTML
<div class="sector-card">
<div class="sector-panel sector-panel__information">
<h2>Big Data</h2>
<p>Lorem ipsum oosh</p>
</div>
<div class="sector-panel sector-panel__study" style="background-image:url('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQDvM3R_A9_W32EdH7pqK-CgCg9fSLcLoXi5EbV_D0CxtrJpXYn');">
<h2>case study</h2>
</div>
</div>
I forked your pen. I just added some more brekpoints to the animation and changed the css slightly on the hover event. I think this is what you want (link to forked pen and css below)
https://codepen.io/ecglover8/pen/qVKBxX
body {
background:#cacaca;
}
.sector-card {
position:relative;
width:50%;
.sector-panel {
width:50%;
display:block;
height:300px;
&__information {
background:#fff;
z-index:1;
position:relative;
}
&__study {
background-size:cover;
z-index:0;
position:absolute;
top:15%;
right:25%;
}
}
&:hover {
.sector-panel__study {
animation:moveFront 2s forwards;
z-index:3;
}
}
}
#keyframes moveFront {
0% { z-index:-1; right:25%; }
49% {z-index:-1;right:0;}
50% {z-index:3;right:0;}
100% {right:25%;}
}
Unfortunately, you can't transition z-index. One thing you can do is transition opacity to make it appear smoother.
Something like:
#keyframes moveFront {
0% { right:25%; opacity: 0; }
100% { right:0%;z-index:3; opacity: 1; }
}
Hope this helps!
Well, the CSS only solution i got was creating another animation that will play when the mouse leave. It does, obviously, an animation when you load the page but thats because it is a CSS only solution:
https://codepen.io/anon/pen/YEvPNB?editors=1100
I just copied the same animation and put the values on backwards.
#keyframes moveBack {
100% {
z-index: -1;
right: 25%;
top: 5%;
}
50% {
z-index: -1;
right: 0;
}
49% {
z-index: 3;
right: 0;
top: 10%;
}
0% {
z-index: 3;
right: 25%;
top: 5%;
}
}
And then i just put the naimation on your .sector-panel__study.
&__study {
background-size: cover;
z-index: 0;
position: absolute;
top: 5%;
right: 25%;
animation: moveBack 1s forwards; // HERE
}
Hope this helps.
Well I managed to do the back to position part but it becomes a bit buggy because there is not opposite to :hover, so this will execute when the div is created.
Changed this to the CSS:
body {
background:#cacaca;
}
.sector-panel__study{
opacity: 0.5;
animation:moveBack 2s backwards;
animation-fill-mode: forwards;
}
.sector-card {
position:relative;
width:50%;
.sector-panel {
width:50%;
display:block;
height:300px;
&__information {
background:#fff;
z-index:1;
position:relative;
}
&__study {
background-size:cover;
z-index:0;
position:absolute;
top:15%;
right:25%;
}
}
&:hover {
.sector-panel__study {
animation:moveFront 2s forwards;
animation-fill-mode: forwards;
}
.sector-panel__information {
opacity: 0.5;
z-index: 0;
}
}
}
#keyframes moveFront {
0% { right:25%; }
50% {z-index:3; right:0;}
100% { opacity: 1; right:25%;}
}
#keyframes moveBack {
0% { z-index: 3; Right:25%; opacity:1;}
50% {z-index:0; Right:0;}
100% { opacity: 0.5; Right:25%;}
}
Can put snipped, you will have to copy this css code and test!

Categories

Resources