I am currently devolving a little slideshow, thing that automatically moves fades in and out the background-images. (opacity as well.)
My issue is that I am trying to use variables to store code to run, as setTimeout is stubborn, and won't run with anything in parentheses in it. (as well I need to use them, or my code will get really messy..ier)
What I currently have is
imgID = 0;
// window.setInterval(nextSLIDE, 1000);
nextSLIDE();
function nextSLIDE( step2 ) {
slideVAR = "slide" + imgID;
window.setTimeout(imgIDchange(), 50);
test2 = window.setTimeout(changeOpacityNINE);
tes5t = window.setTimeout(changeOpacity8, 100); // If you are wondering about the irradical names, that is because I made them all non-unique earlier, and I got lazy, so I made them unique..
test4 = window.setTimeout(changeOpacity7, 200);
test6 = window.setTimeout(changeOpacity6, 300);
tes6t = window.setTimeout(changeOpacity5, 400);
twest = window.setTimeout(changeOpacity4, 500);
testt = window.setTimeout(changeOpacity3, 600);
testyt = window.setTimeout(changeOpacity2, 700);
teswt = window.setTimeout(changeOpacity1, 800);
}
function imgIDchange() {
imgID = imgID + 1;
}
function changeOpacity( opacity ) {
document.getElementById("headerIMG").style.opacity = opacity;
}
var changeOpacityNINE = changeOpacity(0.9);
var changeOpacity8 = changeOpacity(0.8);
var changeOpacity7 = changeOpacity(0.7);
var changeOpacity6 = changeOpacity(0.6);
var changeOpacity5 = changeOpacity(0.5);
var changeOpacity4 = changeOpacity(0.4);
var changeOpacity3 = changeOpacity(0.3);
var changeOpacity2 = changeOpacity(0.2);
var changeOpacity1 = "changeOpacity(0.1);"
var FULL = changeOpacity(1)
And I am looking for a way to make it either
A) Work, and not run the varibles.
B) Or find some sort of other Work around..
If my design is that horrific, and makes your eyes bleed feel free to tell me how I can redo it, but I would rather not redo it all in general. (I am rather lazy..)
If I understand you correctly, you want to call setTimeout with a function and pass arguments to it?
If so, you can simply add the arguments to the end of your setTimeout call. So if you wanted to call
changeOpacity(0.5);
after 1000 ms, then you would use setTimeout like this:
setTimeout(changeOpacity, 1000, 0.5);
With setTimeout, the arguments are as follows:
setTimeout(callback,delay,args);
so you can simply do:
setTimeout(changeOpacity,*DELAY*,0.7); // etc...
Related
I'm trying to make the most simple image slider possibly in pure js, basically by changing the background position, but loop doesn't work at all. I need to repeat the loop continuously.
function slider1(){
var slide = document.getElementById("slider-1");
var slideWidth = 320;
var backPosY = 0;
var backPosX = 0;
var sliderEnd = 960;
var f;
for(f=backPosX;f < sliderEnd; f+=slideWidth){
slide.style.backgroundPosition = "-"+f+"px "+backPosY+"px";
}
setInterval(slider1(),1000);}
setInterval takes function as first parameter, but you passed slider1().
Parentheses means calling function so you are calling slider1 and passing to setInterval only returned value of function call.
In your case slider1 does not return anything, that means that setInterval receives undefined instead of your function.
You need to pass the function itself, not results of its calling.
setInterval(slider1, 1000);
But be aware that every call will start a new interval and you don't want to have multiple intervals running calling the same function.
So call setInterval outside of your function or replace setInterval with setTimeout. Timeout will call your function once and your function will create new timeout and so on.
Edit:
Also your for loop loops through all positions in one moment. But you want to move it by one position.
I would do it like this:
var slide = document.getElementById("slider-1");
var slideWidth = 320;
var backPosY = 0;
var backPosX = 0;
var sliderEnd = 960;
var f = backPosX;
function slider1(){
slide.style.backgroundPosition = "-"+f+"px "+backPosY+"px";
f+=slideWidth;
if(f >= sliderEnd)
f = backPosX;
}
setInterval(slider1, 1000);
Edit 2: This code can be used on multiple sliders:
function moveSlider(slide){ // Slide is now a function parameter
var slideWidth = 320;
var backPosY = 0;
var backPosX = 0;
var sliderEnd = 960;
if(!slide.slidePosition) // If there isn't slidePosition in the element
slide.slidePosition = backPosX; // Initialize it
slide.slidePosition+=slideWidth;
if(slide.slidePosition >= sliderEnd) //
slide.slidePosition = backPosX;
slide.style.backgroundPosition = "-"+slide.slidePosition+"px "+backPosY+"px";
}
function startSlider(slide){ // Start slider's interval
return setInterval(function(){
moveSlider(slide);
}, 1000);
}
function stopSlider(intervalId){ // setInterval return ID which you can use to stop the interval
clearInterval(intervalId);
}
You can then start slider with:
startSlider(document.getElementById("slider-1"));
Notice that I need to pass parameter to moveSlider. So I wrapped in another function doesn't take any parameters and calls moveSlider with slider as parameter. This code example can explain it a bit:
function slide1(){
...
}
// Can be also written as:
slide1 = function(){
...
}
I just removed the middle man slide1 and passed it directly.
So I have a piece of code like
var barlen = $('#SSWEprogressbar').width(),
$elems = $('[data-srcurl]'),
k = 0,
n = $elems.length;
LoadImage();
function LoadImage()
{
var $elem = $($elems[k]);
var img = new Image(),
url = $elem.attr('data-srcurl');
$(img).load(function(){
$('#SSWEloaderfront').attr('src',url);
$('#SSWEloadprogress').width((k+1)/n*barlen + "px");
var srctgt = $elem.attr('data-srctgt');
// change url to src attribute or background image of element
if ( srctgt == "srcattr" ){ $elem.attr('src',url); }
else if ( srctgt == "bgimg" ) { $elem.css('background-image',"url("+url+")"); }
// decide whether to exit the
if ( ++k == n ) { AllyticsSSWEPlayerShow(); }
else { LoadImage(); }
});
img.src = url;
}
and the reason I have it written that way is because load callback needs to be called before the stuff in the function can be executed again. If possible, I'd like to change this from a recursive function to a loop, but I don't know how to do that because there's no way to make a for or while loop "wait" before going on to the next iteration. Or is there?
As I mentioned in the comment you can easily resolve your problem, by using setTimeout(LoadImage, 100); in the else instead of calling the function directly. The 2nd parameter is the delay in ms.
If you understand why setTimeout(LoadImage, 0); is not stupid and not the same as calling the function directly then you understood setTimeout. It puts the function call in the queue, this means other events like clicks or keys that were pressed can be processed before the function is called again and the screen doesn't freeze. It's also impossible to reach max recursion like this, the depth is 1.
I decided to make a function that changes the body background image after every 10 seconds.
function Background()
{
var Background_Stage;
switch(Background_Stage)
{
case 0:
{
$('body').css.('background', '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_1_TEST.png) no-repeat');
Background_Stage++;
setInterval(function(){Background()},10000);
}
case 1:
{
$('body').css.('background', '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png) no-repeat');
Background_Stage++;
setInterval(function(){Background()},10000);
}
case 2:
{
$('body').css.('background', '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png) no-repeat');
Background_Stage = 0;//Reset
setInterval(function(){Background()},10000);
}
}
}
However hen I did something like this
<body onload="Background()"></body>
It doesn't seem to do anything, this might be a dumb thing to ask for help with but this is the first I did when I was learning JavaScript, I should say that I used jQuery for most of this.
There's a few problems with your code:
The value of Background_Stage won't persist between calls to Background, and in any case, you never assign a value to Background_Stage.
Use setTimeout rather than setInterval. setTimeout will call the function once at the end of the allotted time. setInterval will keep calling the same function again and again until explicitly cancelled. The way you have it, you'll end up with lots of concurrent setIntervals running.
You don't need the '.' between css and the following parenthesis.
Finally, try not to repeat yourself, meaning that if you find yourself typing out more or less the same statements over and over, then you can probably make the code cleaner. Something like:
(function()
{
var bgCounter = 0,
backgrounds = [
"../../Styles/Callum_Project1/Images/BACKGROUND_1_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_3_TEST.png"
];
function changeBackground()
{
bgCounter = (bgCounter+1) % backgrounds.length;
$('body').css('background', '#000 url('+backgrounds[bgCounter]+') no-repeat');
setTimeout(changeBackground, 10000);
}
changeBackground();
})();
Now changing the background URLs or adding more is a simple job of editing the backgrounds array.
You can also try this:
function Background(){
var imgs = [
"../../Styles/Callum_Project1/Images/BACKGROUND_1_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_3_TEST.png"
],
len = imgs.length,
idx = -1;
setInterval(function(){
idx = (idx+1)%len;
$("body").css("background", "#000 url("+imgs[idx]+")");
}, 10000);
}
Every time you call background, you instantiate a new local variable called Background_Stage with a value of undefined. This doesn't match any of your switch options.
You need to declare the variable outside of your function (so it persists between calls to the function) and give it a starting value.
Your Backgroud_Stage is not initialized
Your setInterval placement will cause very serious problems
There's also invalid syntax.
Overall, your code can be simpler like this:
var Stage = 0;
setInterval(function() {
var bg = '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_'+(Stage+1)+'_TEST.png) no-repeat';
document.body.style.background = bg;
Stage = ++Stage % 3;
}, 10000);
I am trying to create the fadeIn() function using Javascript. I am having trouble, when I click the fadeIn button, it does not perform a fadeIn animation, instead I have to click it several times to fadeIn. Would anyone know how I can fix this issue?
jsFiddle
// Created a jQuery like reference
function $(selector) {
if (!(this instanceof $)) return new $(selector); // if new object is not defined, return new object
this.selector = selector; // setting selector attribute
this.node = document.querySelector(this.selector); // finds single element from the DOM
};
var fInFrom = 0, fOutFrom = 10;
$.prototype.fadeIn = function() {
var target = this.node,
newSetting = fInFrom / 10;
// Set Default styles for opacity
target.style.display = 'block';
target.style.opacity = newSetting;
// fadeInFrom will increment by 1
fInFrom++;
var loopTimer = setTimeout('this.fadeIn', 50);
if (fInFrom === 10) {
target.style.opacity = 1;
clearTimeout(loopTimer);
fInFrom = 0;
return false;
}
return this;
}
$('#fadeIn').node.addEventListener('click', function() {
$('#box').fadeIn();
});
This line is your problem:
setTimeout('this.fadeIn', 50)
That will set a timeout to evaluate the expression this.fadeIn in the global scope in approximately 50 milliseconds from the current time. There's two problems with that:
It's in the global scope; this is window, not an instance of $, so this.fadeIn is undefined.
Even if it were resolved correctly, you're only evaluating this.fadeIn; you're not calling it. You would need to use this.fadeIn() for it to do anything. (If you do that with the current code, this will reveal your first problem.)
To solve this, pass not a string but a function that does what you want it to do. You might naïvely do this:
setTimeout(function() {
this.fadeIn();
}, 50);
Unfortunately, while we now have lexical scoping for variables, this in JavaScript is dynamic; we have to work around that. Since we do have lexical scoping for variables, we can utilize that: [try it]
var me = this; // store the current value of this in a variable
var loopTimer = setTimeout(function() {
me.fadeIn();
}, 50);
After that's solved, you might want to look into:
Not using global variables to hold the fade state. Even after that fix, running two fade animations at once on different elements won't work as expected. (Try it.)
Only setting the timeout if you need to; right now, you always set it and then clear it if you don't need it. You might want to only set it if you need it in the first place.
First off, let me apologize if my question isn't worded correctly - I'm not a professional coder so my terminology might be weird. I hope my code isn't too embarrassing :(
I have a fade() method that fades an image in and out with a mouse rollover. I would like to use a wrapper object (I think this is the correct term), to hold the image element and a few required properties, but I don't know how to accomplish this. fade() is called from the HTML, and is designed to be dropped into a page without much additional setup (so that I can easily add new fading images to any HTML), just like this:
<div id="obj" onmouseover="fade('obj', 1);" onmouseout="fade('obj', 0);">
The fade(obj, flag) method starts a SetInterval that fades the image in, and when the pointer is moved away, the interval is cleared and a new SetInterval is created to fade the image out. In order to save the opacity state, I've added a few properties to the object: obj.opacity, obj.upTimer, and obj.dnTimer.
Everything works okay, but I don't like the idea of adding properties to HTML elements, because it might lead to a future situation where some other method overwrites those properties. Ideally, I think there should be a wrapper object involved, but I don't know how to accomplish this cleanly without adding code to create the object when the page loads. If anyone has any suggestions, I would greatly appreciate it!
Here's my fader method:
var DELTA = 0.05;
function fade(id, flag) {
var element = document.getElementById(id);
var setCmd = "newOpacity('" + id + "', " + flag + ")";
if (!element.upTimer) {
element.upTimer = "";
element.dnTimer = "";
}
if (flag) {
clearInterval(element.dnTimer);
element.upTimer = window.setInterval(setCmd, 10);
} else {
clearInterval(element.upTimer);
element.dnTimer = window.setInterval(setCmd, 10);
}
}
function newOpacity(id, flag) {
var element = document.getElementById(id);
if (!element.opacity) {
element.opacity = 0;
element.modifier = DELTA;
}
if (flag) {
clearInterval(element.dnTimer)
element.opacity += element.modifier;
element.modifier += DELTA; // element.modifier increases to speed up fade
if (element.opacity > 100) {
element.opacity = 100;
element.modifier = DELTA;
return;
}
element.opacity = Math.ceil(element.opacity);
} else {
clearInterval(element.upTimer)
element.opacity -= element.modifier;
element.modifier += DELTA; // element.modifier increases to speed up fade
if (element.opacity < 0) {
element.opacity = 0;
element.modifier = DELTA;
return;
}
element.opacity =
Math.floor(element.opacity);
}
setStyle(id);
}
function setStyle(id) {
var opacity = document.getElementById(id).opacity;
with (document.getElementById(id)) {
style.opacity = (opacity / 100);
style.MozOpacity = (opacity / 100);
style.KhtmlOpacity = (opacity / 100);
style.filter = "alpha(opacity=" + opacity + ")";
}
}
You are right, adding the handlers in your HTML is not good. You also loose the possible to have several handlers for event attached to one object.
Unfortunately Microsoft goes its own way regarding attaching event handlers. But you should be able to write a small wrapper function to take care of that.
For the details, I suggest you read quirksmode.org - Advanced event registration models.
An example for W3C compatible browsers (which IE is not): Instead of adding your event handler in the HTML, get a reference to the element and call addEventListener:
var obj = document.getElementById('obj');
obj.addEventListener('mouseover', function(event) {
fade(event.currentTarget, 1);
}, false);
obj.addEventListener('mouseout', function(event) {
fade(event.currentTarget, 0);
}, false);
As you can see I'm passing directly a reference to the object, so in you fade method you already have a reference to the object.
You could wrap this in a function that accepts an ID (or reference) and every time you want to attach an event handler to a certain element, you can just pass the ID (or reference) to this function.
If you want to make your code reusable, I suggest to put everything into an object, like this:
var Fader = (function() {
var DELTA = 0.05;
function newOpacity() {}
function setStyle() {}
return {
fade: function(...) {...},
init: function(element) {
var that = this;
element.addEventListener('mouseover', function(event) {
that.fade(event.currentTarget, 1);
}, false);
element.addEventListener('mouseout', function(event) {
that.fade(event.currentTarget, 0);
}, false);
}
};
}())
Using an object to hold your functions reduces pollution of the global namespace.
Then you could call it with:
Fader.init(document.getElementById('obj'));
Explanation of the above code:
We have an immediate function (function(){...}()) which means, the function gets defined and executed (()) in one go. This function returns an object (return {...};, {..} is the object literal notation) which has the properties init and fade. Both properties hold functions that have access to all the variables defined inside the immediate function (they are closures). That means they can access newOpacity and setStyle which are not accessible from the outside. The returned object is assigned to the Fader variable.
This doesn't directly answer your question but you could use the jQuery library. It's simple, all you have to do is add a script tag at the top:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js">
Then your div would look like:
<div id="obj" onmouseover="$('#obj').fadeIn()" onmouseout="$('#obj').fadeOut()">
jQuery will handle all the browser dependencies for you so you don't have to worry about things like differences between firefox and mozilla etc...
If you want to keep your HTML clean, you should consider using JQuery to set up the events.
Your HTML will look like this:-
<div id="obj">
Your JavaScript will look "something" like this:-
$(document).ready(function() {
$("#obj").mouseover(function() {
Page.fade(this, 1);
}).mouseout(function(){
Page.fade(this, 0);
});
});
var Page = new function () {
// private-scoped variable
var DELTA = 0.05;
// public-scoped function
this.fade = function(divObj, flag) {
...
};
// private-scoped function
var newOpacity = function (divObj, flag) {
...
};
// private-scoped function
var setStyle = function (divObj) {
...
};
};
I introduced some scoping concept in your Javascript to ensure you are not going to have function overriding problems.