Can you target an element by its dynamically changing opacity? - javascript

Through the use of a function in jQuery, along with my HTML & CSS, I have a series of different colored divs that change their opacity to appear as though the opaque div moves from left to right. I want the user to be able to click a red button to stop the animation on a square of his/her choosing. Right now I can get the animation to stop (albeit after it finishes its queued animations), but I am having trouble getting the square that has its opacity at 1 (at the time of the button click) stay at opacity 1. Any help would be greatly appreciated.
Here is a jsfiddle http://jsfiddle.net/seifs4/krm6uenj/
$(document).ready(function () {
$.fn.extend({
brighten: function(){
$(this).fadeTo(150, 1);
}
});
$.fn.extend({
fade: function(){
$(this).fadeTo(150, 0.2);
}
});
function animateSequence() {
$('.game-square').each(function (i) {
$(this).delay((i++) * 145).brighten();
$(this).delay((i++) * 5).fade();
});
}
animateSequence()
var interval=setInterval(animateSequence, 1700);
$('#red-button').click(function(){
$('.game-square').each(function(){
if ($('.game-square', this).not().css('opacity') == 0.2){
$(this).css('opacity', '1');
}
});
clearInterval(interval);
});
});

You maybe need something like this:
function animateSequence(){
this.current = 0;
this.squares = $(".game-square");
this.animate = function(){
this.squares.eq(this.current).fadeTo(150, 1, function(){
$(this).fadeTo(150, 0.2)
});
this.current = this.current >= this.squares.length - 1 ? 0 : this.current + 1;
};
this.start = function(){
this.running = setInterval(this.animate.bind(this), 150)
};
this.stop = function(){
this.running = clearInterval(this.running);
this.squares.eq(this.current).stop().css("opacity",1);
alert("Current color: " + this.squares.eq(this.current).attr("class"))
}
}
Demo
This is the advantage of working with objects, a way very readable, simple and orderly.

I will take a different and less complex approach. Perhaps it has even better performance.
Demo http://jsfiddle.net/LkatLkz2/8/
This is the whole code. I use css for animation effect, and class changing opacity.
var sqrs = $('.game-square'),
len = sqrs.length,
i=0,
looping = true;
setInterval(function(){
if (!looping) return;
sqrs.removeClass('full').eq(i).addClass('full');
i = ++i % len;
},400);
$("#red-button").click(function () {
looping = !looping;
});

The JQuery .stop() function help you to stop the animation. I know this is not the best solution for your problem because your opacity stay "1" only a short time.
$('#red-button').click(function(){
clearInterval(interval);
$('.game-square').stop();//this stop the animation
$('.game-square').each(function(){
if ($(this).not().css('opacity') > '0.2'){// I changed this logic
$(this).css('opacity', '1');
}
});
});

Related

Javascript odd behaviour on mouse scroll up / down classes

I'm hoping a Javascript wiz can help a fellow citizen out with resolving a problem. I've a fairly straight forward function. When I scroll down by 1px I would like to apply a bounceDown class, this will run for 5 seconds and the class will then disappear for future running of the same function.
When I scroll up from that current scroll position I would like the bounceUp effect to apply. However the issue is I think the bounceUp effect only works once you scroll past the original scroll but in addition to this if the previous function is still running on it's 5 second transition then it gets jumpy as it's trying to run two classes at the same time so there almost needs to be a delay applied.
Does anyone think they can help, I'd gratefully appreciate it.
<script>
(function($){
$.fn.extend({
addTemporaryClass: function(className, duration) {
var elements = this;
setTimeout(function() {
elements.removeClass(className);
}, duration);
return this.each(function() {
$(this).addClass(className);
});
}
});
})(jQuery);
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 1) {
$(".spanner").addTemporaryClass("BounceDown", 5000);
}
else if (scroll <= 1) {
$(".spanner").addTemporaryClass("BounceUp", 5000);
}
});
</script>
What about a boolean variable that is 'true' when addTemporaryClass is running? So:
(function($){
var classAdded = false; //New
$.fn.extend({
addTemporaryClass: function(className, duration) {
classAdded = true; //New
var elements = this;
setTimeout(function() {
elements.removeClass(className);
classAdded = false; //New
}, duration);
return this.each(function() {
$(this).addClass(className);
});
}
});
})(jQuery);
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 1 /*New*/ && !classAdded /*New*/) {
$(".spanner").addTemporaryClass("BounceDown", 5000);
}
else if (scroll <= 1 /*New*/ && !classAdded /*New*/) {
$(".spanner").addTemporaryClass("BounceUp", 5000);
}
});

Slow/unresponsive animation with jQuery animation

I am writing a small jQuery function and I seem to be having trouble.
What I am trying to do here is when the user scrolls down the page by 90px, a div tag should animate down (from top:-50px to top:0), and vice-versa when they scroll back to the top of the page.
The problem I am having is that the animation seems to be very slow and unresponsive at times. I test in 3 different browsers and different computers but I am having no joy.
Here is my code:
// Show div
var scrollValue = "90";
// Animate functions
var showHead = function (){
$(".element").animate({top: "0"}, 250);
}
var hideHead = function (){
$(".element").animate({top: "-50px"}, 250);
}
$(window).scroll(function() {
if ($(this).scrollTop() > scrollValue) {
showHead();
} else {
hideHead();
}
});
The .element properties:
.element { positoin:fixed; top:-50px; }
Could anyone figure out why my code the hide/showHead functions are so sloppy?
Thanks,
Peter
The scroll event is triggered several times and even though it is rate-limited it keeps being a rather intensive operation. Actually, you may be queuing several animations and the fx stack may be growing very quickly.
One possibility you can try is stopping all previous animations before triggering a new one. You can do this by using .stop().
$(".element").stop().animate({top: "0"}, 250);
The .stop() function also provides some other options which you can use to tweak it even more.
Try this one :
$(window).scroll(function() {
if (window.scrollY > scrollValue) {
showHead();
} else {
hideHead();
}
});
scroll events occurred many time durring user scrolling.
You need to check if your animation is in progress before starting the animation again.
Try this :
// Show div
var scrollValue = "90";
var inProgress = false;
// Animate functions
var showHead = function () {
if(inProgress)
return false;
//Animate only if the animation is not in progress
inProgress = true;
$(".element").animate({
top: "0"
},250,function(){
inProgress = false; //Reset when animation is done
});
}
var hideHead = function () {
if(inProgress)
return false;
//Animate only if the animation is not in progress
inProgress = true;
$(".element").animate({
top: "-50px"
}, 250,function(){
inProgress = false; //Reset when animation is done
});
}
$(window).scroll(function () {
if ($(this).scrollTop() > scrollValue) {
showHead();
} else {
hideHead();
}
});
Assuming you have position:fixed (or some other sort of styling making the bar visible when necessary):
var scrollheight = 90;
var $el = $('.element');
function showHead(){
$el.stop().animate({
top: '0px'
}, 250);
}
function hideHead(){
$el.stop().animate({
top: '-50px'
}, 250);
}
$(window).scroll(function(){
if ($(window).scrollTop() > scrollheight){
showHead();
}else{
hideHead();
}
});
example: http://jsfiddle.net/L4LfL/
try using queue: false and as Alexander said use .stop()
here jsfiddle
http://jsfiddle.net/hwbPz/

How to stop click events from queuing up on multiple click?

What I need to achieve is if we click on submit button, there is particular div should show up.
Here is my code:
http://jsfiddle.net/7tn5d/
But if I click on submit button multiple times, the function calls sort of queue up and run one after other.
Is there a way to invalidate other onclicks when current animation is running?
Code:
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", {}, 1000);
animating = 0;
});
});
To prevent it from performing the action multiple times, simple cease the previous animation. So:
$('#submit_cont').stop().show("blind",{},1000);
However, I have noticed that you have attempted to prevent the animation from running, if an animation is already running. Although it takes 1 second or 1000 milliseconds to show the div, the execution of the condition does not pause until the animation is complete. You must define a function to run after the animation is complete, like so:
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", 1000, function() { animation = 0; });
});
});
Hope that helped...
You almost got it right with the semaphore! It's just that, in jQuery's show(), you would have to put the semaphore reset as an argument. Here's the fixed version - http://jsfiddle.net/snikrs/xe5A3/
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", 1000, function() {
animating = 0;
});
});
});
You can use the :animated selector to check:
$(function () {
$("#submit_tab").click(function (e) {
var $cont = $("#submit_cont");
if (!$cont.is(':animated')) {
$cont.show("blind", {}, 1000);
}
});
});
Now if you stick with the external semaphore idea then its better to stick that on the elemnt with .data() instead of using a global variable:
$(function () {
$("#submit_tab").click(function (e) {
var $cont = $('#submit_cont'),
animating = $cont.data('isAnimating');
if (animating) {
return;
} else {
$cont.data('isAnimating', 1);
$("#submit_cont").show("blind", 1000, function() { $cont.data('isAnimating', 0); });
}
});
});
Something like this (see documentation) :)
$("#submit_cont").show("blind", function(){
animating = 0;
});
You can add a $("#submit_cont").clearQueue(); after the animation finished :
$("#submit_tab").click(function (e) {
$("#submit_cont").show("blind", 1000, function() {
$("#submit_cont").clearQueue();
});
});
Updated JSFiddle
I found a different solution for this, which in my opinion looks cleaner:
var tab = $("submit_tag");
tab.on("click", function(){
var cont = $("submit_cont");
var animating = tab.queue("fx").length;
if(animating === 0){
cont.show("blind", {}, 1000);
}
});

jQuery toggleClass with direction and animation

I've followed a tutorial to add to my site a fixed header after scroll and the logo of the site appear on the fixed part.
That works, the code:
var nav_container = $(".nav-container");
var nav = $("nav");
var logo = $("logo");
nav_container.waypoint({
handler: function(event, direction) {
nav.toggleClass('sticky', direction=='down');
logo.toggleClass('logo_sticky', direction=='down');
if (direction == 'down')
nav_container.css({ 'height' : nav.outerHeight() });
else
nav_container.css({ 'height' : 'auto' });
});
});
How can I add a delay with fade-in to the logo, so it doesn't appear suddenly?
Versions I've tried:
logo.toggleClass('logo_sticky', direction=='down').delay(500).fadeIn('slow');
logo.delay(500).toggleClass('logo_sticky', direction=='down').fadeIn('slow');
(before the toggleClass)
logo.delay(500).fadeIn('slow')
logo.toggleClass('logo_sticky', direction=='down');
(after the toggleClass)
logo.toggleClass('logo_sticky', direction=='down');
logo.delay(500).fadeIn('slow')
To be honest I've tried every single combination that came to my mind lol
new version that I'm trying that don't work either:
$(function() {
var nav_container = $(".nav-container");
var nav = $("nav");
var logo = $("logo");
$.waypoints.settings.scrollThrottle = 30;
nav_container.waypoint({
handler: function(event, direction) {
if (direction == 'down'){
nav_container.css({ 'height':nav.outerHeight() });
nav.addClass('sticky', direction=='down').stop();
logo.css({"visibility":"visible"}).fadeIn("slow");
}
else{
nav_container.css({ 'height':'auto' });
nav.removeClass('sticky', direction=='down').stop();
logo.css({"visibility":"hidden"});
}
},
offset: function() {
return (0);
}
});
});
but if I instead of fadeIn put toggle it animes the change but in a bad direction (the img appear and then toggle to disapear)
thanks
http://api.jquery.com/delay/
http://api.jquery.com/fadein/
use $(yourLogoSelector).delay(delayAmount).fadeIn();
here is proof that it works http://jsfiddle.net/6d8cf/
It seems like the fadeIn only works if you don't have the css the property visibility: hidden, but display:none...
you can do a element.hide(); and then element.fadeIn().
since the hide() changes the layout of the page because it eliminates the item from it this is the solution I came across:
$(function() {
// Do our DOM lookups beforehand
var nav_container = $(".nav-container");
var nav = $("nav");
var logo = $("logo");
$.waypoints.settings.scrollThrottle = 30;
nav_container.waypoint({
handler: function(event, direction) {
if (direction == 'down'){
nav_container.css({ 'height':nav.outerHeight() });
nav.addClass('sticky', direction=='down').stop();
logo.css('opacity',0).animate({opacity:1}, 1000);
}
else{
nav_container.css({ 'height':'auto' });
nav.removeClass('sticky', direction=='down').stop();
logo.css('opacity',1).animate({opacity:0}, 1000);
}
},
offset: function() {
return (0);
}
});
});

How to change jQuery feature tabs script from display none to absolute positioning off the page?

I'm fairly new to jQuery and I'm using the script below. Basically it uses two unordered lists to create tab functionality (one for tabs, one for content). Right now when you click through the tabs, the output is switched from "display:list-item;" to "display:none;". I'm trying to change this to "position:absolute;left:-10000px;" and "position:relative;left:0;" so that all the content gets rendered but just moves off the page rather than be hidden.
I'm having the issue you see at the bottom of the page here http://jqueryui.com/demos/tabs/ except it's not being controlled in the CSS. It's being controlled in the script below somehow that I'm unfamiliar with. Any help would be appreciated.
//INITIALIZATION
$.featureList(
$(".tabs li a"),
$(".output > li"), {
start_item : 0
}
);
//SCRIPT
(function($) {
$.fn.featureList = function(options) {
var tabs = $(this);
var output = $(options.output);
new jQuery.featureList(tabs, output, options);
return this;
};
$.featureList = function(tabs, output, options) {
function slide(nr) {
if (typeof nr == "undefined") {
nr = visible_item + 1;
nr = nr >= total_items ? 0 : nr;
}
tabs.removeClass('current').filter(":eq(" + nr + ")").addClass('current');
output.stop(true, true).filter(":visible").fadeOut();
output.filter(":eq(" + nr + ")").fadeIn(function() {
visible_item = nr;
});
}
var options = options || {};
var total_items = tabs.length;
var visible_item = options.start_item || 0;
options.pause_on_hover = options.pause_on_hover || true;
options.transition_interval = options.transition_interval || 0;
output.hide().eq( visible_item ).show();
tabs.eq( visible_item ).addClass('current');
tabs.click(function() {
if ($(this).hasClass('current')) {
return false;
}
slide( tabs.index( this) );
});
if (options.transition_interval > 0) {
var timer = setInterval(function () {
slide();
}, options.transition_interval);
if (options.pause_on_hover) {
tabs.mouseenter(function() {
clearInterval( timer );
}).mouseleave(function() {
clearInterval( timer );
timer = setInterval(function () {
slide();
}, options.transition_interval);
});
}
}
};
})(jQuery);
The action in that script is happening with .FadeIn and .Fadeout, which animate opacity. Fadeout applies display:none at the end of the opacity animation. Correspondingly, FadeIn only works on elements that are set to display:none. Fadein just won't work on visibility: hidden or opacity:0. Check out the jquery documentation, it's mostly pretty good.
So you want to substitute a css position change for those two lines of code. There are a bunch of different ways to do this, depending mostly on whether or not you want the elements to animate off the page of just leap there.
Also FYI The easiest way to share this sort of stuff for troubleshooting is to make a jsfiddle with a reduced subset of your code, just the relevant stuff, and then everybody can poke away at it until it works. :)

Categories