javascript: how to exit a loop by clicking a button - javascript

I did some searching and I'm not even sure if what I want to do is good javascript practice.
I have a while loop that I would like to exit from early if a stop button is clicked.
$( "#go" ).click(function() {
var gotime = 1;
while (gotime < 100) {
for(i = 0; i < 2; i++){
var divName = "floatName" + i;
console.log(divName);
$( "#" + divName ).animate({
left: Math.random()*500 + "px",
top: Math.random()*500 + "px"
}, 500, function() {
// Animation complete.
});
};
gotime += 1;
$( "stop" ).click(function() {
gotime = 101;
});
};
});
This doesn't work though. I originally had an endless loop (not incrementing gotime).
http://jsfiddle.net/cvoxe465/

Actually it stops if you wait for some time. The problem is you execute animation very often and $.animate have to queue it. There is $.stop method that allow you to stop the currently-running animation. DEMO
$( "#stop" ).click(function() {
gotime = 101;
$('#floatName0, #floatName1').stop(true, true);
});
EDIT:
Note that in the code that you provided there is mistake. Instead $("stop") you need to use $("#stop").

You may use setInterval:
Js:
var interval;
$("#go").click(function () {
var gotime = 1;
interval = setInterval(function () {
for (i = 0; i < 2; i++) {
var divName = "floatName" + i;
console.log(divName);
$("#" + divName).css({
left: Math.random() * 500 + "px",
top: Math.random() * 500 + "px"
});
};
gotime += 1;
if (gotime > 100) {
clearInterval(interval);
}
}, 500)
});
$("#stop").on('click', function () {
clearInterval(interval);
});
css:
#randomFloat {
color: red;
}
#floatName1, #floatName0 {
transition : 0.5s left, 0.5s top;
}
Fiddle

animate doesn't block the loop. The animations are stacked up and then executed, but the loop finishes a lot earlier. Here is something that works:
var loopAllowed = false;
$('#go').click(function(){
loopAllowed = true;
var max = 2;
var loop = function(){
for(var i = 0; i < max; i++){
var divName = "floatName" + i;
$( "#" + divName ).animate({
left: Math.random()*500 + "px",
top: Math.random()*500 + "px"
}, 500, i === max - 1 && loopAllowed ? loop : undefined);
}
};
loop();
});
$('#stop').click(function(){
loopAllowed = false;
});
JSFiddle. We manually call the loop function after the animation has ended (by passing it as the callback function). If loopAllowed is false (e.g. set to false by clicking #stop), then it won't be passed as the callback function and the looping stops.

Related

My script needs page refresh for it to run

Every time I load my page for the first time my script does not load, I need to refresh the page at least 3 times for it to run. How can I make my script run without a page refresh? This particular script is in BABEL.
'use strict';
var deg = 0;
var index = 0;
$('#' + index).css('opacity', '1');
$('.navbar').contextmenu(function () {
return false;
});
$('.navbar').on('mousewheel', function (e) {
var move = -60;
var nextIndex = nextIndex = (index + 1) % 6;
if (e.originalEvent.wheelDelta / 120 <= 0) {
// wheel up
move = 60;
nextIndex = index -1 < 0 ? 5 : index - 1;
}
$('.scroll-list').css('transform', 'rotateX(' + (deg + move) + 'deg)');
$('#' + index).css('opacity', '0.01');
$('#' + nextIndex).css('opacity', '1');
index = nextIndex;
deg = deg + move;
event.stopPropagation();
console.timeEnd('cache');
});
And what if you wrapped your code inside a window.onload function?
window.onload = function() {
// your code
}
Your code will only run when the html document is "ready" and fully loaded.
You are running Javascript that depends on page elements and the javascript is executed before the elements are on the page;
Wrapp all your code inside document.ready function
$(document).ready(function () {
var deg = 0;
var index = 0;
$('#' + index).css('opacity', '1');
$('.navbar').contextmenu(function () {
return false;
});
$('.navbar').on('mousewheel', function (e) {
var move = -60;
var nextIndex = nextIndex = (index + 1) % 6;
if (e.originalEvent.wheelDelta / 120 <= 0) {
// wheel up
move = 60;
nextIndex = index - 1 < 0 ? 5 : index - 1;
}
$('.scroll-list').css('transform', 'rotateX(' + (deg + move) + 'deg)');
$('#' + index).css('opacity', '0.01');
$('#' + nextIndex).css('opacity', '1');
index = nextIndex;
deg = deg + move;
event.stopPropagation();
console.timeEnd('cache');
});
});
Wrap your code in ready function, so that your JavaScript executes after DOM is loaded.

jQuery Promises with chained setTimeouts

I'm doing a little dice game to learn.
What I do is i scrumble the dice X amount of times, keep slowing the random down until it gets to the final value, and that's the "winning number".
But i would like to execute the scrumble 1 by 1 on the dices. Imagine I got 2. And later I do a little zoom effect.
I was thinking I could achieve this by using promises but is not working for me, I don't know what I'm missing.
Here's the JS code:
var counter = 0.8;
var diceNumber = 0;
var rollDice = function(diceId){
var dfd = new $.Deferred();
$('#' + diceId).removeClass('idle');
counter *= 1.2;
diceNumber = Math.round(Math.random()*5) + 1;
$('#' + diceId).removeClass();
$('#' + diceId).addClass('dice_' + diceNumber);
if(counter < 800) {
timeout = setTimeout(rollDice, counter, diceId);
}else{
$('.winner').text(diceNumber);
$('#' + diceId).removeClass();
$('#' + diceId).addClass('animate');
$('#' + diceId).addClass('dice_' + diceNumber)
.animate({ zoom: '1.3' }, 200)
.animate({ zoom: '1' }, 100);
dfd.resolve();
return dfd.promise();
}
}
var startToDice = function() {
rollDice('dice_1').then(rollDice('dice_2'));
}
startToDice();
And what it ends up doing is running both dices simultaneously.
Any advice? Thanks.
You're on the right track. I couldn't test cause I don't have all the elements in place, but try this out:
var counter = 0.8;
var diceNumber = 0;
var rollDice = function(diceId){
var dfd = new $.Deferred();
var roll = function() {
$('#' + diceId).removeClass('idle');
counter *= 1.2;
diceNumber = Math.round(Math.random()*5) + 1;
$('#' + diceId).removeClass();
$('#' + diceId).addClass('dice_' + diceNumber);
if(counter < 800) {
timeout = setTimeout(roll, counter);
}else{
$('.winner').text(diceNumber);
$('#' + diceId).removeClass();
$('#' + diceId).addClass('animate');
$('#' + diceId).addClass('dice_' + diceNumber)
.animate({ zoom: '1.3' }, 200)
.animate({ zoom: '1' }, 100);
dfd.resolve();
}
}
roll();
return dfd.promise();
}
var startToDice = function() {
rollDice('dice_1').then(function(){
rollDice('dice_2');
});
}
startToDice();
Let me know if you get any errors when you run it so I can make adjustments as necessary.
Like comented by bergi:
var startToDice = function() {
rollDice('dice_1').then(function() { rollDice('dice_2'); });
}

can't clear inverval called in function from other function

I can't figure out why this variable is becoming private to the function, even if i try to clear the interval from the console it can't find the variable, I must be doing something stupid. help please, code is below: I cut it down to the relevant parts.
function attack() {
$("#container").append("<div id='attacker' style='position:absolute; width: 128px; bottom:125px'> <img src='attacker.gif' ></div>");
$("#attacker").css("left", $( window ).width());
attackerCheck = setInterval( function() { moveNclear("#attacker", "attackerCheck"); }, 33 );
}
function moveNclear(objectName, intervalname) {
objectP = $(objectName).position();
$(objectName).css("left", (objectP.left - 10) + "px");
if(objectP.left < 0) {
console.log("done");
clearInterval(intervalname);
}
}
You can avoid having to pass the interval reference by making a suitable return from moveNclear(), and testing it back in the calling function.
Also, $("#attacker") (many times over) is horribly inefficient ... and avoidable.
Finally, don't forget to localise your variables with var. Don't use globals.
Try :
function attack() {
var $attacker = $("<div id='attacker' style='position:absolute; width:128px; bottom:125px'> <img src='attacker.gif' /></div>").appendTo("#container").css('left', $(window).width());
var attackerCheck = setInterval(function() {
if(moveNclear($attacker)) {
clearInterval(attackerCheck);
console.log("done");
}
}, 33);
}
function moveNclear($el) {
var pos = $el.position();
pos.left -= 10;
$el.css("left", pos.left + 'px');
return (pos.left <= 0);//true:animation complete; false:animation in progress
}
var attackerCheck = null;
function attack()
{
$("#container").append("<div id='attacker' style='position:absolute; width: 128px; bottom:125px'> <img src='attacker.gif' ></div>");
$("#attacker").css("left", $( window ).width());
attackerCheck = setInterval( function() { moveNclear("#attacker"); }, 33 );
}
function moveNclear(objectName)
{
objectP = $(objectName).position();
$(objectName).css("left", (objectP.left - 10) + "px");
if(objectP.left < 0)
{
console.log("done");
clearInterval(attackerCheck);
}
}

DIV animation and color change

I'm trying to simulate TCP packet transmission, and hopefully I've made much progress. But now I want to fix two minor issues, that I need help with:
1- I want to highlight the corresponding cell in the table on the bottom of the page as yellow when the packet is being sent, and later when its ack is received, change the color to green.
2- The speed variable got from the input does not work!!
My code is here: http://jsfiddle.net/j26Qc/108/
$(document).ready(function () {
var count = 0;
var items = 0;
var packetNumber = 0;
var speed = 0;
var ssth= $("#ssth").val();
var window_left=0;
for(var i=1;i<=32;i++){
$('#table').append("<div class='inline' id='"+i+"'>"+i+"</div>");
}
document.getElementById(1).style.width=22;
$("button").click(function () {
if (count < ssth) {
if(items==0)
items=1;
else
items = items * 2;
count++;
} else {
items = items + 1;
}
window_left+=20;
window_width=items*20;
document.getElementById("window").style.left= window_left+"px";
document.getElementById("window").style.width=window_width+"px";
speed = $("#speed").val();
createDivs(items);
animateDivs();
});
function createDivs(divs) {
packetNumber = 1;
var left = 60;
for (var i = 0; i < divs; i++) {
var div = $("<div class='t'></div>");
div.appendTo(".packets");
$("<font class='span'>" + packetNumber + "</font>").appendTo(div);
packetNumber++;
div.css({
left: left
/* opacity: 0*/
}).fadeOut(0);
//div.hide();
//left += 20;
}
}
function animateDivs() {
$(".t").each(function (index) { // added the index parameter
var packet = $(this);
packet
.delay(index * 200)
.fadeIn(200)
.animate({left: '+=230px'}, speed)
.animate({left: '+=230px'}, speed)
.fadeOut(200, function () {
packet
.css({
top: '+=20px',
backgroundColor: "#f09090"
})
.text('a' + packet.text());
})
.delay(1000)
.fadeIn(200)
.animate({left:'-=230px'}, speed)
.animate({left:'-=230px'}, speed)
.fadeOut(200, function () {
packet
.css({
top: '-=20px',
backgroundColor: "#90f090"
});
});
}).promise().done(function(){
$(".packets").empty();});
}
});
1.
When it comes to coloring it is best to add an extra variable holding the count of items. A quick and dirty way, without adding a variable and instead using window_left / 20, would be in animateDivs():
// First fade
.fadeIn(200, function() {
$('#table #' + (index + window_left/20)).css({background:'yellow'});
})
// ...
// Second fade
.fadeIn(200, function() {
$('#table #' + (index + window_left/20)).css({background:'green'});
})
And in $("button").click(function () { right after first if{}else{}:
for (var i = 0 ; i < items + window_left / 20; ++i)
$('#table #' + (i)).css({background:'#fff'});
2.
When it comes to the speed you need to convert the value to int:
speed = parseInt($("#speed").val());
// Or
speed = +$("#speed").val();

how to use setInterval to continue animation while mouse is over div

I am trying to modify a slideshow to continuously animate while the mouse is over the back or next arrow. If the mouse leaves, I would like the animation to stop where it is.
I found this post and this post which are helpful in telling me I need to use setInterval, but because I am a beginner I am not sure how to implement it with the code I have. I tried updating the miliseconds set in the counter variable but that didn't change anything.
Here is the hover code so far. It advances the image on hover but not continuously.
$(document).ready(function(){
var thumbs = $('ul.thumbHolder li');
var bigImgs = $('ul.imgHolder li');
var mask = $('.imgHolder');
var imgW = $('ul.imgHolder li').width();
var speed = 800;
thumbs.removeClass('selected').first().addClass('selected');
thumbs.click(function () {
var target = $(this).index();
mask.animate({
'left': '-' + imgW * target + 'px'
}, speed);
thumbs.removeClass('selected');
$(this).addClass('selected');
});
$('.Bleft').on('mouseover', function () {
var i = $('ul.thumbHolder li.selected').index();
i--;
$('ul.thumbHolder li.selected').removeClass('selected');
thumbs.eq(i).addClass('selected');
if (i === -1) {
mask.animate({
'left': '-' + imgW * $('ul.thumbHolder li').index() + 'px'
}, speed);
} else {
mask.animate({
'left': '-' + imgW * i + 'px'
}, speed);
}
clearInterval(counter);
});
$('.Bright').on('mouseover', function () {
var i = $('ul.thumbHolder li.selected').index();
i = i >= thumbs.length - 1 ? 0 : i + 1;
$('ul.thumbHolder li.selected').removeClass('selected');
thumbs.eq(i).addClass('selected');
mask.animate({
'left': '-' + imgW * i + 'px'
}, speed);
clearInterval(counter);
});
var count = 0;
var counter = window.setInterval(timer, 5000);
function timer() {
count = count + 0;
if (count >= 0) {
count = 0;
return;
}
mask.animate({
'left': '-' + imgW * count + 'px'
}, speed);
thumbs.removeClass('selected');
thumbs.eq(count).addClass('selected');
}
});
This is an example of what I am trying to achieve (I know it is flash but I think it can be done with jQuery too).
This is a fiddle that has all my work so far.
Thank you for any help.
I think I am close to the solution. This is my idea.
Every ul.imgHolder li is divided in many blocks of 20px ( you can change the size of course ), so if a div has a size of 980px you will have 49 blocks for image.
When mouseover event is fired I will slide for a block every speed milliseconds until the mouseout is fired.
I've implemented only the slide right button, I've deleted partially some logic, sorry!
var $ = jQuery.noConflict(true);
$(document).ready(function(){
var thumbs = $('ul.thumbHolder li');
var bigImgs = $('ul.imgHolder li');
var mask = $('.imgHolder');
var imgW = $('ul.imgHolder li').width(); //Assuming imgW % 20 = 0
var blockSize = 20; //20px
var blocksPerThumb = imgW/blockSize;
var numBlocks = (blocksPerThumb)*thumbs.length;
var speed = 400;
var blockPos = 0;
var currentAnim = null;
thumbs.removeClass('selected').first().addClass('selected');
thumbs.click(function () {
var target = $(this).index();
mask.animate({
'left': '-' + imgW * target + 'px'
}, speed,'linear');
thumbs.removeClass('selected');
$(this).addClass('selected');
});
$('.Bleft').on('mouseover', function () {
});
$('.Bright').on('mouseover', function(){
currentAnim = setInterval(goRight,speed);
}).mouseout(function(){
clearInterval(currentAnim);
});
var goRight = function () {
blockPos = (blockPos+1)%numBlocks;
mask.animate({
'left': '-' + blockSize * blockPos + 'px'
}, speed,'linear');
};
});
Good Work!

Categories

Resources