i created a simple function, which animates values based on the current scroll position.
function scrollTransition(startValue, endValue, initScroll, distance, scrollTop) {
var
min = Math.min,
max = Math.max,
sum;
if(startValue > endValue) {
sum = min(max((endValue - startValue) / distance * (scrollTop - initScroll) + startValue, endValue), startValue);
} else {
sum = min(max((endValue - startValue) / distance * (scrollTop - initScroll) + startValue, startValue), endValue);
}
return sum;
}
All you have to do is setting a start value and an end value, the initial scroll position, when the transition starts and a distance (in px). So if "initScroll" is 500 and distance is 200, the transition ends at 700px (scrollTop). The "problem" is, that it's just a linear animation. What i am trying to do is adding a fifth parameter ("easing") to the function, like you do in the jQuery .animation() function.
These are the easing functions i am talking about (https://github.com/danro/jquery-easing/blob/master/jquery.easing.js), but i am not sure, how to add them to this function, so i can use something like
// in window scroll function
$el.css({
"margin-top" : scrollTransition(-300, 500, 500, 1000, "easeOutBack")
});
Is something like this possible at all or do i have to stick to a linear transition?
Thanks in advance for your help and time.
Well, it took me some time but I think I got it. Because you made your own 'custom' function, it was a bit harder to accomplish.
To explain everything I did, let's start with the absolute basis of linear formulas.
f(x)=x
g(x)=sin(x)
as our easing function (this corresponds to the easing method easeInSine
)Let's consider these functions in a two dimensional plot:
As you can see, I have now drawn two different functions. If we would visualise these functions as our functions in JavaScript, then they are two seperate functions we can call independently. For example:
function linear(x)
{
return x;
}
function sin(x)
{
return Math.sin(x);
}
Now we can use both these functions as a scrollTransition but that's not what we want.
You asked the specific question: How to add the nonlinear function to my custom linear function?
So let's consider some of the possibilities we have with our two functions:
Let's visualise the first point:
The grey lines indicate the original functions and the blue line are the functions added together.
For the second point we would get:
Where again, the grey lines indicate the original functions and the blue line are the functions added together. (well... in this case: 'subtracted from each other')
Let's consider everything we know:
So just like with the graphs, we can add and substract these values to add the functions together.
To accomplish this with your function, I added two parameters to your function:
easingEffect
which should be the name of the nonlinear easing effect you want to add (or substract) from your custom functionplus
which can take on values -1
, 0
and 1
and which will determine how the nonlinear effect is handled:
-1
the nonlinear function will be substracted from your custom linear function0
the nonlinear function will not be used1
the nonlinear function will be added to your custom linear functionAn example of this would be:
$(".element").css({
"opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1),
"left": scrollTransition(0, 200, 0, 300, scrollTop, "easeOutBounce", 1)
});
Then what I did within your function basically comes down to the following:
sum += plus*easingEffect(null, scrollTop, startValue, endValue, distance);
Where the easing effect is determined by the easing js you supplied yourself.
Unfortunately, I ended up doing a lot of manual work because for your custom function we need the easing functions to return values without having to call the jQuery.animate()
function. But you don't have to worry about that anymore: I did all the work already so you can now just sitback and play around with the settings to see what happens.
You can find the (fully implementable) solution here: the code at jsFiddle.
You can do some cool things like this.
Beware of the following things:
For opacity
, adding two values together is quite dangerous because the CSS property will give an error if you're trying to pass an argument that's bigger than 1
. Therefore I do the following:
"opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1),
So I basically reverse the function (I let the function 'work' from 0 to 1 instead of from 1 to 0) and then I do 1-'the function'
to make sure the values are never above 1. Note that this should be coherent with substracting or adding the nonlinear function.
Also, if you scroll down in the javascript, you will see all the functions and the huge switch statement: you must add all of these to your final javascript file.
So what I suggest is that you just copy the whole javascript section to your own project.
Furthermore, the jsFiddle should be self-explanatory.
Good luck and I hope I answered your question!
demrks
did the following:
sum = easeOutBounce(null, sum, startValue, endValue, distance);
To gain more intuition about adding the parameter sum
to the easing functions, consider the following graph:
Where the blue line indicates the outcome of your function.
So what your are basically doing is called a linear transformation
of the easing function or linear mapping
the easing function. You can read more about this here.
But what it basically comes down to is that you are changing 'the form' of the easing function by the following properties:
So if that is what you want to accomplish, then its perfectly fine and you can use it outside of jsFiddle as well. To me it seems a bit messy, though, because you lose control over the exact animation of the whole (the joint function) since you added an extra level of complexity to the parameters. Or in other words: the programming becomes harder because you don't know exactly what the outcome will be.
I hope that answers your last point of interest as well :)
Happy programming!
demrks
asked why the easing functions have limitations on their parameters.
Let's consider such a easing
function:
function easeOutBounce(x, t, b, c, d) {
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
} else {
return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
}
}
//x = null;
//t = currentTime;
//b = begin;
//c = end;
//d = distance;
Simply by looking at the function we come to the following conclusions:
c=0
, then the function will return the value b
b<0
and c=0
, then the function will return the negative value b
c<0
, then the function will return a negative valueNote that we have defined opacity as:
"opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1)
Hence if the function scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1)
returns a negative value, we will have an error in the $(".element").css(...);
property and so nothing will happen.
So basically the easing functions work fine. Just if you apply them to the property opacity we sometimes have the constraint:
endValue > 0
Talking about the behaviour of functions, let's consider another one:
function easeInOutElastic(x, t, b, c, d) {
var s=1.70158;var p=0;var a=c;
if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
if (a < Math.abs(c)) { a=c; var s=p/4; }
else var s = p/(2*Math.PI) * Math.asin (c/a);
if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
}
Note that for this one, the function is highly dependent on the variable d
(distance).
Hence, the formulas work fine.
It's just that you have to be careful for how you apply them and how they behave that might make things complicated.
Regarding working in jsFiddle, be very careful of how you initialise your document.
For example I found that animating from -300
to 200
with easing works fine IF you put the document width
larger than the animation space (space that the animation needs to execute properly).
You can see a working code of animating from -300
to 200
here.
Note that I changed the document width:
body {
height: 2000px;
width: 800px;
}
That should answer your question. Good luck!
To shorten the switch statement
, you can also use:
var call = eval(easingEffect);
sum += call(null, scrollTop, startValue, endValue, distance);
As you can see in THIS example. That might save you some manual work.