第一步拷贝以下组件cropper
cropper.js
// 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.7,
height: device.windowWidth * 0.7 / 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: ['original'], // 可以指定是原图还是压缩图,默认二者都有
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
})
},
initImg(url) {
let _this = this;
wx.getImageInfo({
src: url,
success(resopne) {
console.log(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);
cropper.json
{
"component": true,
"usingComponents": {}
}
cropper.wxml
<view class="container">
<view class="img" style="width:{{ width }}px; height:{{height}}px;" catchtouchstart="touchstartCallback" catchtouchmove="touchmoveCallback" catchtouchend="touchendCallback" >
<image style="transform: translate({{stv.offsetX}}px, {{stv.offsetY}}px) scale({{stv.scale}}) rotate({{ stv.rotate }}deg);width:{{originImg.width}}px; height: {{originImg.height}}px" src="{{ originImg.url }}"></image>
</view>
</view>
cropper.wxss
.container{
width: 100%;
display: flex;
justify-content: center;
align-items: center
}
.img {
overflow: hidden;
background: #fff;
}
第二步页面使用
js
Page({
data: {
originUrl:"cloud://normal-env-ta6pc.6e6f-normal-env-ta6pc-1300924598/meinv/00006.jpg",
ratio: 102 / 152,
},
chooseImg:function(){
var that = this
wx.chooseImage({
count: 1,
sizeType: ['original'],
sourceType: ['album', 'camera'],
success(res) {
that.setData({
originUrl: res.tempFilePaths[0],
})
}
})
}
})
json
{
"usingComponents": {
"cropper":"component/cropper/cropper"
}
}
wxml
<view class="container">
<view class="view-row" style="color:#aaa;font-size:36rpx;margin:30rpx;border-bottom:1rpx solid #aaa;padding:10rpx">custom—拖拽、缩放和旋转</view>
<view style="font-size:32rpx;color:#aaa;margin-bottom:30rpx">请拖拽、缩放或旋转下图</view>
<cropper url="{{ originUrl }}" ratio="{{ ratio }}"></cropper>
<button bindtap='chooseImg' style="margin-top:30rpx">变更图片</button>
</view>