添加缓动到自定义动画功能

Dan*_*iel 2 jquery scroll easing

我创建了一个简单的函数,它根据当前滚动位置设置动画值.

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;
}
Run Code Online (Sandbox Code Playgroud)

您所要做的就是设置起始值和结束值,初始滚动位置,转换开始时和距离(以px为单位).因此,如果"initScroll"为500且距离为200,则转换结束于700px(scrollTop)."问题"是,它只是一个线性动画.我想要做的是在函数中添加第五个参数("缓动"),就像在jQuery .animation()函数中一样.

这些是我正在讨论的缓动函数(https://github.com/danro/jquery-easing/blob/master/jquery.easing.js),但我不确定,如何将它们添加到此函数中,所以我可以使用类似的东西

// in window scroll function
$el.css({
     "margin-top" : scrollTransition(-300, 500, 500, 1000, "easeOutBack")
});
Run Code Online (Sandbox Code Playgroud)

这样的事情是可能的还是我必须坚持线性过渡?

在此先感谢您的帮助和时间.

Jea*_*aul 10

更新:

好吧,我花了一些时间,但我想我明白了.因为你创建了自己的"自定义"功能,所以要完成它有点难度.

直觉

为了解释我所做的一切,让我们从线性公式的绝对基础开始.

  • 假设我们可以将您的自定义函数可视化为线性函数 f(x)=x
  • 假设我们可以将缓动函数可视化为非线性函数.例如,假设我们将函数g(x)=sin(x)视为缓动函数(这对应于缓动方法easeInSine)

让我们在二维图中考虑这些函数:

线性和非线性函数图

如您所见,我现在已经绘制了两个不同的功能.如果我们将这些函数可视化为JavaScript中的函数,那么它们是我们可以独立调用的两个独立函数.例如:

function linear(x)
{
   return x;
}

function sin(x)
{
   return Math.sin(x);
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以将这两个函数用作scrollTransition,但这不是我们想要的.

您问了具体问题:如何将非线性函数添加到我的自定义线性函数中?

因此,让我们考虑一下我们使用两个函数的一些可能性:

  1. 我们可以将它们加在一起
  2. 我们可以减去它们
  3. 我们无能为力
  4. 我们可以取平均值
  5. 等等...

让我们想象第一点:

在此输入图像描述

灰线表示原始功能,蓝线表示添加的功能.

对于第二点,我们会得到:

在此输入图像描述

同样,灰线表示原始功能,蓝线表示添加在一起的功能.(嗯......在这种情况下:'相互减去 ')

代码

让我们考虑一下我们所知道的一切:

  • 我们知道您的函数会返回一定的线性确定
  • 我们知道缓动函数会返回一定的非线性确定

因此,就像图表一样,我们可以添加和减去这些值以将功能添加到一起.

为了完成这个功能,我在你的函数中添加了两个参数:

  • easingEffect 这应该是您要从自定义函数添加(或减去)的非线性缓动效果的名称
  • plus它可以取值-1,0并且1将确定如何处理非线性效应:
    • -1 非线性函数将从您的自定义线性函数中减去
    • 0 不会使用非线性函数
    • 1 非线性函数将添加到您的自定义线性函数中

一个例子是:

$(".element").css({
    "opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1),
    "left": scrollTransition(0, 200, 0, 300, scrollTop, "easeOutBounce", 1)
});
Run Code Online (Sandbox Code Playgroud)

那么我在你的功能中做了什么基本上归结为以下几点:

sum += plus*easingEffect(null, scrollTop, startValue, endValue, distance);
Run Code Online (Sandbox Code Playgroud)

缓和效果由您自己提供的缓和js决定.

不幸的是,我最终做了大量的手动工作,因为对于你的自定义函数,我们需要缓动函数来返回值,不必调用jQuery.animate()函数.但是你不必再担心了:我已经完成了所有的工作,所以你现在可以坐下来玩设置,看看会发生什么.

你可以在这里找到(完全可实现的)解决方案:jsFiddle的代码.

你可以像一些很酷的东西这个.

实施细节

请注意以下事项:

因为opacity,将两个值一起添加是非常危险的,因为如果您尝试传递大于的参数,CSS属性将给出错误1.因此我会做以下事情:

 "opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1),
Run Code Online (Sandbox Code Playgroud)

所以我基本上颠倒了函数(我让函数'工作'从0到1而不是从1到0)然后我1-'the function'确保值永远不会超过1.请注意,这应该与减去或添加非线性函数.

此外,如果您在javascript中向下滚动,您将看到所有函数和巨大的switch语句:您必须将所有这些添加到最终的javascript文件中.

所以我建议你只是将整个javascript部分复制到你自己的项目中.

此外,jsFiddle应该是不言自明的.

祝你好运,我希望我回答你的问题!

更新2

demrks 做了以下事情:

sum = easeOutBounce(null, sum, startValue, endValue, distance);
Run Code Online (Sandbox Code Playgroud)

要获得更多关于将参数添加sum到缓动函数的直觉,请考虑以下图表:

在此输入图像描述

蓝线表示功能的结果.

所以你基本上做的是一个linear transformation缓动函数或linear mapping缓动函数.你可以在这里阅读更多相关信息.

但它基本上归结为您正在通过以下属性更改缓动函数的"形式":

  • 宽松动画"走向多快"
  • 当它开始/终止时

所以,如果这是你想要完成的,那么它完全没问题,你也可以在jsFiddle之外使用它.对我来说,它看起来有点混乱,因为你失去了对整个(联合函数)的精确动画的控制,因为你为参数增加了额外的复杂度.换句话说:编程变得更难,因为你不确切知道结果会是什么.

我希望能回答你最后的兴趣点:)

编程愉快!

更新3

demrks 问为什么宽松功能对其参数有限制.

让我们考虑一下这样一个easing功能:

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;
Run Code Online (Sandbox Code Playgroud)

只需通过查看函数我们得出以下结论:

  • 如果c=0,则函数将返回该值b
    • 如果b<0c=0,则函数将返回负值b
  • 如果c<0,则函数将返回负值

请注意,我们已将不透明度定义为:

"opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1)
Run Code Online (Sandbox Code Playgroud)

因此,如果函数scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1)返回负值,我们将在$(".element").css(...);属性中出错,因此不会发生任何事情.

所以基本上缓和函数工作正常.如果您将它们应用于属性不透明度,我们有时会有约束:

  • endValue > 0

谈到函数的行为,让我们考虑另一个:

 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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,对于这个,该函数高度依赖于变量d(距离).

因此,公式工作正常.

只是你必须小心你如何应用它们以及它们如何表现可能使事情变得复杂.

jsFiddle出了什么问题

关于在jsFiddle中工作,请非常小心如何初始化文档.

例如,我发现,从动画-300200与宽松正常工作如果你把document width比较大的动画空间(空间动画需要正确执行).

你可以-300200 这里看到动画的工作代码.

请注意,我更改了文档宽度:

body {
    height: 2000px;
    width: 800px;
}
Run Code Online (Sandbox Code Playgroud)

这应该回答你的问题.祝好运!

更新4

要缩短switch statement,您还可以使用:

var call = eval(easingEffect);
sum += call(null, scrollTop, startValue, endValue, distance);
Run Code Online (Sandbox Code Playgroud)

正如你在这个例子中看到的那样.这可能会为您节省一些手工工作.