zoukankan      html  css  js  c++  java
  • 前端手势控制图片插件书写一(手势识别的数学原理)

    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)
            })

  • 相关阅读:
    运算符、流程控制
    python数据类型
    Python入门基础
    pandas教程1:pandas数据结构入门
    使用matplotlib绘制多轴图
    使用matplotlib快速绘图
    浙江省新高中信息技术教材,将围绕Python进行并增加编程相关知识点
    [转]ubuntu搭建LAMP环境
    [转]字体精简
    [转]安装PIL时注册表中找不到python2.7
  • 原文地址:https://www.cnblogs.com/qdcnbj/p/11229535.html
Copyright © 2011-2022 走看看