I need the functionality of animating the z-index property of a specific HTML object. I've been able to achieve this animation in two ways that both have their difficulties/drawbacks. Successfully answering this question for me will fix one of the following two issues:
The first is by adapting the JQuery animate command with the step functionality outlined here by the accepted answer:
jQuery's $('#divOne').animate({zIndex: -1000}, 2000) does not work?
The problem with this method for me is that the $('#obj').stop(); command cannot prematurely end the animation when done in this way. It always finishes unless I destroy the object I'm working with and create a new one (which causes blinking obviously). If anyone knows of a way to properly stop a step animation like this, or a work-around for the issue, I'd love to see it.
var div = $('#obj');
$({z: ~~div.css('zIndex')}).animate({z: [-2000, 'linear']}, {
step: function() {
div.css('zIndex', ~~this.z);
},
duration: 10000
});
The second is using a setInterval loop on 20 MS (a speed that is sufficient for my needs) to simply adjust the z-index to what it should be at that point of the "animation". This works great for a few moments, then something causes it to stop working suddenly. The code still runs through the $('#obj').css('z-index', val); line, and val is changing, but it no longer updates the object in the DOM. I've tried it on slower timer settings as well with identical results. Anyone know why JQuery might suddenly no longer be able to set the Z-Index?
function () move {
if (!(MoveX == 0 && MoveY == 0))
{
$('#obj').css('z-index', val);
}
}
$('#obj').stop() doesn't work for you because the animation isn't being performed on $('#obj').
It is being performed on the object $({z: ...}) (with a custom step function). This means you should do something like
var anim = $({z: ~~div.css('zIndex')}).animate({z: [-2000, 'linear']}, {
step: function() {
div.css('zIndex', ~~this.z);
},
duration: 10000
});
// sometime later
anim.stop();
See this demo.
Edit For what it's worth, here is the same demo using an animation interval. I see a syntax error in your second snippet: the function declaration should be
function move() { ...
I assume that's a typo since your code wouldn't even parse. Other than that, I'm not sure why that solution didn't work for you.
Related
I am trying to create a draggable line in a graph via Flot. I have a function that accomplishes that and executes on Flot's Plothover event (which is similar to a mouseMove event) when a certain boolean is true. The function gets called continuously and this has caused the resulting animation to lag significantly. To solve this I tried two approaches:
First I tried using setTimeout. This helped the function run better, but I was unsatisfied. The animation began to lag again if the webpage was left open for more than a minute, I have no idea why. If anyone knows whats up with that any insight would be appreciated.
Second, I tried Underscore's throttle function. I am a little unsure of the syntax, and after some research and debugging this is what I settled on. The following code is inside the event handler:
var throttled1 = _.throttle(singleLine, 50);
throttled1(position);
Where singleLine is the following function, defined outside the event handler:
function singleLine(position) {
adjustLine1[0] = [position, Number.NEGATIVE_INFINITY];
adjustLine1[1] = [position, Number.POSITIVE_INFINITY];
graphData.push({ data: adjustLine1, lines: { show: true }, color: "gray" });
plot.setData(graphData);
plot.draw();
graphData.pop();
}
Keep in mind plot.draw() is a pretty long function (it redraws the entire graph). Anyway, it appears to work because singleLine is successfully called by throttled1(position). However, it is not improving performance at all. Am I using it correctly? Any other insights into how to make this run better are also welcomed. Thanks.
var throttled1 = _.throttle(singleLine, 50);
throttled1 must be initialized oustide of the event listener, so it can track calls and timers internally, event after event.
See JSfiddle!
I am wanting to animate a set of elements and execute a callback when finished like so:
s.selectAll('.active').animate( {
transform: matrix
},
300,
mina.linear,
function() {
//callback doesnt fire
alert('callback')
}
)
The elements are animated correctly but the callback isnt executed.
However, when I apply the animation to a group of elements, the callback is fired:
group.animate( {
transform: matrix
},
300,
mina.linear,
function() {
alert('callback')
}
)
.. But I don't want to put my selected elements in a group as this would cause more complications in other places.
Is it possible to animate a set of elements that I got via a .select() or .selectAll() while being able to fire the callback?
Thanks a lot in advance!
Edit: For future readers, you can animate a set of elements by using forEach and counting if all elements are done animating:
function hideToPoint(elements, x, y, callback) {
var finished = 0;
elements.forEach(function(e) {
e.animate( {
//do stuff
},
300,
mina.linear,
function () {
finished++;
if (finished == elements.length) {
callback();
}
}
)
})
}
I'm going to have a stab at answering a couple of problems, even though I'm not sure if related to the callback. Its hard to tell if its just the example code or not without a proper test like a jsfiddle.
However, there are at least 2 problems in the code above.
Creating a matrix is with
new Snap.Matrix(); // as opposed to Snap.matrix()
Also
elements.animate()
The problem here is that animate acts on one element (edit: looks like it can work on elements within a set, but not the callback as example here, edit2: callbacks on sets may now be supported), not multiple elements as such (you can sometimes apply somethings to a set which deals with them individually, but as far as I'm aware, thats not the case with animate).
So you either want to do a
elements.forEach( function(el) { el.animate({blah: value}, 2000, mina.linear.callback )
});
or if its an svg group (as opposed to a set), the original code would possibly work (but I would call it 'myGroup' or something instead of 'elements' for code readability and guessing what it contains)
fiddle (have included a different animation using snap animation string)
I have several page elements I want to fade out. I then change the css class of them (while they are not visible) then fade them back in.
I thought I had ordered the execution flow properly but sure enough the css class transition is occurring before the fadeOut is complete. Visually what happens is that a person sees the css change and then fadeout occurs.
You can see it at the link below. Between slide 1 & 2 it happens but is not as noticeable as the css change is from class a to class a. Between slide 2 & 3 you can see it as that is from class a to class b.
http://staging.alexandredairy.com
jquery transition code onReady kicks it off:
var txtread =
{
onReady: function(_imgname)
{
txtread.fadeoutText(_imgname);
txtread.fadeinText();
},
fadeoutText: function(_imgname)
{
$("#pagetitle").fadeOut(1250);
$("#pagemenu").fadeOut(1250);
$("#pageslogan").fadeOut(1250);
$("#sitecopy").fadeOut(1550, txtread.TextReadabilityHandler(_imgname));
},
fadeinText: function()
{
$("#pagetitle").fadeIn(1250);
$("#pagemenu").fadeIn(1250);
$("#pageslogan").fadeIn(1250);
$("#sitecopy").fadeIn(1250);
},
TextReadabilityHandler: function(_imgNameSwitch)
{
if(_imgNameSwitch == 'Light')
{
$("#pagetitle").attr('class', 'sitetitle lighttextbackground');
$("#pagemenu").attr('class', 'sf-menu lighttextbackground');
$("#pageslogan").attr('class', 'slogan lighttextbackground');
}
else if (_imgNameSwitch == 'Dark_')
{
$("#pagetitle").attr('class', 'sitetitle darktextbackground');
$("#pagemenu").attr('class', 'sf-menu darktextbackground');
$("#pageslogan").attr('class', 'slogan darktextbackground');
}
else
{ alert(_imgNameSwitch); }
}
}
so I thought order of execution, longer fadeOut, and setting the fadeOut completed function last would keep things in order but alas. I was wrong.
Thank You
Edit
So now I have tried window.setTimeout and it behaves exactly the same as if the timeout doesn't even run???
OK my bad. I originally tried:
window.setTimeout(txtread.TextReadabilityHandler(_imgname), 3000);
and that didn't error or work. I then went back and reread a bit better and saw to use a callback so I rewrote this way:
window.setTimeout(function(){ txtread.TextReadabilityHandler(_imgname); }, 3000);
and now it is working.
My original question still applies though. I understand javascript is an asynchronous programming language but it is imperative no?? Perhaps I am getting terms jumbled in my head.
Does the following execute one after the other:
alert('1');
alert('2');
alert('3');
or do they all execute at once?
Your code includes the following.
onReady: function(_imgname)
{
txtread.fadeoutText(_imgname);
txtread.fadeinText();
}
You are correct in thinking that txtread.fadeinText() will not run until txtread.fadeoutText(_imgname) is complete. However, fadetextOut is completing before you are expecting it to.
fadeoutText: function(_imgname)
{
$("#pagetitle").fadeOut(1250);
$("#pagemenu").fadeOut(1250);
$("#pageslogan").fadeOut(1250);
$("#sitecopy").fadeOut(1550, txtread.TextReadabilityHandler(_imgname));
}
will return almost immediately, having told the various elements to fade out over a period of time. So calling txtread.fadeinText() will not wait for those elements to fade out.
You will need to add some form of callback to fadeinText and fadeoutText, which you can use to let other code know they have finished, like so.
onReady: function(_imgname)
{
txtread.fadeoutText(_imgname, function () {
txtread.fadeinText();
});
}
fadeoutText: function(_imgname, cb)
{
$("#pagetitle").fadeOut(1250);
$("#pagemenu").fadeOut(1250);
$("#pageslogan").fadeOut(1250);
$("#sitecopy").fadeOut(1550, function() {
txtread.TextReadabilityHandler(_imgname);
cb();
});
}
fadeinText: function(cb)
{
$("#pagetitle").fadeIn(1250);
$("#pagemenu").fadeIn(1250);
$("#pageslogan").fadeIn(1250);
$("#sitecopy").fadeIn(1250, cb);
}
The alerts would execute in order. Javascript is single threaded.
Edit: Er, I guess that is true for the most part
Check out this link for a good explination, especially regarding fades, etc.
Is JavaScript guaranteed to be single-threaded?
As Michael said, the javascript will all run at the same time. So, run your fadeout functions, then, once they're finished, call the csschange functions and, once that's complete, run the fade in functions.
I'd be able to write this in jQuery (as it's easy to add a function to run after another is complete). It should be straighforward in plain js, I just don't know the syntax so well . . .
in javascript commands are excuted in order , the thing is if you have error within just one command , it could stop the whole script from excution .
http://www.w3schools.com/js/js_statements.asp
Each statement is executed by the browser in the sequence they are
written.
I've got multiple elements on my page that fade in and out on a timer using javascript setInterval to set them in motion. I have them delayed so they are offset just slightly to create a nice cascading effect, but if you leave the page open long enough, they all catch up to one another and the timing gets all messed up (you've got to leave it for a few minutes).
I have an ugly example of the issue at CodePen here: http://www.cdpn.io/wgqJj
Again, you've got to leave the page open and untouched for a few minutes to see the problem. If you had more items on the page (5 or 10) the problem becomes even more apparent. I've also used this type of effect with several jQuery photo rotator plugins, and over time, the issue always crops up.
Is there any explanation for this?
Here is the code I'm using (I know the javascript could be cleaner):
HTML:
<p id="one">First</p>
<p id="two">Second</p>
<p id="three">Third</p>
JavaScript:
$(document).ready(function() {
var timer1 = setTimeout(startOne,1000);
var timer2 = setTimeout(startTwo,2000);
var timer3 = setTimeout(startThree,3000);
});
function startOne () {
setInterval(flashOne,3000);
}
function startTwo () {
setInterval(flashTwo,3000);
}
function startThree () {
setInterval(flashThree,3000);
}
function flashOne () {
$("#one").fadeTo("slow",0.4).fadeTo("slow",1.0);
}
function flashTwo () {
$("#two").fadeTo("slow",0.4).fadeTo("slow",1.0);
}
function flashThree () {
$("#three").fadeTo("slow",0.4).fadeTo("slow",1.0);
}
Question has already been answered here. Quoting from the top rated answer in this topic:
it will wait AT LEAST 1000MS before it executes, it will NOT wait exactly 1000MS.
Giving an actual answer, I'd solve it like this:
$(function(){
setTimeout(flashOne,1000);
});
function flashOne () {
$("#one").fadeTo("slow",0.4).fadeTo("slow",1.0);
setTimeout(flashTwo,1000);
}
function flashTwo () {
$("#two").fadeTo("slow",0.4).fadeTo("slow",1.0);
setTimeout(flashThree,1000);
}
function flashThree () {
$("#three").fadeTo("slow",0.4).fadeTo("slow",1.0);
setTimeout(flashOne,1000);
}
Like this it's not possible for the timers to mess up, as it's always delayed one second after the item before has flashed.
Consider using a chained setInterval instead as this give a guaranteed slot to the browser. Reference this SO post..
Currently you only use setInterval to start the animation. From there jQuery is handling the "oscillations".
Theoretically using a chained set interval should guarantee a slot, to the browser. More importantly, you can hard code the offset into the code at each interval, instead of only once at the beginning.
The setTimeout() and setInterval() functions do not guarantee that your events run exactly on schedule. CPU load, other browser tasks, and similar can and will affect your timers, therefore they are not reliable enough for your use case.
A solution for this would be asynchronous events (promises or similar) or using the event queue that jQuery supplies. That way you could either nest with callbacks, or queue them up and then fire the queue over again once it hits the last item in the queue. The .queue() API documentation page has an example of this.
I'm creating a error message displaying box which slides out, delays for 3 seconds and then slides in with Mootools. This is what I'm currently doing now, how can I correct it to get it work for me?
var slide = new Fx.Slide($("error"));
slide.slideOut('horizontal').chain(function(){
$("error").set("text", message);
}).chain(function(){
this.slideIn('horizontal').delay(3000);
}).chain(function(){
this.slideOut('horizontal');
});
You basically have your mootools correct, but are missing a few key items that would make your script function properly. I have pasted a working version below, and then made some comments:
var slide = new Fx.Slide($("error"));
slide.slideOut('horizontal').chain(function () {
$('error').set('text', message); this.callChain(); //NOTE
}).chain(function () {
this.slideIn('horizontal');
}).chain(function () {
this.slideOut.delay(3000, this, 'horizontal'); //NOTE
});
Notice the this.callChain() on the
3rd line. Not having this was what
was stopping you seeing anything.
The Fx class uses the callChain()
method internally to start the next
step in the sequence, but if your
argument to chain() doesn't contain
one of Fx's methods, callChain() is
not called, so you have to do it
manually.
Your call to delay was in the wrong place. Delay() delays the execution of the function it is applied to, it does not insert a pause into a chain. Therefore to display the error message for 3sec you need to add delay to the the last function call, because this is the one you want to slow down
Your call to delay was incorrect. Delay applies to the function, not the return value of the function, hence Dimitar's suggestion above. Have a look at function in the mootools core documentation for more info
By the sounds of it, you do not have firebug installed. This would have let you explore the DOM to find that your code changes the margins and then the text, but nothing happens after that. Firebug is super useful, so install it ASAP
My solution (mootools 1.3) is below, and basically relfects what dimitar was suggesting:
$('error').set('slide', {
mode: 'horizontal'
}).get('slide').slideOut().chain(function () {
$('error').set('text', message); this.slideIn();
}, function () {
this.slideOut.delay(3000, this);
});
Hope it helps