HTML5 中手势原理分析与数学知识的实践

实现原理

众所周知,所有的手势都是基于浏览器原生事件touchstart, touchmove, touchend, touchcancel进行的上层封装,因此封装的思路是通过一个个相互独立的事件回调仓库handleBus,然后在原生touch事件中符合条件的时机触发并传出计算后的参数值,完成手势的操作。实现原理较为简单清晰,先不急,我们先来理清一些使用到的数学概念并结合代码,将数学运用到实际问题中,数学部分可能会比较枯燥,但希望大家坚持读完,相信会收益良多。

基础数学知识函数

我们常见的坐标系属于线性空间,或称向量空间(Vector Space)。这个空间是一个由点(Point) 和 向量(Vector) 所组成集合;

点(Point)

可以理解为我们的坐标点,例如原点O(0,0),A(-1,2),通过原生事件对象的touches可以获取触摸点的坐标,参数index代表第几接触点;

向量(Vector)

是坐标系中一种 既有大小也有方向的线段,例如由原点O(0,0)指向点A(1,1)的箭头线段,称为向量a,则a=(1-0,1-0)=(1,1);

 

如下图所示,其中i与j向量称为该坐标系的单位向量,也称为基向量,我们常见的坐标系单位为1,即i=(1,0);j=(0,1);

 

获取向量的函数:

 

向量模

代表 向量的长度,记为|a|,是一个标量,只有大小,没有方向;

几何意义代表的是以x,y为直角边的直角三角形的斜边,通过勾股定理进行计算;

 

getLength

函数:

向量的数量积

向量同样也具有可以运算的属性,它可以进行加、减、乘、数量积和向量积等运算,接下来就介绍下我们使用到的数量积这个概念,也称为点积,被定义为公式:当a=(x1,y1),b=(x2,y2),则a·b=|a|·|b|·cosθ=x1·x2+y1·y2;

共线定理

共线,即两个向量处于 平行 的状态,当a=(x1,y1),b=(x2,y2),则存在唯一的一个实数λ,使得

a=λb,代入坐标点后,可以得到 x1·y2= y1·x2;

因此当x1·y2-x2·y1>0时,既斜率 ka > kb ,所以此时b向量相对于a向量是属于顺时针旋转,反之,则为逆时针;

旋转角度

通过数量积公式我们可以推到求出两个向量的夹角:

cosθ=(x1·x2+y1·y2)/(|a|·|b|);

 

然后通过共线定理我们可以判断出旋转的方向,函数定义为:

矩阵与变换

由于空间最本质的特征就是其可以容纳运动,因此在线性空间中,我们用向量来刻画对象,而矩阵便是用来描述对象的运动;

而矩阵是如何描述运动的呢?

我们知道,通过一个坐标系基向量便可以确定一个向量,例如 

a=(-1,2)

,我们通常约定的基向量是 i = (1,0) 与 j = (0,1); 因此:a = -1i + 2j = -1(1,0) + 2(0,1) = (-1+0,0+2) = (-1,2);

而矩阵变换的,其实便是通过矩阵转换了基向量,从而完成了向量的变换;

例如上面的栗子,把a向量通过矩阵(1,2,3,0)进行变换,此时基向量i由 (1,0)变换成(1,-2)与j由(0,1)变换成(3,0),沿用上面的推导,则a = -1i + 2j = -1(-1,2) + 2(3,0) = (5,-2);

如下图所示:

A图表示变换之前的坐标系,此时a=(-1,2),通过矩阵变换后,基向量i,j的变换引起了坐标系的变换,变成了下图B,因此a向量由(-1,2)变换成了(5,-2);

其实向量与坐标系的关联不变(

a = -1i+2j),是基向量引起坐标系变化,然后坐标系沿用关联导致了向量的变化;

结合代码

其实CSS的transform等变换便是通过矩阵进行的,我们平时所写的translate/rotate等语法类似于一种封装好的语法糖,便于快捷使用,而在底层都会被转换成矩阵的形式。例如transform:translate(-30px,-30px)编译后会被转换成transform : matrix(1,0,0,1,30,30);

 

通常在二维坐标系中,只需要 2X2 的矩阵便足以描述所有的变换了, 但由于CSS是处于3D环境中的,因此CSS中使用的是 3X3 的矩阵,表示为:

其中第三行的0,0,1代表的就是z轴的默认参数。这个矩阵中,(a,b) 即为坐标轴的 i基,而(c,d)既为j基,e为x轴的偏移量,f为y轴的偏移量;因此上栗便很好理解,translate并没有导致i,j基改变,只是发生了偏移,因此translate(-30px,-30px) ==> matrix(1,0,0,1,30,30)~

 

所有的

transform

语句,都会发生对应的转换,如下:

  • // 发生偏移,但基向量不变;

transform:translate(x,y) ==> transform:matrix(1,0,0,1,x,y)

  • // 基向量旋转;

transform:rotate(θdeg)==>transform:matrix(cos(θ·π/180),sin(θ·π/180),sin(θ·π/180),cos(θ·π/180),

0,0)

  • // 基向量放大且方向不变;

transform:scale(s) ==> transform:matrix(s,0,0,s,0,0)

 

translate/rotate/scale等语法十分强大,让我们的代码更为可读且方便书写,但是matrix有着更强大的转换特性,通过matrix,可以发生任何方式的变换,例如我们常见的镜像对称,transform:matrix(-1,0,0,1,0,0);

MatrixTo

然而matrix虽然强大,但可读性却不好,而且我们的写入是通过translate/rotate/scale的属性,然而通过getComputedStyle读取到的 transform却是matrix:

transform:matrix(1.41421, 1.41421, -1.41421, 1.41421, -50, -50);

请问这个元素发生了怎么样的变化?。。这就一脸懵逼了。-_-|||因此,我们必须要有个方法,来将matrix翻译成我们更为熟悉的translate/rotate/scale方式,在理解了其原理后,我们便可以着手开始表演咯~

我们知道,前4个参数会同时受到rotate和scale的影响,具有两个变量,因此需要通过前两个参数根据上面的转换方式列出两个不等式:

cos(θ·π/180)*s=1.41421;

sin(θ·π/180)*s=1.41421;

singleRotate(单指旋转)

结合单指缩放和双指旋转,可以很简单的知道 θ便是我们需要的旋转角度;

// 获取初始向量与实时向量

let rotateV1 = getVector(startPoint, singleBasePoint);

let rotateV2 = getVector(curPoint, singleBasePoint);

// 通过 getAngle 获取旋转角度并触发事件;

this._eventFire('singleRotate', {

    delta: {

        rotate: getAngle(rotateV1, rotateV2),

    },

    origin: ev,

});

 

运动增量

由于touchmove事件是个高频率的实时触发事件,一个拖动操作,其实触发了N次的touchmove事件,因此计算出来的值只是一种增量,即代表的是一次 touchmove事件增加的值,只代表一段很小的值,并不是最终的结果值,因此需要由mtouch.js外部维护一个位置数据,类似于:

//    真实位置数据;

let dragTrans = {x = 0,y = 0};

// 累加上 mtouch 所传递出的增量 deltaX 与 deltaY;

dragTrans.x += ev.delta.deltaX;

dragTrans.y += ev.delta.deltaY;

// 通过 transform 直接操作元素;

set($drag,dragTrans);

END

碧茂课堂精彩课程推荐:

1.Cloudera数据分析课;

2.Spark和Hadoop开发员培训;

3.大数据机器学习之推荐系统;

4.Python数据分析与机器学习实战;

详情请关注我们公众号:碧茂大数据-课程产品-碧茂课堂

现在注册互动得海量学币,大量精品课程免费送!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShuYunBIGDATA

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值