【问题标题】:Add easing to custom animation function为自定义动画功能添加缓动
【发布时间】:2013-07-02 12:47:27
【问题描述】:

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

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;
}

您所要做的就是设置开始值和结束值、初始滚动位置、过渡开始时间和距离(以 px 为单位)。因此,如果“initScroll”为 500,距离为 200,则过渡在 700px (scrollTop) 处结束。 “问题”是,它只是一个线性动画。我想要做的是向函数添加第五个参数(“easing”),就像你在 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")
});

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

提前感谢您的帮助和时间。

【问题讨论】:

    标签: jquery scroll easing


    【解决方案1】:

    更新:

    嗯,我花了一些时间,但我想我明白了。因为您制作了自己的“自定义”功能,所以实现起来有点困难。

    直觉

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

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

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

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

    function linear(x)
    {
       return x;
    }
    
    function sin(x)
    {
       return Math.sin(x);
    }
    

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

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

    让我们考虑一下我们的两个函数的一些可能性:

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

    让我们可视化第一点:

    灰线表示原来的函数,蓝线是加在一起的函数。

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

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

    代码

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

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

    所以就像图表一样,我们可以通过加减这些值来将函数加在一起。

    为了使用您的函数完成此操作,我在您的函数中添加了两个参数:

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

    这方面的一个例子是:

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

    那么我在你的函数中所做的基本上归结为以下几点:

    sum += plus*easingEffect(null, scrollTop, startValue, endValue, distance);
    

    缓动效果由您自己提供的easing js 决定。

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

    您可以在此处找到(完全可实施的)解决方案:the code at jsFiddle

    你可以做一些很酷的事情,比如this

    实施细节

    注意以下事项:

    对于opacity,将两个值相加是非常危险的,因为如果您尝试传递大于1 的参数,CSS 属性会出错。因此,我执行以下操作:

     "opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1),
    

    所以我基本上反转了函数(我让函数“工作”从 0 到 1 而不是从 1 到 0)然后我执行1-'the function' 以确保值永远不会超过 1。请注意,这应该是与非线性函数相减或相加一致。

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

    所以我的建议是您只需将整个 javascript 部分复制到您自己的项目中即可。

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

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

    更新 2

    demrks 做了以下事情:

    sum = easeOutBounce(null, sum, startValue, endValue, distance);
    

    为了更直观地了解将参数 sum 添加到缓动函数中,请考虑下图:

    蓝线表示函数的结果。

    因此,您基本上在做的事情称为缓动函数的linear transformation 或缓动函数的linear mapping。你可以阅读更多关于这个here的信息。

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

    • 缓动动画“运行”的速度有多快
    • 什么时候开始/结束

    因此,如果这是您想要完成的,那么它非常好,您也可以在 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;
    

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

    • 如果c=0,那么函数将返回值b
      • 如果b&lt;0c=0,那么函数将返回负值b
    • 如果c&lt;0,则函数将返回负值

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

    "opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1)
    

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

    所以基本上缓动功能可以正常工作。只是如果您将它们应用于属性不透明度,我们有时会受到约束:

    • endValue &gt; 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;
    }
    

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

    因此,公式可以正常工作。

    只是您必须小心如何应用它们以及如何它们的行为可能会使事情变得复杂。

    jsFiddle 有什么问题

    关于在 jsFiddle 中工作,请非常注意如何初始化文档。

    例如,我发现使用缓动从-300200 的动画效果很好如果你把document width动画空间(空间动画需要正确执行)。

    您可以看到从-300200 here 的动画工作代码。

    注意我改变了文档宽度:

    body {
        height: 2000px;
        width: 800px;
    }
    

    这应该可以回答您的问题。祝你好运!

    更新 4

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

    var call = eval(easingEffect);
    sum += call(null, scrollTop, startValue, endValue, distance);
    

    正如您在THIS 示例中所见。这可能会为您节省一些手动工作。

    【讨论】:

    • 感谢您的回答,但我已经知道如何通过 jQuery animate() 函数使用缓动。对于我的动画,我没有使用 animate() 或类似的东西,如fadeIn()、fadeOut,但我使用我的自定义函数根据滚动位置为元素设置动画。你可以在上面看到我的自定义函数,我称之为“scrollTransition”。目前这是一个线性过渡,但我希望通过 jQuery 缓动(如所述的第五个参数)或至少使用某种缓动来缓和它。但是我数学不是很好,所以我不知道如何添加缓动。
    • 如果可以的话,我会至少再投票 10 次!非常感谢,这正是我想要的。即使我的数学技能不好,我也理解它的完成方式:) 你应该考虑成为一名老师或其他什么东西。我不确定这是否也能正常工作,但我用一些小改动更新了你的小提琴jsfiddle.net/5pYMh/3 而不是将缓动添加到线性函数(如你所述)我使用“sum”作为缓动函数的参数.除了我在小提琴中所做的之外,我的更改可能不适用于动画,必须对其进行测试:)
    • @demrks:感谢您的热情;这是对我付出的工作的完美回报。​​谢谢你的夸奖,我不考虑当老师,但也许当我老了无聊的时候,我应该考虑一下哈哈。要回答您的最后一个兴趣点:检查上面的新更新。祝你好运!
    • 谢谢,这也完全回答了我的最后一点,你说得对,我对小提琴的编辑可能使猜测整个函数的结果变得更加困难。我现在可以开始在我的最终项目中实现你的缓动了 :) 再次感谢!
    • 谢谢,我刚刚意识到它也适用于负值,但起始值需要小于结束值。如果我想从 300 动画到 -200 它不起作用。 Fiddle 现在对我不起作用(服务器停机?),所以我无法向您展示我的示例代码 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    相关资源
    最近更新 更多