Javascript 当惯性滚动算法接近顶部或底部时,如何降低其速度?

Javascript 当惯性滚动算法接近顶部或底部时,如何降低其速度?,javascript,animation,physics,Javascript,Animation,Physics,我已经用javascript为鼠标滚轮编写了一个小型惯性滚动算法 它完美地满足了我的需求,但是缺少了一部分,我似乎无法获得想要的行为 当用户滚动到容器的末尾时,无论是顶部还是底部。我想让动力自然减速到停止。目前,它只是在击中任何一个边缘时立即停止,无论它当前的速度如何 我没有在这里发布大量代码,而是创建了一个小JSFIDLE来说明: 这是我当前代码的简化版本。如果您取消注释行111,您可以看到我正在寻找的行为,如果您从div的顶部向下滚动一点,然后快速地向上拨动鼠标滚轮。您将看到0位置的动量自

我已经用javascript为鼠标滚轮编写了一个小型惯性滚动算法

它完美地满足了我的需求,但是缺少了一部分,我似乎无法获得想要的行为

当用户滚动到容器的末尾时,无论是顶部还是底部。我想让动力自然减速到停止。目前,它只是在击中任何一个边缘时立即停止,无论它当前的速度如何

我没有在这里发布大量代码,而是创建了一个小JSFIDLE来说明:

这是我当前代码的简化版本。如果您取消注释行
111
,您可以看到我正在寻找的行为,如果您从
div
的顶部向下滚动一点,然后快速地向上拨动鼠标滚轮。您将看到
0
位置的动量自然变慢

Inertial.prototype.smoothWheel = function(amt) {
     this.targetY += amt;

     //uncomment this line to see the decelleration almost work against the top edge of the container
     //this.targetY = Math.max(0, this.targetY);

     this.vy += (this.targetY - this.oldY) * this.stepAmt;
     this.oldY = this.targetY;
}
这种方法的问题在于,当鼠标滚轮脉冲时,它只会抑制产生的
this.vy
属性,因此并不总是正常工作,因为用户可能会在容器中以更快的速度从较低的位置滚动,但没有任何持续的鼠标滚轮脉冲。(这很难说清楚,JSFIDLE应该让它更清楚)

当我们到达容器的顶部或底部时,解决方案可能需要以某种方式抑制
this.vy
属性,以便它以比自然
this.fliction
属性允许的更快的速度减速

我很高兴当您达到内容顶部/底部的
300px
时,缓冲区被硬编码。或者,容器高度的百分比也会起作用


任何帮助都将不胜感激

可以通过惯性运动(带摩擦)将速度衰减到足以接触上边缘或下边缘的值,与鼠标滚轮速度无关

假设在当前方向上,给定了行驶距离
x
。因此,需要求出速度v0,它足以通过惯性运动和摩擦移动该距离

当前的滚动动力学(
vy*=摩擦
)对应于层流流体流动。它可以写成微分方程:

dv = - (1 - friction) * v * dt; // velocity change dv in time interval dt
dv / v = - (1 - friction) * dt;
// integrating lhs and rhs with initial conditions (v = v0 at t = 0)
ln(v/v0) = - (1 - friction) * t;
v = v0 * exp(- (1 - friction) * t);
因此,速度随时间从
v0
指数衰减到零

行驶距离:

dx = v * dt = v0 * exp(- (1 - friction) * t) * dt;
// integrating, initial conditions x = 0 at t = 0
x = v0 / (1 - friction) * (1 - exp(- (1 - friction) * t))
因此,可以在无限时间内以起始速度
v0
行驶以下距离:

x = v0 / (1 - friction);
根据离边缘的距离,可以限制速度:

Inertial.prototype.boundVelocity = function () {
    var dist = 0;

    if (this.dir == 1)
        dist = this.scrollerPos;
    else if (this.dir == -1)
        dist = this.contentHeight - this.scrollerHeight - this.scrollerPos;

    var maxv = dist * (1 - this.friction) + 1;

    if (Math.abs(this.vy) > maxv) {
        console.log('reduce velocity ' + this.vy + ' to ' + (-maxv * this.dir) + ', dist: ' + dist);
        this.vy = -maxv * this.dir;
    }
}
对于
maxv
+1
)有一些小的非零最小值,以确保在出现离散化错误的情况下始终命中边缘。当速度可以在
smoothWheel()
中增加时,调用该函数,也可以在
render()
中调用该函数,以避免数值误差累积


可运行的示例:

多么奇妙的答案。简明易懂。非常感谢。