Question

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.

Was it helpful?

Solution

Update:

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.

The Intuition

To explain everything I did, let's start with the absolute basis of linear formulas.

  • Let's say we can visualise your custom function as a linear function f(x)=x
  • Let's say we can visualise the easing functions as a nonlinear function. For example let's say we consider the function 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:

plot of linear and nonlinear function

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:

  1. we can add them together
  2. we can substract them
  3. we can do nothing
  4. we can take the average
  5. etc...

Let's visualise the first point:

enter image description here

The grey lines indicate the original functions and the blue line are the functions added together.

For the second point we would get:

enter image description here

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')

The Code

Let's consider everything we know:

  • We know that your function gives back a certain linear-determined value
  • We know that the easing functions give back a certain nonlinear-determined value

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 function
  • plus 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 function
    • 0 the nonlinear function will not be used
    • 1 the nonlinear function will be added to your custom linear function

An 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.

Details for Implementation

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!

UPDATE 2

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:

enter image description here

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:

  • How fast the easing animation 'goes'
  • When it starts/ terminates

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!

UPDATE 3

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:

  • If c=0, then the function will return the value b
    • If b<0 and c=0, then the function will return the negative value b
  • If c<0, then the function will return a negative value

Note 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.

What's wrong with jsFiddle

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!

Update 4

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top