I would like to know if there is any specific way to get javaScript code to stop executing at some point so as to allow another called function to execute, for example in a sorting algorithm using Div's you call a function which annimates the swapping of the two Div's so you can visually see the sort taking place. I have tried using the setTimeout(c,t); however it does not seem to be be waiting and the Divs do not seem to be moving, if I however place an alert(""); within the moving code it seems to allow the move to take place with thousands to alerts popping up.
The code I have is as follows:
var q;
var w;
function move(x,y)
{
q = x.style.top; // Keep a reference to the Top divs top element
w = y.style.top; // Keep a reference to the Top divs top element
doMove(x,y);
}
function doMove(topDiv, bottomDiv)
{
//alert("in doMove " + topDiv);
topDiv.style.top = parseInt(topDiv.style.top)+2+'px';
bottomDiv.style.top = parseInt(bottomDiv.style.top)-2+'px';
//alert("hi");
if(bottomDiv.style.top != q && topDiv.style.top != w) // Check if the Top and Bottom divs have finally swapped
{
setTimeout(doMove(topDiv,bottomDiv),20); // call doMove in 20msec
}
}
One problem with your code is that in this line:
setTimeout(doMove(topDiv,bottomDiv),20);
You are calling doMove immediately and passing the value undefined as the first parameter to setTimeout. Not entirely sure that the following will solve your problem, but I would recommend trying this:
setTimeout(function() { doMove(topDiv,bottomDiv); }, 20);
Related
I have a page with a lot of Div's, and I am using the panzoom jquery script. In order to speed up the page, I would like to disable the shadow on the divs if the page is zoomed out above a specified value, and enable the shadows if the page is zoomed in. currently I have this code, that is beeing called every 0.5 seconds:
function shadow()
{
var $panzoom = $('.panzoom').panzoom();
var matrix = $panzoom.panzoom("getMatrix");
$("#zoomf").html(matrix[0])
//if zoom is bigger than 0.35 enable shadows
if (matrix[0] > 0.35)
{
var $elements = $('.machinebox').addClass('shadow');
var $elements2 = $('.playerbox').addClass('shadow');
}
else
{
$elements.removeClass('shadow');
$elements2.removeClass('shadow');
}
}
The problems I am facing are basically two:
1) the var $elements does not exist Always, it only exists as long as the shadow exists.. thus, if I zoom out, it removes the shadow and then generates a error:
SCRIPT5007: Unable to get property 'removeClass' of undefined or null reference
de (282,3)
2) when it adds/removes the shadows it freezes for about one second. can this be avoided somehow?
The first problem is caused because the variables $element and $element2 are only declared and initialized when the condition is true. The second one seems to be caused because there are a lot of elements which have the classes machinebox and playerbox.
You can fix both of them by using something like this:
function shadow() {
var matrix = $('.panzoom').panzoom("getMatrix");
$("#zoomf").html(matrix[0])
$('.machinebox:visible, .playerbox:visible').toggleClass("shadow", (matrix[0] > 0.35))
}
For point 2 since you've solved point 1.
the function is running every 0.5 seconds, this is probably why you get that delay.
try pausing it until the next time the user zooms (idk if the library you're using allows you to detect such events)
So far I have a little script that detects the scroll top position and at a set level I want it to trigger a jquery counter. So far I have an array with the maximum number inside var = eightyS = [3]; then there is..
if (y > 630) {
$('.targetS').each(function() {
//counter
delay(1000);
});
} else {
return false;
}
Now I've made something similar in C++ years ago (couldn't do it now with a gun to my head) so I followed a similar logic. But this is where I'm stuck. The idea behind this function is that it will do a read out on screen of 0 then 1 then 2 then 3. Any help is greatly appreciated
You could use a setInterval() which executes a function ever second such as below:
var count = 0;
var interval = setInterval(function(){
count++;
$('#counter').text(count);
}, 1000);
I've created a quick JSFiddle
You should be able to wrap this in to your code fairly easily. You may also want to use clearInterval(interval) to stop the function executing when you scroll back up the page; or when you get in to your else block, which would have the same effect. I've added a clearInterval() example to the JSFiddle on click of the stop link. You'll need to make sure the interval variable is in scope when clearing it.
I'm trying to learn animating in javascript.
I have a path array with x and y coordinates that I try to move through with recursion. But instead of moving the box (box[1]) one step at a time it jumps directly to the last position. If i add an alert in the loop then the animation will "work", so that it just moves the box one step at a time between each alert.
function followPath(){
box1[1].style.left = path[index][0]+'px';
box1[1].style.top = path[index][1]+'px';
index++; //I put an alert("hi"); here and it "worked"
if(index < path.length)
requestAnimationFrame(followPath());
}
function buttonPress(){
index = 0;
followPath();
}
What causes this?
As a sidenote, I had the same sort of problem when i tried to pass variables to a similar recursive function that worked just fine before i tried to pass variables to it.
Thanks.
Argument to requestAnimationFrame is a function, not what function returns. The line:
requestAnimationFrame(followPath());
should be
requestAnimationFrame(followPath);
I'm looking for an effecient way to constantly select the last element within the visible window/viewport.
So far, this is my code:
$(window).scroll(function () {
$('.post-content p').removeClass("temp last")
$('.post-content p').filter(":onScreen").addClass("temp")
$(".temp").eq(-1).addClass("last")
});
As you could probably imagine, this hauls up a lot of resources and doesn't perform very well. Can somebody please suggest from more elegant code?
My knowledge of Javascript is very basic, so please be patient with me. Thank you.
PS: I am using the onScreen plugin for the :onScreen selector: http://benpickles.github.com/onScreen/
Binding the scroll handler
Binding functions to the scroll Event can lead to serious performance problems. The scroll event fires really vigorously on page scroll, so binding functions with resource-heavy code to it is a bad idea.
What John suggests is setting up the interval and thereby having the code only execute some time after a scroll event.
Have a look at this jsfiddle to see difference between the implementations
The indirect handler solution comes at the cost of a noticeable lag between scrolling and executing the code, and it is your decision if you can trade in performance for snappier execution. Be sure to test performance on every browser you support.
Speeding up code execution
There are a lot of different concepts you can use to speed up your code. Regarding your code, it comes down to:
Caching selectors. You reselect elements every time the scroll handler fires, which is unnecessary
Not using jQuery plugins without knowing what they do. In your case, the plugin code is nice and quite straightforward, but for your goal you can have even snappier code.
preventing any unnecessary calculation. With your and the plugin's code, the offset of every element is calculated every time the scroll handler fires.
So what I've come up with is a Jsfiddle with an example how you could do you scroll handler. It's not exactly matched to your DOM because I don't know your html, but it should be easy to match it to your implementation.
I managed to reduce the time used by 95% compared to your code. You can see for yourself by profiling the two samples in chrome.
I assumed you just want to select the last element and you do not need the temp class
So, here's the code with explanations
// Store the offsets in an array
var offsets = [];
// Cache the elements to select
var elements = $('.elem');
// Cache the window jQuery Object
var jWindow = $(window);
// Cache the calculation of the window height
var jWindowHeight = jWindow.height();
// set up the variable for the current selected offset
var currentOffset;
// set up the variable for the current scrollOffset
var scrollOffset;
// set up the variable for scrolled, set it to true to be able to assign at
// the beginning
var scrolled = true;
// function to assign the different elements offsets,
// they don't change on scroll
var assignOffsets = function() {
elements.each(function() {
offsets.push({
offsetTop: $(this).offset().top,
height: $(this).height(),
element: $(this)
});
});
};
// execute the function once. Exectue it again if you added
// or removed elements
assignOffsets();
// function to assign a class to the last element
var assignLast = function() {
// only execute it if the user scrolled
if (scrolled) {
// assigning false to scrolled to prevent execution until the user
// scrolled again
scrolled = false;
// assign the scrolloffset
scrollOffset = jWindowHeight + jWindow.scrollTop();
// only execute the function if no current offset is set,
// or the user scrolled down or up enough for another element to be
// the last
if (!currentOffset || currentOffset.offsetTop < scrollOffset || currentOffset.offsetTop + currentOffset.height > scrollOffset) {
// Iterate starting from the bottom
// change this to positive iteration if the elements count below
// the fold is higher than above the fold
for (var i = offsets.length - 1; i >= 0; i--) {
// if the element is above the fold, reassign the current
// element
if (offsets[i].offsetTop + offsets[i].height < (scrollOffset)) {
currentOffset && (currentOffset.element.removeClass('last'));
currentOffset = offsets[i];
currentOffset.element.addClass('last');
// no further iteration needed and we can break;
break;
}
}
return true;
} else {
return false;
}
}
}
assignLast();
// reassign the window height on resize;
jWindow.on('resize', function() {
jWindowHeight = jWindow.height();
});
// scroll handler only doing assignment of scrolled variable to true
jWindow.scroll(function() {
scrolled = true;
});
// set the interval for the handler
setInterval(assignLast, 250);
// assigning the classes for the first time
assignLast();
I was trying to make a kind of background in which some clouds were moving, but after I got the clouds moving I found that I should either make them stop and return when reaching the browser's max-width, or make them disappear. I was trying to get their position but I can't manage to get all the positions dynamically. Right now (for the sake of simplicity) I'm only using 1 cloud to test and I do this:
$(function () {
var p = $('.clouds').position();
var w = $("#sky").width();
while (p < w);
$('.clouds', this).stop().animate({ left: "+=50000px" }, { queue: false, duration: 90000 });
});
the thing is, that position isn't dynamically refreshed, it sticks with the first one it gets and I have tried to move it inside the while loop but it didn't work...so I'm kinda stuck at the moment...anyone has an idea of how I can achieve this? The image of the cloud is originally set at top:0 left:0
I think this code will be useful to u. Try this out!
$('.clouds').animate({ top: 0 }, { queue: false, duration: 90000 });
setInterval(function () {
if ($(".clouds").position().top == 0) alert("Rain");
}, 5000);
for every 5 seconds, it will check for the position of a "cloud" class if it is zero it will give alert!
for multiple clouds u can use below code
setInterval(function () {
if ($(".clouds").position().top == 0) {
$(".clouds").each(function () {
if ($(this).position().top == 0) $(this).remove();
});
}
}, 1000)
Is the code you've posted a direct copy of what you're using? If so, then the call to animate isn't included in the while loop since it's cut short by the semi-colon. Try to use curly braces; it makes it much easier to maintain and look at. :)
while(p < w) {
$('.clouds',this).stop().animate({left:"+=50000px"},{queue:false, duration:90000});
}
Also, I don't think that loop will ever complete. Neither of those variable's values are changing during iteration so it's never-ending. In order for it to work you'll need to modify (update) the 'p' variable within the loop, on every iteration.
EDIT: Actually, scratch that, the loop won't even begin because elem.position() returns an object, not a number (NaN). To make it work you'll need elem.position().left.
why not use a looping background image and modify the background-position css property?
edit: I don't know if there's a jquery plugin to do this automatically, but it should be easy enough in old fashioned javascript with setInterval and modulus.
for example, your background image is 400 pixels wide,
the css would be:
body {
background: transparent url(yourbackground.png) repeat-x scroll 0 0;
}
and javascript would be:
var BGPosition = 0;
var resetSize=400;
function scrollBodyBG() {
BGPosition = ++BGPosition % resetSize;
$('body').css("background-position", (-1 * BGPosition) + "px 0px");
}
var si = setInterval(scrollBodyBG,100)
Edit: Tested and working (without jquery) as
var BGPosition = 0;
var resetSize=400;
function scrollBodyBG() {
BGPosition = ++BGPosition % resetSize;
document.body.style.backgroundPosition = (-1 * BGPosition) + "px 0px";
}
document.addEventListener("DOMContentLoaded",function() { setInterval(scrollBodyBG,100);},false);
obviously this would need to change for IE event listener support
How about:
while($('.clouds').position().left < $("#sky").width())
{
// do stuff
}
The only way to do this reliably is to listen property changes on DOM elements, using mutation events DOMAttrModified (for ex.) and the proprietary "onpropertychange" on IE.
Someone ported this to Jquery, here's the article.
http://www.west-wind.com/Weblog/posts/453942.aspx
Put it all in a function, let's say moveCloud()
Then use the callback of the animate position and call that function.
At the beginning of the function check the position of the cloud:
-If it is 0 move it to the right until it reaches maxwidth
-If it is the maxwidth, move it to the left until it reaches 0
Once the animation is done, the callback executes and calls again the function, which will move the cloud to the other side of the screen.