How to change jquery animate() duration while animating using step - javascript

So here is the scenario. I'm trying to make a infinite image carousel, and everytime it will show an image that has a class of special .special I want to slow down the animation duration or the scrolling of the animation. So users can see the special image longer. Here is my code.
$photoGalleryList.animate({
left : '-' + (computedWidth) + 'px'
},
{
duration : 10000,
easing : 'linear',
step : function(now, fx) {
if(visibleSpecialImage()) {
// SLOW ANIMATION DURATION
// Tried setting fx.options.duration still no effect
}
}
});
I'm not sure if my approach is right (doing it with step), jquery animate() documentation says
step
Type: Function( Number now, Tween tween )
A function to be called for each animated property of each animated element. This function provides an opportunity to modify the Tween object to change the value of the property before it is set.
I'm not sure if I understood the documentation clearly, But base on what I read it's possible using step, I tried googling my problem and never found any concrete answer So now I'm stackoverflowing and hopefully solve this problem. Thanks

Related

Reversible transition with delay

What I'm trying to do is to have on hover transition or animation (can be triggered via javascript with onmouseover or onmouseenter) that will also be reversible (so the opposite animation should happen on mouse leave) but
the opposite animation should have a delay
it should be able to reverse in the middle of animation without delay
It's hard to describe without showing so please check this codepen that is pretty close to what I'm trying to achieve: http://codepen.io/anon/pen/xROOqO
There are two problems here:
I need to check for elapsed time in transitionend handler, so I would need to update both css and js to update transition time
It still has delay when you quickly hover in and out on the reverse animation - looks like it's stuck in the middle
Is this even possible using css transitions (perhaps keyframes animation) or should I stick to setting timers in javascript and leave out the delay from css?
Not sure if what I'm going to present is simpler, but it seems to address some of your issues, and matches my taste.
The main idea is to admit that the problem is complicated due to multiple states, and address it using a state machine.
This allows for a declarative approach like this one:
const TRANSITIONS = {
'small-inside' : {
'transitionend' : 'big-inside',
'mouseover' : 'small-inside',
'mouseout' : 'small-outside',
},
'small-outside' : {
'transitionend' : 'small-outside',
'mouseover' : 'small-inside',
'mouseout' : 'small-outside',
},
'big-inside' : {
'transitionend' : 'big-inside',
'mouseover' : 'big-inside',
'mouseout' : 'big-outside',
},
'big-outside' : {
'transitionend' : 'small-outside',
'mouseover' : 'big-inside',
'mouseout' : 'big-outside',
},
}
And quite simple handling of events:
function step(e){
box.className = TRANSITIONS[box.className][e.type];
}
box.addEventListener('transitionend', step);
box.addEventListener('mouseover', step);
box.addEventListener('mouseout', step);
Another insight is that you can specify the delay using CSS transition-delay:3s property:
div.small-inside,
div.big-inside {
width: 300px;
}
div.small-outside,
div.big-outside {
width: 150px;
}
div.big-outside {
transition-delay:3s;
}
The proof of concept is here: http://codepen.io/anon/pen/pNNMWM.
What I do not like about my solution is that it assumes that the initial state is small-outside while actually the mouse pointer could be well located within the div when the page loads.
You've mentioned ability to trigger state transitions manually from JS. I believe this is possible as long as you keep track of two separate boolean variables: "is mouse inside?" and "does js asked to grow?". You can not mix them into a one state and expect correct "counting". As you see I already have 2*2=4 states because I'm trying to keep track of {small,big}x{inside,outside} - one could imagine extending it to {small,big}x{inside,outside}x{js-open,js-close} in similar manner, with some extra "events" like 'open' and 'close'.

jquery animation moving and stopping

I got a div with an image inside it using query
$('#super').animate({
left:'150px'
}, {
duration: 10000,});
What iam trying to figure out is how to stop and start animation. So for example it will start to move left 150px and then will stop for 2 seconds and then move left 300px.
Like this:
$('#super').animate({left : '-=150'}).delay(2000).animate({left : '-=300'});
Demo: http://jsfiddle.net/E7akr/
(You can add duration, easing and complete settings to the .animate() calls as desired - obviously the key thing here is the .delay() method.)

JQuery Animate : Change the destination of a prop during the animation

I made a image scrolling with the mouse.
The image scroll to a position based on the mouse position percentage of the window height.
$(imageContainer).mouseenter(function(e){
var scrollingTo = ((e.pageY/$(this).height())-.083) * ( $(imageContainer).prop('scrollHeight') - $(imageContainer).height() );
hijacked = true;
$(imageContainer).animate({scrollTop:scrollingTo},300,function(){hijacked=false;});
}).mousemove(function(e){
if(hijacked) return;
var scrollingTo = ((e.pageY/$(this).height())-.083) * ( $(imageContainer).prop('scrollHeight') - $(imageContainer).height() );
$(imageContainer).scrollTop(scrollingTo);
});
So. in that line
$(imageContainer).animate({scrollTop:scrollingTo},300,function(){hijacked=false;});
I want that scrollingTo change. Because during the animation, the user can move the mouse, changing the scrollingTo variable.
Alright, I managed to cook together a hacky way of dynamically altering an animation. My understanding of the internal animation queue for jQuery is not great, but as far as I know there's no way to alter a queued animation, other than to make it stop. Anyway, here's the key code for an example that alters position, which should be adaptable to scrolling (in fiddle form):
$(document).ready(function () {
var last_update = 0;
$(document).on("mousemove", function (e) {
if (Date.now() - last_update > 50) {
$mover = $("#mover");
$mover.stop();
$mover.animate({ left: e.pageX, top: e.pageY}, 200, "linear");
last_update = Date.now();
}
});
});
There were a couple of tricks to make it work, I'll go through them and try to explain how I believe they could be adapted to scrolling:
The main idea is that on mousemove, the prior event is cancelled, and a new one is started.
I don't believe this will require any changes for scrolling.
Some forms of animation accelerate/decelerate over the course of the animation - it's too hard to preserve this in a constantly changing animation (at least without writing a custom animation function), so the animation easing is set to "linear".
rapidly changing animations takes time (especially for an event as common as mousemove), so there's a limit on how often the animation can change. Before a change to the animation is made, it's ensured that no changes have been made in the last .05 seconds (this is done with "last_update").
I believe if you just swap out the animation properties for your own (scrollTop), this should do what you're looking for.

KineticJS animation with JQuery

I am new in KineticJS and I am stacked. I want to use a simple animation with opacity but I found out that there is not so "simple" as it seems. I read the doc about animations with KineticJS (you won't say simple about this tutorial). What I want to know Is there a simple method to animate things with KineticJS like JQuery or JCanvaScript has? for example
this.animate({
opacity:0,
x: 50
}, 500);
something like this?
If there is not can we use KineticJS with JQuery to make animations simple? I found out THIS project that has very interesting piece of code:
$(logo.getCanvas()).animate({
opacity: 1,
top: "+=50px"
}, 1000);
so guys what do you think? Is it buggy to use this method?
If you just have to do your opacity animation : you should stick to JQuery which will hide the computations done for the animation (and what you were pointed to is a good solution).
If you want more controls over your animation : go with KineticJS.
Through, I think you will have more issues trying to use JQuery animations and KineticJS layers at the same time rather than using only KineticJS (and Kinetic.Animation is pretty simple once you have understand how to play with it)
edit: Quick How-To for animations :
So, as you may have seen, in Kinetic, you do not give the final position like in JQuery : you have an access to a function which is called at each frame of the animation and all the logic have to be placed in it :
<script>
// you should have an object yourShape containing your KineticJS object.
var duration = 1000 ; // we set it to last 1s
var anim = new Kinetic.Animation({
func: function(frame) {
if (frame.time >= duration) {
anim.stop() ;
} else {
yourShape.setOpacity(frame.time / duration) ;
}
},
node: layer
});
anim.start();
</script>

jQueryui animation with inital undefined height

See the following fiddle:
[edit: updated fiddle => http://jsfiddle.net/NYZf8/5/ ]
http://jsfiddle.net/NYZf8/1/ (view in different screen sizes, so that ideally the image fits inside the %-width layouted div)
The image should start the animation from the position where it correctly appears after the animation is done.
I don't understand why the first call to setMargin() sets a negative margin even though the logged height for container div and img are the very same ones, that after the jqueryui show() call set the image where I would want it (from the start on). My guess is that somehow the image height is 0/undefined after all, even though it logs fine :?
js:
console.log('img: ' + $('img').height());
console.log('div: ' + $('div').height());
$('img').show('blind', 1500, setMargin);
function setMargin() {
var marginTop =
( $('img').closest('div').height() - $('img').height() ) / 2;
console.log('marginTop: ' + marginTop);
$('img').css('marginTop', marginTop + 'px');
}
setMargin();
Interesting problem...after playing around with your code for a while (latest update), I saw that the blind animation was not actually firing in my browser (I'm testing on Chrome, and maybe it was firing but I wasn't seeing it as the image was never hidden in the first place), so I tried moving it inside the binded load function:
$('img').bind('load', function() {
...
$(this).show('blind', 500);
});
Now that it was animating, it seemed to 'snap' or 'jump' after the animation was complete, and also seemed to appear with an incorrect margin. This smacks of jQuery not being able to correctly calculate the dimensions of something that hadn't been displayed on the screen yet. On top of that, blind seems to need more explicit dimensions to operate correctly. So therein lies the problem: how to calculate elements' rendered dimensions before they've actually appeared on the screen?
One way to do this is to fade in the element whose dimensions you're trying to calculate very slightly - not enough to see yet - do some calculations, then hide it again and prep it for the appearance animation. You can achieve this with jQuery using the fadeTo function:
$('img').bind('load', function() {
$(this).fadeTo(0, 0.01, function() {
// do calculations...
}
}
You would need to work out dimensions, apply them with the css() function, blind the image in and then reset the image styles back to their original states, all thanks to a blind animation that needs these dimensions explicitly. I would also recommend using classes in the css to help you manage things a little better. Here's a detailed working example: jsfiddle working example
Not the most elegant way of doing things, but it's a start. There are a lot more easier ways to achieve seemingly better results, and I guess I just want to know why you're looking to do image blinds and explicit alignment this way? It's just a lot more challenging achieving it with the code you used...anyways, hope this helps! :)

Categories