前端手势控制图片插件书写一(手势识别的数学原理)

1、前端图片处理需求场景
   前端图片处理应用在很多方面,在做业务过程中我也遇到了以下问题用到前端图片处理插件。
     头像上传
     背景图片上传
     信用卡的Diy卡面上传
     H5贴纸及合成
2、手势控制的数学知识
如果想要做图片旋转放大和拖动操作,一定会涉及到移动端的手势识别和手势操作。
在移动端控制图片操作中涉及到以下几个手势:单指拖动,单指缩放,单指旋转,双指缩放,双指旋转这五种手势 。
下面来介绍下如果使用向量来识别手势。
下图是单指在图片上旋转缩放时的示意图。只需要算出bs向量和bs'向量的夹角和他们的模的比例即可,与双指不同的是,单指手势需要一个中心点的坐标作为base点,这样才能构造出一个向量。
下图是双指在图片上旋转缩放时的示意图。与单指同理。
所以我们需要使用式子来表示出向量的角度和模。
e.touches可以获取到touch事件的手指数量及手指坐标。
a、从touches对象中获取点。 
   Gesture. getPoint();
eg:getPoint(event,index){
return {
x: Math.round(event.touches[index].pageX),
y: Math.round(event.touches[index].pageY),
}
}

 

 
b、从点得到向量。
    Gesture. getVector()
eg:getVector(p1,p2){
let x = Math.round(p1.x - p2.x);
let y = Math.round(p1.y - p2.y);
return { x ,y };
}

 

c、计算向量的模。
   Gesture. getVectorLength()
eg: getVectorLength(vct){
return Math.sqrt(vct.x * vct.x + vct.y * vct.y)
}

 

d、计算两个向量的夹角(向量的数量积)。
        Gesture. getVectorAngle();
eg: getVectorAngle(vct1, vct2){
//首先判断方向
let direction = vct1.x*vct2.y - vct2.x*vct1.y>0?1:-1;
// console.log('direction',direction)
let len1 = this.getVectorLength(vct1);
let len2 = this.getVectorLength(vct2);
let mr = len1*len2;
let dot;
let r;
if(mr === 0) return 0;
 
dot = vct1.x*vct2.x + vct1.y*vct2.y;
r = dot/mr;
console.log(r)
if(r>1){
r =1;
}
if(r<-1){
r=-1;
}
let angle = Math.acos(r)*direction*180/Math.PI;
return angle;
}

 

3、如何表示双指旋转(示例)
首先在touchstart事件开始时,获取到开始触摸时的双指坐标,计算出初始向量和向量的模
startPoint = gesture.getPoint(e, 0);
secondPoint = gesture.getPoint(e, 1);
vector1 = gesture.getVector(secondPoint, startPoint);
// console.error(vector1)
pinchStartLength = gesture.getVectorLength(vector1);

 

然后同理,在touchmove事件触发时计算出目前向量的坐标及向量的模。通过刚刚的公式来计算出两个向量的夹角。
 
最后在touchend结束的时候,双指会出现两个手指如果不同时离开屏幕的现象。这时要在touchstart事件中判断初始手指数量,
如果在touchmove的同时,手指数量突然小于初始数量时,及时return ,避免执行单指move的代码。

 绑定手指事件的实例代码:

let that = this;
target.addEventListener('touchstart', (e) => {
            e.stopPropagation()
            e.preventDefault()
            console.warn('start', e.touches)
            console.warn('target', e.currentTarget)
            this.fingers = e.touches.length;
            if (e.touches.length == 1) {
                this.startPoint = this.gesture.getPoint(e, 0);
                // console.log('startPoint', startPoint)
                //获取图片的初始位置。
                that.getPreTransformMatrix(target)
            }
            else if (e.touches.length == 2) {
                this.startPoint = this.gesture.getPoint(e, 0);
                this.secondPoint = this.gesture.getPoint(e, 1);
                // console.log('startPoint', startPoint)
                // console.log('secondPoint', secondPoint)
                this.vector1 = this.gesture.getVector(this.secondPoint, this.startPoint);
                // console.error(vector1)
                this.pinchStartLength = this.gesture.getVectorLength(this.vector1);
                // console.log(pinchStartLength)
                that.getPreTransformMatrix(target)
            }

        })
        target.addEventListener('touchmove', (e) => {
            let curFingers = e.touches.length;
            // alert(e.touches.length)
            if (curFingers < this.fingers) {
                // alert(fingers)
                return;
            }
            // console.warn('move', e)
            if (e.touches.length == 1) {
                this.currentPoint = this.gesture.getPoint(e, 0);
                let detla;

                detla = {
                    deltaX: this.currentPoint.x - this.startPoint.x,
                    deltaY: this.currentPoint.y - this.startPoint.y,
                }



                this.set(target, {
                    x: detla.deltaX,
                    y: detla.deltaY,
                    scale: 1,
                    rotate: 0,
                })

                // this.set($('#div_bg_img'), this.limit('', $('body'), dragTrans))
            }
            else if (e.touches.length == 2) {
                // touchmove中计算实时的双指向量模;
                let curPoint = this.gesture.getPoint(e, 0);
                let curSecPoint = this.gesture.getPoint(e, 1);

                let vector2 = this.gesture.getVector(curSecPoint, curPoint);
                let pinchLength = this.gesture.getVectorLength(vector2);
                let angle = this.gesture.getVectorAngle(this.vector1, vector2)
                // console.log('pinch', { scale: pinchLength / pinchStartLength })
                // console.log('Rotate', angle)
                // console.log('vector1', vector1)
                // console.log('vector2', vector2)

                this.set(target, {
                    x: 0,
                    y: 0,
                    scale: pinchLength / this.pinchStartLength,
                    rotate: angle,
                })
                // this.set($('#div_bg_img'), this.limit('', $('body'), dragTrans))
            }
        })
        target.addEventListener('touchend', (e) => {
            // console.log('dragTransEND', dragTrans)
            console.log('dragTransEND', e.touches.length)
            console.log(target.firstElementChild)
            let orientation = that.getPhotoOrientation(target.firstElementChild);
            that.drawImagePic(orientation)
        })

 

posted @ 2019-07-23 08:17  前端++  阅读(719)  评论(0编辑  收藏  举报