使用hammer.js实现图片手势缩放及算法解释

关于图片缩放,大家可能会想到的是使用transform:scale(x,y)进行对元素的缩放。
但是对于手势缩放的过程中,我们需要在进行缩放的同时,并且要保证双指之间的中心点一直保持在原来的位置,这是我们需要配合使用translate(x,y)来进行位置的调整。但如何计算得到translate(x,y)中的值呢?

其实除去translate,scale的 transform 属性外,我们还可以通过 矩阵matrix(a,b,c,d,e,f) 进行2D转换。具体可以参考张鑫旭老师的博客理解 CSS3 transform中的Matrix(矩阵)。

根据老师的博客,可以知道matrix(a,b,c,d,e,f) 中的参数a、d分别代表水平方向(x)和垂直方向(y)的放大倍数 相当于scale(a,d) ,e、f分别表示水平方向(x)和垂直方向(y)的偏移值 相当于translate(e,f) ,b、c本篇没有用到,不作解释。

元素中的某个点 (x,y) 通过matrix(a,b,c,d,e,f)转换后,新的坐标为 (ax+cy+e, bx+dy+f)

值得注意的是,元素的变换会根据某个原点来进行变换,而这个原点可以根据transform-origin来设置,默认是元素的正中心,即元素的X轴和Y轴的50%。

为了方便计算,我们把元素铺满整个屏幕。

元素的变换过程:
第一次变换:
1、初始化矩阵matrix(1,0,0,1,0,0),分别对应matrix(a,b,c,d,e,f)
2、获取元素中心的 center(x,y)
3、获取双指的中心point(x,y)
4、双指滑动,然后获取缩放倍数scale(这个scale是双指当前在屏幕坐标之间的距离d1与第一次触碰屏幕时的距离d2的比,即d1/d2,这个hammer.js已经帮你算好了)
5、缩放后,原来双指的中心点会偏移,新坐标与原点在x轴上的距离是(point.x-center.x) * scale,同理新坐标与原点在y轴上距离为(point.y-center.y)*scale,由于原点在屏幕上的坐标并不是(0,0),所以新的坐标必须加上原点的偏移值,新的坐标newpoint(x,y):

newpoint.x = scale * (point.x-center.x) + 0 * (point.y-center.y) + 0 + center.x  
           = scale * point.x - scale * center.x + center.x
           = scale * point.x - (scale - 1) * center.x
newpoint.y = 0 * (point.x-center.x) + scale * (point.y-center.y) + 0 +  center.y
           = scale * point.y - scale * center.y + center.y
           = scale * point.y - (scale - 1) * center.y

6、缩放后,如果想要新的坐标回到最初的位置,需要计算偏移值,point(x,y) - newpoint(x,y),通过以下计算可以知道缩放后,如果想要新的坐标回到起初的位置,需要水平偏移(1 - 缩放倍数)* 起初位置与原点的水平距离 同理,垂直方向偏移(1 - 缩放倍数)* 起初位置与原点的垂直距离

point.x - newpoint.x = point.x - [scale * point.x - (scale - 1) * center.x]
                     = point.x - scale * point.x + (scale - 1) * center.x
                     = (1 - scale) * point.x + (scale - 1) * center.x
                     = (1 - scale) * (point.x - center.x)
同理
point.y - newpoint.y = (1 - scale) * (point.y - center.y)

7、通过矩阵变换

matrix( scale, 0, 0, scale,  (1 - scale) * (point.x - center.x),  (1 - scale) * (point.y - center.y) )
其中  
     a = d = scale,
     e = (1 - scale) * (point.x - center.x) ,
     f = (1 - scale) * (point.y - center.y)
     

配上图,自己意会。
使用hammer.js实现图片手势缩放及算法解释_第1张图片
第一次变换比较简单,第二次之后就要考虑前边的缩放,还有偏移值了。
第二次之后的变换,要注意三点:
1、实际的缩放倍数是:当前操作的倍数乘以上一次操作后的倍数。
2、作为变换依据的原点也偏移了,偏移值为上一次操作后的偏移值。
3、新的偏移值:当前操作后的偏移值要加上上一次操作后的偏移值。
4、在触摸屏幕(touchstart)一瞬间记录一些初始值:lastScale(上一轮操作缩放倍数),nowCenter(新的变换依据点坐标),poscenter(当前触摸中心点与新的依据点的水平和垂直距离)。
5、缩放过程中,当前的实际倍数是当前倍数操作倍数(双指当前在屏幕坐标之间的距离d1与第一次触碰屏幕时的距离d2的比 scale) 乘以 上一轮操作缩放倍数(lastScale)。
6、需要偏移的值:(1 - 当前操作倍数) * 新的触摸中心点与新的中心原点的距离 + 上一轮的偏移值。

第二次之后变换:

我们把matrix看成一个数组
tMatrix = [a, b, c, d, e, f]

lastScale = tMatrix[0]  //上一次的缩放倍数
lastTranslate = { x : tMatrix[4], y : tMartix[5] } //上一次的偏移值
nowCenter = { x : center.x +lastTranslate.x ,  y : center.y + lastTranslate.y } //重新计算后当前操作的依据点
nowScale = lastScale * scale //当前实际倍数为上次的倍数乘以当前操作的倍数(如果表达不清楚请见谅)

poscenter = { x : ev.center.x - nowCenter .x,  y :  ev.center.y - nowCenter .y} //触摸中心点到新的依据点的水平和垂直距离

newX = (1 - scale) * poscenter.x + lastTranslate.x //新的水平偏移值
newY = (1 - scale) * poscenter.y + lastTranslate.y //新的垂直偏移值

最后tMatrix的值
tMatrix = [nowScale, 0, 0, nowScale, newX, newY ]

总结

最后的公式为:

tMatrix = [a, b, c, d, e, f]

nowScale表示当前缩放倍数
lastScale表示上一次缩放操作的次数(初次操作时1)
lastTranslate表示上一次元素的偏移值,初次是(0,0)
p表示当前单指触摸的坐标或者双指触摸点之间的中心坐标
c表示初始时图像或内容框的中心坐标

a = b = nowScale * lastScale
e = ( 1 - nowScale ) * (p.x - ( c.x + lastTranslate.x ) + lastTranslate.x
f = ( 1 - nowScale ) * (p.y - ( c.x + lastTranslate.y ) + lastTranslate.y
Matrix = [a, b, 0, 0, e, f],通过矩阵变换


缩放操作完成后
lastTranslate.x = e
lastTranslate.y = f
lastScale = a

代码如下,源码放在:




	图片缩放
	
	
	
	 


你可能感兴趣的:(前端)