Trying to make progress bar move incrementally - javascript

How can I make my progress bar show in increments based on my question number. Currently it completes to 100% after clicking the next question button. But, I am trying to let it increase in the increments of the question numbers and go backwards if the previous question button is clicked. The codepen with all the code is here. Thank you.
var i = 0;
function moveForward() {
if (i == 0) {
i = 1;
var elem = document.getElementById("myBar");
var width = 10;
var id = setInterval(frame, 10);
function frame() {
if (width >= 100) {
clearInterval(id);
i = 0;
} else {
width++;
elem.style.width = width + "%";
elem.innerHTML = width + "%";
}
}
}
}
function moveBackward() {
if (i == 0) {
i = 1;
var elem = document.getElementById("myBar");
var width = 10;
var id = setInterval(frame, 10);
function frame() {
if (width >= 100) {
clearInterval(id);
i = 0;
} else {
width++;
elem.style.width = width + "%";
elem.innerHTML = width + "%";
}
}
}
}
///// UPDATED FUNCTION
function moveForward(i) {
console.log('i: ' + i);
var elem = document.getElementById("myBar");
switch(i) {
case 0:
elem.style.width = "33%";
elem.innerHTML = "33%";
break;
case 1:
elem.style.width = "66%";
elem.innerHTML = "66%";
break;
case 2:
elem.style.width = "100%";
elem.innerHTMl = "100%";
}
}

The reason it is completing after one click is that setInterval runs the function repetitively every x milliseconds. That means that your frame function runs every 10 milliseconds until it hits the if statement that clears the interval. Since your stop check only stops at width >= 100 it continues to expand until it is set to 100%.
In order to properly track the existing and next widths you will need to have a persistent variable in a global scope and you'll need to pass a target width to frame so that it knows when to actually stop
There are two other issues with your code. The first is that the previous button also increases the width rather than decreasing it, and the other issue is that every time you click the next or previous buttons it first resets the width to 10 and then increases it to 100.

Related

How I use array to get only one function instead of 3 identicals [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 3 years ago.
i'm sorry to ask your help.
I'm trying to get 3 functions in one, using array in Javascript.
Actually, I've this code to run loading bars for each language I'm trying to learn
function js() {
var elem3 = document.getElementById("barone");
var width = 0;
var id = setInterval(frame, 50);
function frame() {
if (width >= 20) {
clearInterval(id);
} else {
width++;
elem3.style.width = width + '%';
elem3.innerHTML = width * 1 + '%';
}
}
}
function php() {
var elem4 = document.getElementById("bartwo");
var width = 0;
var id = setInterval(frame, 50);
function frame() {
if (width >= 30) {
clearInterval(id);
} else {
width++;
elem4.style.width = width + '%';
elem4.innerHTML = width * 1 + '%';
}
}
}
function sql() {
var elem5 = document.getElementById("barthree");
var width = 0;
var id = setInterval(frame, 50);
function frame() {
if (width >= 30) {
clearInterval(id);
} else {
width++;
elem5.style.width = width + '%';
elem5.innerHTML = width * 1 + '%';
}
}
}
That's fine and it works well, but i'm trying to make an array for the div and the percent of loading bars
I've tried several times to shorten this code, and i'm actually stuck. This is the most (i think), closer to the answer:
var skillBar = ["barone","bartwo","barthree"];
var percentBar = [20, 30, 30];
function skill() {
for (var j = 0; j < skillBar.length; j++) {
var elem = document.getElementById(skillBar[j]);
console.log(skillBar[j]);
console.log(percentBar[j]);
var width = 0;
var id = setInterval(frame, 50);
function frame() {
console.log(percentBar[j]) <--- This return undefined
if (width >= percentBar[j]) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
elem.innerHTML = width * 1 + '%';
}
}
}
}
but this doesn't work. The first two console.log works fine. It returns me the values in both arrays, but the third one returns me undefined, so the loading bar never ends. Worst, it only affect the last bar. First and 2nd doesn't load.
I know it's probably obvious for most of you, but I need a little help to make things work.
P.S : Sorry for my english, it's not my native language.
I think you need to take out fram function to outside of the function skill
var skillBar = ["barone","bartwo","barthree"];
var percentBar = [20, 30, 30];
var id;
function frame(j) {
console.log(percentBar[j])
if (width >= percentBar[j]) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
elem.innerHTML = width * 1 + '%';
}
}
function skill() {
for (var j = 0; j < skillBar.length; j++) {
var elem = document.getElementById(skillBar[j]);
console.log(skillBar[j]);
console.log(percentBar[j]);
var width = 0;
id = setInterval(frame(j), 50);
}
}
skill()
<div id="barone"></div>
<div id="bartwo"></div>
<div id="barthree"></div>

how to hide an element at the end of javascript animation

I know similar questions have been asked before, but the answers did not help me because they are too advanced for me and my simple animation. I am at the very beginning of javascript. On my website, I have the simple code for moving an element from one posotion to another. I would like to have it disappear when it reaches the final position, not fading out, just suddenly disappear. Should I do it with opacity change? How do I write it? My code is the following.
function myMove() {
var elem = document.getElementById("animation");
var pos = 100 ;
var id = setInterval(frame, 5);
function frame() {
if (pos == 380) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
To hide an element simply set style.display to 'none'.
For example:
function myMove() {
var elem = document.getElementById("animation");
var pos = 100 ;
var id = setInterval(frame, 5);
function frame() {
if (pos == 380) {
clearInterval(id);
// this is the key line
elem.style.display = 'none';
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
Just as a heads up, using chained setTimeouts can be better than using setInterval in HTML animation. The reason being that if the animation (and/or other scripts on the page) takes longer than the interval the browser will become unresponsive. With a chain of setTimeouts, the clock doesn't start ticking until the end of the current frame.
For example, you could do:
function myMove() {
var elem = document.getElementById("animation");
var pos = 100 ;
function frame() {
if (pos == 380) {
// this is the key line
elem.style.display = 'none';
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
// set a timeout for 5 ms
setTimeout(myMove, 5);
}
}

Javascript conflicting with eachover

I have two pieces of java script, one for showing the result percentage in a progress bar, one to show the speed in a different bar.
at the moment only one bar is reviving data the other is not.
**Javascript*
// Progress bar javascript reults
{
var elem = document.getElementById("myBar");
var width = 0;
var id = setInterval(frame, 50);
function frame() {
if (width >= document.getElementById("results-percentile-2").innerHTML) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
document.getElementById("demo").innerHTML = width * 1 + '%';
}
}
}
// End javascript progress bar results
// Progress bar javascript speed
{
var elem = document.getElementById("myBarspeed");
var width = 0;
var id = setInterval(frame, 50);
function frame() {
if (width >= document.getElementById("results-speed").innerHTML) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
document.getElementById("speed").innerHTML = width * 1 + '%';
}
}
}
// End javascript progress bar speed
HTML
<div class="scale-container-main ">
<div id="percentile-scale" class="scale">
results bar: Your results
<div id="demo">0%</div>
<div class="myProgress">
<div id="myBar" style="width:0"></div>
</div>
speed bar: Your speed
<div id="speed">0%</div>
<div class="myProgress">
<div id="myBarspeed" style="width:0"></div>
</div>
</div>
</div>
You could use let instead of var inside each block, and
let frame = function() { .... }
but frame would have to be moved above setInterval line
Also, the above only works on recent decent broswers, which means it wont work in IE
An alternative, equally valid method is to use IIFE's - this works in IE!
(function() {
var elem = document.getElementById("myBar");
var width = 0;
var id = setInterval(frame, 50);
function frame() {
if (width >= document.getElementById("results-percentile-2").innerHTML) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
document.getElementById("demo").innerHTML = width * 1 + '%';
}
}
}());
// End javascript progress bar results
// Progress bar javascrip speed
(function() {
var elem = document.getElementById("myBarspeed");
var width = 0;
var id = setInterval(frame, 50);
function frame() {
if (width >= document.getElementById("results-speed").innerHTML) {
clearInterval(id);
} else {
width++;
elem.style.width = width + '%';
document.getElementById("speed").innerHTML = width * 1 + '%';
}
}
}());
The only advantage to the above is that variable names can be useful and meaningful and guaranteed not to clash with anything else (sort of)
You can't have two functions with the same name. Rename one 'frame' function to something else and change it in your setInterval. Also use different variables to store the interval in.

Moving div elements stored in array

var move = function() {
Xpos = Math.round(Math.random() * 95);
food[num].css('left', Xpos + '%');
interval = setInterval(function() {
console.log(i);
var posTop = food[num].offset().top / $(window).height() * 100;
while(posTop < 80) {
if(posTop === 80) {
num++;
break;
}
posTop += 1;
food[num].css('top', posTop + '%');
break;
}
}, speed);
}
//Color the circle
circleColor();
move();
}
OK so this is my code. It creates a circle(a <div> element) on top of the screen and gives it a random x coordinate. Than it puts it in food[] array. The entire code starts by clicking the button, but every time I press the button again the circle that was last moving stops, function creates a new one and the new one moves. Is there a way I can make all elements in the array move without depending on each other?
http://jsfiddle.net/yqwjqx31/
I understand why this happens but I have no idea how to fix it.
First you're using a global variable num in setInterval function handler, so its value get modified while using it in new cercle create, secondly you're clearing interval of the last cercle you created before creating a new cercle. It means you're sharing the same interval between all cercles. Use instead an array of intervals just like var food =[] and use a temporary variable to prevent the index value modification inside your setInterval handler. Here's a working fiddle
//Interval
var interval =[];
var tempNum = num;
interval[num] = setInterval(function() {
var posTop = food[tempNum].offset().top / $(window).height() * 100;
while(posTop < 80) {
if(posTop === 80) {
break;
}
posTop += 1;
food[tempNum].css('top', posTop + '%');
break;
}
}, speed);
Increment your num variable
//Color the circle
circleColor();
move();
num++;
Your move function is only responsible for moving the last generated div via createCircle. If you want to move them all till collision, you need to loop through them all and move them accordingly. Or, you can animate them via CSS.
Here is the working version :
http://jsfiddle.net/yqwjqx31/3/
Notice how the setInterval callback loops through all the div and pushes them down until their height is 80.
var move = function () {
interval = setInterval(function () {
for (var i = 0; i < food.length; ++i) {
var posTop = food[i].offset().top / $(window).height() * 100;
if (posTop < 80) posTop += 1;
food[i].css('top', posTop + '%');
}
}, speed);
}

Tweaking animation to make divs appear more frequently

I am creating a whack-a-mole style game where the user had to click on the correct number in accordance to a sum above that is randomly generated each time a question is answered. The problem that I am having is that the user sometimes has to wait a long time before the answer they need actually appears, and sometimes it takes around ten second for anything to appear. I need the animation to make the divs appear more frequently but I don't know how to make this happen.
Here is the animation attributes for the number divs
function randomFromTo(from, to) {
return Math.floor(Math.random() * (to - from + 1) + from);
}
function scramble() {
var children = $('#container').children();
var randomId = randomFromTo(1, children.length);
moveRandom("char" + randomId);
}
var currentMoving = [];
function moveRandom(id) {
// If this one's already animating, skip it
if ($.inArray(id, currentMoving) !== -1) {
return;
}
// Mark this one as animating
currentMoving.push(id);
var cPos = $('#container').offset();
var cHeight = $('#container').height();
var cWidth = $('#container').width();
var bWidth = $('#' + id).width();
var bHeight = $('#' + id).css('top', '395px').fadeIn(100).animate({
'top': '-55px'
}, AnimationSpeed).fadeOut(100);
maxWidth = cPos.left + cWidth - bWidth;
minWidth = cPos.left;
newWidth = randomFromTo(minWidth, maxWidth);
$('#' + id).css({
left: newWidth
}).fadeIn(1000, function () {
setTimeout(function () {
$('#' + id).fadeOut(1000);
// Mark this as no longer animating
var ix = $.inArray(id, currentMoving);
if (ix !== -1) {
currentMoving.splice(ix, 1);
}
window.cont++;
}, 1000);
});
}
Can someone show me how to make it so that there is always a set number of answers on the screen at once, rather than having long waiting periods with now numbers?
Fiddle:http://jsfiddle.net/xgDZ4/3/

Categories