Javascript-当惯性滚动算法接近顶部或底部时,如何减速?

我用javascript编写了一个用于鼠标滚轮的小惯性滚动算法.

它完全可以满足我的需求,但是缺少一部分,我似乎无法获得想要的行为.

当用户滚动到容器的末端时,无论是顶部还是底部.我想动力自然减速到停止.目前,无论其前进速度如何,只要碰到任一边缘,它都会立即停止.

我没有在此处发布大量代码,而是创建了一个小jsfiddle来说明:

https://jsfiddle.net/o8xLw68L/8/

这是我当前代码的简化版本.如果取消注释第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属性,因此不能始终正常工作,因为用户可能以较低的速度从容器中的下部向下滚动,但没有任何继续鼠标滚轮脉冲. (这很难说清楚,jsFiddle应该更清楚一点)

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

我很高兴将阻尼区域硬编码为内容顶部/底部的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()中则是为了避免数值误差累积而调用该函数.

可运行的示例:https://jsfiddle.net/c675bkn9/

上一篇:如何在Python中直观地表示多量子位系统?


下一篇:牛顿重力模拟