// component/cropper/cropper.js const device = wx.getSystemInfoSync(); var twoPoint = { x1: 0, y1: 0, x2: 0, y2: 0 } Component({ /** * 组件的属性列表 */ properties: { ratio: { type: Number, observer: function (newVal, oldVal) { this.setData({ width: device.windowWidth * 0.8, height: device.windowWidth * 0.8 / newVal }) } }, url: { type: String, observer ( newVal, oldVal ) { this.initImg( newVal ) } } }, /** * 组件的初始数据 */ data: { width: device.windowWidth * 0.8, //剪裁框的宽度 height: device.windowWidth * 0.8 / (102 / 152), //剪裁框的长度 originImg: null, //存放原图信息 stv: { offsetX: 0, //剪裁图片左上角坐标x offsetY: 0, //剪裁图片左上角坐标y zoom: false, //是否缩放状态 distance: 0, //两指距离 scale: 1, //缩放倍数 rotate: 0 //旋转角度 }, }, /** * 组件的方法列表 */ methods: { uploadTap() { let _this = this wx.chooseImage({ count: 1, // 默认9 sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success(res) { _this.initImg( res.tempFilePaths[0]); } }) }, rotate() { let _this = this; _this.setData({ 'stv.rotate': _this.data.stv.rotate % 90 == 0 ? _this.data.stv.rotate = _this.data.stv.rotate + 90 : _this.data.stv.rotate = 0 }) }, back(){ this.triggerEvent("getBack", {}) }, // canvas剪裁图片 cropperImg() { let _this = this; let ctx = wx.createCanvasContext('imgcrop',this); let cropData = _this.data.stv; ctx.save(); // 缩放偏移值 let x = (_this.data.originImg.width - _this.data.originImg.width * cropData.scale) / 2; let y = (_this.data.originImg.height - _this.data.originImg.height * cropData.scale) / 2; //画布中点坐标转移到图片中心 let movex = (cropData.offsetX + x) * 2 + _this.data.originImg.width * cropData.scale; let movey = (cropData.offsetY + y) * 2 + _this.data.originImg.height * cropData.scale; ctx.translate(movex, movey); ctx.rotate(cropData.rotate * Math.PI / 180); ctx.translate(-movex, -movey); ctx.drawImage(_this.data.originImg.url, (cropData.offsetX + x) * 2, (cropData.offsetY + y) * 2, _this.data.originImg.width * 2 * cropData.scale, _this.data.originImg.height * 2 * cropData.scale); ctx.restore(); ctx.draw(false, ()=> { wx.canvasToTempFilePath({ canvasId: 'imgcrop', success(response) { _this.triggerEvent("getCropperImg", { url: response.tempFilePath, type: _this.data.originImg.type }); }, fail( e ) { wx.showToast({ title: '生成图片失败', icon: 'none' }) } }, this); }); }, initImg(url) { wx.showToast({ icon: 'loading', mask: true }); let _this = this; wx.getImageInfo({ src: url, success(resopne) { let innerAspectRadio = resopne.width / resopne.height; if (innerAspectRadio < _this.data.width / _this.data.height) { _this.setData({ originImg: { url: url, width: _this.data.width, height: _this.data.width / innerAspectRadio }, stv: { offsetX: 0, offsetY: 0 - Math.abs((_this.data.height - _this.data.width / innerAspectRadio) / 2), zoom: false, //是否缩放状态 distance: 0, //两指距离 scale: 1, //缩放倍数 rotate: 0 }, }) } else { _this.setData({ originImg: { url: url, height: _this.data.height, width: _this.data.height * innerAspectRadio }, stv: { offsetX: 0 - Math.abs((_this.data.width - _this.data.height * innerAspectRadio) / 2), offsetY: 0, zoom: false, //是否缩放状态 distance: 0, //两指距离 scale: 1, //缩放倍数 rotate: 0 } }) } } }) }, //事件处理函数 touchstartCallback: function (e) { if (e.touches.length === 1) { let { clientX, clientY } = e.touches[0]; this.startX = clientX; this.startY = clientY; this.touchStartEvent = e.touches; } else { let xMove = e.touches[1].clientX - e.touches[0].clientX; let yMove = e.touches[1].clientY - e.touches[0].clientY; let distance = Math.sqrt(xMove * xMove + yMove * yMove); twoPoint.x1 = e.touches[0].pageX * 2 twoPoint.y1 = e.touches[0].pageY * 2 twoPoint.x2 = e.touches[1].pageX * 2 twoPoint.y2 = e.touches[1].pageY * 2 this.setData({ 'stv.distance': distance, 'stv.zoom': true, //缩放状态 }) } }, //图片手势动态缩放 touchmoveCallback: function (e) { let _this = this fn(_this, e) }, touchendCallback: function (e) { //触摸结束 if (e.touches.length === 0) { this.setData({ 'stv.zoom': false, //重置缩放状态 }) } } } }) /** * fn:延时调用函数 * delay:延迟多长时间 * mustRun:至少多长时间触发一次 */ var throttle = function (fn, delay, mustRun) { var timer = null, previous = null; return function () { var now = +new Date(), context = this, args = arguments; if (!previous) previous = now; var remaining = now - previous; if (mustRun && remaining >= mustRun) { fn.apply(context, args); previous = now; } else { clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); } } } var touchMove = function (_this, e) { //触摸移动中 if (e.touches.length === 1) { //单指移动 if (_this.data.stv.zoom) { //缩放状态,不处理单指 return; } let { clientX, clientY } = e.touches[0]; let offsetX = clientX - _this.startX; let offsetY = clientY - _this.startY; _this.startX = clientX; _this.startY = clientY; let { stv } = _this.data; stv.offsetX += offsetX; stv.offsetY += offsetY; stv.offsetLeftX = -stv.offsetX; stv.offsetLeftY = -stv.offsetLeftY; _this.setData({ stv: stv }); } else if (e.touches.length === 2) { //计算旋转 let preTwoPoint = JSON.parse(JSON.stringify(twoPoint)) twoPoint.x1 = e.touches[0].pageX * 2 twoPoint.y1 = e.touches[0].pageY * 2 twoPoint.x2 = e.touches[1].pageX * 2 function vector(x1, y1, x2, y2) { this.x = x2 - x1; this.y = y2 - y1; }; //计算点乘 function calculateVM(vector1, vector2) { return (vector1.x * vector2.x + vector1.y * vector2.y) / (Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) * Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y)); } //计算叉乘 function calculateVC(vector1, vector2) { return (vector1.x * vector2.y - vector2.x * vector1.y) > 0 ? 1 : -1; } let vector1 = new vector(preTwoPoint.x1, preTwoPoint.y1, preTwoPoint.x2, preTwoPoint.y2); let vector2 = new vector(twoPoint.x1, twoPoint.y1, twoPoint.x2, twoPoint.y2); let cos = calculateVM(vector1, vector2); let angle = Math.acos(cos) * 180 / Math.PI; let direction = calculateVC(vector1, vector2); let _allDeg = direction * angle; // 双指缩放 let xMove = e.touches[1].clientX - e.touches[0].clientX; let yMove = e.touches[1].clientY - e.touches[0].clientY; let distance = Math.sqrt(xMove * xMove + yMove * yMove); let distanceDiff = distance - _this.data.stv.distance; let newScale = _this.data.stv.scale + 0.005 * distanceDiff; if (Math.abs(_allDeg) > 1) { _this.setData({ 'stv.rotate': _this.data.stv.rotate + _allDeg }) } else { //双指缩放 let xMove = e.touches[1].clientX - e.touches[0].clientX; let yMove = e.touches[1].clientY - e.touches[0].clientY; let distance = Math.sqrt(xMove * xMove + yMove * yMove); let distanceDiff = distance - _this.data.stv.distance; let newScale = _this.data.stv.scale + 0.005 * distanceDiff; if (newScale < 0.2 || newScale > 2.5) { return; } _this.setData({ 'stv.distance': distance, 'stv.scale': newScale, }) } } else { return; } } //为touchMove函数节流 const fn = throttle(touchMove, 10, 10);