| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117 | Component({    properties: {        /**              * 图片路径         */        'imgSrc': {            type: String        },        /**         * 裁剪框高度         */        'height': {            type: Number,            value: 200        },        /**         * 裁剪框宽度         */        'width': {            type: Number,            value: 200        },        /**         * 裁剪框最小尺寸         */        'min_width': {            type: Number,            value: 100        },        'min_height': {            type: Number,            value: 100        },        /**         * 裁剪框最大尺寸         */        'max_width': {            type: Number,            value: 300        },        'max_height': {            type: Number,            value: 300        },        /**         * 裁剪框禁止拖动         */        'disable_width': {            type: Boolean,            value: false        },        'disable_height': {            type: Boolean,            value: false        },        /**         * 锁定裁剪框比例         */        'disable_ratio': {            type: Boolean,            value: false        },        /**         * 生成的图片尺寸相对剪裁框的比例         */        'export_scale': {            type: Number,            value: 3        },        /**         * 生成的图片质量0-1         */        'quality': {            type: Number,            value: 1        },        'cut_top': {            type: Number,            value: null        },        'cut_left': {            type: Number,            value: null        },        /**         * canvas上边距(不设置默认不显示)         */        'canvas_top': {            type: Number,            value: null        },        /**         * canvas左边距(不设置默认不显示)         */        'canvas_left': {            type: Number,            value: null        },        /**         * 图片宽度         */        'img_width': {            type: null,            value: null        },        /**         * 图片高度         */        'img_height': {            type: null,            value: null        },        /**         * 图片缩放比         */        'scale': {            type: Number,            value: 1        },        /**         * 图片旋转角度         */        'angle': {            type: Number,            value: 0        },        /**         * 最小缩放比         */        'min_scale': {            type: Number,            value: 0.5        },        /**         * 最大缩放比         */        'max_scale': {            type: Number,            value: 2        },        /**         * 是否禁用旋转         */        'disable_rotate': {            type: Boolean,            value: false        },        /**         * 是否限制移动范围(剪裁框只能在图片内)         */        'limit_move': {            type: Boolean,            value: false        }    },    data: {        el: 'image-cropper', //暂时无用        info: wx.getSystemInfoSync(),        MOVE_THROTTLE: null, //触摸移动节流settimeout        MOVE_THROTTLE_FLAG: true, //节流标识        INIT_IMGWIDTH: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸)        INIT_IMGHEIGHT: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸)        TIME_BG: null, //背景变暗延时函数        TIME_CUT_CENTER: null,        _touch_img_relative: [{            x: 0,            y: 0        }], //鼠标和图片中心的相对位置        _flag_cut_touch: false, //是否是拖动裁剪框        _hypotenuse_length: 0, //双指触摸时斜边长度        _flag_img_endtouch: false, //是否结束触摸        _flag_bright: true, //背景是否亮        _canvas_overflow: true, //canvas缩略图是否在屏幕外面        _canvas_width: 200,        _canvas_height: 200,        origin_x: 0.5, //图片旋转中心        origin_y: 0.5, //图片旋转中心        _cut_animation: false, //是否开启图片和裁剪框过渡        _img_top: wx.getSystemInfoSync().windowHeight / 2, //图片上边距        _img_left: wx.getSystemInfoSync().windowWidth / 2, //图片左边距        watch: {            //监听截取框宽高变化            width(value, that) {                    if (value < that.data.min_width) {                        that.setData({                            width: that.data.min_width                        });                    }                    that._computeCutSize();                },                height(value, that) {                    if (value < that.data.min_height) {                        that.setData({                            height: that.data.min_height                        });                    }                    that._computeCutSize();                },                angle(value, that) {                    //停止居中裁剪框,继续修改图片位置                    that._moveStop();                    if (that.data.limit_move) {                        if (that.data.angle % 90) {                            that.setData({                                angle: Math.round(that.data.angle / 90) * 90                            });                            return;                        }                    }                },                _cut_animation(value, that) {                    //开启过渡300毫秒之后自动关闭                    clearTimeout(that.data._cut_animation_time);                    if (value) {                        that.data._cut_animation_time = setTimeout(() => {                            that.setData({                                _cut_animation: false                            });                        }, 300)                    }                },                limit_move(value, that) {                    if (value) {                        if (that.data.angle % 90) {                            that.setData({                                angle: Math.round(that.data.angle / 90) * 90                            });                        }                        that._imgMarginDetectionScale();                        !that.data._canvas_overflow && that._draw();                    }                },                canvas_top(value, that) {                    that._canvasDetectionPosition();                },                canvas_left(value, that) {                    that._canvasDetectionPosition();                },                imgSrc(value, that) {                    that.pushImg();                },                cut_top(value, that) {                    that._cutDetectionPosition();                    if (that.data.limit_move) {                        !that.data._canvas_overflow && that._draw();                    }                },                cut_left(value, that) {                    that._cutDetectionPosition();                    if (that.data.limit_move) {                        !that.data._canvas_overflow && that._draw();                    }                }        }    },    attached() {        this.data.info = wx.getSystemInfoSync();        //启用数据监听        this._watcher();        this.data.INIT_IMGWIDTH = this.data.img_width;        this.data.INIT_IMGHEIGHT = this.data.img_height;        this.setData({            _canvas_height: this.data.height,            _canvas_width: this.data.width,        });        this._initCanvas();        this.data.imgSrc && (this.data.imgSrc = this.data.imgSrc);        //根据开发者设置的图片目标尺寸计算实际尺寸        this._initImageSize();        //设置裁剪框大小>设置图片尺寸>绘制canvas        this._computeCutSize();        //检查裁剪框是否在范围内        this._cutDetectionPosition();        //检查canvas是否在范围内        this._canvasDetectionPosition();        //初始化完成        this.triggerEvent('load', {            cropper: this        });    },    methods: {        /**         * 上传图片         */        upload() {                let that = this;                wx.chooseImage({                    count: 1,                    sizeType: ['original', 'compressed'],                    sourceType: ['album', 'camera'],                    success(res) {                        const tempFilePaths = res.tempFilePaths[0];                        that.pushImg(tempFilePaths);                        wx.showLoading({                            title: '加载中...'                        })                    }                })            },            /**             * 返回图片信息             */            getImg(getCallback) {                this._draw(() => {                    wx.canvasToTempFilePath({                        width: this.data.width * this.data.export_scale,                        height: Math.round(this.data.height * this.data.export_scale),                        destWidth: this.data.width * this.data.export_scale,                        destHeight: Math.round(this.data.height) * this.data.export_scale,                        fileType: 'png',                        quality: this.data.quality,                        canvasId: this.data.el,                        success: (res) => {                            getCallback({                                url: res.tempFilePath,                                width: this.data.width * this.data.export_scale,                                height: this.data.height * this.data.export_scale                            });                        }                    }, this)                });            },            /**             * 设置图片动画             * {             *    x:10,//图片在原有基础上向下移动10px             *    y:10,//图片在原有基础上向右移动10px             *    angle:10,//图片在原有基础上旋转10deg             *    scale:0.5,//图片在原有基础上增加0.5倍             * }             */            setTransform(transform) {                if (!transform) return;                if (!this.data.disable_rotate) {                    this.setData({                        angle: transform.angle ? this.data.angle + transform.angle : this.data.angle                    });                }                var scale = this.data.scale;                if (transform.scale) {                    scale = this.data.scale + transform.scale;                    scale = scale <= this.data.min_scale ? this.data.min_scale : scale;                    scale = scale >= this.data.max_scale ? this.data.max_scale : scale;                }                this.data.scale = scale;                let cutX = this.data.cut_left;                let cutY = this.data.cut_top;                if (transform.cutX) {                    this.setData({                        cut_left: cutX + transform.cutX                    });                    this.data.watch.cut_left(null, this);                }                if (transform.cutY) {                    this.setData({                        cut_top: cutY + transform.cutY                    });                    this.data.watch.cut_top(null, this);                }                this.data._img_top = transform.y ? this.data._img_top + transform.y : this.data._img_top;                this.data._img_left = transform.x ? this.data._img_left + transform.x : this.data._img_left;                //图像边缘检测,防止截取到空白                this._imgMarginDetectionScale();                //停止居中裁剪框,继续修改图片位置                this._moveDuring();                this.setData({                    scale: this.data.scale,                    _img_top: this.data._img_top,                    _img_left: this.data._img_left                });                !this.data._canvas_overflow && this._draw();                //可以居中裁剪框了                this._moveStop(); //结束操作            },            /**             * 设置剪裁框位置             */            setCutXY(x, y) {                this.setData({                    cut_top: y,                    cut_left: x                });            },            /**             * 设置剪裁框尺寸             */            setCutSize(w, h) {                this.setData({                    width: w,                    height: h                });                this._computeCutSize();            },            /**             * 设置剪裁框和图片居中             */            setCutCenter() {                let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;                let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;                //顺序不能变                this.setData({                    _img_top: this.data._img_top - this.data.cut_top + cut_top,                    cut_top: cut_top, //截取的框上边距                    _img_left: this.data._img_left - this.data.cut_left + cut_left,                    cut_left: cut_left, //截取的框左边距                });            },            _setCutCenter() {                let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;                let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;                this.setData({                    cut_top: cut_top, //截取的框上边距                    cut_left: cut_left, //截取的框左边距                });            },            /**             * 设置剪裁框宽度-即将废弃             */            setWidth(width) {                this.setData({                    width: width                });                this._computeCutSize();            },            /**             * 设置剪裁框高度-即将废弃             */            setHeight(height) {                this.setData({                    height: height                });                this._computeCutSize();            },            /**             * 是否锁定旋转             */            setDisableRotate(value) {                this.data.disable_rotate = value;            },            /**             * 是否限制移动             */            setLimitMove(value) {                this.setData({                    _cut_animation: true,                    limit_move: !!value                });            },            /**             * 初始化图片,包括位置、大小、旋转角度             */            imgReset() {                this.setData({                    scale: 1,                    angle: 0,                    _img_top: wx.getSystemInfoSync().windowHeight / 2,                    _img_left: wx.getSystemInfoSync().windowWidth / 2,                })            },            /**             * 加载(更换)图片             */            pushImg(src) {                if (src) {                    this.setData({                        imgSrc: src                    });                    //发现是手动赋值直接返回,交给watch处理                    return;                }                // getImageInfo接口传入 src: '' 会导致内存泄漏                if (!this.data.imgSrc) return;                wx.getImageInfo({                    src: this.data.imgSrc,                    success: (res) => {                            this.data.imageObject = res;                            //图片非本地路径需要换成本地路径                            if (this.data.imgSrc.search(/tmp/) == -1) {                                this.setData({                                    imgSrc: res.path                                });                            }                            //计算最后图片尺寸                            this._imgComputeSize();                            if (this.data.limit_move) {                                //限制移动,不留空白处理                                this._imgMarginDetectionScale();                            }                            this._draw();                        },                        fail: (err) => {                            this.setData({                                imgSrc: ''                            });                        }                });            },            imageLoad(e) {                setTimeout(() => {                    this.triggerEvent('imageload', this.data.imageObject);                })            },            /**             * 设置图片放大缩小             */            setScale(scale) {                if (!scale) return;                this.setData({                    scale: scale                });                !this.data._canvas_overflow && this._draw();            },            /**             * 设置图片旋转角度             */            setAngle(angle) {                if (!angle) return;                this.setData({                    _cut_animation: true,                    angle: angle                });                this._imgMarginDetectionScale();                !this.data._canvas_overflow && this._draw();            },            _initCanvas() {                //初始化canvas                if (!this.data.ctx) {                    this.data.ctx = wx.createCanvasContext("image-cropper", this);                }            },            /**             * 根据开发者设置的图片目标尺寸计算实际尺寸             */            _initImageSize() {                //处理宽高特殊单位 %>px                if (this.data.INIT_IMGWIDTH && typeof this.data.INIT_IMGWIDTH == "string" && this.data.INIT_IMGWIDTH.indexOf("%") != -1) {                    let width = this.data.INIT_IMGWIDTH.replace("%", "");                    this.data.INIT_IMGWIDTH = this.data.img_width = this.data.info.windowWidth / 100 * width;                }                if (this.data.INIT_IMGHEIGHT && typeof this.data.INIT_IMGHEIGHT == "string" && this.data.INIT_IMGHEIGHT.indexOf("%") != -1) {                    let height = this.data.img_height.replace("%", "");                    this.data.INIT_IMGHEIGHT = this.data.img_height = this.data.info.windowHeight / 100 * height;                }            },            /**             * 检测剪裁框位置是否在允许的范围内(屏幕内)             */            _cutDetectionPosition() {                let _cutDetectionPositionTop = () => {                        //检测上边距是否在范围内                        if (this.data.cut_top < 0) {                            this.setData({                                cut_top: 0                            });                        }                        if (this.data.cut_top > this.data.info.windowHeight - this.data.height) {                            this.setData({                                cut_top: this.data.info.windowHeight - this.data.height                            });                        }                    },                    _cutDetectionPositionLeft = () => {                        //检测左边距是否在范围内                        if (this.data.cut_left < 0) {                            this.setData({                                cut_left: 0                            });                        }                        if (this.data.cut_left > this.data.info.windowWidth - this.data.width) {                            this.setData({                                cut_left: this.data.info.windowWidth - this.data.width                            });                        }                    };                //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中)                if (this.data.cut_top == null && this.data.cut_left == null) {                    this._setCutCenter();                } else if (this.data.cut_top != null && this.data.cut_left != null) {                    _cutDetectionPositionTop();                    _cutDetectionPositionLeft();                } else if (this.data.cut_top != null && this.data.cut_left == null) {                    _cutDetectionPositionTop();                    this.setData({                        cut_left: (this.data.info.windowWidth - this.data.width) / 2                    });                } else if (this.data.cut_top == null && this.data.cut_left != null) {                    _cutDetectionPositionLeft();                    this.setData({                        cut_top: (this.data.info.windowHeight - this.data.height) / 2                    });                }            },            /**             * 检测canvas位置是否在允许的范围内(屏幕内)如果在屏幕外则不开启实时渲染             * 如果只写一个参数则另一个默认为0,都不写默认超出屏幕外             */            _canvasDetectionPosition() {                if (this.data.canvas_top == null && this.data.canvas_left == null) {                    this.data._canvas_overflow = false;                    this.setData({                        canvas_top: -5000,                        canvas_left: -5000                    });                } else if (this.data.canvas_top != null && this.data.canvas_left != null) {                    if (this.data.canvas_top < -this.data.height || this.data.canvas_top > this.data.info.windowHeight) {                        this.data._canvas_overflow = true;                    } else {                        this.data._canvas_overflow = false;                    }                } else if (this.data.canvas_top != null && this.data.canvas_left == null) {                    this.setData({                        canvas_left: 0                    });                } else if (this.data.canvas_top == null && this.data.canvas_left != null) {                    this.setData({                        canvas_top: 0                    });                    if (this.data.canvas_left < -this.data.width || this.data.canvas_left > this.data.info.windowWidth) {                        this.data._canvas_overflow = true;                    } else {                        this.data._canvas_overflow = false;                    }                }            },            /**             * 图片边缘检测-位置             */            _imgMarginDetectionPosition(scale) {                if (!this.data.limit_move) return;                let left = this.data._img_left;                let top = this.data._img_top;                var scale = scale || this.data.scale;                let img_width = this.data.img_width;                let img_height = this.data.img_height;                if (this.data.angle / 90 % 2) {                    img_width = this.data.img_height;                    img_height = this.data.img_width;                }                left = this.data.cut_left + img_width * scale / 2 >= left ? left : this.data.cut_left + img_width * scale / 2;                left = this.data.cut_left + this.data.width - img_width * scale / 2 <= left ? left : this.data.cut_left + this.data.width - img_width * scale / 2;                top = this.data.cut_top + img_height * scale / 2 >= top ? top : this.data.cut_top + img_height * scale / 2;                top = this.data.cut_top + this.data.height - img_height * scale / 2 <= top ? top : this.data.cut_top + this.data.height - img_height * scale / 2;                this.setData({                    _img_left: left,                    _img_top: top,                    scale: scale                })            },            /**             * 图片边缘检测-缩放             */            _imgMarginDetectionScale() {                if (!this.data.limit_move) return;                let scale = this.data.scale;                let img_width = this.data.img_width;                let img_height = this.data.img_height;                if (this.data.angle / 90 % 2) {                    img_width = this.data.img_height;                    img_height = this.data.img_width;                }                if (img_width * scale < this.data.width) {                    scale = this.data.width / img_width;                }                if (img_height * scale < this.data.height) {                    scale = Math.max(scale, this.data.height / img_height);                }                this._imgMarginDetectionPosition(scale);            },            _setData(obj) {                let data = {};                for (var key in obj) {                    if (this.data[key] != obj[key]) {                        data[key] = obj[key];                    }                }                this.setData(data);                return data;            },            /**             * 计算图片尺寸             */            _imgComputeSize() {                let img_width = this.data.img_width,                    img_height = this.data.img_height;                if (!this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {                    //默认按图片最小边 = 对应裁剪框尺寸                    img_width = this.data.imageObject.width;                    img_height = this.data.imageObject.height;                    if (img_width / img_height > this.data.width / this.data.height) {                        img_height = this.data.height;                        img_width = this.data.imageObject.width / this.data.imageObject.height * img_height;                    } else {                        img_width = this.data.width;                        img_height = this.data.imageObject.height / this.data.imageObject.width * img_width;                    }                } else if (this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {                    img_width = this.data.imageObject.width / this.data.imageObject.height * this.data.INIT_IMGHEIGHT;                } else if (!this.data.INIT_IMGHEIGHT && this.data.INIT_IMGWIDTH) {                    img_height = this.data.imageObject.height / this.data.imageObject.width * this.data.INIT_IMGWIDTH;                }                this.setData({                    img_width: img_width,                    img_height: img_height                });            },            //改变截取框大小            _computeCutSize() {                if (this.data.width > this.data.info.windowWidth) {                    this.setData({                        width: this.data.info.windowWidth,                    });                } else if (this.data.width + this.data.cut_left > this.data.info.windowWidth) {                    this.setData({                        cut_left: this.data.info.windowWidth - this.data.cut_left,                    });                };                if (this.data.height > this.data.info.windowHeight) {                    this.setData({                        height: this.data.info.windowHeight,                    });                } else if (this.data.height + this.data.cut_top > this.data.info.windowHeight) {                    this.setData({                        cut_top: this.data.info.windowHeight - this.data.cut_top,                    });                }!this.data._canvas_overflow && this._draw();            },            //开始触摸            _start(event) {                this.data._flag_img_endtouch = false;                if (event.touches.length == 1) {                    //单指拖动                    this.data._touch_img_relative[0] = {                        x: (event.touches[0].clientX - this.data._img_left),                        y: (event.touches[0].clientY - this.data._img_top)                    }                } else {                    //双指放大                    let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX);                    let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY);                    this.data._touch_img_relative = [{                        x: (event.touches[0].clientX - this.data._img_left),                        y: (event.touches[0].clientY - this.data._img_top)                    }, {                        x: (event.touches[1].clientX - this.data._img_left),                        y: (event.touches[1].clientY - this.data._img_top)                    }];                    this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));                }!this.data._canvas_overflow && this._draw();            },            _move_throttle() {                //安卓需要节流                if (this.data.info.platform == 'android') {                    clearTimeout(this.data.MOVE_THROTTLE);                    this.data.MOVE_THROTTLE = setTimeout(() => {                        this.data.MOVE_THROTTLE_FLAG = true;                    }, 1000 / 40)                    return this.data.MOVE_THROTTLE_FLAG;                } else {                    this.data.MOVE_THROTTLE_FLAG = true;                }            },            _move(event) {                if (this.data._flag_img_endtouch || !this.data.MOVE_THROTTLE_FLAG) return;                this.data.MOVE_THROTTLE_FLAG = false;                this._move_throttle();                this._moveDuring();                if (event.touches.length == 1) {                    //单指拖动                    let left = (event.touches[0].clientX - this.data._touch_img_relative[0].x),                        top = (event.touches[0].clientY - this.data._touch_img_relative[0].y);                    //图像边缘检测,防止截取到空白                    this.data._img_left = left;                    this.data._img_top = top;                    this._imgMarginDetectionPosition();                    this.setData({                        _img_left: this.data._img_left,                        _img_top: this.data._img_top                    });                } else {                    //双指放大                    let width = (Math.abs(event.touches[0].clientX - event.touches[1].clientX)),                        height = (Math.abs(event.touches[0].clientY - event.touches[1].clientY)),                        hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),                        scale = this.data.scale * (hypotenuse / this.data._hypotenuse_length),                        current_deg = 0;                    scale = scale <= this.data.min_scale ? this.data.min_scale : scale;                    scale = scale >= this.data.max_scale ? this.data.max_scale : scale;                    //图像边缘检测,防止截取到空白                    this.data.scale = scale;                    this._imgMarginDetectionScale();                    //双指旋转(如果没禁用旋转)                    let _touch_img_relative = [{                        x: (event.touches[0].clientX - this.data._img_left),                        y: (event.touches[0].clientY - this.data._img_top)                    }, {                        x: (event.touches[1].clientX - this.data._img_left),                        y: (event.touches[1].clientY - this.data._img_top)                    }];                    if (!this.data.disable_rotate) {                        let first_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[0].y, _touch_img_relative[0].x);                        let first_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[0].y, this.data._touch_img_relative[0].x);                        let second_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[1].y, _touch_img_relative[1].x);                        let second_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[1].y, this.data._touch_img_relative[1].x);                        //当前旋转的角度                        let first_deg = first_atan - first_atan_old,                            second_deg = second_atan - second_atan_old;                        if (first_deg != 0) {                            current_deg = first_deg;                        } else if (second_deg != 0) {                            current_deg = second_deg;                        }                    }                    this.data._touch_img_relative = _touch_img_relative;                    this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));                    //更新视图                    this.setData({                        angle: this.data.angle + current_deg,                        scale: this.data.scale                    });                }!this.data._canvas_overflow && this._draw();            },            //结束操作            _end(event) {                this.data._flag_img_endtouch = true;                this._moveStop();            },            //点击中间剪裁框处理            _click(event) {                if (!this.data.imgSrc) {                    //调起上传                    this.upload();                    return;                }                this._draw(() => {                    let x = event.detail ? event.detail.x : event.touches[0].clientX;                    let y = event.detail ? event.detail.y : event.touches[0].clientY;                    if ((x >= this.data.cut_left && x <= (this.data.cut_left + this.data.width)) && (y >= this.data.cut_top && y <= (this.data.cut_top + this.data.height))) {                        //生成图片并回调                        wx.canvasToTempFilePath({                            width: this.data.width * this.data.export_scale,                            height: Math.round(this.data.height * this.data.export_scale),                            destWidth: this.data.width * this.data.export_scale,                            destHeight: Math.round(this.data.height) * this.data.export_scale,                            fileType: 'png',                            quality: this.data.quality,                            canvasId: this.data.el,                            success: (res) => {                                this.triggerEvent('tapcut', {                                    url: res.tempFilePath,                                    width: this.data.width * this.data.export_scale,                                    height: this.data.height * this.data.export_scale                                });                            }                        }, this)                    }                });            },            //渲染            _draw(callback) {                if (!this.data.imgSrc) return;                let draw = () => {                    //图片实际大小                    let img_width = this.data.img_width * this.data.scale * this.data.export_scale;                    let img_height = this.data.img_height * this.data.scale * this.data.export_scale;                    //canvas和图片的相对距离                    var xpos = this.data._img_left - this.data.cut_left;                    var ypos = this.data._img_top - this.data.cut_top;                    //旋转画布                    this.data.ctx.translate(xpos * this.data.export_scale, ypos * this.data.export_scale);                    this.data.ctx.rotate(this.data.angle * Math.PI / 180);                    this.data.ctx.drawImage(this.data.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height);                    this.data.ctx.draw(false, () => {                        callback && callback();                    });                }                if (this.data.ctx.width != this.data.width || this.data.ctx.height != this.data.height) {                    //优化拖动裁剪框,所以必须把宽高设置放在离用户触发渲染最近的地方                    this.setData({                        _canvas_height: this.data.height,                        _canvas_width: this.data.width,                    }, () => {                        //延迟40毫秒防止点击过快出现拉伸或裁剪过多                        setTimeout(() => {                            draw();                        }, 40);                    });                } else {                    draw();                }            },            //裁剪框处理            _cutTouchMove(e) {                if (this.data._flag_cut_touch && this.data.MOVE_THROTTLE_FLAG) {                    if (this.data.disable_ratio && (this.data.disable_width || this.data.disable_height)) return;                    //节流                    this.data.MOVE_THROTTLE_FLAG = false;                    this._move_throttle();                    let width = this.data.width,                        height = this.data.height,                        cut_top = this.data.cut_top,                        cut_left = this.data.cut_left,                        size_correct = () => {                            width = width <= this.data.max_width ? width >= this.data.min_width ? width : this.data.min_width : this.data.max_width;                            height = height <= this.data.max_height ? height >= this.data.min_height ? height : this.data.min_height : this.data.max_height;                        },                        size_inspect = () => {                            if ((width > this.data.max_width || width < this.data.min_width || height > this.data.max_height || height < this.data.min_height) && this.data.disable_ratio) {                                size_correct();                                return false;                            } else {                                size_correct();                                return true;                            }                        };                    height = this.data.CUT_START.height + ((this.data.CUT_START.corner > 1 && this.data.CUT_START.corner < 4 ? 1 : -1) * (this.data.CUT_START.y - e.touches[0].clientY));                    switch (this.data.CUT_START.corner) {                    case 1:                        width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;                        if (this.data.disable_ratio) {                            height = width / (this.data.width / this.data.height)                        }                        if (!size_inspect()) return;                        cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width);                        break                    case 2:                        width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;                        if (this.data.disable_ratio) {                            height = width / (this.data.width / this.data.height)                        }                        if (!size_inspect()) return;                        cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height)                        cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width)                        break                    case 3:                        width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;                        if (this.data.disable_ratio) {                            height = width / (this.data.width / this.data.height)                        }                        if (!size_inspect()) return;                        cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height);                        break                    case 4:                        width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;                        if (this.data.disable_ratio) {                            height = width / (this.data.width / this.data.height)                        }                        if (!size_inspect()) return;                        break                    }                    if (!this.data.disable_width && !this.data.disable_height) {                        this.setData({                            width: width,                            cut_left: cut_left,                            height: height,                            cut_top: cut_top,                        })                    } else if (!this.data.disable_width) {                        this.setData({                            width: width,                            cut_left: cut_left                        })                    } else if (!this.data.disable_height) {                        this.setData({                            height: height,                            cut_top: cut_top                        })                    }                    this._imgMarginDetectionScale();                }            },            _cutTouchStart(e) {                let currentX = e.touches[0].clientX;                let currentY = e.touches[0].clientY;                let cutbox_top4 = this.data.cut_top + this.data.height - 30;                let cutbox_bottom4 = this.data.cut_top + this.data.height + 20;                let cutbox_left4 = this.data.cut_left + this.data.width - 30;                let cutbox_right4 = this.data.cut_left + this.data.width + 30;                let cutbox_top3 = this.data.cut_top - 30;                let cutbox_bottom3 = this.data.cut_top + 30;                let cutbox_left3 = this.data.cut_left + this.data.width - 30;                let cutbox_right3 = this.data.cut_left + this.data.width + 30;                let cutbox_top2 = this.data.cut_top - 30;                let cutbox_bottom2 = this.data.cut_top + 30;                let cutbox_left2 = this.data.cut_left - 30;                let cutbox_right2 = this.data.cut_left + 30;                let cutbox_top1 = this.data.cut_top + this.data.height - 30;                let cutbox_bottom1 = this.data.cut_top + this.data.height + 30;                let cutbox_left1 = this.data.cut_left - 30;                let cutbox_right1 = this.data.cut_left + 30;                if (currentX > cutbox_left4 && currentX < cutbox_right4 && currentY > cutbox_top4 && currentY < cutbox_bottom4) {                    this._moveDuring();                    this.data._flag_cut_touch = true;                    this.data._flag_img_endtouch = true;                    this.data.CUT_START = {                        width: this.data.width,                        height: this.data.height,                        x: currentX,                        y: currentY,                        corner: 4                    }                } else if (currentX > cutbox_left3 && currentX < cutbox_right3 && currentY > cutbox_top3 && currentY < cutbox_bottom3) {                    this._moveDuring();                    this.data._flag_cut_touch = true;                    this.data._flag_img_endtouch = true;                    this.data.CUT_START = {                        width: this.data.width,                        height: this.data.height,                        x: currentX,                        y: currentY,                        cut_top: this.data.cut_top,                        cut_left: this.data.cut_left,                        corner: 3                    }                } else if (currentX > cutbox_left2 && currentX < cutbox_right2 && currentY > cutbox_top2 && currentY < cutbox_bottom2) {                    this._moveDuring();                    this.data._flag_cut_touch = true;                    this.data._flag_img_endtouch = true;                    this.data.CUT_START = {                        width: this.data.width,                        height: this.data.height,                        cut_top: this.data.cut_top,                        cut_left: this.data.cut_left,                        x: currentX,                        y: currentY,                        corner: 2                    }                } else if (currentX > cutbox_left1 && currentX < cutbox_right1 && currentY > cutbox_top1 && currentY < cutbox_bottom1) {                    this._moveDuring();                    this.data._flag_cut_touch = true;                    this.data._flag_img_endtouch = true;                    this.data.CUT_START = {                        width: this.data.width,                        height: this.data.height,                        cut_top: this.data.cut_top,                        cut_left: this.data.cut_left,                        x: currentX,                        y: currentY,                        corner: 1                    }                }            },            _cutTouchEnd(e) {                this._moveStop();                this.data._flag_cut_touch = false;            },            //停止移动时需要做的操作            _moveStop() {                //清空之前的自动居中延迟函数并添加最新的                clearTimeout(this.data.TIME_CUT_CENTER);                this.data.TIME_CUT_CENTER = setTimeout(() => {                        //动画启动                        if (!this.data._cut_animation) {                            this.setData({                                _cut_animation: true                            });                        }                        this.setCutCenter();                    }, 1000)                    //清空之前的背景变化延迟函数并添加最新的                clearTimeout(this.data.TIME_BG);                this.data.TIME_BG = setTimeout(() => {                    if (this.data._flag_bright) {                        this.setData({                            _flag_bright: false                        });                    }                }, 2000)            },            //移动中            _moveDuring() {                //清空之前的自动居中延迟函数                clearTimeout(this.data.TIME_CUT_CENTER);                //清空之前的背景变化延迟函数                clearTimeout(this.data.TIME_BG);                //高亮背景                if (!this.data._flag_bright) {                    this.setData({                        _flag_bright: true                    });                }            },            //监听器            _watcher() {                Object.keys(this.data).forEach(v => {                    this._observe(this.data, v, this.data.watch[v]);                })            },            _observe(obj, key, watchFun) {                var val = obj[key];                Object.defineProperty(obj, key, {                    configurable: true,                    enumerable: true,                    set: (value) => {                            val = value;                            watchFun && watchFun(val, this);                        },                        get() {                            if (val && '_img_top|img_left||width|height|min_width|max_width|min_height|max_height|export_scale|cut_top|cut_left|canvas_top|canvas_left|img_width|img_height|scale|angle|min_scale|max_scale'.indexOf(key) != -1) {                                let ret = parseFloat(parseFloat(val).toFixed(3));                                if (typeof val == "string" && val.indexOf("%") != -1) {                                    ret += '%';                                }                                return ret;                            }                            return val;                        }                })            },            _preventTouchMove() {}    }})
 |