How do I get this SetInterval to stop on hover off? - javascript

I have a stack of images I'm bringing in from YouTube, and I want the top image to fade out on hover and then start a rotating slideshow of the next 3 images. I've almost got it working but I'm having an issue with getting the SetInterval to stop when I hover off of the thumbnail.
thumbRotate: function(){} //This is up in the main object
//hover state over thumbs and slideshow animation
$('#youtube-widget ul a').hover(
// hover-in
function(){
$this = $(this);
$(this).children('.title-overlay').children('h5, img, span').stop(true, true).animate({opacity: '0'}, 200, function() {
$.Modules.VideoWidget.thumbRotate = setInterval(function() {
var topImage = $this.children('img:first');
topImage.stop(true, true).fadeOut(500).next().stop(true, true).fadeIn(500).end().appendTo($this);
}, 2000);
});
//hover-out
}, function() {
clearInterval($.Modules.VideoWidget.thumbRotate);
$(this).children('.title-overlay').children('h5, img, span').stop(true, true).animate({opacity: '1'}, 200);
}
);
edit: I noticed that hovering over the thumbnail seems to be increasing animation exponentially. For some reason the animations seem to be stacking up on themselves, but I don't really understand why.

Here is the problem - .hover() and .mouseover()...
Both of these functions perform an action not only when the cursor enters the element but also every time the mouse moves a single pixel within the element. In other words those 2 functions are great for simpler interactions, but it is necessary to use .mouseenter() and mouseleave() to setup interval functions otherwise you end up setting a new interval every time the cursor moves within the element (which can be a lot).
new fiddle - http://jsfiddle.net/b3Mb8/2/
new code -
//thumb rotate animation on hover
function startRotate($this) {
$.Modules.VideoWidget.thumbRotate = setInterval ( function() {
topImage = $this.children('img').filter(":first");
topImage.animate({opacity: '0'}, 500).next().animate({opacity: '1'}, 500).end().appendTo($this);
}, 800);
}
function stopRotate() {
clearInterval($.Modules.VideoWidget.thumbRotate);
}
$("#youtube-widget ul a").mouseenter(function() {
$this = $(this);
startRotate($this);
}).mouseleave(function() {
stopRotate();
});
//hover state over thumbs and slideshow animation
$('#youtube-widget ul a').hover( function(){
$this.children('.title-overlay').children('h5, img, span').stop(true, true).animate({opacity: '0'}, 300, function() {
});
//hover-out
}, function() {
$this.children('.title-overlay').children('h5, img, span').stop(true, true).animate({opacity: '1'}, 300);
});

It's an issue with your variable name I think. It's working here:
I just added this and used it in both intervals
var hoverInterval;
http://jsfiddle.net/b3Mb8/

Related

Jquery animate created element

I made div, if i click on it, jquery makes bullet and that element is animated. This is code:
$('.square').click(function() {
$('<div class="bullet"></div>').appendTo($('body')).animate({
'margin-top': 554
}, 2000, function() {
$(this).remove();
});
});
It works properly when I'm not clicking second time on div before animation is done. If i do this, my second "bullet" starts animation from position of first.
How to fix that? Thank's for help :)
UPDATE##
Here's the jsfiddle with problem:
https://jsfiddle.net/2ghj1x45/
it's because the elements all have a size because they aren't positioned absolutely so each bullet div you add has display block, so will get it's own line where it's height is bullet size + margin top , which increases as it's animated. try instead using position absolute so the bullet div doesn't affect the layout of any other div
like so
$(bullet).animate({ top: value });
Why not timeout the click function with a variable:
var animating = false;
$('.square').click(function() {
if(!animating) {
animating = true;
setTimeout(function() {
animating = false;
}, 2000);
$('<div class="bullet"></div>').appendTo($('body')).animate({
'margin-top': 554
}, 2000, function() {
$(this).remove();
});
}
});
EDIT:
Updated JSfiddle

Using a jquery slider for text instead of images?

This may be a little too specific, but I have a jquery slider that I am using <p> classes instead of images to cycle through customer quotes. Basically the problem I am running into right now is when it is static and non moving (JS code is commeneted out) they are aligned how I want them to be. As soon as the JS is un commented, they stretch out of view and you just see a white box?
Any ideas?
How I want each panel to look like:
jsfiddle
So I sort of made this my Friday project. I've changed a whole lot of your code, and added a vertical-align to the quotes and authors.
Here's the fiddle http://jsfiddle.net/qLca2fz4/49/
I added a whole lot of variables to the top of the script so you could less typing throughout.
$(document).ready(function () {
//rotation speed and timer
var speed = 5000;
var run = setInterval(rotate, speed);
var slides = $('.slide');
var container = $('#slides ul');
var elm = container.find(':first-child').prop("tagName");
var item_width = container.width();
var previous = 'prev'; //id of previous button
var next = 'next'; //id of next button
Since you used a % based width I'm setting the pixel widths of the elements in case the screen is reszed
slides.width(item_width); //set the slides to the correct pixel width
container.parent().width(item_width);
container.width(slides.length * item_width); //set the slides container to the correct total width
As you had, I'm rearranging the slides in the event the back button is pressed
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
I combined the prev and next click events into a single function. It checks for the ID of the element targeted in the click event, then runs the proper previous or next functions. If you reset the setInterval after the click event your browser has trouble stopping it on hover.
//if user clicked on prev button
$('#buttons a').click(function (e) {
//slide the item
if (container.is(':animated')) {
return false;
}
if (e.target.id == previous) {
container.stop().animate({
'left': 0
}, 1500, function () {
container.find(elm + ':first').before(container.find(elm + ':last'));
resetSlides();
});
}
if (e.target.id == next) {
container.stop().animate({
'left': item_width * -2
}, 1500, function () {
container.find(elm + ':last').after(container.find(elm + ':first'));
resetSlides();
});
}
//cancel the link behavior
return false;
});
I've found mouseenter and mouseleave to be a little more reliable than hover.
//if mouse hover, pause the auto rotation, otherwise rotate it
container.parent().mouseenter(function () {
clearInterval(run);
}).mouseleave(function () {
run = setInterval(rotate, speed);
});
I broke this in to its own function because it gets called in a number of different places.
function resetSlides() {
//and adjust the container so current is in the frame
container.css({
'left': -1 * item_width
});
}
});
//a simple function to click next link
//a timer will call this function, and the rotation will begin :)
And here's your rotation timer.
function rotate() {
$('#next').click();
}
It took me a little bit, but I think I figured out a few things.
http://jsfiddle.net/qLca2fz4/28/
First off, your console was throwing a few errors: first, that rotate wasn't defined and that an arrow gif didn't exist. Arrow gif was probably something you have stored locally, but I changed the 'rotate' error by changing the strings in the code here to your actual variables.
So, from:
run = setInterval('rotate()', speed);
We get:
run = setInterval(rotate, speed);
(No () based on the examples here: http://www.w3schools.com/jsref/met_win_setinterval.asp)
But I think a more important question is why your text wasn't showing up at all. It's because of the logic found here:
$('#slides ul').css({'left' : left_value});
You even say that this is setting the default placement for the code. But it isn't..."left_vaule" is the amount that you've calculated to push left during a slide. So if you inspect the element, you can see how the whole UL is basically shifted one slide's worth too far left, unable to be seen. So we get rid of 'left_value', and replace it with 0.
$('#slides ul').css({'left' : 0});
Now, there's nothing really handling how the pictures slide in, so that part's still rough, but this should be enough to start on.
Let me know if I misunderstood anything, or if you have any questions.
So, a few things:
1) I believe you are trying to get all of the lis to be side-by-side, not arranged up and down. There are a few ways to do this. I'd just make the ul have a width of 300%, and then make the lis each take up a third of that:
#slides ul {
....
width: 300%;
}
#slides li {
width: calc(100% / 3);
height:250px;
float:left;
}
2) You got this right, but JSFiddle automatically wraps all your JS inside a $(document).ready() handler, and your function, rotate needs to be outside, in the normal DOM. Just change that JSFiddle setting from 'onload' to 'no wrap - in head'
3) Grabbing the CSS value of an element doesn't always work, especially when you're dealing with animating elements. You already know the width of the li elements with your item_width variable. I'd just use that and change your code:
var left_indent = parseInt($('#slides ul').css('left')) - item_width;
$('#slides ul').animate({'left' : left_indent}, 1500, function () {
to:
$('#slides ul').stop().animate({'left' : -item_width * 2}, 1500, function () {
4) Throw in the .stop() as seen in the above line. This prevents your animations from overlapping. An alternative, and perhaps cleaner way to do this, would be to simply return false at the beginning of your 'next' and 'prev' functions if #slides ul is being animated, like so:
if ($('#slides ul').is(':animated')) return false;
And I think that's everything. Here's the JSFiddle. Cheers!
EDIT:
Oh, and you may also want to clearInterval at the beginning of the next and prev functions and then reset it in the animation callback functions:
$('#prev').click(function() {
if ($('#slides ul').is(':animated')) return false;
clearInterval(run);
$('#slides ul').stop().animate({'left' : 0}, 1500,function(){
....
run = setInterval('rotate()', speed);
});
});

jQuery animate within animate callback works only once

I have two pagination links which trigger a jQuery animation.
A callback function on the animation triggers a second animation.
This works fine, however, it only works the first time the function is called.
Each time after, the first of the 2 animations works and the second one does not, it merely changes the CSS without the effect.
I'm racking my brain here, to no effect (pun intended).
function switchItem(e) {
e.preventDefault();
// If not current piece
if($(this).hasClass('light')) {
/* VARIABLES */
var container = $('.portfolio footer .portfolio_content');
var link = $(this).attr('id');
var newItem = $(this).html();
/*===================================================
* This is the Key part here
===================================================*/
/* FIRST ANIMATION */
container.animate({
'right':'-100%'
}, 300, 'swing',
// Callback Function
function() {
$(this).html('').css({'left':'-100%'});
$.get('inc/portfolio/'+link+'.php', function(data) {
container.html(data);
/* SECOND ANIMATION */
container.animate({
'left':'0%'
}, 300, 'swing');
});
});
}
}
Here is the demonstration: http://eoghanoloughlin.com/my_site/#portfolio
See working sample here, your left is conflicting with your first right -100% animation and at the end if you don't reset the right then it will conflict with your second left animation
http://jsfiddle.net/PAdr3/2/
reset left before animating
container.css('left', 'auto');
and reset right when complete
container.animate({
'left':'0%'
}, 300, 'swing', function() {
$(this).css('right', 'auto');
});
When you replace the html in a page with new content, it will not automatically add listeners or other jquery enhancements that are added via javascript.
I suspect you need to apply these again after you put the content you fetched with $.get into the page.
Another alternative, is to add all the content in one load, but make the second page hidden. This is probably a nicer alternative than using $.get
I think that the animate function does not string until the first animate is ready. The docs say:
If supplied, the complete callback function is fired once the
animation is complete. This can be useful for stringing different
animations together in sequence.
Something like this might work:
function switchItem(e) {
e.preventDefault();
// If not current piece
if($(this).hasClass('light')) {
/* VARIABLES */
var container = $('.portfolio footer .portfolio_content');
var link = $(this).attr('id');
var newItem = $(this).html();
/*===================================================
* This is the Key part here
===================================================*/
/* FIRST ANIMATION */
container.animate({
'right':'-100%'
}, 300, 'swing',
// Callback Function
function() {
$(this).html('').css({'left':'-100%'});
$.get('inc/portfolio/'+link+'.php', function(data) {
container.html(data);
});
}).complete(
/* SECOND ANIMATION */
container.animate({
'left':'0%'
}, 300, 'swing');
);
}
}

jQuery - use .hover instead of .click

I have the following code on my page.
http://jsfiddle.net/SO_AMK/r7ZDm/
As you see it's a list of links, and every time a link is clicked, the popup box opens up right underneath the link in question.
Now, what I need to do is basically the same, except I need to use the .hover event and delay the execution by 2 seconds. So instead of clicking, the user should keep the cursor over a link for 2 seconds.
Sounds simple enough but I can't get the positioning to work properly. here's what I tried:
$('a.showreranks').hover(function()
{
$(this).data('timeout', window.setTimeout(function()
{
position = $(this).position();
$('#rerank_details').css('top', position.top + 17);
$('#rerank_details').slideToggle(300);
}, 2000));
},
function()
{
clearTimeout($(this).data('timeout'));
});
Can someone modify this to make it work?
Try like this:
$('a.showreranks').hover(function()
{
var self = this;
$(this).data('timeout', window.setTimeout(function() {
var position = $(self).offset();
$('#rerank_details').css('top', position.top + 17);
$('#rerank_details').slideToggle(300);
}, 2000));
},
function()
{
clearTimeout($(this).data('timeout'));
});
DEMO
jsFiddle demo
$('ul').on('mousemove','li',function(e){
var m = {x: e.pageX, y: e.pageY};
$('#rerank_details').css({left: m.x+20, top: m.y-10});
}).on('mouseenter','li',function(){
var t = setTimeout(function() {
$('#rerank_details').stop().slideDown(300);
},2000);
$(this).data('timeout', t);
}).on('mouseleave','li',function(){
$('#rerank_details').stop().slideUp(300);
clearTimeout($(this).data('timeout'));
});
The setTimeout will act like a hover intent that actually delays the execution for 2 seconds and counts the time hovered inside a data attribute of the hovered element - that gets 'nulled' on mouseleave.
I added also a few lines of code that will make your tooltip follow the mousemove.

transition background-image/css change on hover?

I have a thumb nail inside another div, when the thumbnail is hovered I want the parent div to fade/transition to the background of the thumbnail, then fade back to the original image after hover.
I have this so far which changes the parent background to that of the thumbnail and back but with no transition.
$(document).ready(function() {
var originalBG;
var hoverBG;
$(".alt-img").hover(
function () {
originalBG = $(this).parent().css('backgroundImage');
hoverBG = $(this).css('backgroundImage');
$(this).parent().css('backgroundImage',hoverBG);
},
function () {
$(this).parent().css('backgroundImage',originalBG);
}
);
});
There is no 'build-in' solution for fading in/out a backgroundImage, but you may play around with chaining animate()
.animate({opacity: 0.5}, 1000)
for instance. Or use .css() aswell to just set a new opacity level.
Based on what jAndy suggested I was able to come up with this:
$(document).ready(function() {
var originalBG;
var hoverBG;
$(".alt-img").hover(
function () {
originalBG = $(this).parent().css('background-image');
hoverBG = $(this).css('background-image');
//$(this).parent().css('background-image',hoverBG);
$(this).parent().animate({opacity: 0.1}, 200,
function () {
$(this).css('background-image',hoverBG);
$(this).animate({opacity: 1}, 200);
}
);
},
function () {
//$(this).parent().css('background-image',originalBG);
$(this).parent().animate({opacity: 0.1}, 200,
function () {
$(this).css('background-image',originalBG);
$(this).animate({opacity: 1}, 200);
}
);
}
);
});
Its not a true cross-fade because it fades the original image out, then fades the new image in. But a close compromise.

Categories

Resources