How to deal with over 100 moving rectangles without lag - javascript

I have this fiddle : https://jsfiddle.net/reko91/e6uwqnof/2/
On button press it creates 50 rectangles that all move down towards the bottom of the screen.
for(i=0;i<50;i++){
enemyArray.push(new enemy(normalBullet.x+i*5, normalBullet.y, normalBullet.speed, 1, 10, "#F00"));
}
Works fine on first click, but once I start adding more, it really starts to lag. Is there a best of practice way of dealing with hundreds of moving elements ? Or is HTML and Javascript not the best language to deal with this amount of moving data ?

Your main problem is in the update function:
function update() {
// enemy.update();
//if (keystate[SpaceBar]) {
$('#newEnemy').click(function() {
createNewEnemy()
})
//...
}
Probably a mistake, but you're attaching the event every time update gets called, which is 60 times per seconds! (Until it can't do it anymore, that is.)
This means that every time you press the button, you generate a ton of elements right in the canvas.
Move the event listener addition outsite update and you're golden.

You are assigning button pushes inside the frame loop, so when you push it, it's actually calling the button push however many times the loop has run.
Move this code outside:
$('#newEnemy').click(function() {
console.log("createEnemy");
createNewEnemy()
});

Related

Repeating the click animation in jquery

I am using jquery to display text when clicked on a state with some animation. The problem is the animation effect is running only for the first time the state is clicked and not on the second time. The code is as follows:
$("#maharashtra").live("click",function(){
$("#mainbg").hide();
$("#divmaha").animate({left:"700px"});
$("#divmaha").show() ;
$("#divguj").hide();
$("#divgoa").hide();
$("#divkerala").hide();
$("#divassam").hide();
$("#divmeghalaya").hide();
$("#divarunachal").hide();
$("#divmizoram").hide();
$("#divkarnataka").hide();
$("#divandhra").hide();
$("#divtamilnadu").hide();
$("#divraj").hide();
$("#divjammu").hide();
$("#divuttaranchal").hide();
$("#divhp").hide();
$("#divharyana").hide();
$("#divpunjab").hide();
$("#divdelhi").hide();
$("#divmadhya").hide();
$("#divjharkhand").hide();
$("#divchattisgarh").hide();
$("#divup").hide();
$("#divorissa").hide();
$("#divbihar").hide();
$("#divwestbengal").hide();
$("#divsikkim").hide();
$("#divtripura").hide();
$("#divnagaland").hide();
});
That's because your animation has already been performed. Now, introduce a "Reset" button and add reverse of everything in the animation so it moves back to its original place. Now again whenever someone would click that animate button, it'll animate.
Btw, you can compress this code. Combine the selectors and separate them with comma.
Try to make it on
$("#maharashtra").on("click",function(){ });
Since you havent provided your full code i have another guess that you may not have reset the animation.
after hiding all that stuffs.. are u showing all dose hidden stuffs before the second click.?
because animation get performed on first click. try this. you will get to know what the problem.
$("#maharashtra").live("click",function(){
reset();
$("#mainbg").hide();
$("#divmaha").animate({left:"+=700px"});
$("#divmaha").show() ;
});
function reset ()
{
//reset your element to original position here and then you dont need write +=700px you can simply write left:"700px"
}
Now your element will get animatte to left by 700px on each click if you want to.
fiddle: http://jsfiddle.net/chetandoke/QwWUn/

Limiting click detection on the page [javascript]

I'm trying to limit the user's ability to click on an object to a certain time limit. I looked around and found that apparently, setTimeout() is the correct function to use for this type of thing. I've applied the function to my code, but its not working. I'm thinking/know now that the problem is that the setTimeout in my code isn't limiting the actual click event, which I need to do. Here is a snippet of my click code:
function clickRun(event) {
var $objectVersion = correspondingObject(event.target.id);
if (isAnyVisible() == false) { // none open
$objectVersion.makeVisible();
} else if (isAnyVisible() && $objectVersion.isVisible()) { //click already open div
$objectVersion.makeInvisible();
} else if (isAnyVisible() && $objectVersion.isVisible()==false) { //different div open
searchAndDestroy();
$objectVersion.delay(600).makeVisible();
};
};
$('.ChartLink').click(function(event) {
setTimeout(clickRun(event),5000);
});
I've also created a JSFiddle to represent what I'm talking about: http://jsfiddle.net/FHC7s/
Is there a way to achieve limiting the actual click detection on the page?
I think the easiest way to do it is to keep track of the time of the previous click and if the current click is too soon after that, then don't do anything:
onClick = function(){
if(new Date().getTime() - lastCheck < MIN_CLICK_SPACING) return;
}
Have a look at this JSFiddle, I've set it up so you can have the button disable itself for time duration after detecting a click. Just make sure to remember how your closures are operating with your setTimeouts.
Your code contains an error... your line should be
setTimeout(function(){clickRun(event)},5000);
but even then I don't think that's exactly what you're looking for; that code will "delay" the click by 5 seconds, not actually prevent more clicks. If your true intent is to ignore all clicks after a certain amount of time, then I would go with mowwalker's answer; there's no way to stop the clicks, but you can check to see if you should honor them or not.

Jquery Cycle changing options on the fly

I want to change the options for jquery cycle dynamically on the page. Specifically, I want the speed to drop. According to one of it's creator, you can use 'cycle.opts' to do this. In my example I have specifically
$('.cycle-streams').cycle({
fx: 'scrollVert',
continuous: 1,
speed: 1000,
delay: 0,
easing: 'linear'
});
var changedOpts = $('.cycle-streams').data('cycle.opts');
$('.cycle-streams').mouseover(function() {
var changedOpts = $('.cycle-streams').data('cycle.opts');
changedOpts.speed = 1000000000000;
$('.cycle-streams').data('cycle.opts', changedOpts);
});
I've been working on this for some time now and am lost as to what I'm doing wrong. Any help would be appreciated. The jsfiddle is here... http://jsfiddle.net/bmXgj/
I changed your fiddle to this:
var changedOpts = $('.cycle-streams').data('cycle.opts');
$('.cycle-streams').mouseover(function() {
//hover in
$('.cycle-streams').cycle('pause');
changedOpts.speedIn = 500;
changedOpts.speedOut = 500;
$('.cycle-streams').cycle('next');
$('.cycle-streams').cycle('resume');
});
$('.cycle-streams').mouseout(function() {
//hover out
$('.cycle-streams').cycle('pause');
changedOpts.speedIn = 3000;
changedOpts.speedOut = 3000;
//$('.cycle-streams').cycle('next');
$('.cycle-streams').cycle('resume');
});​
I noticed that you were re-declaring 'changedOpts' for some reason. When I watched this variable in the console, it was coming out as undefined. Since you already defined it I just kept using it.
also you were never resetting the state of the cycle. I added pause and resume. It appears to work now but it is not perfect. The last side needs to clear before the new speeds will be used, so drastic jumps (3000 to 500 for example) allow for a noticeable delay when trying to speed up. I also added a next statement.
I noticed that when the plugin was handling next it was clearing the timeouts. So I figured if I stored the remaining time (Pause), then moved to the next slide (next), then resumed the show (resume) that the time would be restored. This seems to be working.
The 'next' action, is not needed when going from fast to slow because you will not usually notice the 'orphan' slide when leaving the container because it is cycling quickly. I put it in there for good measure in case your speeds are not that far apart.
Also I noticed you were only changing one speed. I am assuming, without looking at the guts of the plugin, that the 'speed' option is used at initialization only. After adding the other two speeds I got the right action. After reviewing the 'guts' of the plugin, I am certain that the speed option is used for synchronizing the other two speeds. If they all do not match you may get out of sync. The initialization code uses the 'speed' to set 'speedIn' and 'speedOut', so we need to change those two to affect the 'running' speed.
http://jsfiddle.net/bmXgj/6/
EDIT: did not need to pause and resume.
EDIT2: I did need the pause and resume, but I also needed a next. Also the 'speed' option can be ignored once it is set the first time to start the cycle. It appears to be shorthand for speedIn = speedOut = X

setTimeout increases everytime it is cleared and called again

This is one of the stranger things I have come across.
http://cabbibo.com
Basically, on my site, there are a bunch of spinning shapes. Each spinning shape sets a timeout when it is first called, to make it spin. Whenever a visitor clicks on the webpage, these shapes are cleared and randomly generated again.
The problem is that on the second click they are spinning a bit faster. on the third click even faster, and by the fourth click they are spinning so fast that they get super choppy and unfluid.
When watching the site with the chrome://flags FPS counter, it will start at an EVEN 60 fps, and then by the time it gets to the fourth or fifth click, it will be jumping between 20 and 50 fps.
an abbreviated section of the code is as follows:
//creates timeout variable OUTSIDE the timeout function, so it can be cleared
var t;
var speedRandom;
function getRandSpeed(){
var randomSpeed = (Math.random()*.01);
if (randomSpeed<=.001){
randomSpeed=.001;
}else if(randomSpeed>=.005){
randomSpeed=.005;
}
console.log(randomSpeed);
if (rightSpin==0){
speedRandom=randomSpeed;
rightSpin=1;
}else{
speedRandom=-randomSpeed;
rightSpin=0;
}
}
objs[whichImg].speed = speedRandom;
function rotateDrawing(whichImg){
//This is the function that centers the object
centerImg(whichImg);
//translates the object to the centered point (different for each frame)
objs[whichImg].ctx.translate(objs[whichImg].centeredX,objs[whichImg].centeredY);
//rotates to the correct angle
objs[whichImg].ctx.rotate(objs[whichImg].angle);
//draws the image
objs[whichImg].ctx.drawImage(objs[whichImg].image,0,0,objs[whichImg].height,objs[whichImg].width);
//adds to the angle of the object
objs[whichImg].angle+=objs[whichImg].speed;
t=setTimeout(function(){rotateDrawing(whichImg)},40);
}
//THE ABOVE CODE WILL BE EXECUTED FOR EVERY SHAPE (TOTAL AROUND 5)
//this is what is called when the screen is clicked
function destroy(){
functionThatClearsAllTheImages();
clearTimeout(t);
rotateDrawing(whichImg);
}
This code may have some holes in it, but it does function, the problem is that after the fifth click it is choppy.
I can add more code if anybody needs it, but any suggestions would be extraordinarily helpful!
The Problem was that each time I created a new object, the timeout lay within that creation code. This meant that the timeout was called 5 times, and when I cleared it, it was only cleared once.
In order to solve the problem, I created one timeout function that contained a loop within it that would rotate the shapes. This meant that everytime I had to clear it, it would essential clear the loop for all 5 shapes!

How can I reveal content and maintain its visibility when mousing to a child element?

I'm asking a question very similar to this one—dare I say identical?
An example is currently in the bottom navigation on this page.
I'm looking to display the name and link of the next and previous page when a user hovers over their respective icons. I'm pretty sure my solution will entail binding or timers, neither of which I'm seeming to understand very well at the moment.
Currently, I have:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
$(this).siblings(dropdown).fadeIn();
}, function(){
setTimeout(function(){
dropdown.fadeOut();
}, 3000);
});
});
with its respective HTML (some ExpressionEngine code included—apologies):
<p class="older_entry">Older<span class="hide_me">Older entry:
<br />
{title}</span></p>
{/exp:weblog:next_entry}
<p class="blog_home">Blog Main<span class="hide_me">Back to the blog</span></p>
{exp:weblog:prev_entry weblog="blog"}
<p class="newer_entry">Newer<span class="hide_me">Newer entry:
<br />
{title}</span></p>
This is behaving pretty strangely at the moment. Sometimes it waits three seconds, sometimes it waits one second, sometimes it doesn't fade out altogether.
Essentially, I'm looking to fade in 'span.hide_me' on hover of the icons ('a.paginate_link'), and I'd like it to remain visible when users mouse over the span.
Think anyone could help walk me through this process and understand exactly how the timers and clearing of the timers is working?
Thanks so much, Stack Overflow. You guys have been incredible as I walk down this road of learning to make the internet.
If you just want to get it working, you can try to use a tooltip plugin like this one.
If you want to understand how this should be done: first, get rid of the timeout, and make it work without it. The difference (from the user's point of view) is very small, and it simplifies stuff (developing and debugging). After you get it working like you want, put the timeout back in.
Now, the problem is you don't really want to hide the shown element on the navigator mouse-out event. You want to hide it in its own mouse out event. So I think you can just pass the first argument to the navigator hover function, and add another hover to dropdowns, that will have an empty function as a first argument, and the hiding code in its second argument.
EDIT (according to your response to stefpet's answer)
I understand that you DO want the dropdown to disappear if the mouse moves out of the navigator, UNLESS its moved to the dropdown itself. This complicates a little, but here is how it can be done: on both types of items mouse-out event, you set a timer that calls a function that hides the dropdown. lets say the timer is 1 second. on both kind of item mouse-in even, you clear this timer (see the w3school page on timing for syntax, etc). plus, in the navigator's mouse-in you have to show the dropdown.
Another issue with the timer in your code is that it will always execute when mouse-out. Due to the 3 seconds delay you might very well trigger it again when mouse-over but since the timer still exist it will fade out despite you actually have the mouse over the element.
Moving the mouse back and forth quickly will trigger multiple timers.
Try to get it to work without the timer first, then (if really needed) add the additional complexity with the delay (which you must keep track of and remove/reset depending on state).
Here was the final working code, for anyone who comes across this again. Feel free to let me know if I could have improved it in any ways:
$(document).ready(function() {
var dropdown = $('span.hide_me');
var navigator = $('a.paginate_link');
dropdown.hide();
$(navigator).hover(function(){
clearTimeout(emptyTimer);
$(this).siblings(dropdown).fadeIn();
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
$(dropdown).hover(function(){
clearTimeout(emptyTimer);
}, function(){
emptyTimer = setTimeout(function(){
dropdown.fadeOut();
}, 500);
});
});

Categories