数学的 H5 应用:拖动阻尼

我们在 ios 应用(特别是浏览器)中经常看到这样的 “橡皮筋” 效果:当页面滚动到边缘时若继续拖动,其位移变化量和拖动距离成反比;就像橡皮筋一样,拉动的距离越大则继续发生形变的难度越大,也就是所受到的阻尼力越大:

接下来我会基于 vue 和 移动端 Touch 事件实现这样的 “橡皮筋” 效果。

阻尼曲线

以横坐标为 拖动距离,纵坐标为 实际位移 建立坐标轴。如此,符合 “橡皮筋” 效果的数学函数模型并不难找,我在这里提供两个基础函数模型,对数函数幂函数

各自对应的函数图像趋势大致如下:

数学的 H5 应用:拖动阻尼_第1张图片

为了满足 H5 向下拖动的实际场景,我们需要对函数体进行微调。此外,还需要设置一个 容器高度值 作为被拖动元素的位移最大值的参考。那么函数调整为:

不妨设,绘制函数图像:

数学的 H5 应用:拖动阻尼_第2张图片

可见曲线差距不大,我们选择基于幂函数来制作 demo:

数学的 H5 应用:拖动阻尼_第3张图片

如 gif 图所示,在刚开始往下拖动的阶段,元素发生了较大幅度的跳动,这是由于该阶段的函数值,也就是元素的位移甚至比手指拖动的距离还要大,从而产生不合理的 “跳动”。

使,借助 WolframAlpha计算引擎 求解得 ,因此在的区间内,都是比大的。

换句话说,我们需要 降低函数图像曲线首段的陡度,使元素随手指拖动的变化幅度更加平缓。由于数学水平有限,我在这里仅提供一种比较麻烦的方式 —— 分段线性函数

以 ios 原生的 “橡皮筋” 效果为参考,经过大量的测试,我刻画出了一套较为合理的分段线性函数:

同样地使,绘制函数图像:

数学的 H5 应用:拖动阻尼_第4张图片

demo 实际效果:

数学的 H5 应用:拖动阻尼_第5张图片

函数效率

对于 JS 引擎来说,简单的线性四则运算要比复杂的幂函数、对数函数等运算耗时更短,性能损耗更低。但是在拖动阻尼的场景下,由于实现分段线性函数需要利用循环和声明更多的临时变量,代码性能往往比单单调用 Math.pow()Math.log() 方法要低很多。

我对上述中的三种函数模型都分别提供了代码实现及 测试用例:

数学的 H5 应用:拖动阻尼_第6张图片
linear: 分段线性函数,log: 对数函数,pow: 幂函数

性能差距惨不忍睹…

那么,我们能否找出一个合适的数学表达式,既能符合或近似于上面提出的分段线性函数的图像曲线,又能降低性能损耗呢?

曲线拟合

在分段线性函数的图像上取样关键点:

x 0 500 1000 1500 2500 6000 8000 10000 12000
y 0 90 160 210 260 347.5 357.5 367.5 377.5

通过 在线曲线拟合神器,使用 四参数方程模型 拟合曲线,得

如果有条件的话,这里建议使用 matlab 做曲线拟合。

舍去,其他常数四舍五入,并化简表达式,得

通过 Wolfram Cloud平台 绘制该表达式在范围的图像曲线:

数学的 H5 应用:拖动阻尼_第7张图片

Prefect!

然而这个表达式是在的条件下的,我们需要还原值,最终表达式为

瞧瞧 性能表现 :

数学的 H5 应用:拖动阻尼_第8张图片
curve: 拟合函数,linear: 分段线性函数,log: 对数函数,pow: 幂函数

多点触控

在元素拖动的交互场景里,实现多点触控其实非常简单,主要围绕 TouchEvent 事件中的

  • TouchEvent.touches 对象
    包含所有当前接触触摸平面的触点的 Touch 对象;
  • TouchEvent.changedTouches 对象
    包含从上一次触摸事件到此次事件过程中状态发生改变的触点的 Touch 对象。譬如某个触点从触摸平面中释放时,touchend 事件中的 changedTouches 对象就会包含该触点;

处理流程如下:

  1. 当有新触点接触平面时,touchstart 事件被触发,以 Touch.identifierid 缓存触点起始坐标;
  2. 触点移动时,touchmove 事件被触发,根据 id 计算各个触点当前位置与起始坐标的偏移值并求和;
  3. 当有触点从平面中释放时,touchend 事件被触发,记录该触点所“贡献”的偏移值,若所有触点都已释放则重置;

代码实现

提供的 demo 仅支持在移动端预览:https://codepen.io/JunreyCen/pen/LoryNp


  
    
    
  
  
    

Reference

  • MDN: TouchEvent

你可能感兴趣的:(数学的 H5 应用:拖动阻尼)