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.
Related
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.
Issue:
I am using the Circle Progress JQuery plugin (version: 0.6.0) for a project and have made some modifications to it, however, each circle seems to repeat itself (or loop) for an extended period of time rather than only performing the animation once.
Due to the modifications made, such as adding a link to where if it is clicked, the animation begins, doesn't seem to be where the issue lies. It's when you start to scroll down, and when you do - every circle starts animating based on the percentage set but keeps repeating itself several times before it stops. It should only start the animation for each circle once when the user scrolls down but I can't seem to figure out the root of why this is occurring.
Here is what I have:
$('.about_nav a:nth-of-type(2)').click(function () {
function animateElements() {
$('.progressbar').each(function () {
var elementPos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
var percent = $(this).find('.circle').attr('data-percent');
var percentage = parseInt(percent, 10) / parseInt(100, 10);
var animate = $(this).data('animate');
if (elementPos < topOfWindow + $(window).height() - 30 && !animate) {
$(this).data('animate', false); // Change this 'false -or- true' - Currently set to false so that each time a user clicks on 'Skill-set' link, animation occurs
$(this).find('.circle').circleProgress({
startAngle: -Math.PI / 2,
value: percent / 100,
thickness: 2, // Change this for thickness
fill: {
color: '#16A085'
}
}).on('circle-animation-progress', function (event, progress, stepValue) {
$(this).find('.percent').text((stepValue*100).toFixed(0) + "%"); // NOTE: Change '.toFixed(0)' to '.toFixed(1)' to get 1 decimal place to the right...
}).stop();
}
});
}
animateElements();
$('.about_body_wrapper').scroll(animateElements);
});
Here is a rough demo of what I mean: DEMO - Click "Skill-set" tab and scroll down.
Any help on this would be greatly appreciated!
so I think I've achieved what you wanted on This updated(again) JSFIDDLE
basically, I set the data-animate property to true right before the animation begins, which stops any subsequent animate calls from animating it again (the looping issue you were seeing).
Then, I took the animateElements function definition out of the click handling event. I did this so I could call it on a more global scope. I now call animateElements in the click handler that changes the tabs. Had to do that because it being fired on page load was making all the elements offsetTop = 0 because they started out hidden.
Lastly, I added an init property to the animate elements function which resets all the data-animate to false when true. Its only true when called from a tab click, not by the scroll event.
heres the relevant code update:
...new init param (also have to make room for the scroll event passed in)
function animateElements(e, init) {
if(init){
$('.progressbar').data('animate', false);
}
...animateElements is now initially called by the tab click handler
$(currentlist).fadeOut(250, function () {
$(newlist).fadeIn(200, function(){
animateElements({}, true);
});
});
lastly, note theres a bunch of stuff in there now you can cut out now that I forgot to in the jsfiddle from when I was proving the concept.
cheers!
I'm trying to count the number of times a user scrolled the page (any direction) and moved his mouse using this jquery code:
$(window).bind('scroll',function(e){
scrolling++;
});
$(window).bind('mousemove',function(e){
mouse_moved++;
});
The problem with this is one scroll event or one mouse movement gives the variables 'scrolling' and 'mouse_moved' a very high amount instead of just incrementing it by one.
It seems whenever the scrubber / mouse position changed it is counting it as one event already, even though the original event isn't done yet.
How can I do this correctly? Count one scrolling and mouse movement event properly?
You need to track your state, e.g. detect when scrolling/moving starts, then again when it ends. And you need to decide what "ending" means — how long does the mouse have to be stationary again before you decide it's stopped moving? 5ms? 10? 15?
var scrolling = 0;
var scrollTimeout = 0;
$(window).bind('scroll',function(e){
cancelTimeout(scrollTimeout);
scrollTimeout = setTimeout(doneScrolling, 10); // 10 = 10ms
});
function doneScrolling() {
scrollTimeout = 0;
++scrolling;
}
...and similarly with the mouse move (with its own separate timer).
I have about 50 Images that should be shown one after another inside a div.
The delay between showing one image then another is about 750 milliseconds and decreasing with each image.
I made sure that all images are loaded before this animation kicks in, by using:
(window).load(function() { });
The animaton is done using setTimeout
var index = 1;
function newImage(index) {
var interval = setTimeout( function(){
$("#image-container .image").css("display","none");
$("#image-container .image:nth-child("+index+")").css("display","block");
clearTimeout(interval);
index = index + 1;
newImage(index);
},delay[index-1]);
}
Where delay is an array of delays, something like [750,750,650,...].
The animation works fine, but there's a visual delay as fast as a blink of an eye, where no image is shown and only the background is visible, how can I avoid it?
try to use visibility css property instead of display
I try to make a mousewheel event script, but getting some issues since I'm using an Apple Magic Mouse and its continue-on-scroll function.
I want to do this http://jsfiddle.net/Sg8JQ/ (from jQuery Tools Scrollable with Mousewheel - scroll ONE position and stop, using http://brandonaaron.net/code/mousewheel/demos), but I want a short animation (like 250ms) when scrolling to boxes, AND ability to go throught multiple boxes when scrolling multiple times during one animation. (If I scroll, animation start scrolling to second box, but if I scroll again, I want to go to the third one, and if I scroll two times, to the forth, etc.)
I first thought stopPropagation / preventDefault / return false; could "stop" the mousewheel velocity (and the var delta) – so I can count the number of new scroll events (maybe with a timer) –, but none of them does.
Ideas?
EDIT : If you try to scroll in Google Calendars with these mouses, several calendars are switched, not only one. It seems they can't fix that neither.
EDIT 2 : I thought unbind mousewheel and bind it again after could stop the mousewheel listener (and don't listen to the end of inertia). It did not.
EDIT 3 : tried to work out with Dates (thanks to this post), not optimal but better than nothing http://jsfiddle.net/eZ6KE/
Best way is to use a timeout and check inside the listener if the timeout is still active:
var timeout = null;
var speed = 100; //ms
var canScroll = true;
$(element).on('DOMMouseScroll mousewheel wheel', function(event) {
// Timeout active? do nothing
if (timeout !== null) {
event.preventDefault();
return false;
}
// Get scroll delta, check for the different kind of event indexes regarding delta/scrolls
var delta = event.originalEvent.detail ? event.originalEvent.detail * (-120) : (
event.originalEvent.wheelDelta ? event.originalEvent.wheelDelta : (
event.originalEvent.deltaY ? (event.originalEvent.deltaY * 1) * (-120) : 0
));
// Get direction
var scrollDown = delta < 0;
// This is where you do something with scrolling and reset the timeout
// If the container can be scrolling, be sure to prevent the default mouse action
// otherwise the parent container can scroll too
if (canScroll) {
timeout = setTimeout(function(){timeout = null;}, speed);
event.preventDefault();
return false;
}
// Container couldn't scroll, so let the parent scroll
return true;
});
You can apply this to any scrollable element and in my case, I used the jQuery tools scrollable library but ended up heavily customizing it to improve browser support as well as adding in custom functionality specific to my use case.
One thing you want to be careful of is ensuring that the timeout is sufficiently long enough to prevent multiple events from triggering seamlessly. My solution is effective only if you want to control the scrolling speed of elements and how many should be scrolled at once. If you add console.log(event) to the top of the listener function and scroll using a continuous scrolling peripheral, you will see many mousewheel events being triggered.
Annoyingly the Firefox scroll DOMMouseScroll does not trigger on magic mouse or continuous scroll devices, but for normal scroll devices that have a scroll and stop through the clicking cycle of the mouse wheel.
I had a similar problem on my website and after many failed attempts, I wrote a function, which calculated total offset of selected box and started the animation over. It looked like this:
function getOffset() {
var offset = 0;
$("#bio-content").children(".active").prevAll().each(function (i) {
offset += $(this)[0].scrollHeight;
});
offset += $("#bio-content").children(".active")[0].scrollHeight;
return offset;
}
var offset = getOffset();
$('#bio-content').stop().animate( {
scrollTop: offset
}, animationTime);
I hope it gives you an idea of how to achieve what you want.
you can try detecting when wheel stops moving, but it would add a delay to your response time
$(document).mousewheel(function() {
clearTimeout($.data(this, 'timer'));
$.data(this, 'timer', setTimeout(function() {
alert("Haven't scrolled in 250ms!");
//do something
}, 250));
});
source:
jquery mousewheel: detecting when the wheel stops?
or implement flags avoiding the start of a new animation
var isAnimating=false;
$(document).bind("mousewheel DOMMouseScroll MozMousePixelScroll", function(event, delta) {
event.preventDefault();
if (isAnimating) return;
navigateTo(destination);
});
function navigateTo(destination){
isAnimating = true;
$('html,body').stop().animate({scrollTop: destination},{complete:function(){isAnimating=false;}});
}