jQuery Promises with chained setTimeouts - javascript

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

Related

Issue linking images to dynamically created jquery elements

So, I'm very new, so apologies if this is a silly question. I have worked out a Trivia Quiz for my learning to code classes I'm taking. I want to display an image on the confirmation screen that shows whether the user was right or wrong. I think the code is correct-ish? I'm not sure what isn't working.
I left out the main Question and answer object for space. Sorry if I didn't format this ideally? I'm still kinda figuring out how things work here.
Here is my code for reference:
//array to help me iterate and insert images
var imgArray = ["question1", "question2", "question3", "question4", "question5", "question6", "question7", "question8", "question9", "question10", "question11", "question12", "question13"];
var currentQuestion = 0;
var win = 0;
var lose = 0;
var unanswered = 0;
var time = 30;
//set up divs to contain our info
var rightDiv = $("<div class='rightAns'></div>");
var timerDiv = $("<div class='countdown'><h3></h3></div>");
var questionDiv = $("<div class='question'><h1></h1></div><br>");
var answerDiv = $("<div class='answers'></div>");
//object keys to return questions in order
var keys = Object.keys(questions);
var key = keys[n];
var n = 0;
//function to setup and restart game
function reset() {
$("#start-button").hide("slow");
$("#start-here").hide("slow");
win = 0;
lose = 0;
unanswered = 0;
n = 0;
key = keys[n];
currentQuestion = 0;
$("#question-block").empty();
var reset = function () {
time = 30;
$(".rightAns").empty();
$(".rightAns").remove();
// $("#image").empty();
$("#time-remaining").append(timerDiv);
$(".countdown h3").html("Time Remaining: " + time);
$("#question-block").append(questionDiv);
$("#question-block").append(answerDiv);
}
reset();
//function to show questions
function showQuestion() {
$(".question h1").html(questions[key].question);
for (var i = 0; i < questions[key].answers.length; i++) {
$(".answers").append("<button class='answer btn btn-danger btn-lg m-1'>" + questions[key].answers[i] + "</button>");
}
$(".answers button").on("click", function () {
var selected = $(this).text();
//if then to check question correctness
if (selected === questions[key].correct) {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$(answerDiv).remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").text("That's Correct!!");
$("#image").html('<img src = ".assets/images/' + imgArray[currentQuestion] + '" width = "400px">');
win++;
currentQuestion++;
} else {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$(answerDiv).remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").text("Nope! The correct answer was: " + questions[key].correct);
$("#image").html('<img src = ".assets/images/' + imgArray[currentQuestion] + '" width = "400px">');
lose++;
currentQuestion++;
}
n++;
key = keys[n];
//checking to see if there are more questions left
if (checkForLast()) {
finalScore();
} else {
setTimeout(countReset, 3 * 1000);
setTimeout(reset, 3 * 1000);
setTimeout(showQuestion, 3 * 1000);
}
});
}
showQuestion();
var counter = setInterval(count, 1000);
//show time remaining for each question
function count() {
time--;
$(".countdown h3").html("Time Remaining: " + time);
if (time < 1) {
clearInterval(counter);
$(timerDiv).remove();
$(questionDiv).remove();
$(".answers button").remove();
$("#correct-answer").append(rightDiv);
$(".rightAns").html("You took too long! The correct answer was: " + questions[key].correct);
unanswered++;
n++;
key = keys[n];
if (checkForLast()) {
finalScore();
} else {
setTimeout(countReset, 3 * 1000);
setTimeout(reset, 3 * 1000);
setTimeout(showQuestion, 3 * 1000);
}
}
}
function checkForLast() {
if (key === undefined) {
return true;
}
return false;
}
//timer for the message after you choose your answer
function countReset() {
counter = setInterval(count, 1000);
}
//showthe final score screen
function finalScore() {
$(".rightAns").remove();
$("#image").empty();
$("#question-block").prepend("<h2>Unanswered: " + unanswered + "</h2>");
$("#question-block").prepend("<h2>Incorrect: " + lose + "</h2>");
$("#question-block").prepend("<h2>Correct: " + win + "</h2>");
$("#start-button").show();
$("#start-here").show();
}
};
//function to start game on button click
$(document).on("click", "#start-button", reset);
});
After tinkering for a bit, I dropped the "." at the beginning of the call and added the .jpg to the section after imgArray[currentQuestion]. That solved it. Thanks for the suggestions.

javascript: how to exit a loop by clicking a button

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.

Creating a game in JQuery

I am trying to create a simple game on a webpage.
The game should be like this:
The web page should display at random times images placed in random positions on the browser window.
Each image lasts on the browser window for a short period of time and then it disappears.
If the user clicks an image before it disappears, he/she gets a point.
The game ends when the user wins 10 points.
So far I managed to display all elements on a page at random positions, then delete them, and display them again.
Right now I am having problems with the count of each click.
JavaScript
$(document).ready(function () {
timeOut();
});
function timeOut() {
setInterval(function () {
deleteImages();
createImages();
}, 3000);
}
function createImages() {
var myarray = ["img/Angel.gif", "img/Angry.gif", "img/BigSmile.gif",
"img/Confused.gif", "img/Cool.gif", "img/Crying.gif",
"img/Eyebrow.gif", "img/Goofy.gif", "img/Happy.gif"];
var count = 0;
var div;
for (var i = 0; i < 9; i++) {
var randPos = 0 + Math.floor(Math.random() * 500);
this.img = document.createElement("img");
div = document.createElement("div");
$("div").attr("id", "div" + i);
var randNew = 0 + Math.floor(Math.random() * (5));
var rand = 0 + Math.floor(Math.random() * (9 - count));
this.img.src = myarray[rand];
$('#div' + i).css("left", randPosition());
$('#div' + i).css("right", randPosition());
$('#div' + i).css("top", randPosition());
$('#div' + i).css("bottom", randPosition());
$('#div' + i).css("position", "relative");
$('#div' + i).show();
div.appendChild(this.img);
$("body").prepend(div);
myarray.splice(rand, 1);
count++;
}
//setTimeout(function(){ jQuery("div").hide(); }, 3000);
}
function deleteImages() {
$("div").remove();
}
function randPosition() {
return 0 + Math.floor(Math.random() * 500);
}
$(function () {
$("div").click(function (e) {
var offset = $(this).offset();
var relativeX = (e.pageX - offset.left);
var relativeY = (e.pageY - offset.top);
alert("X: " + relativeX + " Y: " + relativeY);
});
});
css
.active-div{
position:relative;
}
.menu-div{
position:absolute;
top:0;
right:0;
display:none;
}
Use a counter and increment when you click an image:
var count = 0;
count++;
Also you need to reapply the click event because you are recreating new elements instead of moving the already created ones:
Call this:
$("div").click(function(e) {
var offset = $(this).offset();
var relativeX = (e.pageX - offset.left);
var relativeY = (e.pageY - offset.top);
});
after createImages function like so:
var count = 0;
var holder;
$(document).ready(function(){
timeOut();
});
function addOnClicks() {
$("div").on('click',function(e) {
var offset = $(this).offset();
var relativeX = (e.pageX - offset.left);
var relativeY = (e.pageY - offset.top);
count++;
if(count >= 10)
{
deleteImages();
clearInterval(holder);
alert("Game Over");
}
});
}
function timeOut(){
holder = setInterval(function(){deleteImages();createImages();addOnClicks(); }, 3000);
}
function createImages(){
var myarray=["img/Angel.gif","img/Angry.gif","img/BigSmile.gif",
"img/Confused.gif","img/Cool.gif","img/Crying.gif",
"img/Eyebrow.gif","img/Goofy.gif","img/Happy.gif"
];
var count=0;
var div;
for (var i = 0; i < 9; i++) {
var randPos = 0 + Math.floor(Math.random() * 500);
this.img = document.createElement("img");
div = document.createElement("div");
$("div").attr("id","div"+i);
var randNew = 0 + Math.floor(Math.random() * (5));
var rand = 0 + Math.floor(Math.random() * (9-count));
this.img.src = myarray[rand];
$('#div'+i).css("left", randPosition());
$('#div'+i).css("right",randPosition());
$('#div'+i).css("top",randPosition());
$('#div'+i).css("bottom",randPosition());
$('#div'+i).css("position","relative");
$('#div'+i).show();
div.appendChild(this.img);
$("body").prepend(div);
myarray.splice(rand,1);
count++;
}
//setTimeout(function(){ jQuery("div").hide(); }, 3000);
}
function deleteImages(){
$("div").remove();
}
function randPosition(){
return 0 + Math.floor(Math.random() * 500);
}
.active-div{
position:relative;
}
.menu-div{
position:absolute;
top:0;
right:0;
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Use an incremented variable like so:
$(function() {
var click_count = 0;
$("div").click(function(e) {
click_count++;
});
});

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!

Slideshow - make a jQuery Plugin from working code fails

I've created a little slideshow with images out of a folder with jQuery and with help from stackoverflow and other snippets.
Images are named 1.jpg, 2.jpg ... 1-b.jpg, 2-b.jpg...The special thing is, that every image-change 3 images are loaded. The first time the images in the HTML (3 images too) are replaced.
2 of the 3 new images are blurred, to have a fade from current to - blurred current - into blurred next - next. Works fine and looks really great.
Now I want to make a real jQuery plugin out of that, because I want to change the startup (image Nr.) and imageLast (here go back to startup) on every site. Well I don't know if there are problems with the logic of the original code to make a plugin. My trials failed. Please have a look.
Original working code:
// slideshow ----------------------------------------------------------------------------
(function() {
var pauseTime = 7000;
function slideShow(index) {
var imagePath = "slider-team";
var startup = 1;
var startindex = index+startup-1;
var index1 = startindex+1;
var lastImage = 6;
var fadeTime = 700;
var fadeTime2 = 500;
var fadeTime3 = 1000;
var theImage1 = new Image();
var theImage2 = new Image();
var theImage3 = new Image();
var url = imagePath + "/" + startindex + ".jpg";
var urlb = imagePath + "/" + startindex + "-b.jpg";
var url2b = imagePath + "/" + index1 + "-b.jpg";
$(theImage1, theImage2, theImage3).load(function () {
$(theImage1).prependTo("#slider");
$(theImage2).prependTo("#slider");
$(theImage3).prependTo("#slider");
$("#slider img:last").fadeOut(fadeTime, function() {
$(this).remove();
$("#slider img:last").fadeOut(fadeTime2, function() {
$(this).remove();
$("#slider img:last").fadeOut(fadeTime3, function() {
$(this).remove();
setTimeout(function() {
slideShow((index % (lastImage-startup)) + 1)
}, pauseTime);
});
});
});
});
theImage1.src = url;
theImage2.src = urlb;
if(startup+index === lastImage) {
theImage3.src = "slider/" + startup + "-b.jpg";
} else {
theImage3.src = url2b;
};
}
$(document).ready(function() {
// Img 1 is already showing, so we call 2
setTimeout(function() { slideShow(2); }, pauseTime);
});
})();
Trial to make a plugin:
// slideshow ----------------------------------------------------------------------------
(function($) {
$.blurSlider = function(index, settings){
var config = {
'startup':1;
'lastImage':17;
};
if(settings){$.extend(config, settings);}
var pauseTime = 7000;
//function slideShow(index) {
var imagePath = "slider-opt";
//var startup = 1;
var startindex = index+startup-1;
var index1 = startindex+1;
//var lastImage = 17;
var fadeTime = 700;
var fadeTime2 = 500;
var fadeTime3 = 1000;
var theImage1 = new Image();
var theImage2 = new Image();
var theImage3 = new Image();
var url = imagePath + "/" + startindex + ".jpg";
var urlb = imagePath + "/" + startindex + "-b.jpg";
var url2b = imagePath + "/" + index1 + "-b.jpg";
$(theImage1, theImage2, theImage3).load(function () {
$(theImage1).prependTo("#slider");
$(theImage2).prependTo("#slider");
$(theImage3).prependTo("#slider");
$("#slider img:last").fadeOut(fadeTime, function() {
$(this).remove();
$("#slider img:last").fadeOut(fadeTime2, function() {
$(this).remove();
$("#slider img:last").fadeOut(fadeTime3, function() {
$(this).remove();
setTimeout(function() {
slideShow((index % (config.lastImage-config.startup)) + 1)
}, pauseTime);
});
});
});
});
theImage1.src = url;
theImage2.src = urlb;
if(config.startup+index === config.lastImage) {
theImage3.src = "slider/" + config.startup + "-b.jpg";
} else {
theImage3.src = url2b;
};
// }
};
return this;
$(document).ready(function() {
// Img 1 is already showing, so we call 2
setTimeout(function() { $.blurSlider(2); }, pauseTime);
});
})(jQuery);
I don't know if in plugins you need to set up the selector. Here I don't, because the selector didn't change. The call of document.ready inside the plugin is the other thing that might cause problems.

Categories

Resources