So I made an animation where a div called "slider" appears from the left side of the screen, expands to the right and then disappears on the right side of the screen. What I have done is start with width: 0; then transform to the full width, change position to right and have the width go back to 0 and change display to none. The animation works fine, but probably with excessive use of the setTimeout. Is there a better way to write this piece of JavaScript and have one animation start when the previous has finished without the use of setTimout?
window.addEventListener("DOMContentLoaded", function(){
slider.style.width = "60%";
slider.style.position = "absolute";
setTimeout(function(){
slider.style.right = "25%";
slider.style.width = "0px";}, 750);
setTimeout(function(){
slider.style.display = "none";}, 1500);
});
Related
For a website I made a JS, to animate a div upon scroll. I was animating the CSS top value, but since I had a transition applied to that property, I had to come up with a way of animating "top" without the lag that CSS transitions results in.
I came up with this inside a function:
//Get the Div Element
var div = document.querySelector('.someclass');
//Disable Transition
div.style.transition= 'none';
//Change the top value - value was connected to scroll
div.style.top = anumber + 'px';
//Reset Transition to the CSS's file default
div.style.transition = '';
But this resulted in the unwanted lag again, because it somehow ignored the "Disable Transition" step.
To make sure that each step would be executed, I came up with the Idea to wrap the "Reset" step into a setTimeout function. I changed this line:
//Reset Transition to the CSS's file default
div.style.transition = '';
to
//Reset Transition to the CSS's file default
setTimeout(function () {
div.style.transition = '';
},1);
And Tadaa, it worked. But now I'm wondering, if there was a cleaner way to prevent the first line of not being executed, and of course an explenation why it even happened.
I appreciate all the help!
Changes to the DOM only get reflected to the underlying model when the CSS engine runs, which only happens if JS stopped running. By using setTimeout the execution of JS ends, the CSS engine has time to run, then the timer fires and JS runs again.
You could solve ut a bit more elegantly with:
const tick = () => new Promise(resolve => setTimeout(resolve));
(async function() {
//Get the Div Element
var div = document.querySelector('.someclass');
//Disable Transition
div.style.transition= 'none';
//Change the top value - value was connected to scroll
div.style.top = anumber + 'px';
await tick();
//Reset Transition to the CSS's file default
div.style.transition = '';
})();
So I'm trying to add a progress bar to the "Superslides" slider. I've used setInverval to trigger this when a slide finishes animating and for the most part it works.
I also added a little bit that resets the interval if someone clicks one of the links on the slider (next slide, prev, or pagination) and that also works however the slider has touch support using hammer.js and when I try to do the same thing after a swipe event it doesn't seem to reset properly. It resets the progess bar's width back to 0 but the interval continues despite trying to clear it.
I'm probably doing something fairly stupid but I've been scratching my head for a while so I thought I'd ask what I'm doing wrong.
$(document).on('animated.slides', function() {
var progressBar = $('#progress-bar');
width = 0;
progressBar.width(width);
var interval = setInterval(function() {
width += 1;
progressBar.css('width', width + '%');
if (width >= 100) {
clearInterval(interval);
}
//Trying to reset on swipe (I've also tried putting this below outside of interval
Hammer($slides[0]).on("swipeleft swiperight", function(e) {
width = 0;
clearInterval(interval);
});
}, 160);
//reset on anchor click
$("#slides a").click(function(){
clearInterval(interval);
});
});
I believe I solved the issue myself. The slider's implementation uses $slides as a variable for "#slider" and then uses that to trigger the swipe animations. I copied and pasted this into my interval function as is. When I used the id rather than the variable it seems to have worked.
I would like to move my image down the screen from the top left to the bottom left. I call two functions when the body loads:
window.onload = function() {
MoveRight();
MoveDown();
};
I then retreive the width and height of the clients browser window (to ensure the animation stops when it reaches the sides of the window):
document.body.style.height = height;
document.body.style.width = width;
The function "MoveDown()" is this:
function MoveDown(){
for(var i = 0; i < ; i++)
{
document.getElementById("Amanda").style.top=+i;
}
}
For some reason when I load the webpage, the image just sits in the top left. I had hoped the for loop would increment the "top" value by 1px every time, until such time that it was touching the bottom of the window when it would stop.
If it helps, the image position is set to relative with left and top both set to 0px.
If anyone could help it would be great.
*I collect the width as I want the image to move diagonally but figured that if I got moving down figured out I could easily change the code to make it go sideways at the same time.
The reason it's not moving is most likely (depending on browser) because you're not setting the units. Try
document.getElementById("Amanda").style.top=i+"px";
However, you'll find that it jumps straight down rather than animating. The reason is your loop executes all in one go without giving the browser a chance to redraw. There are a number of ways of getting around this, but one simple one would be like this
function MoveDown() {
var i=0;
function step() {
document.getElementById("Amanda").style.top=i+"px";
i++;
if (i<=100) setTimeout(step,10);
}
step();
}
Do you have position: absolute or position: relative (or position: fixed) as styling for your image?
Asking this because top applies only to positioned elements (and by default elements have position: static which is they are not explicitly positioned).
See https://developer.mozilla.org/en-US/docs/Web/CSS/top and https://developer.mozilla.org/en-US/docs/Web/CSS/position
On rereading your question, this loop of yours looks like an endless loop. Consider adding a stop rule for it, or as suggested in the comments - if you do not need some kind of sliding animation, just put css rule for bottom: 0
You'll want to use setTimeout or setInterval (I can never remember) with some interval and a function that increments the top value every time it runs. Then cancel the timeout/interval when the image reaches it's destination!
I am trying to create a very simple slideshow.
I would like the slideshow to pause on hover and resume when the user moves their mouse off the slideshow (#slide_container). While the slideshow works fine, and so does the hover (to an extent), if I flick my mouse on and off the slideshow repeatedly, it completely messes the slide and starts animating sporadically (check the fiddle below to see what I mean).
I tried adding promise, so that before animating it completes any queued animation, but despite this, the behaviour remains.
How should I go about fixing this?
Here is the fiddle: http://jsfiddle.net/hR6wZ/
my js code:
$(document).ready(function() {
//get variables
var slide_width = $('.slider_container').width();
var number_of_slides = $('.slider_container .slide').length;
var slider_width = slide_width*number_of_slides;
//set element dimensions
$('.slide').width(slide_width);
$('.slider').width(slider_width);
var i = 0;
var hover_switch = 0;
$('.slider_container').hover(function() {
//Hover mode on
hover_switch = 1;
}, function() {
//Hover mode off
hover_switch = 0;
sliderLoop()
});
function animateSlider() {
$(":animated").promise().done(function() {
$('.slider').finish().animate({ marginLeft: -(slide_width * i) });
});
}
function sliderLoop() {
setTimeout(function(){
//Only runs if hover mode is off;
if(i < number_of_slides-1 && !hover_switch) {
i++;
animateSlider();
sliderLoop();
}
else if (!hover_switch)
{
i = 0;
animateSlider();
sliderLoop()
}
},4000);
}
sliderLoop();
});
EDIT: also I did try using stop instead of finish() but this didn't fix the issue..
Becuase your calling the slider loop each time you hover out everytime even if you hover back and forth like ten times it tells it and queus it up to animate the x amount of times you did that.
What you can try is Only have the slider loop check right then and their when it's about to animate if it is being hovered or not and don't call the slider loop from the every time that it hovers out.
Another way is right before it begins animating set a variable for the duration of the animation to tell it not to call the animateSlider function if Currently_animating
so add && !currently_animating to each if statement within the sliderloop function.
That method however will help but probably the first way would be better as then it will never animate more then every x miliseconds or however long you set it to be.
But in General you probably should not call the sliderloop function if hover_switch = 0 becuase then it will just queue up the slider loop each time you hover out.
I have a div container which sticks to the bottom of the page. When the mouse moves out of the div, I want the div to sink after 3 seconds. When the mouse moves over the div, I want the div to rise to its original position. The problem is when the mouse moves over and out of the div very quickly, the div keeps moving up towards the top of the page.
var timer = null;
var moving_distance = $("#scroller").height()-($(window).height()-$("#slideshow").height());
$("#scroller").mouseenter(function(event){
if(timer)
{
clearTimeout(timer);
$("#scroller").animate({top:'-='+moving_distance},1000);
}
}).mouseleave(function(event){
if(!timer){
timer = setTimeout(function(){
$("#scroller").animate({top:'+='+moving_distance},1000);
},3000);
}
});
I have had success stacking a null animation in front of the animation I want rather than using setTimeout.
For instance,
var moving_distance = $("#scroller").height()-($(window).height()-$("#slideshow").height());
var firstEnter = true;
$("#scroller").mouseenter(function(event){
if (firstEnter)
firstEnter = false;
else {
$("#scroller").stop();
$("#scroller").animate({top:'+=0', 3000);
$('#scroller').animate({top:'-='+$('#scroller').top()), 1000);
}
}).mouseleave(function(event){
$('#scroller').stop();
$("#scroller").animate({top:'+=0', 3000);
$('#scroller').animate({top:'+='+moving_distance), 1000);
});
I am guessing from your description that you want the div to stand still until the mouse is moved into the div. Then when the mouse leaves for the first time it should sink. After that, when the mouse comes back again, it should return to its original position. I think this will be close to doing that.
HTH