I am trying to make a program in JavaScript that functions similar to a "Whack-a-Mole" game. I have everything figured out except for one thing. I would like to have each "mole" disappear after a brief time if it is not clicked on. The function that generates the moles is shown below. I am not entirely sure how to go about hiding the moles, but I would like to do so by selecting them by a uniquely generated ID, as shown in the code. There is a global variable "count" that is used to generate each ID.
function addMole(){
var yPos = numOne();
var xPos = numTwo();
if (timeLeft > 0){
$("#gamespace").append('<img id="i'+count+'" src="img/mole.gif" style="top:'+yPos+'px;left:'+xPos+'px;" />');
count++;
setTimeout("addMole()", Math.floor(Math.random()*2000));
};
};
I have tried using this function, but it doesn't seem to do anything and I'm not sure how or where to call it or if I'm even using the right selector.
function noMole(){
$("#i"+count).delay(2000).hide();
};
I'd probably go with something like the following:
function addMole() {
var yPos = numOne();
var xPos = numTwo();
if (timeLeft > 0) {
//make a new mole and have a reference to it
var newMole = $('<img src="img/mole.gif" style="top:' + yPos + 'px;left:' + xPos + 'px;" />');
//put the mole in the game
$("#gamespace").append(newMole);
//add another mole in a random amount of time
setTimeout(addMole, Math.floor(Math.random() * 2000));
//remove the created mole after 5 seconds
setTimeout(function(){ newMole.remove(); }, 5000);
};
};
You don't need a lookup. You just need the reference.
Related
I'm trying to add a simple counter in the bottom of my app like this one:
And it is very simple atm, 80 is my array.length that is being populated through my axios request.
<div>{people.length.toLocaleString()}</div>
And as I scroll down the page, using react-infinite-scroll, the number goes up and up and this is just fine. What I'm trying to do is subtract the number as the user goes back up the page.
Is this something harder than I'm thinking? If so, don't give me the full answer, just give me the path to follow. Thanks.
This is what I'm trying to accomplish: https://mkorostoff.github.io/hundred-thousand-faces/
you can do by using scroll event with window.innerHeight and the element bottom height to check whether its available inside the display window.
You can try like this using onscroll event which is available in library itself.
let counter = 0;
[listofElement].find(ele => {
var conditionHeight = window.innerHeight;
var cordinat = ele.getBoundingClientRect().top;
counter++;
return conditionHeight < cordinat;
});
You can check here with sample working part.
Looking at the source of the page you've linked, the code uses this function to get the size of the page:
function getScrollPercent() {
var face_width = document.getElementById('first').clientWidth;
var face_height = document.getElementById('first').clientHeight;
var body = document.documentElement || document.body;
var faces_per_row = Math.floor(main.clientWidth / face_width);
var total_height = total / faces_per_row * face_height;
var scroll_percent = (body.scrollTop - main.offsetTop + body.clientHeight) / total_height;
var count = Math.floor(scroll_percent * total);
var chunked_count = count - (count % faces_per_row);
if (chunked_count > 0) {
counter.classList = "fixed";
}
else {
counter.classList = "";
}
return (chunked_count > 0) ? chunked_count : 0;
}
The essential bit is var scroll_percent = (body.scrollTop - main.offsetTop + body.clientHeight) / total_height;. Basically, if you can calculate your total height (assuming that isn't infinite), then you can use body.clientHeight, +/- offsets, divided by totalHeight to figure out how far down the page you are. Call this from an event listener on scroll, and you should be good to go.
Incidentally, if this is the infinite scroll library you're talking about using, it's no longer maintained in favor of react-infinite-scroller.
using react-infinite-scroll, you can't back axios request results or remove generated doms.
The solution is calculating width and height of every doms and calculate offset.
Check how many doms are above the scrollReact and so so.
I am not sure how to remove a mole at a random timed interval, any thoughts? the instructions are..One of the few tasks which remains is to make the randomly appearing moles, disappear at random! Each randomly added mole should also disappear after a separately random time.
function timeDecrease(){
$("#timer").show();
$("#timer").html(time + " seconds left")
time -= 1;
if (time >0)
{
t = setTimeout("timeDecrease()",1000);
}
else time = 0;
};
function randomMole(min,max){
return Math.floor(Math.random() * (max - min + 1)) + min;
};
function addMole(){
yPos = getY();
xPos = getX();
$("#gamespace").append('<img class= "Image" img src="img/mole.png"
style ="top:'+yPos+'px; bottom:
'+xPos+'px;left:'+xPos+'px;right:'+yPos+'px;"/>');
moreMoles = setTimeout(addMole,randomMole(0,2000));
In your addMole function, store a reference to the new mole and set a timer to remove it.
let newMole = $(`<img
class="Image"
src="img/mole.png"
style="top: ${yPos}px; left: ${xPos}px;"
>`);
$("#gamespace").append(newMole);
setTimeout(newMole.remove.bind(newMole), randomMole(1000, 2000));
moreMoles = setTimeout(addMole,randomMole(0,2000));
We use template literals because they hurt less than concatenating strings. newMole.remove() would remove the new mole from the DOM, but calling it as a setTimeout callback won't work. It would be called by window, so the this keyword would be set to window, but jQuery expects this to be set to the element you're removing. newMole.remove.bind(newMole) gives us a version of newMole.remove with this explicitly set to newMole.
I am making an info screen, and for that, it needs to show reviews from their customers pulled from Trustpilot.
I got the reviews and everything formatted in HTML showing the 20 latest, but I want to present it very sweet. I am not a JavaScript guru, but I thought i would do it using jQuery and its fadein function.
What is want, is have 20 unique divs fading in with X milliseconds difference popping randomly up. By unique I mean, that each div must have unique content. And by randomly popping up, I mean that if box 1 spawns first, then the next should be 5, then 14 etc, and then another cycle the next time around.
Just like what I made here;
$(function() {
var box = $('.box');
var delay = 100;
for (i = 0; i < 30; i++) {
setTimeout(function() {
var new_box = box.clone();
$('.container').append(new_box);
new_box.fadeIn();
}, delay);
delay += 500; // Delay the next box by an extra 500ms
}
});
http://jsfiddle.net/CCawh/5/
Is this even possible, and how would this be done?
I am very new to JavaScript, so please bear with me if I ask to much
Thanks in advance.
EDIT:
The HTML i want to spawn will all be wrapped in divs, so it would go like this;
<div id="one">content</div>
<div id="two">content</div>
<div id="three">content</div>
<div id="four">content</div>
etc.
Made up a nice function for you. I believe this may be what you are looking for
Here's a rundown of how it works :
Populate an array with numbers randomly generated 1-10 in this case.
Run through that array with a set interval, and when everything has
been added stop the interval
pretty straightforward from there. Set the visibility etc. You should be able to change up the function to dynamically add HTML elements and what-not, but just giving you something to start with.
var usedNum = [];
var i, j, y;
i = 0;
for(y = 0; y < 10; y++){
var x = Math.floor((Math.random() * 10) + 1);
if(!isUsed(x)) usedNum.push(x);
else y--;
}
var showInterval = setInterval ( function(){
if(i == 10){
clearInterval(showInterval);
}
$(".container div[data-line='" + usedNum[i] + "']").css({opacity: 0.0, visibility: "visible"}).animate({opacity: 1.0});
i++;
}, 500);
function isUsed(num) {
var used = false;
for(j = 0; j < usedNum.length; j++){
if(usedNum[j] == num){
used = true;
}
}
return used;
}
Demo fiddle : http://jsfiddle.net/xS39F/3/
Edit:
You can also mess around with the speed of the animation. In this demo (http://jsfiddle.net/adjit/XYU34/1/) I set the speed to 1000 so the next element starts fading in before the last element was done fading in. Makes it look a little smoother.
Instead of using a for loop and setTimeout, would setInterval work better for what you need? Some HTML might help better understand what you're trying to achieve.
$(function() {
var box = $('.box');
var delay = 100;
var interval = setInterval(function() {
var new_box = box.clone();
$('.container').append(new_box);
new_box.fadeIn();
}, delay);
delay += 500; // Delay the next box by an extra 500ms
}, delay);
});
I need to have 2 of these one page but each with different percentages. When I try re-writing the JS or even use different class/ID names it still always pulls from the first SPAN.
http://jsfiddle.net/K62Ra/
<div class="container">
<div class="bw"></div>
<div class="show"></div>
<div id="bar" data-total="100">
<div class="text">Currently at <br/><span>70</span><br><i>Click To Give</div>
</div>
JS and CSS in the Fiddle.
Much Thanks.
This one will work smoothly:
http://jsfiddle.net/K62Ra/7/
$('.bar').each(function() {
var percentStart = 0;
var total = $(this).data('total');
var percent = parseInt($(this).find('span').html());
$(this).find('> div').addClass("load");
var that = this;
var timer = setInterval(function() {
$(that).siblings('.show').css('height', percentStart/total*100+'%');
$(that).css('height', percentStart/total*100+'%');
$(that).find('span').html('%'+percentStart);
if(percentStart<percent) { percentStart=percentStart+1; return; }
clearInterval(timer);
}, 35);
});
The interval has to be terminated as well, or it will run infinitely (though not doing anything).
I've changed your id="bar" into a class. Then I'm running a each loop for the .bar classes. here is the fiddle: http://jsfiddle.net/K62Ra/3/
here is the code:
$('.bar').each(function (index, element) {
percent = $(this).find('span').html();
total = $(this).attr('data-total');
percentStart = 0;
setInterval(function () {
$('.show').css('height', percentStart / total * 100 + '%');
$(this).css('height', percentStart / total * 100 + '%');
$(this).find('span').html('%' + percentStart);
if (percentStart < percent) {
percentStart = percentStart + 1;
}
}, 35);
});
$(".bar div").addClass("load");
Like some of the comments have stated, having duplicate ids is bad design and can cause some weird errors.
You can find a solution to your problem by changing a number of things. One, instead of
referring to divs in you selectors by id'#', you can infer them by class '.' like
$('.bar')
The next step would be to ensure exclusivity for each div with class 'container' by using a closure
$('.container').each(function(){
var x
var y
.
.
});
And finally, avoid 'selecting' elements in the selector directly, but use $(this) and .find() to ensure you are within the current div with class 'container'.
http://jsfiddle.net/K62Ra/5/
$('.container').each(function(){
var percent = $(this).find('div.bar div span').html();
var total = $(this).find('div.bar').attr('data-total');
var percentStart = 0;
var that = $(this);
setInterval(function() {
that.find('.show').css('height',percentStart/total*100+'%');
that.find('div.bar').css('height',percentStart/total*100+'%');
that.find('div.bar div span').html('%'+percentStart);
if(percentStart<percent) {percentStart=percentStart+1;}
},35);
$(this).find("div.bar div").addClass("load");
});
There are already several good answers here. I would recommend validating your html. Also some of your css was causing weirdness when there was scrolling involved (fixed background images weren't scrolling.)
I took a slightly different approach than everyone else. Instead of using a setInterval I went with $.animate and a step function. Like others, I chose a class to target each of the items: 'fill-me-up'.
Fiddle: http://jsfiddle.net/LFbKs/6/
NOTE: Check the fiddle since I modified the HTML (very slightly) and the css to a larger degree.
// for each item we need to "fill up"
$('.fill-me-up').each(function(){
// cache DOM references
var this$ = $(this)
, bar$ = this$.find('.bar')
, show$ = this$.find('.show')
, span$ = bar$.find('div span')
// the target percentage height for this item
, p = span$.text()
// combine '.bar' and '.show' so we can apply the animation to both
, toAnimate = $().add(bar$).add(show$);
// add class causing fade-in
bar$.find('div').addClass('is-visible');
// animate height to target height over 2 seconds and
// at each step, update the span with a truncated value
toAnimate.animate(
{ height: p+'%' },
{
duration: 2000,
step: function( currentStep ) {
span$.html('%'+currentStep.toFixed(0));
}
}
);
});
Cheers
I want my div element to work like a timer and shows random numbers with an interval of 1s. http://jsfiddle.net/NHAvS/46/. That is my code:
var arrData = [];
for (i=0;i<1000;i++)
{
arrData.push({"bandwidth":Math.floor(Math.random() * 100)});
}
var div = document.getElementById('wrapper').innerHTML =arrData;
document.getElementById('wrapper').style.left = '200px';
document.getElementById('wrapper').style.top = '100px';
but the problem is that it only shows 1 data at a time. any idea how to fix it?
Thanks
Do this:
setInterval(myfun,1000);
var div = document.getElementById('wrapper');
function myfun(){
div.innerHTML ='bandwidth :'+Math.floor(Math.random() * 100);
}
Take a Look: http://jsfiddle.net/techsin/NHAvS/49/
Note: your example was messed up as on left side it was set to load in head which means your div would be undefined every time your script loads before your dom. so setting it to onload make it works little more. :D
Note: also you seem to be chaining functions as in jquery, but in javascript you don't do that. The functions are made to do that. i.e. div= ..getElementById..innerHtml='balbla'; would set div = bla... not element.
You're better off using jQuery and CSS to achieve your desired result. jQuery to find the element and to display the random number; and CSS instead of manually setting the position. (Obviously jQuery is just a personal choice and document.getElementById will suffice - but if you're planning on manipulating the DOM a lot, jQuery is probably a better route to take). See updated fiddle
$(function () {
var arrData = [];
for (i = 0; i < 1000; i++) {
arrData.push({
"bandwidth": Math.floor(Math.random() * 100)
});
}
var index = 0;
setInterval(function(){
$("#wrapper").text(arrData[index].bandwidth);
index++;
}, 1000);
});
You can do it like this:
var delay = 1000, // 1000 ms = 1 sec
i;
setTimeout(function() {
document.getElementById('wrapper').innerHTML = arrData[i];
i++;
}, delay);