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

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();
}
}
});
});

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>

How to animate slide left smoothly?

I have the following
$('.left_arrow').hover(function() {
$('.chart').stop().animate({
left: "+=10"
});
},
function() {
$('.chart').stop();
});
And I want to have it when you mouse over the arrow it smoothly moves the .chart to the left, and the right arrow it moves it to the right. I am doing this by applying a - left (-7500px is the max) to move it to the left and a 0 is the farthest it can go right.
The above moves it over 10, but it doesn't keep on moving it. How can I get it so it keeps on moving it. I was using something like
$('.left_arrow').hover(function() {
$('.chart').stop().animate({
left: "-7500px"
}, 20000);
},
function() {
$('.chart').stop();
});
But the problem is if I am say -6500px over it takes 20 seconds to go the rest of the 1000, vs 20 seconds to go the full distance. So the speed is skewed, I want a standard increment.
Basically what you need is a rate function. I had the same issue when I was creating my carousel.
rate = distance/time
So, your rate is 0.375
Now, all you will need to do is find the distance and you can adjust your timing accordingly.
time = distance/0.375
So it should look something like this:
$('.left_arrow').hover(function() {
var distance = /*Get Distance Remaining*/
var sd = 7500;
var time = 20000;
var rate = sd/time;
var time = distance/rate
$('.chart').stop().animate({
left: "-7500px"
}, time);
},
function() {
$('.chart').stop();
});
Obviously it would need some tweaking to get just right. But the concept is there.
For my situation, because I was using a <ul> since it was a carousel this is the way I got distance:
distance = Math.abs($ul.position().left);
Not fully understanding the question, but you can increment/decrement animations like so:
$('.chart').stop().animate({
"left": "+=100px"
}, 250);
Note the += operator.
EDIT: This answer is only partially correct. Animation behavior on hover is not as desired. Trying to solve.

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?

jquery rotate callback not called if image not rotated

I have this piece of code rotating an image and then moving it - which works fine unless the image does not rotate - meaning the current angle of the image is equal to the angle it should rotate to - in this case the callback function is not called, so there is no animation. The rotate function comes from a plugin.
$("#Ship" + shipID).rotate({
duration: 500,
angle: $(this).getRotateAngle(),
animateTo: parseInt(rotate),
callback: function () {
$("#" + shipID).animate({
left: parseInt(moveX),
top: parseInt(moveY)
}, 500, function () {
});
}
})
If the animate function is written after the rotate - then the rotate and animation happen at the same time.
I don't think I can force the callback as I would have to edit the plugin (but im not sure about that). Is there a way to write the animate after the rotate, but wait for rotate to finish? I guess one way would be is to use delay, but is there a more proper way?
You have to check the rotation before you try to execute anything with the plugin. I'm not exactly sure how you'll check the current rotation, but:
var currentRotation = $("#Ship" + shipID).getRotateAngle();
if(currentRotation != rotate) {
$("#Ship" + shipID).rotate({
duration: 500,
angle: $(this).getRotateAngle(),
animateTo: parseInt(rotate),
callback: function () {
$(this).rotate({
animateTo: rotate
});
$("#" + shipID).animate({
left: parseInt(moveX),
top: parseInt(moveY)
}, 500);
}
});
}
Depending on your exact setup and how the plugin works, you may need to check your currentRotation inside of the plugin method. Or, you may need to set up some events to execute the if statement. Again, this would depend on how you're brinding this all together (how do you know when you want something to rotate?)

how to remove a method with a callback or otherwise

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.

Categories