Stop timeOut and animation on mouseenter and continue on mouseleave - javascript

I wanted to get rid of a slider-plugin, so i tried to build my own,
everything works nice but i´m stuck to stop the whole thing on hover and restart it again on mouseleave,
here is my js :
function startPslider(val) {
if (!val) {
val = 0;
}
var holder = 'slideHolder';
var text = 'slideText';
startInterval(holder, text, val);
}
function startInterval(holder, text, val) {
var t;
var i = val;
if (i > 2) {
i = 0
}
$('#' + holder + i).animate({
opacity: 1,
}, function () {
$(this).addClass('active')
$('.' + text + i).animate({
opacity: 1,
left: 0
}, 1200);
t = setTimeout(function () {
$('.' + text + i).animate({
opacity: 0,
left: '-400px'
}, 1200);
$('#' + holder + i).animate({
opacity: 0,
}, 2200).removeClass('active');
startPslider(i + 1);
}, 4000)
});
// Here´s the not working hover-function
$('#hpCanvas').hover(function () {
clearTimeout(t);
}, function () {
var id = $('.active').attr('id');
var slide = id.substring(11, 22);
console.log(slide)
startPslider(slide);
});
}
$(function () {
startPslider();
});
tryed to solve this with adding class 'active' to the current holder and at hover-out try to catch the current-slide number (val) and restart it again, starting on the correct slide, but it´s not working as I wish,
have a look at this fiddle, http://jsfiddle.net/zDh76/ you will find html and css there, as you see everything works fine as long you do not hover.
Maybe anyone has a helping hint how to stop the animation, clear the timer and go on with the correct slide on mouseleave?
UPDATE
i separated start and end-interval
function startPslider(i) {
if(!i){
i=0;
}
if(i >2){
i=0
}
console.log('started Slider with slide:'+i)
var holder = 'slideHolder';
var text = 'slideText';
startInterval(holder, text, i);
}
function startInterval(holder,text,i) {
var t;
var v;
console.log('started Interval with slide:'+i);
$('#'+holder+i).animate({
opacity:1,
}, function(){
$('.'+text+i).animate({
opacity:1,
left:0
},1200);
t= setTimeout(function(){endInterval(holder,text,i); },4000);
});
}
function endInterval(holder,text,i,cont){
console.log('end Interval with slide:'+i);
$('.'+text+i).animate({
opacity:0,
left:'-400px'
},1200);
$('#'+holder+i).animate({
opacity:0,
},2200, function(){
$('.slideHolder').css('opacity',0);
i = i+1;
startPslider(i);
});
}

I found it out myself,
i needed to unbind the hover event on #hpCanvas inside the mouseleave function like
$('#hpCanvas').hover(function(){
$('.slideHolder, .slideText').stop(true,true);
clearTimeout(t)
},function(){
endInterval(holder,text,i);
$('#hpCanvas').unbind('mouseenter mouseleave')
})
as the next call to bind it with hover event is inside the mouseleave-part of the first hover event.
thanks anyway for everyone reading this

Related

jQuery animate array skip to last

I am trying to animate an array of images using Jquery. When I have one element in the array it works fine but when I have more then one element it just animates the last element of the array.
I set the src of the img tag and move it to the right. The moveRight function move the image to the right and call moveLeft to move it to the left. The moveLeft function moves the image to the left and fade it.
$.each(imageArray, function (i, val) {
$("#b").attr("src", imageArray[i].src);
moveRight();
}
function moveRight(){
$("#b").animate({left: "+=500"}, 2000, moveLeft)
}
function moveLeft(){
$("#b").animate({left: "-=500"}, 2000,fade)
}
Is there a way each image can be moved right and left / or just left or right instead of having the last one moving only. I am trying to figure out what is wrong with my code.
I think the best thing you can do is to use a recursive method. Here is an example (check jsFiddle):
var MyApp = {
Items: {
Elements: $('div'),
Loaded: 0
},
Start: function(){
if( this.Items.Elements.length == this.Items.Loaded ) return; // return.. or play a sound, then return to stop iterations
this.Items.Elements.eq(this.Items.Loaded).animate({ left: '50%' }, {
duration: 1000,
complete: function(){
MyApp.Items.Loaded++;
MyApp.Start();
}
});
}
};
$(function(){
MyApp.Start();
});
It's an example but you can do it easily by this way.
How about this variant: http://jsbin.com/xezetuboye/1/edit?html,js,output ?
var arr = [
'http://e404.pw/pictures/evernote-logo.png',
'http://e404.pw/pictures/font-face.png',
'http://e404.pw/pictures/html-coder.jpg'
];
var count = 0;
function setImg(){
if(arr.length <= count){ return; }
$("#b").attr("src", arr[count]);
moveRight();
count++;
}
function moveRight(){
$("#b").animate({left: "+=500"}, 2000, moveLeft);
}
function moveLeft(){
$("#b").animate({left: "-=500"}, 2000, setImg);
}
setImg();
Try utilizing .queue(). Note, if changing src of same img element , would have to wait until each image loaded.
var imageArray = [
"http://lorempixel.com/100/100/cats",
"http://lorempixel.com/100/100/animals",
"http://lorempixel.com/100/100/technics",
"http://lorempixel.com/100/100/nature"
];
var b = $("#b");
var cycle = function cycle() {
return b.queue("slide", $.map(imageArray, function(val, i) {
return function(next) {
$(this).fadeOut(50).attr("src", val);
this.onload = function() {
return $(this).fadeIn(50, function() {
return moveRight.call(this).then(function() {
return moveLeft.call(this)
}).then(next);
});
}
}
})).dequeue("slide");
};
function moveRight() {
return $(this).animate({
left: "500"
}, 2000).promise()
}
function moveLeft() {
return $(this).animate({
left: 0
}, 2000).promise()
}
var infiniteCycle = function infiniteCycle() {
return cycle().promise("slide").then(infiniteCycle)
};
infiniteCycle();
#b {
position: relative;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<img id="b" />
Here's a very basic example of what you're trying to achieve. From here you can try and animate the transition, switch it so buttons activate a left/right change. I would suggest playing around with this until you comfortable with the basic functionality. From there you can look into plugins/libraries that can help you. http://jsfiddle.net/306Lqov5/1/
HTML
<img id="b" src="http://placehold.it/100/100&text=Image 1" />
JavaScript
var images = [
'http://placehold.it/100/100&text=Image 1',
'http://placehold.it/100/100&text=Image 2',
'http://placehold.it/100/100&text=Image 3',
'http://placehold.it/100/100&text=Image 4'
];
var index = 1, //start at one since we have the first image in by defualt
img = $('#b');
setInterval(function(){
img.attr('src', images[index]);
index++; //index = index + 1;
if (index == images.length){ //if we've reached the length of the array reset to zero
index = 0;
}
},2000); //switch ever 2 seconds

Previous and Next functions for js slider

I have almost finished this slider, but I don't know how to implement the functionality for next() and prev(). How can I implement these functions?
http://jsfiddle.net/M4t4L/11/
$(function () {
var container = $("#scene"),
i = 0,
count = container.find("li").length,
j = container.find("li").length - 1,
isAnimating = false;
container.find("li:first").css({
"width": "100%"
});
$("#trigger").click(function (e) {
if (!isAnimating) {
isAnimating = true;
e.preventDefault(e);
i++; if (i >= count) { i = 0; }
j++; if (j >= count) { j = 0; }
container.find("li")
.finish()
.removeClass('active')
.last()
.width(0)
.addClass("active")
.animate({
"width": "100%"
}, 800,
function () {
container.find("li").first().appendTo(container);
isAnimating = false;
});
}
});
});
The problem is that when I implement these functions and press the next or prev. Displays the last slide on one second, and then switches to the desired
http://jsfiddle.net/M4t4L/9
If you want to get a Next or Prev function running, you want to take control of the number of the slider where you are. I'm afraid you will have to play around with your i/j and make the position go in both directions.
Right now you count up your i and j, where you might want to go is to have a position var and an array of slider objects, then the click only would have to call for the next/prev object to be loaded and the animation can begin.
Something like this maybe..
var pos = 0;
var container = $('#scene').find('li');
$('.back').click(function() {
pos = pos - 1;
moveIt(pos);
});
$('.forth').click(function() {
pos = pos +1;
moveIt(pos);
});
function moveIt(pos) {
container[pos]... // Your animation goes here
}

Adding delay to DIV animation

I'm trying to create div boxes step by step and animate them for several times when a button is pressed. I have a running code, and everything is going well. It goes right to the endhost, then it goes left again to its original place. This is mainly what I do, and also the demo is found here: http://jsfiddle.net/54hqm/3/
Now I want to happen after each click, is basically to move each DIV one after another, with a delay, instead of moving the whole stack of DIVs at once. I don't exactly know what to do. Can anyone help me with that?
$(document).ready(function () {
var count = 0;
var items = 0;
var packetNumber = 0;
var speed = 0;
$("button").click(function () {
if (count < 4) {
items = items + 1;
count++;
} else {
items = items * 2;
}
speed = $("#speed").val();
createDivs(items);
animateDivs();
});
function createDivs(divs) {
packetNumber = 1;
var left = 60;
for (var i = 0; i < divs; i++) {
var div = $("<div class='t'></div>");
div.appendTo(".packets");
$("<font class='span'>" + packetNumber + "</font>").appendTo(div);
packetNumber++;
div.css("left",left+"px");
div.hide();
left += 20;
}
}
function animateDivs() {
$(".t").each(function () {
var packet = $(this);
packet.show();
packet.animate({
left: '+=230px'
}, speed);
packet.animate({
left: '+=230px'
}, speed);
packet.animate({
top: '+=20px',
backgroundColor: "#f09090",
text: '12'
}, speed / 4, "swing", function () {
$('.span').fadeOut(100, function () {
$(this).text(function () {
return 'a' + $(this).text().replace('a', '');
}).fadeIn(100);
});
});
packet.delay(1000).animate({left:'-=230px'}, speed);
packet.animate({left:'-=230px'}, speed);
}).promise().done(function(){
$(".packets").empty();});
}
});
You can make this with 2 small modifications:
In your each() function, add the index parameter to know the index of the currently animating packet:
$(".t").each(function (index) {
Before your animate calls, insert a packet.delay() with a delay increasing with every item:
packet.delay(index * 250);
I updated your fiddle to show results.
Update: I made a second version based on your comment.

.next() not working as intended

So,
if($(this).hasClass('active')){
$(this).removeClass('active');
$(this).prev().addClass('active');
}
works fine, it adds the class "active" to this previous div of the same kind.
if($(this).hasClass('active')){
$(this).removeClass('active');
$(this).next().addClass('active');
}
However, adds the class to the next div (as i intend for it to do) for about 0.5 of a second BUT then removes it.
Here's ALL of the jQuery (as per your comments below) - Please do not comment on my horrible code organization
$(window).load(function () {
// Initial variables
var numberSlides = 0;
var currentSlide = 1;
var ready = true;
var pageWidthR = $(document).width() - 352;
var pageWidthL = $(document).width() - 352;
// Update number of slides by number of .slide elements
$('#features-slider .slide').each(function () {
numberSlides++;
});
// Go through each slide and move it to the left of the screen
var i = 0;
$($('#features-slider .slide').get().reverse()).each(function () {
if (i == 0) {
} else {
var newWidth = i * 115;
$(this).css('left', '-' + newWidth + '%');
}
i++;
});
// Animate the first slide in
$('#features-slider .slide:last-child').addClass('active').animate({
left: 0
}, 1500);
// Remove the loading message
$('#loading').fadeOut(1000, function () {
$('#loading').remove();
// Now that we're done - we can show it
$('#features-slider').show();
});
/***** Left and Right buttons *****/
/* Right */
$('#rightbutton').click(function () {
var numberSlides = 0;
$('#features-slider .slide').each(function () {
numberSlides++;
});
var index = $('.slide.active').index() + 1;
if (!$('.slide').is(':animated') && index != 1) {
$('#features-slider .slide').each(function () {
if ($(this).hasClass('active')) {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) + 115;
} else {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) + 115;
}
$(this).animate({
left: newLeft + '%'
}, 1500);
if ($(this).hasClass('active')) {
$(this).removeClass('active');
$(this).prev().addClass('active');
}
});
}
});
/* Left */
$('#leftbutton').click(function () {
var numberSlides = 0;
$('#features-slider .slide').each(function () {
numberSlides++;
});
var index = $('.slide.active').index() + 1;
if (!$('.slide').is(':animated') && index != numberSlides) {
$('#features-slider .slide').each(function () {
if ($(this).hasClass('active')) {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) - 115;
} else {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft) - 115;
}
$(this).animate({
left: newLeft + '%'
}, 1500);
if ($(this).hasClass('active')) {
$(this).next().addClass('active');
$(this).removeClass('active').not($(this).next());
}
});
}
});
});
$(document).ready(function () {
// Hide the slider and show a loading message while we do stuff and the images / DOM loads - Also disable overflow on the body so no horizontal scrollbar is shown
$('body').css('overflow-x', 'hidden');
$('#features-slider').hide();
$('#loading').html('<center> <img id="loader" src="/wp-content/themes/responsive/library/images/ajax-loader.gif" /> Loading</center>');
});
RESOLVED
New left button function :
$('#leftbutton').click(function(){
var numberSlides = 0;
$('#features-slider .slide').each(function(){
numberSlides++;
});
var index = $('.slide.active').index()+1;
if( !$('.slide').is(':animated') && index != numberSlides ){
var done = false;
$('#features-slider .slide').each(function(){
if($(this).hasClass('active')){
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft)-115;
} else {
var currentLeft = $(this).css('left');
var newLeft = parseInt(currentLeft)-115;
}
$(this).animate({left: newLeft+'%'}, 1500);
if($(this).hasClass('active') && done == false){
$(this).next().addClass('active');
$(this).removeClass('active');
done = true;
}
});
});
If you're iterating forward through the elements, then it should be clear what's going on - you add the "active" class to the next element, and then the next iteration takes it away.
This is just a guess however as you did not post enough code for me (or anybody else) to be sure.
edit — ok now that you've updated the question, it's clear that the guess was correct. The .each() function will iterate forward through the elements. When an element has the "active" class, and the code removes it and adds it to the next element, then on the next iteration the work is undone.
Since you are referencing this and by the behavior you're describing, you are likely iterating a loop for a list of elements. As a result, you are completing the action you want but the next iteration is removing the previous changes due to your usage of removing a class and then adding the class back.
As it stands now, your code does not illustrate how this occurence can be happening.
Update:
As suspected, you seem to be looping as signified by: each(function(){. While iterating through your objects the class is being pushed forward and is not acting as desired. You are stating add the class to the next element, but remove it from the current element, and this behavior continues through your iteration.
On a side note, update your code to call removeClass() on the current object first, before adding it to the next object:
if ($(this).hasClass('active')) {
$(this).removeClass('active').next().addClass('active');
}

'Pulsing' a border in Javascript/JQuery

I am in the process of applying validation on a web form -one of the things I would like to do is add a pulsing border to the div which contains the erroneous input.
This solution: border highlighting loop with jquery and http://jsfiddle.net/Ue4wy/4/ pretty much hits the mark.
But I want to be able to fade the yellow border to black on the click handler & reset the loop (this example pauses the loop), so the next time the user hits submit it starts again.
Reseting the colour to black works using the code below (though I am sure there is a more elegant solution), but how do I reset the loop?
$('#weight').animate({
borderBottomColor: '#000',
borderLeftColor: '#000',
borderRightColor: '#000',
borderTopColor : '#000'
}, 'fast' );
Any ideas appreciated!
I've updated the update() function to accept an argument, i, which is then called in the click handler, along with window.clearTimeout():
var addClickHandler = function() {
$("div").click(function() {
window.clearTimeout(timer);
update(0);
});
};
This does require that the other calls to update() also need to pass the i:
var update = function(i) {
$("div").css("border-color", 'rgb(' + i + ',' + i + ',' + 0 + ')');
};
JS Fiddle demo.
Edited to amend the click-handler to offer a toggle (stop/start) for the animation:
var addClickHandler = function() {
$("div").toggle(function() {
window.clearTimeout(timer);
update(0);
}, function() {
anim.go();
});
};
JS Fiddle demo.
Edited for a slightly more context-aware click-handler, this version checks for the existence of the timer variable and, if it isn't found, starts the animation. If it is found then it clears the timeout, sets the timer to false and calls update(0) to reset the borders to black:
var addClickHandler = function() {
$("div").click(function() {
console.log(timer);
if (!timer){
timer = window.setTimeout(anim.go, 30);
}
else {
window.clearTimeout(timer);
timer = false;
update(0);
}
});
JS Fiddle demo.
References:
toggle().
window.clearTimeout().
Here's a jQuery UI effect to pulsate the border:
$.effects.borderPulsate = function(o) {
return this.queue(function() {
var elem = $(this),
mode = $.effects.setMode(elem, o.options.mode || 'show'),
times = (o.options.times || 5),
duration = o.duration ? o.duration : $.fx.speeds._default,
isVisible = elem.is(':visible'),
color = (o.options.color || 'rgb(255,255,0)'),
startColor = (o.options.startColor || elem.css('border-color') || 'transparent');
if (!isVisible) {
elem.show();
}
if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) {
times--;
}
for (var i = 0; i < times; i++) {
elem.animate({ 'border-color': color }, duration, o.options.easing, function() {
elem.css( 'border-color', startColor );
});
}
elem.animate({ 'border-color': color }, duration, o.options.easing, function() {
(o.callback && o.callback.apply(this, arguments));
});
elem
.queue('fx', function() { elem.dequeue(); })
.dequeue();
});
};
http://jsfiddle.net/cdeutsch/TjkNd/
You can change colors on all borders at the same time with borderColor, but you don't need to animate that. You could add a reset method to your object to take care of the whole thing:
var reset = function() {
i = 0;
step = 10;
up = true;
if(timer) window.clearTimeout(timer);
timer = null;
$('#weight').css('borderColor', '#000');
}
Then on your click handler, you call anim.reset() after anim.stop().

Categories