5坑之hammer手势操作之同时缩放、旋转、移动画布canvas

在使用hammer.js开发移动终端的绘图类App时,我们需要用手指来处理画布的缩放/旋转和移动。

一般来说我们会考虑到使用 DOM 的CSS3 属性transform来操作。比如:

scale(x,y)

translate(x,y)

rotate(d)

但是编码时,会有不少坑。如:

坑1:分别处理scale/rotate等时,影响其他属性。

分别处理touch的rotatemove,pinchmove事件时,如果我们只是操作:

$(“#id”).css(“transform”,”rotate(“ + e.rotation + “deg)”);

会发现角度虽然改变了,但是缩放又变回了原值。


同样,在pinchmove中处理scale时也是如此。


开始时,想使用matrix来处理这个问题,后来涉及到较复杂的计算就放弃了(总之没达到我要的效果,也不知是计算的问题还是调用次序的问题)。

后来发现,其实可以同时操作,写法是在每个函数中增加空格。如:

$(“#id”).css(“transform”,”translate(“ + e.deltaX + “px,” + e.deltaY + “px) scale(“ + e.scale + “,” + e.scale + “) rotate(“ + e.rotation + “deg)”);


坑2:需要注意的是,不要忘了在相应的数值后加上deg和px,否则会执行错误。


坑3:手指捏放时需要将e.scale的作用减弱,否则会出现缩放很快的情况。

我使用的方法是连续开3次平方根:

var scale = Math.sqrt(Math.sqrt(Math.sqrt(e.scale)));

这样处理后感觉缩放速度感受更好了。


坑4:scale值是相对于canvas初始值的,这个不算很坑,但需要了解。


坑5:每次旋转时,需要考虑旋转开始时的角度,要根据当前的canvas角度做相应处理,否则会产生跳动。

代码如下,自己体会吧:

var initAngle = 0;

var preAngle = 0;

var tempAngleFlag = 0;

var deltaAngle = 0;

var startRotateAngle = 0;


在手势处理的switch中,略去无关代码

case "rotatestart":

//当每次rotatestart时,e.rotation不从0开始。

startRotateAngle = e.rotation.toFixed(2);

tempAngleFlag = 0;

break;

case

"rotatemove":

//转动的角度

if (cvsObj.obj != null) {

if(tempAngleFlag == 0){

preAngle = startRotateAngle;

tempAngleFlag ++;

}else{

deltaAngle = e.rotation - preAngle;

cvsObj.current.rotate = initAngle + deltaAngle; //cvsObj.current.rotate 用来记录当前canvas对象的角度

cvsObj.current.rotate = cvsObj.current.rotate % 360; //防止超出360

}

scale = "scale(" + cvsObj.scale + "," + cvsObj.scale + ")";

rotate = "rotate(" + cvsObj.current.rotate + "deg)";

translate = "translate(" + e.deltaX + "px," + e.deltaY + "px)";

style = translate + " " + scale + " " + rotate;

$("#id").css("transform",style);

}

break;

case

"rotateend":

initAngle = cvsObj.current.rotate;

break;


5坑之hammer手势操作之同时缩放、旋转、移动画布canvas


分享到:


相關文章: