PDA

View Full Version : Javascript Fading with "Ease" like flash



myyoungfamily
11-28-2007, 05:43 PM
Hey Guys, (John)

I've been using flash actionscript and have learned how to fade and resize objects with an ease at the end. Meaning, the effect slows down as it approaches it's end.

I don't always use flash so I'd like to do the same thing with Javascript.

Currently I'm using this fade function:


//change the opacity for different browsers
function changeOpac(opacity, id) {
var object = document.getElementById(id).style;
object.opacity = (opacity / 100);
object.MozOpacity = (opacity / 100);
object.KhtmlOpacity = (opacity / 100);
object.filter = "alpha(opacity=" + opacity + ")";
}


With these variables:


var speed = 80; //set the time to complete the fade
var ease = 75; //set a value to ease the fade ending
var dur = Math.round(speed / 10);
var timer = 0;


It gets applied with a for loop like this:


//fade in new image
for(i = 0; i <= 100; i++) {
var o = i+((speed/ease)*dur);
setTimeout("changeOpac(" + o + ",'" + imageid + "')",(timer * dur));
timer++;
}


It works fine like this, but I think I'm missing something here


var o = i+((speed/ease)*dur);

to make the ease effect / slow down at the end

myyoungfamily
11-29-2007, 06:41 PM
The way this would work in flash actionscript would be:

end opacity = this

start opacity = this

new opacity = current opacity + ((end opacity - current opacity)*(speed))/(ease*(i/2));

function here to change the opacity to the value of "new opacity"


Basically...
You're determining the difference between the current and end opacity because that value should continually get smaller. So any multiples or divisions will also get smaller as the loop nears the end. Also the value of ease should be increasing to magnify the slowing effect.

I just don't know how to accomplish this in Javascript

jscheuer1
11-30-2007, 04:15 PM
I think you are introducing too many adjustable variables. I mean, if the amount of opacity change varies with each iteration, why does the frequency with which iterations are repeated also have to change? I may have misunderstood that part though. I based the following on assuming that we are increasing the object's opacity, and that we are going from 0 to 100, with an initial jump of 4 (that's what c+[o-c]/25 would be at first). So, it is a work in progress. The smoothOp function should really be a smoothUpOp function, a smoothDownOp function could be made, or code and an argument to determine the direction of opacity change could be used. All the numbers could be played with and/or made into arguments:


//change the opacity for different browsers
function changeOpac(o, id) {
if(o==0||o==100)
clearTimeout(changeOpac.t);
var object = document.getElementById(id).style;
if(changeOpac.m=='ie')
object.filter = "alpha(opacity=" + o + ")";
else if(changeOpac.m)
object[changeOpac.m] = (o / 100);
}
;(function(){
if(typeof changeOpac.m=='undefined'){
var e=document.documentElement, t=function(s){return typeof e.style[s]=='string';};
changeOpac.m=e.filters? 'ie' : t('opacity')? 'opacity' : t('MozOpacity')? 'MozOpacity' : t('KhtmlOpacity')? 'KhtmlOpacity' : null;
}})();

function smoothOp(o, id){
clearTimeout(changeOpac.t);
var m=changeOpac.m;
if(!m) return;
var obj = document.getElementById(id);
var c=m=='ie'? +obj.filters.alpha.opacity : obj.style[m]*100;
if(c<o-1){
changeOpac(Math.ceil(c+[o-c]/25), id)
changeOpac.t=setTimeout(function(){smoothOp(o, id);},50)
}
else changeOpac(o, id)
}

Notes: I didn't like your original changeOpac function because it changed the invalid styles for browsers, as well as the valid one(s), and did this each time it ran. The addition of an anonymous function to determine the valid type of opacity available, and if any make it a property of the changeOpac function available to any function, does so as the page loads, once.

myyoungfamily
11-30-2007, 07:28 PM
lol, that opacity function is something I found. I was wondering about all those changes. I guess I'll be kind enough not to give them credit here.

I'm gonna take a good look at your script and implement you stuff into what I've been working on. I've already worked out a function where you can set the in or the out of the fade.

Thanks,
Stay tuned...

myyoungfamily
11-30-2007, 09:28 PM
John,

Ok, I'll admit your coding level is far superior to mine, but here's what I've got working...

live:
www.justrpics.com/youngfamily & choose a gallery


javascript function:


//change the opacity for different browsers
function changeOpac(o, id) {
if(o==0||o==100)
clearTimeout(changeOpac.t);
var object = document.getElementById(id).style;
if(changeOpac.m=='ie')
object.filter = "alpha(opacity=" + o + ")";
else if(changeOpac.m)
object[changeOpac.m] = (o / 100);
}
;(function(){
if(typeof changeOpac.m=='undefined'){
var e=document.documentElement, t=function(s){return typeof e.style[s]=='string';};
changeOpac.m=e.filters? 'ie' : t('opacity')? 'opacity' : t('MozOpacity')? 'MozOpacity' : t('KhtmlOpacity')? 'KhtmlOpacity' : null;
}})();

function fadeImage(inORout, stOp, toOp, speed, ease, when, delay, dur, imageid){

// Definitions for function variables
// inORout - set the fade to in or out
// stOp - set the start opacity for the fade
// toOp - set the ending opacity
// speed - set speed for the fade to be completed 1=slow - 10=fast
// ease - set the level of the fade slowing 1=light - 5=strong
// when - set when the fade will begin to ease 1=sooner - 50=later
// delay - set a delay or pause for the fade 0=nodelay - 5=longdelay
// dur - set the duration of the fade 10=shorter - 20=longer


clearTimeout(changeOpac.t);
speed = speed*2;
var timer = 0;
o = stOp;


if(inORout == 'in'){
setTimeout(function(){
//fade in new image
for(i = stOp; i <= toOp; i++) {

if (o <= when){
o += (((toOp-o)/(25))*speed)/(ease/2);
}else{
o += (((toOp-o)/(100))*speed)/(ease);
}

changeOpac.t=setTimeout("changeOpac(" + o + ",'" + imageid + "')",(timer * dur));
timer++;
}
},(delay*100));
}

if(inORout == 'out'){
setTimeout(function(){
//fade in new image
for(i = stOp; i >= toOp; i--) {

if (o >= when){
o -= (((o-toOp)/(25))*speed)/(ease/2);
}else{
o -= (((o-toOp)/(100))*speed)/(ease);
}

changeOpac.t=setTimeout("changeOpac(" + o + ",'" + imageid + "')",(timer * dur));
timer++;
}
},(delay*100));
}

}



Let me know what you think and if you can make any improvements for me..

myyoungfamily
12-01-2007, 01:49 AM
Also...
One of the things I am noticing is that when multiple fades overlap each other (like on the image strip of my site) there is a tendency for the fades to get jumpy. I'm assuming they are interrupting each other or fighting for browser priority. Is this a flaw in the script or just a limitation of Javascript?

jscheuer1
12-01-2007, 07:24 AM
Now you are starting to look a bit like:

http://home.comcast.net/~jscheuer1/side/files/fade_advanced_preset_write.htm

Which has speed adjustment (interval and increment) but not 'slow down' or 'starting opacity' ones. Generally the starting opacity should be the image's current opacity, with thought given to that, rather than imposing it. That should eliminate some jumpiness. But the thing about jumpiness when one fade ends because another is starting is a potential problem. But it requires that someone select another image before the current fading in is complete. What should be happening, with your current setup, is that the 'top' image becomes the background and fully opaque, then the new top image starts to fade in.

The fading can be applied to multiple images, but with only two 'canvases' in your setup, one of which (the background) is always 100% opaque, there isn't much you can do to avoid this other than make another canvas. Needless to say that would get complicated. Or, you could force the user to wait until the current image has completed its fade in before allowing a new image to be selected.

myyoungfamily
12-01-2007, 08:05 AM
John,
I don't mind the look alike. I'll take that as a compliment...

I was unaware of how to get an items current opacity. I didn't know if you had to deal with all the various browser crap to do that. Is it possible to get the current opacity on the fly? For instance, each time through the for loop, I'd like to be retrieving the items opacity. That would make my formulas much simpler because that's kinda what I was trying to achieve with stOp - o. Instead of getting the current opacity I was getting the difference between the current and final opacity. In order to make the easing work, you need a variable that changes each time through.

Can you explain something to me?
What's the difference between o = something & o += something
I'm assuming that the latter is adding the current value of o+something to o. The same as o + o+something Is that right?

jscheuer1
12-01-2007, 08:21 AM
This line in my smoothOp function:


var c=m=='ie'? +obj.filters.alpha.opacity : obj.style[m]*100;

in conjunction with the other existing code from that post retrieves the current opacity as c.

You're right about:


x += 4;

Say x was 2, it would now be 6. However, don't confuse that with:


var c = . . . +obj.filters.alpha.opacity

a possible outcome of the conditional setting of c. There the plus sign merely guarantees that c will be a number, not a string. If you give a number that is a string a sign, it becomes a number, as long as it can (no letters or other non-numeric characters involved). The same thing happens when you multiply it, that's why I didn't have to 'sign' the other expression (obj.style[m]*100) in the conditional.

myyoungfamily
12-01-2007, 08:32 AM
thanks... that makes sence

I don't know how much you know about Flash actionscript but in my experience it didn't trip over itself when I had multiple calculations going at the same time.
Here's two examples:
www.wpprint.com - all the text flying in is done with code there's only two frames in this swf.
www.todayspixel.com/smilecenter - the slideshow allows me to fade and move at the same time and the buttons fade much slower onmouseout.

Is it your understanding that Javascript isn't designed to do this kind of thing?

jscheuer1
12-01-2007, 09:21 AM
Well, multi-threading isn't built into javascript. If you set one timeout while another is cued, things can get strange, and varies by browser. If you are using the same timeout for two things at once, it will almost always get messed up. Clearing one timeout before instituting another potentially conflicting one isn't always the best approach as far as the actual results go, but it is generally the safest.

And that's just timeouts. You cannot be fading the same image element both in and out at the same time without problems, even (or especially) if you are changing its source in the process.

All that said, if you keep things straight, there is usually a way to get the effect you are after, whatever it is. The only problem being that some browsers just can't keep up. FF is one of the worst at this, but they are constantly improving.

myyoungfamily
12-01-2007, 04:38 PM
hmm, when I started doing web design I was led to believe FF was the best. I'm running the newest Mac OS (Leopard) and I've given up on FF because it doesn't seem to be that compatible. What's your browser of choice?

Back on the topic of the day...
Would it be possible or a good practice to create a new timeout each time the function gets called. I don't think it would be hard to do, I could just attach a variable to the name and increment it each time through. Yes, No?

jscheuer1
12-02-2007, 06:29 AM
FF is one of the best browsers. But there are many things a browser is expected to do. Performing rapidly occurring sequential javascript actions so smoothly as to appear to be multi-threaded is only one of these things.

FF's strong points are security (though I recently saw some talk of that changing now that it is so widely used and therefore becoming a target of hackers), flexibility, and intuitive interface, perhaps more.

Personally, I like Opera.

As to your other idea, that could help in cases where the same time out being instituted over again is the problem, but not in cases where a cued timeout is causing a thread issue for a new timeout, and not in cases where accessing the same image element for style opacity changes more than once at a time is the issue.

I would favor an approach of not starting a new process that affects the image element until any similar previous process is completed.

Something like:


function smoothOp(o, id){
smoothOp.fading=true;
clearTimeout(changeOpac.t);
var m=changeOpac.m;
if(!m) return;
var obj = document.getElementById(id);
var c=m=='ie'? +obj.filters.alpha.opacity : obj.style[m]*100;
if(c<o-1){
changeOpac(Math.ceil(c+[o-c]/25), id)
changeOpac.t=setTimeout(function(){smoothOp(o, id);},50)
}
else {changeOpac(o, id), smoothOp.fading=false};
}

The smoothOp.fading property is available to all functions, so other processes (such as even allowing the script to change to another image while one is still fading in) could be suspended, or temporarily suspended on the basis of its existence, or value if it exists.

myyoungfamily
12-03-2007, 05:43 AM
So, without a value of "true", would this prevent the function from operating period or just not on a single object? What I'm getting at is that the function being run simultaneously isn't really creating a problem, it's when the function gets called again on the same object before the first call completes.

If you go here:
http://www.justrpics.com/youngfamily/index.php?gallery=Jonathan%27s+Favorite+Cars
and try moving you mouse quickly back and forth on a couple of the images on the image strip at the bottom. You'll probably see a little flicker. I'm assuming this is because the previous function hasn't completed.

here's my current code:


function fadeImage(inORout, stOp, toOp, speed, ease, when, delay, dur, imageid){

// Definitions for function variables
// inORout - set the fade to in or out
// stOp - set the start opacity for the fade
// toOp - set the ending opacity
// speed - set speed for the fade to be completed 1=slow - 10=fast
// ease - set the level of the fade slowing 1=light - 5=strong
// when - set when the fade will begin to ease 1=sooner - 50=later
// delay - set a delay or pause for the fade 0=nodelay - 5=longdelay
// dur - set the duration of the fade 10=shorter - 20=longer


clearTimeout(changeOpac.t);

var m=changeOpac.m;
if(!m) return;
var obj = document.getElementById(imageid);
var c=m=='ie'? +obj.filters.alpha.opacity : obj.style[m]*100;

speed = speed*2;
var timer = 0;
o = stOp;


if(inORout == 'in'){
setTimeout(function(){
//fade in new image
for(i = stOp; i <= toOp; i++) {

if (o <= when){
o += (((toOp-o)/(25))*speed)/(ease/2);
}else{
o += (((toOp-o)/(100))*speed)/(ease);
}

changeOpac.t=setTimeout("changeOpac(" + o + ",'" + imageid + "')",(timer * dur));
timer++;
}
},(delay*100));
}

if(inORout == 'out'){
setTimeout(function(){
//fade in new image
for(i = stOp; i >= toOp; i--) {

if (o >= when){
o -= (((o-toOp)/(25))*speed)/(ease/2);
}else{
o -= (((o-toOp)/(100))*speed)/(ease);
}

changeOpac.t=setTimeout("changeOpac(" + o + ",'" + imageid + "')",(timer * dur));
timer++;
}
},(delay*100));
}

}


Is there anything I can do to remedy this or am I just being anal?

jscheuer1
12-03-2007, 07:40 AM
You are being a bit anal, but it probably can be worked out one way or another. Setting the flag is just half (if that) the battle in this case. Use of it someplace(s) in the chain of events must be made for it to have any value. A flag may not even be the best approach for what you are talking about. Perhaps just a delay with cancellation if the mouse moves away too soon.

It is unclear to me what functions you are using for what though, if I get some time to look into it I will.

I would have (as mentioned earlier) used two functions. One based on my smoothOp, just renaming it to smoothUpOp (remember to rename all internal and external references to it as well), and another like it, with a few changes:


function smoothDownOp(o, id){
var m=changeOpac.m;
if(!m) return;
var obj = document.getElementById(id);
var c=m=='ie'? +obj.filters.alpha.opacity : obj.style[m]*100;
if(c>o+1){
changeOpac(Math.floor(c-[c-o]/25), id)
setTimeout(function(){smoothDownOp(o, id);},50)
}
else changeOpac(o, id)
}

My thinking here being that it is best to keep things as simple as possible, at least until the overall process is ironed out.

myyoungfamily
12-03-2007, 03:00 PM
lol, thanks for the honesty...

I'll try separating my up and down fades