我创建了一个简单的函数,该函数根据当前滚动位置为值设置动画。
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)。 “问题”是,它只是线性动画。我想做的就是像在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")
});
像这样根本不可能吗?还是我必须坚持线性过渡?
在此先感谢您的帮助和时间。
最佳答案
更新:
好吧,我花了一些时间,但我想我明白了。因为您创建了自己的“自定义”功能,所以很难完成。
直觉
为了解释我所做的一切,让我们从线性公式的绝对基础开始。
假设我们可以将您的自定义函数可视化为线性函数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
如果
b<0
和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(...);
属性中将出现错误,因此将不会发生任何事情。因此,基本上,缓动功能可以正常工作。只是将它们应用于属性不透明度,有时我们也会受到约束:
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;
}
请注意,对于此函数,该函数高度依赖于变量
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示例中看到的。这样可以省去一些手工工作。
关于jquery - 向自定义动画功能添加缓动,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17471537/