PDA

View Full Version : A really problematic script.



inkosi
08-08-2007, 12:20 AM
Ok, I'm pretty new to javascript, and I've just been learning through tutorials.

With my limited knowledge I'm trying to put together a cross fade effect when switching DIV sections of a page. Everything was working fine until I tried to write the element of it which changes the opacity of the divs. Basically variables stop being defined.

The code is pretty short and simple(i knew it was too simple :( ), so here you go. I included the corresponding HTML.



<script type="text/javascript">

var ids=['features','cs','faq'];

function fire(id)
{
var myobj=document.getElementById(id).style;

for (var i=0;i<ids.length;i++)
{
if (ids[i]==id)
{
myobj.opacity=0;
myobj.display='block';
for(i=0;i<100;i++)
{
setTimeout('myobj.opacity=i/10', 8*i);
}
}

else
{
document.getElementById(ids[i]).style.display='none';
}
}
}
</script>

<div><input type='submit' Onclick='fire("faq")' value='faq'><input type='submit' Onclick='fire("features")' value='feat'><input type='submit' Onclick='fire("cs")' value='cs'></div>

<div id="faq" style="display:none;">
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</p>
</div>

<div id="cs" style="display:none;">
<p>
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
</p>
</div>


<div id="features">
<p>
Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.
</p>
</div>




The evil function itself:


for(i=0;i<100;i++)
{
setTimeout('myobj.opacity=i/10', 8*i);
}



The script returns the error "myobj" is not defined when it seems to work well enough for the preceding for and if functions. If I remove the 'var' before the myobj declaration(thus making it global, correct??), the script returns the error that "i" is undefined! That one is truly bewildering to me. I tried another change I've forgotten by now, but it returned the error "fire()" is not defined. It looks like no matter what I do some variable becomes undefined, or none are defined at all within the setTimeout.

I'm at a total loss, I've been reading about setTimeout and passing arguments/variables, but I can't find what I need. Can somebody provide some insight into this issue? I've been pulling my hair out for days trying to get this over with, and I would think that an experinced javascripter could write a working version of this in less than ten minutes.

Going completely bonkers over here. Save me!

O_o !!!!

jscheuer1
08-08-2007, 02:38 AM
You obviously have other problems, but you might actually be able to work those out for yourself once you get over this hurdle. The setTimeout() method will not remember what myobj and i are by the time it fires, unless you do it like so:


setTimeout(function(){myobj.opacity=i/10;}, 8*i);

inkosi
08-08-2007, 04:58 AM
Not surprising there are other errors to come since I'm very new, though I wish you wouldn't be vague about it. There's not a lot of help available where you can talk it out with some one, so working it all out with nothing but google can be stupidly time consuming for simple things like this(not even knowing what to search for besides the error name which is just too broad). When I do find somewhere that I can talk it out, mostly people seem pretty resistant, which begs the question of why they're there in the first place. I don't know what the deal is, and I'm undecided which is more of a challenge, figuring out javascript or figuring out their grumpiness, so you should know how relieving your response is. That short sentence is the only decent response regarding this issue from some one knowledgable of javascript in almost what would have been 3 days of trying.

Now here comes the part where I've learned to cringe, and maybe you will too.

I've haven't got the first clue why wrapping that statement in a function allows the timeout to remember the variables, and why it won't know them without it. So could you elaborate on that? Or at the very least point me the right direction for finding out the reasons behind it?

jscheuer1
08-08-2007, 01:15 PM
To have any hope of explaining this, I need to define scope. Scope (put in a simple way) can be seen as the level of nesting within a function that a variable is defined. If you have:


var a1='blah';

function test(){
var a1='bleh';
alert(a1);
}

test();

alert(a1);

It will fire two alerts, both of a1, but the first will be the nested (local) value of 'bleh' and the second will be the global value of 'blah'.

Now, on to the larger question about timeouts, I'm not really sure why it works. I think it is because a function is a constructor, it makes a new object in the scope in which it is created. But, a string is just a set of instructions - that is what the other method you were using is (denoted by the fact that it is enclosed in quotes) - if the objects referred to in it are not in the global scope at the time that it fires, it cannot find them.

About other errors in your code - there were none, at least not of the variety where the browser spits out an error. I assumed that there were probably errors in logic though because, when I ran the now working code, nothing faded in or out, and I thought that was the point, or part of the point of the code. I did play with the code a bit to see if I could get it to fade and concluded that the now working timeout was probably happening too frequently to have any noticeable effect upon the opacity of the element it was directed at. But, it may have referred to the wrong element, or in the wrong way. I figured that wasn't what you were asking about and that you might want to try getting that working for yourself, or that I had missed the point and that wasn't what you were trying to do. In any case, I was uncertain what exact result was expected. This makes it real hard to 'fix' anything.

inkosi
08-08-2007, 05:41 PM
Well, The foundation of the script works correctly, before I add the timeout, which leaves me at a loss because it's not related at all the preceding statements. The timeout throws a wrench in the whole thing, and actually seems to not work at all even when it can read the variables. When the div sections do switch, they show instantly. This changes when I remove the "8*i" millisecond expression, and it will then display a single delay for the entire loop of whatever literal value I give, when it should give a delay each time it iterates(so far as i understand, which obviously is incorrect).

I'll explain what I was thinking when i started writing this.

The foundation loops through my array "ids", and compares each position with the parameter passed by the onclick event, if the comparison doesn't evaluate to true, it sets display to "none", if it does of course it sets display to "block".



<script type="text/javascript">

var ids=['features','cs','faq'];

function fire(id)
{
var myobj=document.getElementById(id).style;

for (var i=0;i<ids.length;i++)
{
if (ids[i]==id)
{
myobj.display='block';
}

else
{
document.getElementById(ids[i]).style.display='none';
}
}
}
</script>

<div><input type='submit' Onclick='fire("faq")' value='faq'><input type='submit' Onclick='fire("features")' value='feat'><input type='submit' Onclick='fire("cs")' value='cs'></div>

<div id="faq" style="display:none;">
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</p>
</div>

<div id="cs" style="display:none;">
<p>
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
</p>
</div>


<div id="features">
<p>
Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.
</p>
</div>


If you want to try it out, it should work fine. That took me all of two minutes to figure out and write, I thought the rest was that simple too(and dangit according to the way W3schools describes things it should be).

What I needed to do then was make it invisible when its display property was set to block, to facilitate a fade in without a blink side effect(opacity 100&#37;-->0%-->100% is bad right?)

Then I needed to gradually increase the opacity from zero, and the only way I know to increment was with a loop, so of course I added a loop (http://www.w3schools.com/js/js_loop_for.asp) according to w3schools, but since the loop is instant as far as we're concerned, I added a timeout (http://www.w3schools.com/js/js_timing.asp) again according to its description at w3schools.

I had thought that the loop, according to the way W3schools defines things, would work like so:

----
1st iteration:

i=0

opacity set to (0/10)=0 and delay set to (8*0)=0 miliseconds.

2nd iteration:

i=1

opacity set to(1/10)=.1 delay set to (8*1)=8 milliseconds.
----

And so on! The only obvious error I noted was that to determine opacity "i" should be devided by 100 instead of 10, so that it evaluates to 1 on the final iteration, because the opacity property treats 1 as 100%. The total delay should have been just right as it's based off one I've seen.

I've looked at some other peoples cross faders, and they use a loop and a timeout as well! I just don't get what the difference is between what I've done, except that they always seem to join two strings together when defining the function that the delay is supposed to be applied to.

For example the cross fader that inspired my attempt uses:



setTimeout( 'setOpacity(' + (i / 10) + ')' , 8 * i );


where setOpacity is:



function setOpacity( value )
{
document.getElementById("styled_popup").style.opacity = value / 10;
}


It's completely maddening! And that's before I try to figure out why the timeout that can read the variables completely fudges the scripts ability to set display to none when the initial comparison evaluates to false! The timeout should change nothing regarding that! It's never run if it evaluates to false! ... AHHH!!

EDIT:

I searched for the original page where I first encountered the fade-in effect. You can view it here (http://dhtmlpopups.webarticles.org/fade-effects.php).

That fade effect is I'm trying to achieve whenever I switch a div.

inkosi
08-09-2007, 03:47 AM
Ok, here's an update. I've decided that putting my own spin on this cross fade just isn't within my skill yet, and it's just not worth the hassle. I need to get this done, I've spent way too much time on it.

So, I took the original cross fade code from the tutorial I linked to at the end of the above post, which is proven to work already, and am trying to squeeze the ability to read multiple elements in without making major changes. I've tried to pass "id" as a parameter between all the functions, but this new attempt returns the error "document.getElementById(id) has no properties". I guess this means it's not actually passing the variable, and it's looking for the literal "id" rather than the variable "id" with the id of the element contained within, so how do I do it properly?


The testing code:


<script type="text/javascript">
function setOpacity(id,value) {
document.getElementById(id).style.opacity = value / 10;
document.getElementById(id).style.filter = 'alpha(opacity=' + value * 10 + ')';
}

function fadeInMyPopup(id) {
for( var i = 0 ; i <= 100 ; i++ )
setTimeout( 'setOpacity(id,' + (i / 10) + ')' , 8 * i );
}

function fireMyPopup(id) {
setOpacity(id,0);
document.getElementById(id).style.display = "block";
fadeInMyPopup(id);
}

</script>

<input type="submit" value="test it" onclick="fireMyPopup(test)">
<div id="test" style="width:300px;"><p>dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf dfsdfdfsdfdfsdf dfsdfdfsdf </p></div>


It seems I have a real problem with things not existing when i refernce them... thoughts anybody? I even tried defining "id" as a global variable with the name of the element in it, but it still returned the error that there were no properties.

jscheuer1
08-09-2007, 03:52 AM
That's what I was saying, the fading component didn't seem to work. I have done quite a bit of work with fading text and images (I stay away from text these days though because IE 7 no longer supports it well enough for my tastes).

All of the fading operations I have either written or have worked on have this characteristic of being called as a separate function from the main function of a script unless all that they are doing is fading. The main reason for this is that, in order for fading to be noticeable, it must be incremental.

The easiest way to achieve that is to call a function that adds or subtracts the increment and checks to see whether or not the target opacity has been achieved. If not, it sets a timeout to call itself again and add another increment. If the target opacity has been reached, it stops.

Here is a unit that will do fading in or out and that is very easy to use. It is designed for images, but a division will work just as well, it just won't look as good as I think it should in IE 7, as IE 7 loses its anti-aliasing quality for text that is faded:

http://www.dynamicdrive.com/forums/showthread.php?t=22534

inkosi
08-09-2007, 03:59 AM
wow, awesome. I guess I should have looked around.

Thanks jscheuer1! Lifesaver!



I'm going to watch a javascript vid from lynda.com to try and get a grip on things. Hopefully by the end of it i'll have some clue as to what on earth is going on.