I want to apply a random animation on my slideshow image. First, I tried adding an animation such as scale but it didn't work as I wanted it to.
Things I want to fix:
Smoothness on fadein
Random animation (can be anything at this point, I just want to see how it's done)
Fiddle: http://jsfiddle.net/jzhang172/e7cLtsg9/1/
$(function() {
$('img').hide();
function anim() {
$("#wrap img").first().appendTo('#wrap').fadeOut(3500).addClass('transition').addClass('scaleme');
$("#wrap img").first().fadeIn(3500).removeClass('scaleme');
setTimeout(anim, 3700);
}
anim();
});
body,
html {
margin: 0;
padding: 0;
background: black;
}
#wrap img {
position: absolute;
top: 0;
display: none;
width: 100%;
height: 100%;
}
.transition {
transition: 10s;
}
.scaleme {
transition: 10s;
transform: scale(1.3);
}
.box {
height: 300px;
width: 500px;
position: relative;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
<div id="wrap">
<img src="http://elegantthemes.com/preview/InStyle/wp-content/uploads/2008/11/s-1.jpg" />
<img src="http://elegantthemes.com/preview/InStyle/wp-content/uploads/2008/11/s-5.jpg" />
<img src="http://elegantthemes.com/preview/InStyle/wp-content/uploads/2008/11/s-3.jpg" />
</div>
</div>
Here is a sample using CSS animations and jQuery (for achieving the randomness of animations). If you don't wish to use CSS animations and want to stick to transitions + jQuery effects (like fadeIn), you can still adapt this code to support it because the base idea will still remain the same. I am not too comfortable with jQuery effects and have hence stuck to using CSS animations.
Below is an overview of how it is being done (refer inline comments for more details):
Inside a wrapper there are a group of images that are part of the slide-show (like in your demo).
Using CSS #keyframes, a list of animations (one of which would be used randomly) is created in addition to the default fade-in-out animation. This list is also maintained in an array variable (in JS for picking up a random one from the list).
On load, the default fade-in-out animation and one random animation is added to the 1st element.
An animationend event handler is added to all of the images. This event handler will be triggered when the animation on an element ends. When this is triggered, animation on the current element is removed and the default fade-in-out + a random animation is added to the next element.
The animations are added using inline styles because if we add multiple CSS classes each with one different animation, then the animation in the latest class will override the others (that is, they will not happen together).
A loop effect is achieved by checking if the current element has any other img sibling elements. If there are none, the animation is added back to the 1st element.
$(window).load(function() {
$img = $('img'); // the images
var anim = ['zoom', 'shrink', 'move-down-up', 'move-right-left']; // the list of random animations
var rand = Math.floor(Math.random() * 4) + 1; // random number
$img.each(function() { // attach event handler for each image
$(this).on('animationend', function(e) { // when animation on one image has ended
if (e.originalEvent.animationName == 'fade-in-out') { // check the animation's name
rand = Math.floor(Math.random() * 4) + 1; // get a random number
$(this).css('animation-name', 'none'); // remove animation on current element
if ($(this).next('img').length > 0) // if there is a next sibling
$(this).next('img').css('animation-name', 'fade-in-out, ' + anim[rand - 1]); // add animation on next sibling
else
$img.eq(0).css('animation-name', 'fade-in-out, ' + anim[rand - 1]); // else add animation on first image (loop)
}
});
});
$img.eq(0).css('animation-name', 'fade-in-out, ' + anim[rand - 1]); //add animation to 1st element on load
})
#wrapper {
height: 250px;
width: 300px;
position: relative;
}
img {
position: absolute;
z-index: 1;
bottom: 20px;
left: 10px;
opacity: 0;
transform-origin: left top; /* to be on the safe side */
animation-duration: 3s; /* increase only if you want duration to be longer */
animation-fill-mode: backwards; /* fill mode - better to not change */
animation-iteration-count: 1; /* no. of iterations - don't change */
animation-timing-function: ease; /* better to leave as-is but can be changed */
}
#keyframes fade-in-out {
0%, 100% {
opacity: 0;
}
33.33%, 66.66% { /* duration is 3s, so fade-in at 1s, stay till 2s, fade-out from 2s */
opacity: 1;
}
}
#keyframes zoom {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.5);
}
}
#keyframes shrink {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(.5);
}
}
#keyframes move-down-up {
0%, 100% {
transform: translateY(0px);
}
50% {
transform: translateY(50px);
}
}
#keyframes move-right-left {
0%, 100% {
transform: translateX(0px);
}
50% {
transform: translateX(50px);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrapper">
<img src="https://placehold.it/200/000000/ffffff" />
<img src="https://placehold.it/200/ff0000/ffffff" />
<img src="https://placehold.it/200/00ff00/ffffff" />
<img src="https://placehold.it/200/0000ff/ffffff" />
</div>
Related
I know that it is possible to set the animation of an element by id either in a stylesheet or in JS from the DOM. The issue is that I want the animation to execute every time a click action on a specific element is performed by the user. Adding the animation to an element's style in JS seems to add it permanently so that the keyframes animation cannot be performed again, (only performed once when the window finishes loading). I also thought about using jQuery's .animate() function however all documentation points to it animating over CSS specific styles and not setting/calling the animation style attribute as if I were to set it using CSS. I want to know the best way of executing my animation over an element when another element is clicked on by the user and consistently executing the animation for each click.
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate(0, -20%);
}
to {
opacity: 1;
transform: translate(0, 0);
}
}
The current way I'm setting animation for an element:
$("#element").css("animation", "fadeInDown 0.5s ease-in 0s 1");
This is a toggling animation using transition and jquery, without using .animate()
$(document).ready(function() {
$('button').click(function() {
var box = $('.box')
box.removeClass("show")
setTimeout(function(){
box.addClass("trans").addClass("show")
setTimeout(function(){
box.removeClass("trans")
},100)
},200)
});
});
.box {
background: red;
height: 50px;
width: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
opacity: 0;
transform: translate(0, -20%);
}
.box.trans {
transition: all 0.7s;
}
.box.show {
opacity: 1;
transform: translate(0, 0);
}
<button>Test</button>
<div class="box show"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
It's my first answer on stack overflow.
I had the same question about animation.
What I did last was just like Vivek Patel's answer, but instead of toggling the css keyframe, I created a separated class only for css animation("animation-fadeInDown"), and toggle it.
Because the animation-name "fadeInDown" is correponding to the #keyframes name, so if you separate it you could apply the animation to other elements, by just toggling the animation class.
And, you can still do the css deco to the original box seperately, which might be more clear to read.
I hope this is close to what you looking for.
$('button').click(() => {
$('.box').toggleClass('animation-fadeInDown');
});
.box {
width: 50px;
height: 50px;
background: black;
}
.animation-fadeInDown {
animation: fadeInDown 0.5s ease-in 0s 1
}
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate(0, -20%);
}
to {
opacity: 1;
transform: translate(0, 0);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="box"></div>
<button>
Test
</button>
Basically CSS animation only runs once when the page loads. So it is not possible to re-trigger it again. Here is the workaround for your use case: Remove the element from the page entirely and re-insert it.
Try this:
$('button').click(() => {
var oldDiv = $('#animated-div');
newDiv = oldDiv.clone(true);
oldDiv.before(newDiv);
$("." + oldDiv.attr("class") + ":last").remove();
});
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate(0, -20%);
}
to {
opacity: 1;
transform: translate(0, 0);
}
}
.animated-div {
animation: fadeInDown 0.5s ease-in 0s 1
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="animated-div" class="animated-div" style="width: 50px; height: 50px; background: black"></div>
<button>
Test
</button>
This is an simple example that use jquery to animate in Queue as it works in #keyframes. The transition duration and animation duration gives more control on the animation character.
$(document).ready(function() {
$('button').click(function() {
$('.box')
.css('transition', 'all 0.2s')
.animate({ opacity: 0 }, {
duration: 200,
step: function(now) {
$(this).css({ opacity: now });
$(this).css({ transform: 'translate(0, -20%)' });
}
})
.animate({ opacity: 1 }, {
duration: 600,
step: function(now) {
$(this).css({ opacity: now });
$(this).css({ transform: 'translate(0, 0)' });
}
})
});
});
.box {
background: red;
height: 50px;
width: 50px;
position: absolute;
margin-top: 50px;
margin-left: 50px;
}
<button>Test</button>
<div class="box"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
I'm trying to build a puzzle game website. I'm using webkit animation to rotate (and translate) two images.
My plan is to have rotating gears attached to the left and right edge of my page, offset in a way that only half of each image is shown at a time.
The animation works fine but
(1) i am unable to pause it, and
(2) depending on window size the images are moved out of view (with an automatic scrollbar popping up) or into full view.
The setup is pretty simple:
I have 3 divs: one bar at the top with 100% width and two divs with 50% width below as containers for my images.
I might need to add more below or in between the two divs down the road but for now a solution for this would be good enough^^
For the animation i have a pseudo button on each side which adds a pause class to my images.
HTML
<div id="div-left">
<p>Hey this is the left div</p>
<img src="images/zahnrad.png" alt="zahnrad" id="image1">
<p id="pausebtn1" onclick="pause1()">pause</p>
</div>
<div id="div-right">
<p>hey this is the right div</p>
<img src="images/zahnrad.png" alt="zahnrad" id="image2">
<p id="pausebtn2" onclick="pause2()">pause</p>
</div>
CSS
#image1{
-webkit-animation: rotation-left 30s infinite linear;
}
#image1.paused1::-webkit-progress-value{
-webkit-animaion-play-state:paused;
animaion-play-state:paused;
}
#image2{
align: right;
-webkit-animation: rotation-right 30s infinite linear;
}
#image2.paused2::-webkit-progress-value{
-webkit-animaion-play-state:paused;
animaion-play-state:paused;
}
/* Animations */
#-webkit-keyframes rotation-left{
from {
-webkit-transform: translate(-50%,0px) rotate(0deg);
}
to{
-webkit-transform: translate(-50%,0px) rotate(359deg);
}
}
#-webkit-keyframes rotation-right{
from {
-webkit-transform:translate(+50%,0px) rotate(0deg);
}
to{
-webkit-transform:translate(+50%,0px) rotate(-359deg);
}
}
Javascript
function pause1() {
console.log("pause img 1");
document.getElementById('image1').classList.toggle("paused1");
}
function pause2() {
console.log("pause img 2");
document.getElementById('image2').classList.toggle("paused2");
}
So to sum it all up:
I have two images in the wrong places. They are animated. My two buttons are working but trying to pause the animation by adding a paused class doesn't function.
Any help would be appreciated and i'll see if i can add images later
You shouldn't be targeting ::-webkit-progress-value, that's for <progress> elements. Just toggle the class onto the element:
button.addEventListener('click', function () {
square.classList.toggle('paused');
});
#square {
animation: rotate 1s infinite;
background: lightblue;
border: 1px solid black;
height: 100px;
left: 50px;
position: absolute;
top: 50px;
width: 100px;
}
#square.paused {
animation-play-state: paused;
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<button id="button">Pause/Resume</button>
<div id="square">Rotate</div>
I have made a group of elements and set a hover for their class
.cards:hover {
transition: 0.2s;
transform: translate( 0px, -50px);
height: 180px;
width: 120px;
background-size: 120px 180px;
}
There are 10 elements in the class and i have a JS file that onclick singles out the element and i want it to spin so i write the JS and i tell it to add a transform after the click like
document.getElementById(idTag).style.transition = "3s ease";
document.getElementById(idTag).style.transform = "rotate(270deg)";
but it doesn't rotate it. Instead it goes directly to 270 degrees in the shortest possible path. If i remove the transform from the hover then it rotates like normal but if i have a transform on hover it doesn't work. Is there a conflict or something with the hover effect ?
In order to transition vertical displacement (translate) and rotation separately you should probably use a different way of moving the element upwards. Using the top property and a relative position. Then you could have the following css code...
.cards {
position: relative;
transition: top 0.2s, transform 3s ease;
height: 180px;
width: 120px;
background-size: 120px 180px;
top: 0px;
transform: rotate(0deg);
}
.cards:hover {
top: -50px;
}
.cards.rotate {
transform: rotate(270deg);
}
And the following code within your click listener to add the rotate class for rotation after the click.
document.getElementById(idTag).classList.add('rotate')
Now the cards should move up on hover, but rotate on click with separate speeds.
function drawCard() {
var Deck = document.getElementsByClassName("cards");
var idTag = this.id;
document.getElementById(idTag).classList.remove("cards");
document.getElementById(idTag).classList.add("draw-card");
for (i = 0; i < Deck.length; i++) {
Deck[i].style.display = "none";
}
document.getElementById(idTag).style.transition = "2s";
document.getElementById(idTag).style.left = "100px";
document.getElementById(idTag).style.animation = "rotate 2s linear forwards";
on click I separate the picked card by changing the class and then cycle through the rest of the class to make the rest of the cards dissapear. After that I add the rotate animation with the key frames in CSS
#keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
I am placing a DIV element on the screen using CSS translate. This works fine, except that when the same element is displaced later, the original displacement is discarded.
Set the CSS start position with javascript
div.style.transform ="translate(800px, 400px)";
After setting the starting position randomly with javascript, the CSS animation just resets it back.
CSS Animation
#keyframes testanimation {
0% {
transform: translateY(20px);
}
100% {
transform: translateY(80px);
}
}
How can I combine CSS translations, to take previous displacements into account? In this case, the goal is to have the animation start at randomised locations. The 20px - 80px should be relative.
The best way to do this I would guess is to fetch the previous transform, add something to those values and then apply the new transform.
Another suggestion is to set the position of the element using position, left and top. Using the following code for example:
div.style.position = "absolute";
div.style.left = "800px";
div.style.top = "400px";
That way, the transform would then apply to that position instead of relative to your previous transform.
If it is only about transform, then you need to reset each value in the animation, else it will be overwritten by animation rules.
example:
div {/* translate value reduced to fit in snippet window */
border:solid;
height:40px;
width:40px;
transform:translatex(180px) translatey(140px);
animation:2s testanimation forwards;
}
#keyframes testanimation {
0% {
transform:translatex(180px) translatey(150px)
}
100% {
transform:translatex(180px) translatey(180px)
}
}
<div></div>
Your style to apply to start width should be :
div.style.transform ="translatex(800px) translatey(400px)";
and the animation :
#keyframes testanimation {
0% {
transform:translatex(800px) translatey(420px)
}
100% {
transform:translatex(800px) translatey(480px)
}
}
in order to update only the translatey value
translate or position:relative + coordonates have the same effects/results.
You can also combine them
div {/* value reduced to fit window's demo */
border:solid;
height:40px;
width:40px;
position:relative;
transform:translate(80px,40px);
animation:2s testanimation forwards;
}
#keyframes testanimation {
0% {
top : 20px
}
100% {
top:40px
}
}
<div></div>
the other way round works too :
div {
/* value reduced to fit window's demo */
border: solid;
height: 40px;
width: 40px;
position: relative;
left: 80px;
top: 40px;
animation: 2s testanimation forwards;
}
#keyframes testanimation {
0% {
transform: translatey(20px)
}
100% {
transform: translatey(40px)
}
}
<div></div>
An example of my comment above:
#wrapperDiv {
width: 100px;
height: 100px;
background: green;
transform: translate(400px, 200px) rotate(50deg);
}
#yourDiv {
width: 100px;
height: 100px;
background: red;
animation: testanimation 2s infinite;
}
#keyframes testanimation {
0% {
transform: translateY(20px) rotate(0deg);
}
100% {
transform: translateY(80px) rotate(40deg);
}
}
<div id="wrapperDiv">
<div id="yourDiv">
<div>
<div>
The div#yourDiv will get a transform relative to its parent div#wrapperDiv transform.
I think a more general solution would be to parse the css transform property, as this allows you to keep animating an element without having to worry about its state.
This is the solution I use for this case:
parseTransformMatrix = function(str){
const match_float = "[+\\-]?(?:0|[1-9]\\d*)(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?"
const match_sep = "\\s*,?\\s*"
m = str.match(RegExp(`matrix\\((${match_float}(?:${match_sep}${match_float})*)\\)`))
if(!m || !m.length || m.length < 2) return null
return m[1].match(RegExp(match_float, 'g')).map(x => parseFloat(x))
}
// Test parseTransformMatrix method
console.log(parseTransformMatrix("matrix(1, 0, 0, 1, 96.2351, 309.123)"));
getElementTranslate = function(e){
let t = e.css("transform")
let r = { left: 0, top: 0 }
if(!t) return r
mat = parseTransformMatrix(t)
if(!mat || !mat.length || mat.length != 6) return r
r.left = mat[4]
r.top = mat[5]
return r
}
Here, e is a jQuery element, but you could easily use getPropertyValue instead if you don't want to have this dependency.
Using these functions, you can do something like:
let t = getElementTranslate(e)
e.css({transform:`translate(${t.left+20}px,${t.top+80}px)`})
When I add the .shown class to my #overlay I would like the opacity to fade in for 2secs, then immediately reverse and fade out for 2 seconds, creating a sort of "flashing" effect.
I tried just removing the class but that doesn't show any animation at all. This is my sample markup/CSS:
HTML:
<div id="outer">
This is some text
<div id="overlay"></div>
</div>
CSS:
#overlay {
...
opacity: 0;
transition: opacity 2s ease-in-out;
}
#overlay.shown {
opacity: 0.3;
}
Attemped JS:
// Wait 2 seconds from page load...
setTimeout(function() {
// Add shown class to trigger animation
document.getElementById("overlay").classList.add("shown");
// Want to remove the class and hoped this would reverse the animation...
// it doesn't
document.getElementById("overlay").classList.remove("shown");
}, 2000);
jsFiddle
use css animation with keyframes
#keyframes myFlash
{
0% {opacity:0;}
50% {opacity:0.3;}
100% {opacity:0;}
}
#-webkit-keyframes myFlash /* Safari and Chrome */
{
0% {opacity:0;}
50% {opacity:0.3;}
100% {opacity:0;}
}
#overlay {
...
opacity: 0;
}
#overlay.shown {
animation:myFlash 2s;
-webkit-animation:myFlash 2s; /* Safari and Chrome */
}
It looks like you could use a second timeout after the first animation completes..
// Wait 2 seconds from page load...
setTimeout(function() {
// Animate Forward
document.getElementById("overlay").classList.add("shown");
setTimeout(function(){
// Animate Back
document.getElementById("overlay").classList.remove("shown");
},2000);
}, 2000);
There are lots of changes i have done to achieve your out put please check following code
Your css
#outer {
width: 100px;
height: 100px;
position: relative;
}
#overlay {
top: 0;
left: 0;
position: absolute;
width: 100%;
height: 100%;
background: #336699;
opacity: 0;
transition: opacity 2s ease-in-out;
}
#overlay.shown {
display: block;
opacity: 0.5;
}
Your js
setTimeout(function() {
$("#overlay").addClass("shown");
var def = $('#overlay').promise();
def.done(
function () {
$('body').stop().delay(5000).queue(function(){
$("#overlay").removeClass("shown");
});
});
}, 2000);
There was no delay between first and second so how it will show animation which you have done
Please check working demo.....Demo