how to remove a method with a callback or otherwise - javascript

I have the following code that animates an object with a delay of 800 ms:
$('#navMenu').mousemove(function (e) {
thisX = e.pageX
if (thisX >= 1625) {
$('#prbBtnHolder').animate({ left: '-=150' }, 300).delay(800);
}
});
If the #prbBtnHolder has a certain css left property i want to be able to remove the delay()method and stop the animation. How do i do this? This is what I've tried so far:
//...
$('#prbBtnHolder').animate({ left: '-=150' }, 300).delay(800);
if ($('#prbBtnHolder').css('left') < -100) {
$(this).animate({left: '-=0px'});
}
But this does not remove the delay method nor does it achieve the desired effect. Any other ideas?

In order to clear the effects queue, you'll need to use the step callback to see if your condition is met.
http://api.jquery.com/animate/
$('#prbBtnHolder').animate({
left: '-=150'
},
{
duration: 300,
step: function(now, fx) {
if (now < -100) {
// uncomment and you'll see the next animation
$(fx.elem).clearQueue().stop();
}
}
}).delay(800).animate({ width: '200px', height: '200px' }, 300);
Here is a jsbin example:
http://jsbin.com/utejew/3

$(this).clearQueue();
jQuery Docs for clearQueue
Removes all elements in the effect Queue for the given Element. Otherwise you could use js native setTimeoutfunction to animate which can easily be cleared with clearTimeout.
Before you Animate $('#prbBtnHolder') you can calculate how far the Button is away from -100 and animate it only that far.

Related

How to replace margin-left animation with transform in Jquery animate() to fix laggy multislider

I'll preface this by saying my initial problem is difficult to reproduce.
Brief explanation of my problem following, question is at the bottom.
So I am using the Jquery multislider for a project.
Here is a link to it: Multislider
Now my issue is that the animation of the moving elements seems to lag... Sometimes.
It jumps instead of moving smoothly.
The way the element works is by applying the animate() method to the first item and applies an inline margin-left property to the first .item
With some research I have found that CSS animations often cause problems when margins are used for the animation(among some other properties like top/bottom/left/right, as well as height/width) and that using transform is preferable.
So far so good.
This is the snippet in the javascript that creates the animation:
function singleLeft(){
isItAnimating(function(){
reTargetSlides();
$imgFirst.animate(
{
marginLeft: -animateDistance /* This is the part that causes me problems */
}, {
duration: animateDuration,
easing: "swing",
complete: function(){
$imgFirst.detach().removeAttr('style').appendTo($msContent);
doneAnimating();
}
}
);
});
}
function singleRight(){
isItAnimating(function(){
reTargetSlides();
$imgLast.css('margin-left',-animateDistance).prependTo($msContent);
$imgLast.animate(
{
marginLeft: 0
}, {
duration: animateDuration,
easing: "swing",
complete: function(){
$imgLast.removeAttr("style");
doneAnimating();
}
}
);
});
}
Now if I understand it correctly, I have to replace the marginLeft: -animateDistance portion with a transformX property, is that correct?
But I am failing to make it work.
So my question is, how can I replace the marginLeft: -animateDistance portion with transform: translateX() and add the animateDistance variable between the parentheses?
I have tried something like transform: "translateX(-$(animateDistance))", but that just disables the animation entirely.
Am I missing something?
I'm open for other suggestions to solve the issue of the laggy animation as well, this just is the conclusion I came to.
You can use animate with $(this) and .css() if you use step()
let test = "100";
$('div h2').animate({ pxNumber: test }, {
step: function(pxNumber) {
$(this).css('transform','translateX(-' + pxNumber + 'px )');
},
duration:'slow',
easing: "swing",
complete: function(){
console.log('Animation done');
// doneAnimating();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div><h2>Move it</h2></div>

returning the position of an element continuously

I have an object which is animated and falling from the top of the window to the bottom of the window. this works fine, but I would like to return the position of the element continuously.
At the moment I have this code
var pos = function() {
console.debug(jQuery('.element').position());
}
jQuery(window).on('mousemove', pos);
Which returns the position of the class "element" when the mouse is moving, I have also tried the event handler "live" but it is not working.
Is there any event handler I can use which will continuously return the position of them elemnt?
Thank you
Use .animate()'s step callback to track whatever you want, from position to timing:
var $test = $("span");
$("#element").animate({ top: 300 }, {
duration: 5000,
step: function(now, fx) {
$test.text( now );
}
});
#element{
position:absolute;
top: 0;
background:red;
width:40px;
height:40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span></span> px
<div id="element"></div>
http://api.jquery.com/animate/
A small suggestion, if you don't want to lose your fingers writing jQuery all over the place....
jQuery(function( $ ){ // DOM ready and jQuery $ alias secured
// Free to use $ as you usually would
});
You could use setInterval to execute a function at given interval.
setInterval(function () {
// do something here
}, 1000); // each 1 sec, starts after 1s

how to stop animation once max width is reached

I am working to make a slider that moves continuously while the users mouse is positioned over the arrow. It works but it keeps moving even when the content has ended.
How can I make it stop so that the forward/back motion is disabled once all the slides have been viewed, or so that they can't go backwards when they are viewing the first slide?
My code is below - open to other methods to achieve this type of slider if what I have is bad.
$(document).ready(function() {
var timer;
$("#leftarrow").hover(function() {
timer = setInterval(function() {slideLeft();}, 50);
}, function() {
clearInterval(timer);
});
$("#rightarrow").hover(function() {
timer = setInterval(function() {slideRight();}, 50);
}, function() {
clearInterval(timer);
});
function slideLeft() {
$("img#background").stop().animate({
'left': '-=200px'
}, 50);
$(".mid").stop().animate({
'left': '-=20px'
}, 50);
console.log('alert');
}
function slideRight() {
$("img#background").stop().animate({
'left': '-=200px'
}, 50);
$(".mid").stop().animate({
'left': '+=20px'
}, 50);
}
});
Here is a fiddle with my slider: http://jsfiddle.net/rYYDv/
You can use an additional if:
For slide left:
if(($(".mid").position().left) >= -500){ .. }
For slide right:
if(($(".mid").position().left) <= -10){ .. }
Disadvantage: You have to take care of the correct values manually. Which is not a problem, if the pictures don't change very often.
You should probably also add an additional else to ensure a correct final position (for the animate left property). But i think you get the idea.
http://jsfiddle.net/rYYDv/2/
I do not have enough points to comment on this post; hence, I'm writing it down here -
Similar post: How to make the Animate jQuery method stop at end of div?

How to track element movement and trigger function at specific spot?

I have a #ball that when clicked uses jquery animate to move down 210px using this code:
$('#ball').click(function() {
$(this).animate({
top: '+=210px'
}, 500);
setTimeout(crack, 400);
});​
currently Im using Timeout to trigger the next function which is "crack".
Instead I want to track the movement of #ball and when its css top = 210px I want to trigger the function crack(), how can I do this?
I saw in a somewhat similar post that the Step function might be what I'm looking for, but I am not sure how to approach that solution based on the info provided at http://api.jquery.com/animate/
Look at Demo: http://jsfiddle.net/EnigmaMaster/hbvev/4/
I am not sure why you want to use a tracker if you know that the ball will reach the box in 210px.
If you want to get rid of setTimeout, then use the .animate callback function which will be called when the ball reaches the box.
$('#ball').click(function() {
$(this).animate({
top: '+=210px'
}, 500, crack); //<== crack will be called after ball animation
});​
DEMO
Incase if you want to call crack when the ball touches the box and still continue the movement of box then you can execute it 2 steps like below,
$('#ball').click(function() {
$(this).animate({
top: '+=180px'
}, 400, function() {
crack();
$(this).animate({
top: '+=30px'
}, 100);
});
});
Also check this version for fun in slow motion http://jsfiddle.net/skram/hbvev/8/
If you truly want to do something based on the position of the ball, then yes, step is probably the best way to go:
$('#ball').click(function() {
$(this).animate({
top: '+=210px'
}, {
duration: 500,
step: function() {
if($(this).offset().top > 208) {
crack();
}
}
});
});
Demo: http://jsfiddle.net/qJjnN/1/
Now, there are a couple of caveats:
There will be a possible performance hit.
The position at each step will not necessarily be a whole number, and the object will not exist at every pixel between the start and stop location.
step is not called on the final position, so you cannot actually check for 210 if it is the final location.
Taking those into mind, you will not be able to check for the exact position of 210px. Instead, you will want to watch when it passes a certain position and only trigger crack at that point and not every point after:
$('#ball').click(function() {
var cracked = false;
$(this).animate({
top: '+=210px'
}, {
duration: 500,
step: function() {
if($(this).offset().top > 208 && !cracked) {
cracked = true;
crack();
}
}
});
});
Demo: http://jsfiddle.net/qJjnN/2/
The step function also has parameters now and fx that can be used to see the current value of the css being animated. step is called for each step of each css attribute being animated. So, you have to be careful using those, because you need to look at fx to see what attribute value you are looking at (if you are animating more than one, i.e. top and left).
$('#ball').click(function() {
var cracked = false;
$(this).animate({
top: '+=210px'
}, {
duration: 500,
step: function(now, fx) {
if(fx.prop != 'top') {
return;
}
if(now > 208 && !cracked) {
cracked = true;
crack();
}
}
});
});

fadeOut() and slideUp() at the same time?

I have found jQuery: FadeOut then SlideUp and it's good, but it's not the one.
How can I fadeOut() and slideUp() at the same time? I tried two separate setTimeout() calls with the same delay but the slideUp() happened as soon as the page loaded.
Has anyone done this?
You can do something like this, this is a full toggle version:
$("#mySelector").animate({ height: 'toggle', opacity: 'toggle' }, 'slow');
For strictly a fadeout:
$("#mySelector").animate({ height: 0, opacity: 0 }, 'slow');
Directly animating height results in a jerky motion on some web pages. However, combining a CSS transition with jQuery's slideUp() makes for a smooth disappearing act.
const slideFade = (elem) => {
const fade = { opacity: 0, transition: 'opacity 400ms' };
elem.css(fade).slideUp();
};
slideFade($('#mySelector'));
Fiddle with the code:
https://jsfiddle.net/00Lodcqf/435
In some situations, a very quick 100 millisecond pause to allow more fading creates a slightly smoother experience:
elem.css(fade).delay(100).slideUp();
This is the solution I used in the dna.js project where you can view the code (github.com/dnajs/dna.js) for the dna.ui.slideFade() function to see additional support for toggling and callbacks.
The accepted answer by "Nick Craver" is definitely the way to go. The only thing I'd add is that his answer doesn't actually "hide" it, meaning the DOM still sees it as a viable element to display.
This can be a problem if you have margin's or padding's on the 'slid' element... they will still show. So I just added a callback to the animate() function to actually hide it after animation is complete:
$("#mySelector").animate({
height: 0,
opacity: 0,
margin: 0,
padding: 0
}, 'slow', function(){
$(this).hide();
});
It's possible to do this with the slideUp and fadeOut methods themselves like so:
$('#mydiv').slideUp(300, function(){
console.log('Done!');
}).fadeOut({
duration: 300,
queue: false
});
I had a similar problem and fixed it like this.
$('#mydiv').animate({
height: 0,
}, {
duration: 1000,
complete: function(){$('#mydiv').css('display', 'none');}
});
$('#mydiv').animate({
opacity: 0,
}, {
duration: 1000,
queue: false
});
the queue property tells it whether to queue the animation or just play it right away
Throwing one more refinement in there based on #CodeKoalas. It accounts for vertical margin and padding but not horizontal.
$('.selector').animate({
opacity: 0,
height: 0,
marginTop: 0,
marginBottom: 0,
paddingTop: 0,
paddingBottom: 0
}, 'slow', function() {
$(this).hide();
});

Categories