Jquery/Javascript only running a custom function once after CSS changes - javascript

I'm using Jquery to draw lines between the cells in a web-based spreadsheet application. I accomplish this with a mixture of background-image, background-position and background-repeat. The entire system is working very nicely, and allows me to map between different cells in the application.
However, I'm having some trouble with my Jquery/Javascript code.
function draw_line(start_row, start_col, finish_row, finish_col){
//Change CSS background properties
}
function loadData(){
for (i = 0; i < values; i++){
//Add element to spreadsheet - change CSS properties.
//Draw line between the two cells
draw_line(start_row, start_column, line, column);
}
}
loadData();
The problem is that although the for loop should run several times for all the elements involved, it will actually only run once. However, if I comment out the draw_line function, the for loop executes the correct number of times, and all of the elements get placed on the spreadsheet.
I've also tried running setTimeout, but that didn't help. Anyone every experienced this sort of behavior before? (Just for reference, I'm running JQuery v1.6.4, on FF)
Hope someone can help. Thanks!

I have no idea if this is actually causing your problem, but it's bad and risky code so you should fix it. This line of your code:
for (i = 0; i < values; i++)
is using an implicitly declared global variable as i. If any other code you are running is also doing that, then the value of i will get trounced and wreck your for loop.
Change that line to this to make i a local variable so nothing else can trounce it:
for (var i = 0; i < values; i++)

Related

draw function not looping as expected

I'm a beginner on here, so apologies in advance for naivety. I've made a simple image on Brackets using Javascript, trying to generate circles with random x and y values, and random colours. There are no issues showing when I open the browser console in Developer Tools, and when I save and refresh, it works. But I was expecting the refresh to happen on a loop through the draw function. Any clues as to where I've gone wrong?
Thanks so much
var r_x
var r_y
var r_width
var r_height
var x
var y
var z
function setup()
{
r_x = random()*500;
r_y = random()*500;
r_width = random()*200;
r_height = r_width;
x = random(1,255);
y= random(1,255);
z= random(1,255);
createCanvas(512,512);
background(255);
}
function draw()
{
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
Brackets.io is just your text editor (or IDE if you want to be technical) - so we can remove that from the equation. The next thing that baffles me is that something has to explicitly call your draw() method as well as the setup() method -
I'm thinking that you're working in some sort of library created to simplify working with the Canvas API because in the setup() method you're calling createCanvas(xcord,ycord) and that doesn't exist on it's own. If you want to rabbit hole on that task check out this medium article, it walks you thru all the requirements for creating a canvas element and then drawing on that canvas
Your also confirming that you're drawing at least 1 circle on browser refresh so i think all you need to focus on is 1)initiating your code on load and 2)a loop, and we'll just accept there is magic running in the background that will handle everything else.
At the bottom of the file you're working in add this:
// when the page loads call drawCircles(),
// i changed the name to be more descriptive and i'm passing in the number of circles i want to draw,
// the Boolean pertains to event bubbling
window.addEventListener("load", drawCircles(73), false);
In your drawCircles() method you're going to need to add the loop:
// im using a basic for loop that requires 3 things:
// initialization, condition, evaluation
// also adding a parameter that will let you determine how many circles you want to draw
function drawCircles(numCircles) {
for (let i = 0; i < numCircles; i++) {
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
}
here's a link to a codepen that i was tinkering with a while back that does a lot of the same things you are
I hope that helps - good luck on your new learning venture, it's well worth the climb!
Thank you so much for your help! What you say makes sense - I basically deleted the equivalent amount of code from a little training exercise downloaded through coursera, thinking that I could then essentially use it as an empty sandpit to play in. But there's clearly far more going on under the hood!
Thanks again!

html DOM node limits

I am working on a terminal emulator for fun and have the basics of the backend up and running. However I keep running into performance problems on the frontend.
As you all probably know is that each character in a terminal window can have a different style. (color, backdrop, bold, underline etc). So my idea is was to use a <span> for each character in the view window and apply an inline style if necesary so I have the degree of control I need.
The problem is that the performance is horrendous on a refresh. Chrome can handle it on my pc with about 120 ops per second and firefox with 80. But internet explorer barely gets 6. So after my stint with html I tried to use canvas but the text on a canvas is ultra slow. Online I read caching helps so I implement a cache for each character and could apply colors to the then bitmapped font with some composite operation. However this is way way slower than DOM.
Then I went back to the dom and tried using document.createDocumentFragment but it performs a little bit worse then just using the standard.
I have no idea on where to begin optimization now. I could keep track on what character changes when but then I will still run into this slowness when the terminal gets a lot of input.
I am new to the DOM so I might do something completely wrong...
any help is appreciated!
Here is a jsperf with a few testcases:
http://jsperf.com/canvas-bitma32p-cache-test/6
Direct insertion of HTML as string text is surprisingly efficient when you use insertAdjacentHTML to append the HTML to an element.
var div = document.getElementById("output");
var charCount = 50;
var line, i, j;
for (i = 0; i < charCount; i++) {
line = "";
for (j = 0; j < charCount; j++) {
line += "<span style=\"background-color:rgb(0,0,255);color:rgb(255,127,0)\">o</span>";
}
div.insertAdjacentHTML("beforeend","<div>"+line+"</div>");
}
#output{font-family:courier; font-size:6pt;}
<div id="output"></div>
The downside of this approach is obvious: you never get the chance to treat each appended element as an object in JavaScript (they're just plain strings), so you can't, for example, directly attach an event listener to each of them. (You could do so after the fact by querying the resultant HTML for matching elements using document.querySelectorAll(".css selector).)
If you're truly just formatting output being printed to the screen, insertAdjacentHTML is perfect.

Should this For-Loop, in theory, work?

I have a question over at collision-detection about a similar issue, but it's not exactly the same. I had an issue with a new game project (I'm trying to learn more about HTML5 Canvases and Socket.io) in which my collisions weren't working. I thought that my issue was centered on collisions, but now I'm starting to think something different. The reason I have a different issue posted here at the for-loop area is because I'm not sure if my issue is for-loop related or collision-detection related. Either way, I'd be happy to take one of my questions down.
This code is looping every frame to get the active positions of bullets and ships. If the bullet touches the ship, it'll be removed and some health points will be removed from the ship.
Tutorial I was using: http://jlongster.com/Making-Sprite-based-Games-with-Canvas
That aside, here's my checkCollisions code. It seems that the collision function is working, because when I started to log all the positions every time we had an iteration, it seemed that the position of my object was changing every single time. Is this one of those for-loop issues where I'm going to need a callback?
Thank you so much in advance for all your help. I'll be sure to upvote/select every response that helps out! :)
SOLVED! Turns out one of my arrays wasn't being passed in correctly. I'd like to thank you guys for telling me to always split it into multiple functions, that really helped me figure that one out!
// Let's start out here: I have a players[] array
//that's essentially a list of all players on the server
// and their positions. I omitted server connection functionality since that's not my error
// source.
function checkCollisions() {
for (var i = 0; i < players.length; i++) { // Iterating through all players
var pos = [players[i].posX, players[i].posY];
var size = [SHIP_WIDTH, SHIP_HEIGHT]; // This is the size of each player, it's a ship game. So these are constants.
if (players[i].userId != PLAYER.userId) { // Each player has a userId object, this is just doublechecking if we're not uselessly iterating
for (var j = 0; j < bullets.length; j++) { // We're now looping through bullets, an array of all the bullets being shot by players
var pos2 = bullets[j].pos;
var size2 = BULLET_SIZE;
var sender = bullets[j].sender;
if (boxCollides(pos, size, pos2, size2)) { // Collision code
if (sender != players[i].userId) {
bullets.splice(j, 1);
i--; // Tried here with j--, and by removing the entire line. Unfortunately it doesn't work :(
break;
}
}
}
}
}
}
Have you tried using console.log to see where the program is breaking? This might help you determine if there are multiple bugs or if it's just this one. If there's something wrong in a previous statement, you may not know it if you've fixed the i-- / j-- ...?
Edit: AH I see that you've fixed things, after I'd posted this. Well congrats and good job!

Putting JQuery .css into conditional statement

Ok, so I've made a timer that makes parts of my SVG map fadeOut as they cross certain thresholds. However, I want to mess with other parts of the CSS.
I looked at this post, but couldn't make sense of it in terms of my problem.
** Edits Below**
Thanks for the help, I took a look at my code and tried to clean out some of the stuff that didn't need to be there. I also restructured my if statement, putting it inside of the JQuery code. I tried the suggestion below, assigning the var timer outside the interval function, but then my start button no longer worked and the script started running on page load. So, I moved it back to keep things working.
Also, put my code into JSFiddle, but I couldn't get it to work correctly. Will spend some more time familiarizing myself with that in the meantime. Thank you for introducing me to that.
As for my original question:
the .animate() tag works so long as I set it to change the opacity attribute, but has no effect on the other attributes I want to change. I know SVG and CSS have different attribute names, and I've tried both types of names. Here is my code below. I am trying to get the .animate() effect to change the fill color and stroke-width.
var i,timer;
i = 2013;
function start() {
timer = self.setInterval("increment()", 800 )
}
function increment() {
i++;
document.getElementById("timer_out").innerHTML = i ;
$(document).ready( function() {
if (i == 2014) {
$('#AL').animate( {
opacity: 0.3 } , 500 );
}
});
}
function stop() {
clearInterval(timer);
timer = null;
}
function reset() {
stop();
i=2013;
document.getElementById("timer_out").innerHTML = i;
}
I'm really just concerned with the JQuery statement, which works perfectly fine until I replace opacity with a different CSS attribute.
Thanks again for the attention and advice.
1) if you divide any number by 1 you get the original number, your divisions are doing nothing as far as i can tell.
2) setInterval should be written:
timer = setInterval(increment, ( 1000 / divide ))
also note increment() and start() are not good name choices to have in global scope, how many people will think of those names, use anonymous functions maybe to contain scope
(function()
{
// function is now contained within anonymous function scope and not accessible outside
function increment(){}
})()
3) logically step though your code in your head. your code wont work
4) create a fiddle of what you have done so far

How to prevent "A script on this page is causing Internet Explorer to run slowly" without changing MaxScriptStatements in the registry?

We are using Bing and/or Google javascript map controls, sometimes with large numbers of dynamically alterable overlays.
I have read http://support.microsoft.com/kb/175500/en-us and know how to set the MaxScriptStatments registry key.
Problem is we do not want to programmatically set this or any other registry key on users' computers but would rather achieve the same effect some other way.
Is there another way?
Hardly anything you can do besides making your script "lighter". Try to profile it and figure out where the heaviest crunching takes place, then try to optimize those parts, break them down into smaller components, call the next component with a timeout after the previous one has finished and so on. Basically, give the control back to the browser every once in a while, don't crunch everything in one function call.
Generally a long running script is encountered in code that is looping.
If you're having to loop over a large collection of data and it can be done asynchronously--akin to another thread then move the processing to a webworker(http://www.w3schools.com/HTML/html5_webworkers.asp).
If you cannot or do not want to use a webworker then you can find your main loop that is causing the long running script and you can give it a max number of loops and then cause it to yield back to the client using setTimeout.
Bad: (thingToProcess may be too large, resulting in a long running script)
function Process(thingToProcess){
var i;
for(i=0; i < thingToProcess.length; i++){
//process here
}
}
Good: (only allows 100 iterations before yielding back)
function Process(thingToProcess, start){
var i;
if(!start) start = 0;
for(i=start; i < thingToProcess.length && i - start < 100; i++){
//process here
}
if(i < thingToProcess.length) //still more to process
setTimeout(function(){Process(thingToProcess, i);}, 0);
}
Both can be called in the same way:
Process(myCollectionToProcess);

Categories