Slot Machine simultaneous jQuery animation not working - javascript

I'm trying to create Slot Machine effect for lottery.
The target numbers will be already set, so that once the stop button is pressed it should stop on that number.
Everything is working fine for slot 1. But if I add the same code for slot 2 and slot 3 then it's creating the problem.
Below given is the code:
$(document).ready(function() {
s1 = 1;
s2 = 1;
s3 = 1;
num1 = 6;
num2 = 5;
num3 = 7; //Target for 3 slots
i = 100; //Top margin for animation
$('#start').click(function() {
animateslot(50, 0);
});
$("#stop").click(function() {
stopanimationslot1(50, 0);
});
});
function animateslot(d = 150, i = 0) {
i = i + 100;
$('#slot1').animate({
marginTop: -i
}, {
duration: d,
complete: function() {
$("#slot1").append("<h3>Column " + s1 + "</h3>");
s1++;
if (s1 > 9) {
s1 = 1;
}
console.log(s1);
animateslot(d, i);
}
});
//If below given code is added it doesn't work**
/*
$('#slot2').animate(
{
marginTop: -i
},
{
duration: d,
complete: function() {
$("#slot2").append("<h3>Column "+s2+"</h3>");
s2++;
if(s2>9){
s2 = 1;
}
console.log("s2="+s2);
animateslot(d, i);
}
}
);
*/
}
function stopanimationslot1(d = 150, i = 0, num = 1) {
$('#slot1').stop();
i = i + 100;
$('#slot1').animate({
marginTop: -i
}, d, function() {
if (Math.abs(i / 100) == num1) {
$('#slot1').clearQueue().stop(false, true);
console.log("finished");
} else {
$("#slot1").append("<h3>Column " + s1 + "</h3>");
s1++;
if (s1 > 9) {
s1 = 1;
}
stopanimationslot1(d + 50, i, num);
}
});
}
#slot1 h3,
#slot2 h3,
#slot3 h3 {
width: 100px;
height: 100px;
border: 1px solid #999;
margin: 0;
}
#slotmachine {
max-height: 100px;
overflow: hidden;
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Start<br><br>
Stop<br><br>
<div class="container">
<div class="row" id="slotmachine">
<div class="col-sm-4" id="slot1">
<h3>Column 1</h3>
</div>
<div class="col-sm-4" id="slot2">
<h3>Column 1</h3>
</div>
<div class="col-sm-4" id="slot3">
<h3>Column 1</h3>
</div>
</div>
</div>
Also can be found here: https://jsfiddle.net/sushanttayade123/fqkgvu59/

The reason why it's not working as expected lies in animateslot(d, i);.
After pressing start:
Slot 1 completes and calls animateslot()
Slot 2 completes and also calls animateslot()
On the next "animation cycle", the method will not run once as it did before, but twice, which results in the stuttery behaviour. The amount of calls will constantly grow at a factor of two for every cycle.
To fix this, either call animateSlot() once after all animations have completed or move every slot into it's own function (animateSlot1(), animateSlot2(), ...).
A word of advice at the end: I wouldn't recommend adding a new node after every spin, as this can cause performance drops.

Related

Javascript how do I use a while loop on this animation?

I've been working with javascript for a few days now but I'm currently stuck on while looping/using switches this animation.
essentially the program will "level up" into a new colored image after moving 3 times, and start from the beginning. I have a gold level up so far, but I want to keep changing colors for the next level ups. I'm trying to add a new classlist to the animated image, a different one for every counter, but nothing seems to be working. this is how I have it:
$("#go").click(function() {
var dest = parseInt($("#block").css("margin-left").replace("px", "")) + 100;
if (dest < 400) {
$("#block").animate({
marginLeft: dest + "px"
}, 700);
} else {
$("#block").animate({
marginLeft: "10px"
}, 100);
//if counter = 1
document.getElementById('block').classList.add("gold")
//if counter = 2
//document.getElementById('block').classList.remove("gold")
//document.getElementById('block').classList.add("pink")
//... etc
//counter += 1
}
});
and here is the link to run the program (click the run text)
http://jsfiddle.net/mept9g1u/
Hope someone can help!
You need to initialise your counter variable to 0 outside of the click event listener, otherwise it's reset to 0 every time you click.
var counter = 0 // ⭐️ Declare counter here
$("#go").click(function() {
var dest = parseInt($("#block").css("margin-left").replace("px", "")) + 100;
if (dest < 400) {
$("#block").animate({ marginLeft: dest + "px" }, 700);
} else {
$("#block").animate({ marginLeft: "10px" }, 100);
counter++;
if (counter === 1) {
document.getElementById('block').classList.add("gold")
}
if (counter === 2) {
document.getElementById('block').classList.remove("gold")
document.getElementById('block').classList.add("pink")
}
// etc.
}
});
$(document).ready(function(){
function BoxAnimate(){
var count= 0;
while( count < 6){
$(".boxanimate").eq(count).stop(true, true).delay(1000*count).animate({
left:"400px"
});
count++;
}
}
BoxAnimate();
});
.boxanimate { background:Green;
margin-bottom:10px;
margin-left:30px;
height:150px;
width:150px;
font-family:Arial;
font-size:30px;
text-align:center;
color:#fff;
line-height:150px;
position:relative;
clear:both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="ani-wrp">
<div class="boxanimate"> data1 </div>
<div class="boxanimate"> data2 </div>
<div class="boxanimate"> data3 </div>
<div class="boxanimate"> data4 </div>
<div class="boxanimate"> data5 </div>
</div>

setInterval() to add class then remove class for same amount of time

I am trying to make a simple 'Simon Game'. I am currently stuck trying to add a class 'on' to a div for one second, then remove that class for the same amount of time.
So I have four divs that I am blinking on and off depending on a sequence of numbers, e.g. [0, 1, 2, 3]. This would blink div[0] on for one second and off for one second then move to div[1], on and off and so on.
Here is my function
/**
* sequence => array [0, 1, 2, 3]
* speed => int 1000 (one second)
*/
playSequence: function(sequence, speed){
var self = this;
// removes class 'on'
view.turnOffPads();
setTimeout(function(){
// adds the 'on' class to a specific div
view.lightUpPad(model.startupSequence[model.count]);
}, speed / 2);
setTimeout(function(){
model.count++; // keeps track of the iterations
if (model.count < sequence.length) { // if we are still iterating
self.playSequence(sequence, speed); // light up the next div
} else {
model.count = 0; // set back to zero
}
}, speed);
},
The problem with this is that I am using two setTimeout functions with one another and although it works I am wondering if there is a better way. If you look I am using a count variable in my model object to keep track of iterations.
Here is my full javascript app so far...
$(function(){
var model = {
on: false,
strictMode: false,
startupSequence: [0, 1, 2, 3, 3, 3, 2, 1, 0, 3, 2, 1, 0, 2, 1, 3],
score: 0,
sequence: [],
count: 0,
}
var controller = {
init: function(){
view.cacheDOM();
view.bindEvents();
},
getSequence: function(){
// get a random number from one to 4
var random = Math.floor(Math.random() * 4);
// push it to the sequence array
model.sequence.push(random);
console.log(model.sequence);
// play it
this.playSequence(model.sequence);
},
/**
* sequence => array [0, 1, 2, 3]
* speed => int 1000 (one second)
*/
playSequence: function(sequence, speed){
console.log(sequence.length);
var self = this;
view.turnOffPads();
setTimeout(function(){
view.lightUpPad(model.startupSequence[model.count]);
}, speed / 2);
setTimeout(function(){
model.count++;
if (model.count < sequence.length) {
self.playSequence(sequence, speed);
} else {
model.count = 0;
}
}, speed);
// view.turnOffPads();
},
}
var view = {
cacheDOM: function(){
this.$round = $('#round');
this.$start = $('#start');
this.$strict = $('#strict');
this.$pad = $('.pad');
this.$padArray = document.getElementsByClassName('pad');
},
bindEvents: function(){
this.$start .change(this.start.bind(this));
this.$strict.change(this.setStrictMode.bind(this));
},
start: function(){
// turn on pads
if (model.on) {
this.$pad.removeClass('on');
this.$round.text('--');
model.on = false;
// reset everything
} else {
this.$round.text(model.score);
model.on = true;
controller.playSequence(model.startupSequence, 100)
// controller.getSequence();
}
},
lightUpPad: function(i){
$(this.$padArray[i]).addClass('on');
},
turnOffPads: function(){
this.$pad.removeClass('on');
},
setStrictMode: function(){
if (model.strictMode) {
model.strictMode = false;
} else {
model.strictMode = true;
}
}
}
controller.init();
});
Is there a cleaner way to add a class, and then remove a class?
Use setInterval instead of setTimeout I have created four divison and blink each division for 1 sec.
var i = 0,
j = 4;
function blink(i) {
new Promise(function(resolve, reject) {
x = setTimeout(function() {
document.querySelectorAll(".post-text")[i].classList.add("myClass");
resolve("added");
}, 1000)
}).then(function(a) {
new Promise(function(res, rej) {
setTimeout(function() {
clearInterval(x);
document.querySelectorAll(".post-text")[i].classList.remove("myClass");
res("deleted");
}, 1000)
}).then(function(a) {
i++;
if (i < j) {
blink(i);
} else {
i = 0;
blink(i);
}
});
});
}
blink(i);
.myClass {
background-color:yellow;
}
<div class="post-text">A</div>
<div class="post-text">B</div>
<div class="post-text">C</div>
<div class="post-text">D</div>
I think you could turn a list of buttons into a sequence of commands. Then you could use a single setInterval to play commands until it runs out of commands. The setInterval could use 1 second intervals if you want on and off to take just as long, but you could also set it to a little faster to easily allow for different durations.
The example below isn't really based on your code, but just to illustrate the idea. It starts (at the button of the code) with an array of buttons pressed. Those are passed to getSequence. This will return an array of commands, in this case simply the color of the button to switch on, so a sequence could be red,red,red,red,'','','','' to have red light up for 4 'intervals', and then switch it off for 4 'intervals'. This way you could create complicates sequences, and with minor adjustments you could even light up multiple buttons simultaneously.
The interval in the example is set to 1/10 of a second. Each color plays for 10 steps (= 1 second), and each pause plays for 5 steps (= .5 second). In the console you see the basis array of buttons/colors to play, followed by the more elaborate sequence that is played.
// The play function plays a sequence of commands
function play(sequence) {
var index = 0;
var lastid = '';
var timer = setInterval(function(){
// End the timer when at the end of the array
if (++index >= sequence.length) {
clearInterval(timer);
return;
}
var newid = sequence[index];
if (lastid != newid) {
// Something has changed. Check and act.
if (lastid != '') {
// The last id was set, so lets switch that off first.
document.getElementById(lastid).classList.remove('on');
console.log('--- ' + lastid + ' off');
}
if (newid != '') {
// New id is set, switch it on
document.getElementById(newid).classList.add('on');
console.log('+++ ' + newid + ' on');
}
lastid = newid;
}
}, 100);
}
// generateSequence takes a list of buttons and converts them to a
// sequence of color/off commands.
function generateSequence(buttons) {
var result = [];
for (var b = 0; b < buttons.length; b++) {
// 'On' for 10 counts
for (var i = 0; i < 10; i++) {
result.push(buttons[b]);
}
if (b+1 < buttons.length) {
// 'Off' for 5 counts
for (var i = 0; i < 5; i++) {
result.push('');
}
}
}
// One 'off' at the end
result.push('');
return result;
}
var buttons = ['red', 'green', 'red', 'yellow', 'yellow', 'blue'];
console.log(buttons);
var sequence = generateSequence(buttons);
console.log(sequence);
play(sequence);
div.button {
width: 100px;
height: 100px;
opacity: .5;
display: inline-block;
}
div.button.on {
opacity: 1;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
#yellow {
background-color: yellow;
}
#blue {
background-color: blue;
}
<div id="red" class="button"></div>
<div id="green" class="button"></div>
<div id="yellow" class="button"></div>
<div id="blue" class="button"></div>
TLDR ;)
All you need to do is to use setInterval() or setTimeout() and within the callback function use element.classList.toggle() to add or remove a class from the element.
If/when you want the blinking to stop, just use clearTimeout() or clearInterval().
Here's an example:
var d = document.getElementById("test");
var b = document.querySelector("button");
b.addEventListener("click", function(){
// Cancel the timer
clearTimeout(timer);
});
// Assign the timer's ID to a variable so that
// you can stop it later
var timer = setInterval(function(){
// Toggle the use of the lightUp class
test.classList.toggle("lightUp");
},1000);
#test {
width:100px;
height:100px;
background-color:blue; /* <-- blue will be the default color */
}
#test.lightUp {
background-color:yellow;
}
<div id="test"></div>
<button>Stop Blinking</button>

Jquery number counter for updates

I have this jquery functions. I want to make it just one function so I can get thesame results by just calling a function and passing some arguements.
As you can see, the function does basically the same thing counting numbers. I would love to just have one function , then parse out arguments to get the same results. something like startcount(arg1, arg2);
var one_countsArray = [2,4,6,7,4252];
var two_countsArray = [3,3,4,7,1229];
var sumemp = one_countsArray.reduce(add, 0);
var sumallis = two_countsArray.reduce(add, 0);
function add(a, b) {
return a + b;
}
var count = 0;
var inTv = setInterval(function(){startCount()},100);
var inTv2 = setInterval(function(){startCount2()},100);
function startCount()
{
if(count == sumemp) {
clearInterval(inTv);
} else {
count++;
}
$('.stats_em').text(count);
}
var count2 = 10;
function startCount2()
{
if(count2 == sumallis) {
clearInterval(inTv2);
} else {
count2++;
}
$('.stats_iss').text(count2);
}
div {
padding:50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height:100px;
border-radius:50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>
How about a very simple jquery plugin
$.fn.countTo = function(arrNums){
var self = this;
function add(a,b){
return a+b;
}
var current = 0;
var max = arrNums.reduce(add,0);
var int = setInterval(function(){
if(current == max)
clearInterval(int);
else
current++;
self.text(current);
},100);
return this;
}
$('.stats_em').countTo([2,4,6,7,4252]);
$('.stats_iss').countTo([3,3,4,7,1229]);
div {
padding:50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height:100px;
border-radius:50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>
When you notice you're rewriting chunks of similar code, moving to one generic function is the right approach! The best way to start is by trying to determine what you're parameters would be:
count and count2 show that you need a start count for your timer to start at
sumemp and sumpallis show that you need to be able to specify a maximum count
inTv and inTv show that you need to be able to set the interval
$('.stats_iss') and $('.stats_em') show that you need to be able to determine the output element
This means your final class, function or jquery extension will at least have a signature that resembles this:
function(startCount, maximumCount, interval, outputElement) { }
Once you've written this, you can paste in the code you already have. (I've replaced your setInterval with a setTimeout, other than that, not much changed)
var createCounter = function(start, max, interval, outputElement) {
var count = start;
var timeout;
var start = function() {
count += 1;
outputElement.text(count);
if (count < max) {
timeout = setTimeout(start, interval);
}
}
var stop = clearTimeout(timeout);
return {
start: start,
stop: stop
}
}
var one_countsArray = [2, 4, 6, 7, 300];
var two_countsArray = [3, 3, 4, 7, 100];
var sumemp = one_countsArray.reduce(add, 0);
var sumallis = two_countsArray.reduce(add, 0);
function add(a, b) {
return a + b;
}
var counters = [
createCounter(0, sumemp, 100, $('.stats_em')),
createCounter(10, sumallis, 100, $('.stats_iss'))
];
counters.forEach(function(counter) {
counter.start();
});
div {
padding: 50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height: 100px;
border-radius: 50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>

Perform click on one div after the other

I hope you understand my problem.
At the moment I have a JS-function that choses randomly a div of a specific Html-Class.
Now i would like to rewrite the function that it picks one div after the other, just like they are ordered in the HTML-content.
How can I do this?
For information: the random selection is made with jquery and looks like this:
function pickrandom() {
var elems = $(".classname");
if (elems.length) {
var keep = Math.floor(Math.random() * elems.length);
console.log(keep);
$(elems[keep]).click();
}
}
Thanks
$(document).on('click', '.classname', function(){
var self = $(this);
var total_items = $('.classname').length; // 10
var index = self.index(); //2 for 3rd element
if (index < total_items) {
setTimeout(function () {
$('.classname').eq(index+1).trigger('click');
}, 3000);
}
});
this will call the next clicks in 3 sec interval
i don't know why you are using a randomizer function.you can allow the user to make that click
Hopefully this helps you - can't see your markup, but it should get you on the right track. I've also changed your .click() to a .trigger('click') which should be quite a bit more dependable.
JavaScript
function pickrandom() {
var elems = $(".classname");
if (elems.length) {
var curTarget = Math.floor(Math.random() * elems.length);
console.log(curTarget);
$(elems[curTarget]).trigger('click');
// Find index of our next target - if we've reached
// the end, go back to beginning
var nextTarget = curTarget + 1;
if( nextTarget > elems.length ) {
nextTarget = 0;
}
// Wait 3 seconds and click the next div
setTimeout( function() { $(elems[nextTarget]).trigger('click'); }, 3000 );
}
}
$("div").click(function() {
var el = $(this);
setTimeout(function() {
console.log(el.text());
el.toggleClass("click");
}, 2000);
});
var random = Math.floor((Math.random() * $("div").length) + 1);
var index = random - 1;
console.log("Random number: ", random);
var clicker = setInterval(function() {
if (index === $("div").length) {
clearInterval(clicker);
console.log("cleared interval");
} else {
$("div").eq(index).click();
index++;
}
}, 2000)
div {
height: 50px;
width: 100%;
border: 2px solid black;
background-color: lightgreen;
margin-bottom: 10px;
text-align: center;
font-size: 30px;
}
.click {
background-color: lightblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
Div 1
</div>
<div>
Div 2
</div>
<div>
Div 3
</div>
<div>
Div 4
</div>
<div>
Div 5
</div>
<div>
Div 6
</div>

jQuery when data reach 0 alert

I have this code:
jQuery/JavaScript
$(document).ready(function () {
function min() {
var number = parseInt($('span').html());
return number - 30;
}
function add() {
var number = parseInt($('span').html());
return number + 31;
}
$("#container").click(function () {
$('span').text(min());
});
$("#box").click(function () {
$('span').text(add());
});
var time = parseInt($('b').html());
if (time <= 0) {
alert("AAAAA");
};
});
CSS
#container{
background: #00ff00;
width: 500px;
height:500px;
}
#box{
background: black;
width: 100px;
height:100px;
color: white;
cursor: pointer;
}
HTML
<div id="container">
<span> 60 </span>
<div id="box"> </div>
</div>
when you click on you text in change for +31 and -30 so you will got 61 because default is 60 and but if you click on text in span will change for -30 only and it will display 30 i wish to alert when text in span reach 0 i made this but didn't work.
does any one know how to fix it?
I think that I'm not understanding completely to you. Maybe this the next link can help you.
You have some errors, check the solution.
$(document).ready(function(){
var $span = $('span');
function min() {
var number = parseInt($span.html());
return number - 30;
}
function add() {
var number = parseInt($span.html());
return number + 31;
}
$("#container").click(function(){
$('span').text(min());
checkTime();
});
$("#box").click(function(){
$('span').text(add());
checkTime();
});
function checkTime() {
debugger
var time = parseInt($span.html());
if (time <= 0) {
alert("AAAAA");
};
}
});
Please next time publish your problem in JSfiddle or similar.
I think you're selector to get the span is incorrect. You also need to execute the check after you decrement the value.
$(document).ready(function(){
function min() {
var number = parseInt($('span').html());
return number - 30;
}
function add() {
var number = parseInt($('span').html());
return number + 31;
}
$("#container").click(function(){
$('span').text(min());
CheckValue();
});
$("#box").click(function(){
$('span').text(add());
});
function CheckValue() {
var val = parseInt($('#container > span').html());
if (val <= 0) {
alert("AAAAA");
}
}
);

Categories