Jquery each loop + setTimeout problems with increments - javascript

http://jsfiddle.net/fxLcy/ - example with setTimeout
http://jsfiddle.net/fxLcy/1/ - this is the demo without setTimeout. All elements on right place, but i really need that delayed animation =/
I want to place 6 cards per row via css transition and setTimeout. The point is, that i cant use increment for my left and top parameters inside setTimeout, because this thing just summarizes all my increments and sets elements onto final place.
var self = $(this);
if (increment % 6 === 0 && increment !== 0) {
topIncrement++;
leftIncrement = 0;
};
setTimeout(function() {
self.css({'left' : 10 + leftIncrement * (resizedWidth + 20),
'top' : $("#controlPanel").height() + 10 + topIncrement * (resizedHeight + 20)});
}, increment * 500)
leftIncrement++;
increment++;

So the issue is the variable is being shared accross the timeouts, you want to the javascript to close on each x and y position (you want each tmeout to take a snapshot of the x/y values - javascript closure).
So taking your above code and changing the setTimeout to the following I believe did the trick (please see updated fiddle)
var valuex = 10 + leftIncrement * (resizedWidth + 20);
var valuey = $("#controlPanel").height() + 10 + topIncrement * (resizedHeight + 20)
setTimeout(function() {
self.css({'left' : valuex,
'top' : valuey});
}, increment * 500)

Related

Animation changes the position of div's

Well I've implementes some divs and when I start the page I want them animate, they do, but the problem is that sometimes one div overlaps another one then I see a blank space... How could I avoid this? I'm doing this :
This is how I change the divs :
function swap(d1, d2){
var topaux, leftaux;
topaux = d1.css("top");
leftaux = d1.css("left");
d1.animate({
top: d2.css("top"),
left: d2.css("left"),
}, { duration: 1000, queue: false });
d2.animate({
top: topaux,
left: leftaux,
}, { duration: 1000, queue: false });
}
This is how I'm trying to do it now, but after try this, I didn't have any animation so I had this code and it worked I mean no overlaps between div's....
d1.css("top", d2.css("top"));
d1.css("left", d2.css("left"));
d2.css("top", topaux);
d2.css("left", leftaux);
I call this function (swap) when I'm shuffling the divs as follows :
function swapdivs(){
var i,r, c, d1, d2;
for (i = 1; i < 100; i++) {
r = Math.floor((Math.random() * rows) + 1);
c = Math.floor((Math.random() * columns) + 1);
d1= $("#r"+r+"c"+c);
r = Math.floor((Math.random() * rows) + 1);
c=Math.floor((Math.random() * columns) + 1);
d2 = $("#r"+r+"c"+c);
swap(d1,d2);
}
}
This is the jfiddle
What I'm missing?
Ok, now i see the problem.
In your barrejarPeces function you're scrambling randomly all elements multiple times (100)
for (i = 1; i < 100; i++) {
In the interanvipeces function you try to switch the position of 2 different elements with an animation of 1000ms, calculating their css attributes top and left
Well, the problem is when one (or both) elements are already switching position (since the barrejarPeces function will scramble 100 times without waiting any animation to finish), top and left values won't be correct.
So there are 2 possible solutions:
Don't use animation delay (try to set to 0 instead of 1000 in your fiddle and you'll see it works)
Scramble all elements just once (see my example here, where i changed some logic)

How do I get a variables value to be constantly decreased when operated on (+/- the requested change) (in javascript:alert boxes))

<script>
var x = 40
function ale() {
a = document.getElementById("find").value
if (a == 'Spark' || a == 'Fire') {
var monster = x
var damage = Math.floor(Math.random() * 10)
alert('Enemy has ' + (monster - damage) + ' Health!');
}
else if
(a == 'water' || a == 'bubble') {
var monster = x
var damagew = 10
alert('Enemy has ' + (monster - damagew) + ' Health!')
}
Hi so what happens is whenever I type for example water the health of what x was 40 is now 30 but now I click it again and it tells me its the same thing 30 when I want to be 20 and then if I type fire for it to give me 20 - Math.floor(Math.Random()*10) to give something like 17 pretty much how my text based game works. But as for now it just keeps giving me 30 everytime I write water. Is it possible to get the x value working where it can constantly be edited then maintain its value after its been edited by for example a subtraction?
you have to decrease x by 10 if you want 20 next time on click.X=X-damagew after alert.
What you would need to do is this:
(a == 'Spark' || a == 'Fire') {
var monster = x
var damage = Math.floor(Math.random() * 10)
alert('Enemy has ' + (monster - damage) + ' Health!');
HEALTHVARIABLE -= damage;
}
HEALTHVARIABLE is just to be used in place of whatever you are currently using as the variable to store your monsters' health.
I can't help but point out that you are missing a curly bracket in your code. I'm not sure whether you just didn't copy the last line of your code that contains said bracket, or you have another bracket somewhere else out of place in your code that makes up for it and forces it to still work, but if you are still having an issue with your code that is something you should look at. Best of luck.

background-position change in increments with jQuery

I'm trying to workout an efficient way to cycle though in 25% increments the background image of an element, but when it gets to 100% it would go back to 0% on the next increment.
I can do something like this:
var currentPos = $('.ele1').css('background-position');
var elementPositions = currentPos.split(' ');
var x = Number(elementPositions[0].replace(/[^0-9-]/g, ''));
//var y = Number(elementPositions[1].replace(/[^0-9-]/g, ''));
// only want to do the x axis
x = (x == 100) ? 0 : x += 25;
$('.ele1').css('background-position', x + "%" + " 0");
But I don't like the fact I have to call the element twice. Is there a more efficient way to increment a % with jQuery and have it reset back to 0% after 100%?
I did think to do it with CSS .classes. But I don't really want to be restricted to what's in my style sheet.
You can pass a callback function to jQuery's .css() method:
$('.ele1').css('background-position', function (i, value) {
var x = parseInt(value, 10);
return (x == 100 ? 0 : x + 25) + "%" + " 0";
});
If you're calling this from within a loop/timer/event/whatever, you should cache the $('.ele1') object.

Javascript animate math

I'm struggling to get my head around such simple Math, well at least it seems it should be simple.
I'm basically trying to mirror what jQuery's .animate does, but to no luck.
Here's a simplified version of what I have so far:
var args = {
speed: 1000, // 1 second.
left: 65 // distance.
}, rot, step;
// Terrible math.
rot = step = (((args.left / args.speed) * 10) - 0.10);
var t = setInterval(function() {
if(elem.style.left >= args.left) {
clearInterval(t);
return;
}
rot += step;
elem.style.left = rot;
}, 10);
Please excuse any illogical code (or math), I've been messing around for a good few hours and totally lost my sanity.
Edit:
Here's the way I would do it.
var start_time = Date.now();
// Get the starting time in milliseconds
var t = setInterval(function() {
var delta_time = Date.now() - start_time;
// Get time that has elapsed since starting
if (delta_time >= 1000) {
// if it's been a second
clearInterval(t);
// Stop the timer
elem.style.left = args.left + 'px';
// Set the element to exactly the value it should be (avoids having it set to a float value)
return;
}
elem.style.left = delta_time * args.left / args.speed + 'px';
// Move the element according to how much time has elapsed
}, 10);​
This method has a few advantages. For example, you can adjust the interval to make it more or less smooth, and it won't mess up the animation.
The reason why your solution was taking longer than one second is because of how you used setInterval. setInterval doesn't account for the time your code takes to run, so the total time is always increased by a bit. You can fix this by using delta timing (like in my example).
Try using useing sin and cos to calculate rotation Some what like this
newx = distance * Math.cos(direction) + x
newy = distance * Math.sin(direction) + y
Not sure , this will solve your problem I guess you want to to do a smooth rotation
Try making it as a function it will work , I am not seeing any problem in your math ,
like this
function move(elem) {
var left = 0
function frame() {
left++ // update parameters
elem.style.left = left // show frame
if (left == 100) // check finish condition
clearInterval(id)
}
var id = setInterval(frame, 10) // draw every 10ms
}
Well for one it should be
var args = { ... }
assuming you have the elem set up correctly, you're going to need a inline styling of the attribute you want to animate. Also, you're going to need to parse the style since it has the 'px' attached to it, but you can always add that after you do the math within the interval function.
I set up something here so you can mess around with the settings and whatnot.
edit:
http://jsfiddle.net/mb4JA/2/
edit2:
this should be one second
http://jsfiddle.net/mb4JA/4/
final answer ;) http://jsfiddle.net/mb4JA/10/
You should be able to put any speed in there, and have it animate for that amount of seconds.

Animate counter using Javascript

I have a couple of fairly simple javascript functions which animate the transition of a number, going up and down based on user actions. There are a number of sliders on the page which within their callback they call recalculateDiscount() which animates the number up or down based on their selection.
var animationTimeout;
// Recalculate discount
function recalculateDiscount() {
// Get the previous total from global variable
var previousDiscount = totalDiscount;
// Calculate new total
totalDiscount = calculateDiscount().toFixed(0);
// Calculate difference
var difference = previousDiscount - totalDiscount;
// If difference is negative, count up to new total
if (difference < 0) {
updateDiscount(true, totalDiscount);
}
// If difference is positive, count down to new total
else if (difference > 0) {
updateDiscount(false, totalDiscount);
}
}
function updateDiscount(countUp, newValue) {
// Clear previous timeouts
clearTimeout(animationTimeout);
// Get value of current count
var currentValue = parseInt($(".totalSavingsHeader").html().replace("$", ""));
// If we've reached desired value, end
if (currentValue === newValue) { return; }
// If counting up, increase value by one and recursively call with slight delay
if (countUp) {
$(".totalSavingsHeader").html("$" + (currentValue + 1));
animationTimeout = setTimeout("updateDiscount(" + countUp + "," + totalDiscount + ")", 1);
}
// Otherwise assume we're counting down, decrease value by one and recursively call with slight delay
else {
$(".totalSavingsHeader").html("$" + (currentValue - 1));
animationTimeout = setTimeout("updateDiscount(" + countUp + "," + totalDiscount + ")", 1);
}
}
The script works really well for the most part however there are a couple of problems. Firstly, older browsers animate more slowly (IE6 & 7) and get confused if the user moves the slider again whilst it is still within the animation.
Newer browsers work great EXCEPT for on some occasions, if the user moves the slider mid-animation, it seems that it starts progressing in the wrong direction. So for updateDiscount() gets called with a new value and a directive to count up instead of down. As a result the animation goes the wrong direction on an infinite loop as it will never reach the correct value when it's counting in the wrong direction.
I'm stumped as to why this happens, my setTimeout() experience is quite low which may be the problem. If I haven't provided enough info, just let me know.
Thank you :)
Here is how you use setTimeout efficiently
animationTimeout = setTimeout(function {
updateDiscount(countUp,totalDiscount);
},20);
passing an anonymous function help you avoid using eval.
Also: using 1 millisecond, which is too fast and will freeze older browsers sometimes. So using a higher which will not even be noticed by the user can work better.
Let me know if this works out for you
OK think it's fixed...
Refactored code a little bit, here's final product which looks to have resolved bug:
var animationTimeout;
function recalculateDiscount() {
var previousDiscount = parseInt(totalDiscount);
totalDiscount = parseInt(calculateDiscount());
if (($.browser.msie && parseFloat($.browser.version) < 9) || $.browser.opera) {
$(".totalSavingsHeader").html("$" + totalDiscount);
}
else {
if (previousDiscount != totalDiscount) {
clearTimeout(animationTimeout);
updateDiscount(totalDiscount);
}
}
}
function updateDiscount(newValue) {
var currentValue = parseInt($(".totalSavingsHeader").html().replace("$", ""));
if (parseInt(currentValue) === parseInt(newValue)) {
clearTimeout(animationTimeout);
return;
}
var direction = (currentValue < newValue) ? "up" : "down";
var htmlValue = direction === "up" ? (currentValue + 1) : (currentValue - 1);
$(".totalSavingsHeader").html("$" + htmlValue);
animationTimeout = setTimeout(function () { updateDiscount(newValue); }, 5);
}
Will give points to both Ibu & prodigitalson, thank you for your help :)

Categories

Resources