Slideshow's animation doesn't work - javascript

In this Vue component, I tried to make a slideshow.
The logic works this way:
1) Making an array of all sources of pictures I want to put in(array: pictures)
2) Set a variable(Count) to 0, so that it starts from the start.
3) Putting v-bind:src="pictures[count]" on an img tag so that it changes the source by the variable(count)
4) Putting functions on 2 buttons that returns in images or goes forward in images.
<template>
<div>
<img v-bind:src="pictures[count]" alt="">
<button #click="Switching(1)">Forward</button>
<button #click="Switching(-1)">Back</button>
<p>{{this.count + 1}}</p>
</div>
</template>
<script>
export default {
data() {
return {
count: 0,
pictures: [
"http://www.hotel-bb.com/image.htm?id=93652",
"https://s-ec.bstatic.com/images/hotel/max1280x900/681/68184730.jpg",
"https://images.all-free-download.com/images/graphiclarge/hd_picture_of_the_beautiful_natural_scenery_03_166249.jpg",
"https://images.all-free-download.com/images/graphiclarge/the_beach_at_dusk_couple_of_picture_165871.jpg"
],
stop: false
};
},
methods: {
Switching: function(n) {
this.count += n;
if (this.count > this.pictures.length - 1) {
this.count = 0;
} else if (this.count < 0) {
this.count = this.pictures.length - 1;
}
}
}
};
</script>
<style scoped>
#keyframes slideInFromLeft {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(0);
}
}
img {
max-width: 800px;
height: 500px;
animation: 1s ease-out 0s 1 slideInFromLeft;
}
</style>
It works properly. The problem is that when I put an animation on it, it doesn't work except for the first picture that loads, when I switch by the two buttons, the pictures don't get animated.
I tried transition: 0.5s, animation and Keyframes and nothing works. I'm guessing that it is because the pictures don't appear but they get loaded and src gets changed. How I can make it work?

For building a slideshow on Vue JS, I suggest Vueper Slides. It will do all that for you.
Unless it is for a learning purpose.

Related

Transition Opacity w/javascript not working

I want to fadein a component after ajax call completes and jquery has rebuilt DOM.
I have this setup:
index.html:
<head>
<style>
body {
opacity: 0;
transition: opacity 2s;
}
</style>
</head>
<body onload="document.body.style.opacity='1'">
<div class="content">
<!-- Markup for content -->
</div>
</body>
main.css
.content {
opacity: 0;
transition: opacity 6s;
transition: opacity 2s;
-webkit-transition: opacity 6s;
-moz-transition: opacity 6s;
}
main.js
$(document).ready(function () {
const contentEl = document.querySelector(".content");
$(".submit").on("click", async function (e) {
e.preventDefault();
console.log(contentEl.style.opacity);
if (contentEl.style.opacity == 1) {
contentEl.style.opacity = 0;
console.log("Style opacity is in if and = %s", contentEl.style.opacity);
}
// Do Ajax and update DOM via jQuery
contentEl.style.opacity = 1;
}
The first time thru .content fades in as expected as well as fade in of whole page on initial render. However subsequent times thru there is no transition effect. Logging shows that I am changing style.opacity from 1 -> 0 and back to 1 after initial iteration. Any CSS guru's versed in CSS's dark secrets input advice appreciated.
$(document).ready(function () {
const contentEl = document.querySelector(".content");
contentEl.style.opacity = 1; // Define initial opacity (starting val)
$(".submit").on("click", async function (e) {
e.preventDefault();
contentEl.style.opacity = 0; // on click set opacity to 0?
FadeIn(); // Let's Fade from 0 to 1!
});
let FadeIn = () => { // Function
if (contentEl.style.opacity < 1) { // If opacity doesn't equal 1
contentEl.style.opacity += 0.2; // Let's add 0.2!
setTimeout(FadeIn(), 300); // Hell let's repeat that more 300ms
}
}; // Once we equal 1 we should be done
});
I don't play with the JQuery like that, I much rather too use CSS entirely for the animation process of these types of things, it's cleaner (less jitter). I'm assuming this is what you're sort of after though, a simple set value and slowly loop till finished. Button will start out 1 opacity, when clicked jump to 0 and slowly climb its way back up to 1.

How to animate or use transitions on a message pop up with javascript and css?

I currently have the message displaying and disappearing as I want but the transition isn't working, This is what I tried.
const alertMsg = document.querySelector('.alert');
contactForm.addEventListener('submit', formSubmitted);
function formSubmitted(e) {
//other stuff
alertMsg.style.display = 'block';
setTimeout(() => {
alertMsg.style.display = 'none';
}, 5000);
}
.alert {
transition: all 0.5s ease-out;
}
<div class="alert">Your message has been sent, I will get back to you as soon as possible.</div>
The message just instantly disappears and reappears, how can I use the transition currently to make some sort of animation?
This is my first question so sorry if I missed any information out, I will add any more if needed. Thanks
You can't transition (or animate) the display property. the display property is either on or off there's nothing to transition or animate.
What you can do is animate opacity and alter the display property at start and end.
something like:
#keyframes showBlock {
from { display: block; opacity: 0; }
to { opacity: 1; }
}
#keyframes hideBlock {
from { opacity: 1; }
to { opacity: 0; display: none; }
}

How do you cancel and reset css animations in react?

What I am trying to do
I have a sprite sheet and I am using it for some simple animations. I have a "player" that has two animations. One for attacking and one for standing. The current behavior is as follows: "stand" is the default animation. When the player is clicked, the "attack" animation is played and switched back to "stand."
For the special case that the player is clicked while attacking, I want the animation "attack" animation to reset.
My code
// React Component
class Player extends React.Component {
constructor(props) {
super(props);
this.state = {
timeout: null
};
}
attack(e) {
if (this.state.timeout) { clearTimeout(this.state.timeout); }
var $el = $(e.target);
$el.css({
backgroundPosition: '0 220px',
animationName: 'attack',
width: '300px'
});
this.state.timeout = setTimeout(function() {
$el.css({
backgroundPosition: 'left top',
animationName: 'stand',
width: '250px'
});
}, 2000);
}
render () {
return (
<div onClick={this.attack.bind(this)} className="player main">{this.props.name}</div>
);
}
}
/* The css */
.player {
width: 250px;
height: 220px;
background: url('assets/player.png') left top;
animation: stand 1.2s steps(3) infinite;
animation-direction: alternate;
}
#keyframes stand {
100% {
background-position: -750px 0;
}
}
#keyframes attack {
100% {
background-position: -900px 220px;
}
}
What I tried to do
I knew that since I setTimeout the "stand" animation, I would have to cancel it and make a new setTimeout to go after the "stand" animation. However, it still looks a bit funky. I tried to use forceUpdate() to see if I could just rerender and reset everything and then start the "attack" animation, but it doesn't seem to do anything.
I have another idea using jquery to remove and reattach the dom element but I feel like it would get messy and I believe I might be approaching this problem the wrong way. Do you guys have any ideas?
For complex animations, you can use https://github.com/chenglou/react-motion which can learnt from https://egghead.io/playlists/react-react-animation-using-react-motion and https://egghead.io/lessons/react-react-motion-introduction-to-the-spring-component
For simple ones, I would rather add and remove classes from element to enable the animation and reset it.
And if I am understanding it correctly, you are using jQuery inside react. Well to update the CSS, you should not use it inside react.
There should be more strong reasoning to use jQuery in react because updating inline css is very simple in react.
Following is the way I would attempt to do it:
// React Component
class Player extends React.Component {
constructor(props) {
super(props);
this.state = {
direction: null,
timeout: null
};
}
attack(e) {
//following line can be used to identify multiple targets
//let target = (e.target);
if (this.state.timeout !== null) {
window.clearTimeout(this.state.timeout)
}
let timeout = setTimeout(() => {
this.setState({
direction: null,
timeout: null
});
}, 8000)
let direction = null;
if (e.ctrlKey) {
direction = 'anticlockwise'
} else {
direction = 'clockwise'
}
if (this.state.direction !== direction) {
this.setState({
direction, timeout
});
}
}
render() {
let classNames = ["player", "main"];
let styles = {}
if (this.state.direction !== null) {
if (this.state.direction === 'clockwise')
styles.zoom = 0.8
else
styles.zoom = 1.2
classNames.push(this.state.direction)
}
return ( < div onClick = {
this.attack.bind(this)
}
style={styles}
className = {
classNames.join(' ')
} > {
this.props.name
} < /div>
);
}
}
ReactDOM.render(<Player / > , document.getElementById('game'));
.player {
width: 100px;
height: 100px;
margin: 50px;
zoom: 1;
transition: all linear 0.3s;
display: inline-block;
background-color: #ccc;
animation-timing-function: linear;
}
.clockwise {
animation: clockwise 5s infinite;
}
.anticlockwise {
animation: anticlockwise 5s infinite;
}
#keyframes clockwise {
0% {
transform: rotate(0deg)
}
50% {
transform: rotate(180deg)
}
100% {
transform: rotate(360deg)
}
}
#keyframes anticlockwise {
0% {
transform: rotate(360deg)
}
50% {
transform: rotate(180deg)
}
100% {
transform: rotate(0deg)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="game"></div>

Why do we need to clear the animation when running it multiple times in JavaScript?

Yesterday I asked a question (original question) that was promptly answered, but even though a solution was found, I don't understand why this is working the way it is. I can duplicate this solution for other things I need to do but before I continue on I would like to understand why this works the way it does.
So basically I made three functions that called each other. The 1st called the second upon "animationend" and the second called the third upon an "animationend" and the finally the third function called the first to start the cycle all over again - BUT My original code though lacked;
document.getElementById("rightBoxTwo").style.animation = "none";
which was needed in-order for the third function to call the first so the cycle starts all over again. Without the above code in each function the three functions would work only once and then stop. The answer that StackOverFlow user; ScientiaEtVeritas gave me included a CodePen which had a working example of what I needed and a brief explanation
So, I think you have several options: What could work is that you
reset the the animation of rightBox in function runTwo with
animation: none. If you assign scrollTextTwo 10s back to the
rightBox it should start again. Equivalent for the other ones.
So finally my question is WHY does the animation need to be cleared, and why does the .style.animation = "none"; accomplish this?
below is the working code after a solution was presented...
<body onload="runOne()">
function runOne() {
var x = document.getElementById("rightBox");
x.addEventListener("animationend",runTwo);
document.getElementById("rightBox").style.animation = "scrollTextTwo 10s";
document.getElementById("rightBoxTwo").style.animation = "none";
}
function runTwo() {
var x = document.getElementById("rightBoxTwo");
x.addEventListener("animationend",runThree);
document.getElementById("rightBoxTwo").style.animation =
"scrollTextTwo 10s";
document.getElementById("rightBoxThree").style.animation = "none";
}
function runThree() {
var x = document.getElementById("rightBoxThree");
x.addEventListener("animationend",runOne);
document.getElementById("rightBoxThree").style.animation =
"scrollTextTwo 10s";
document.getElementById("rightBox").style.animation = "none";
}
The simplest reason is because setting the animation to the same thing twice (or more times) in a synchronous manner like a for loop is the same as doing it once:
let box = document.getElementById('box');
// animation happens once
for (let i = 0; i < 5; i++) {
box.style.animation = 'fade .5s';
}
#keyframes fade {
from {
opacity: 1
}
to {
opacity: 0
}
}
#box {
height: 200px;
width: 200px;
margin: 50px;
background: #018bbc;
}
<div id="box"></div>
The behavior is the same even if you delay the animation so each time it runs after a possible render:
let box = document.getElementById('box');
// animation still happens once
for (let i = 0; i < 5; i++) {
setTimeout(function() {
box.style.animation = 'fade .5s';
}, i * 1000);
}
#keyframes fade {
from {
opacity: 1
}
to {
opacity: 0
}
}
#box {
height: 200px;
width: 200px;
margin: 50px;
background: #018bbc;
}
<div id="box"></div>
But if I reset the animation before each step, the engine has to re-set the animation, which in a way means to "install the animation again", meaning it will be animated again:
let box = document.getElementById('box');
box.addEventListener('animationend', function() {
box.style.animation = 'none';
});
// animation now happens every time
for (let i = 0; i < 5; i++) {
setTimeout(function() {
box.style.animation = 'fade .5s';
}, i * 1000);
}
#keyframes fade {
from {
opacity: 1
}
to {
opacity: 0
}
}
#box {
height: 200px;
width: 200px;
margin: 50px;
background: #018bbc;
}
<div id="box"></div>
You don't really need javascript for something like this. Keyframes let you define styles by percent complete. Using that you can time 2 animations for a similar result:
#keyframes progress {
0% { width: 0px;}
50% { width: 600px;}
100% {width: 600px;}
}
#keyframes progress2 {
0% { width: 600px;}
49% { width:600px;}
50% { width: 0px;}
100% {width: 600px;}
}
div {
width:600px;
height:50px;
background-color:black;
}
#rightBox {
animation: progress 4s infinite;
}
#rightBoxTwo {
animation: progress2 4s infinite;
}
<div id="rightBox"></div>
<div id="rightBoxTwo"></div>

Javascript trigger (progressbar) when on screen

i am currently making my own 1-page portfolio website for school and i had this cool idea that i want to show how far ive become in some coding languages by using a progressbar, for example, c# = 60% and that would be 60% of a circle. i think i can do that bu using the internet but i would like it to start / end at 60 when i'm scrolling down and it should start the progressbar when it is on screen. i do not know and cannot find on how to trigger the code when the (in this case progressbar) is visible on screen.
note: i am a fairly new javascript programmer and a fairly new user so please explain if i did something wrong.
Here is a working example of triggering an animation when you scroll to 75% of an image's height using the Intersection Observer API:
const images = document.querySelectorAll('.animate-me');
const config = {
root: null, // viewport
rootMargin: '0px',
threshold: 0.75
};
let observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.intersectionRatio >= config.threshold) {
entry.target.classList.add("active");
}
});
}, config);
images.forEach(image => {
observer.observe(image);
});
.spacer {
height: 400px;
}
.animate-me.active {
animation: anim1 .7s ease-out;
}
#keyframes anim1 {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<div class="spacer">(Scroll down)</div>
<img src="https://picsum.photos/200" class="animate-me">
<div class="spacer"></div>
You should be able to translate this to your own use case, but please share more specifics if you are looking for something else.

Categories

Resources