更新:
嗯,我花了一些时间,但我想我明白了。因为您制作了自己的“自定义”功能,所以实现起来有点困难。
直觉
为了解释我所做的一切,让我们从线性公式的绝对基础开始。
- 假设我们可以将您的自定义函数可视化为线性函数
f(x)=x
- 假设我们可以将缓动函数可视化为非线性函数。例如,假设我们将函数
g(x)=sin(x) 视为我们的缓动函数(这对应于缓动方法easeInSine)
让我们在二维图中考虑这些函数:
如您所见,我现在绘制了两个不同的函数。如果我们将这些函数可视化为 JavaScript 中的函数,那么它们就是我们可以独立调用的两个独立函数。例如:
function linear(x)
{
return x;
}
function sin(x)
{
return Math.sin(x);
}
现在我们可以将这两个函数用作 scrollTransition 但这不是我们想要的。
您问了具体问题:如何将非线性函数添加到我的自定义线性函数中?
让我们考虑一下我们的两个函数的一些可能性:
- 我们可以将它们加在一起
- 我们可以减去它们
- 我们无能为力
- 我们可以取平均值
- 等等……
让我们可视化第一点:
灰线表示原来的函数,蓝线是加在一起的函数。
对于第二点,我们会得到:
同样,灰线表示原始功能,蓝线是添加在一起的功能。 (嗯......在这种情况下:'相减')
代码
让我们考虑一下我们所知道的一切:
- 我们知道您的函数返回某个线性确定的值
- 我们知道缓动函数返回某个非线性确定值
所以就像图表一样,我们可以通过加减这些值来将函数加在一起。
为了使用您的函数完成此操作,我在您的函数中添加了两个参数:
-
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)
});
那么我在你的函数中所做的基本上归结为以下几点:
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
- 如果
c<0,则函数将返回负值
请注意,我们将不透明度定义为:
"opacity": 1-scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1)
因此,如果函数scrollTransition(0, 1, 0, 400, scrollTop, "easeInSine", 1) 返回负值,我们将在$(".element").css(...); 属性中出现错误,因此不会发生任何事情。
所以基本上缓动功能可以正常工作。只是如果您将它们应用于属性不透明度,我们有时会受到约束:
说到函数的行为,我们再考虑另一个:
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 中工作,请非常注意如何初始化文档。
例如,我发现使用缓动从-300 到200 的动画效果很好如果你把document width 比动画空间(空间动画需要正确执行)。
您可以看到从-300 到200 here 的动画工作代码。
注意我改变了文档宽度:
body {
height: 2000px;
width: 800px;
}
这应该可以回答您的问题。祝你好运!
更新 4
要缩短switch statement,您还可以使用:
var call = eval(easingEffect);
sum += call(null, scrollTop, startValue, endValue, distance);
正如您在THIS 示例中所见。这可能会为您节省一些手动工作。