在使用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;
…
閱讀更多 午間畫道 的文章