381 lines
15 KiB
JavaScript
Executable File
381 lines
15 KiB
JavaScript
Executable File
const defaultData = {
|
|
isShowCropper:false,
|
|
// 初始化的宽高
|
|
cropperInitW: 750,
|
|
cropperInitH: 750,
|
|
// 动态的宽高
|
|
cropperW: 750,
|
|
cropperH: 750,
|
|
// 动态的left top值
|
|
cropperL: 0,
|
|
cropperT: 0,
|
|
|
|
transL: 0,
|
|
transT: 0,
|
|
|
|
// 图片缩放值
|
|
scaleP: 0,
|
|
imageW: 0,
|
|
imageH: 0,
|
|
|
|
// 裁剪框 宽高
|
|
cutL: 0,
|
|
cutT: 0,
|
|
cutB: 0,
|
|
cutR: 0,
|
|
|
|
qualityWidth: '',
|
|
innerAspectRadio: 750 / wx.getSystemInfoSync().windowWidth,
|
|
|
|
C_CONSTANTS:{
|
|
SCREEN_WIDTH : 750,
|
|
PAGE_X:0, // 手按下的x位置
|
|
PAGE_Y:0, // 手按下y的位置
|
|
PR : wx.getSystemInfoSync().pixelRatio, // dpi
|
|
T_PAGE_X:{}, // 手移动的时候x的位置
|
|
T_PAGE_Y:{}, // 手移动的时候Y的位置
|
|
CUT_L:0, // 初始化拖拽元素的left值
|
|
CUT_T:0, // 初始化拖拽元素的top值
|
|
CUT_R:0, // 初始化拖拽元素的
|
|
CUT_B:0, // 初始化拖拽元素的
|
|
CUT_W:0, // 初始化拖拽元素的宽度
|
|
CUT_H:0, // 初始化拖拽元素的高度
|
|
IMG_RATIO:0, // 图片比例
|
|
IMG_REAL_W:0, // 图片实际的宽度
|
|
IMG_REAL_H:0, // 图片实际的高度
|
|
IMG_TYPE:'',//图片的格式
|
|
DRAFG_MOVE_RATIO : 750 / wx.getSystemInfoSync().windowWidth //移动时候的比例
|
|
}
|
|
};
|
|
let data = {};
|
|
|
|
try{
|
|
data = JSON.parse(JSON.stringify(defaultData));
|
|
}catch(e){console.log(e)};
|
|
|
|
Component({
|
|
properties: {
|
|
imageSrc:{
|
|
type:String,
|
|
value:'',
|
|
observer(newVal, oldVal) {
|
|
if(newVal !== oldVal){
|
|
this.setData({
|
|
isShowCropper:true
|
|
},() => {
|
|
this.loadImage();
|
|
})
|
|
}
|
|
|
|
}
|
|
},
|
|
isCircleCrop:{
|
|
type:Boolean,
|
|
value:false
|
|
},
|
|
enableScale:{
|
|
type:Boolean,
|
|
value:false
|
|
},
|
|
ratio:{
|
|
type:Number,
|
|
value:1
|
|
}
|
|
},
|
|
data,
|
|
ready(){
|
|
if(this.data.isCircleCrop){
|
|
//圆形裁剪 强制比例为1
|
|
this.setData({
|
|
ratio:1
|
|
})
|
|
}
|
|
},
|
|
methods: {
|
|
loadImage() {
|
|
let {ratio,imageSrc} = this.data;
|
|
let {IMG_REAL_W,IMG_REAL_H,IMG_RATIO,SCREEN_WIDTH,IMG_TYPE} = this.data.C_CONSTANTS;
|
|
wx.getImageInfo({
|
|
src: imageSrc,
|
|
success: res => {
|
|
IMG_REAL_W = res.width;
|
|
IMG_REAL_H = res.height;
|
|
IMG_RATIO = IMG_REAL_W / IMG_REAL_H;
|
|
IMG_TYPE = res.type === 'png' ? 'png' : 'jpg';
|
|
// 根据图片的宽高显示不同的效果 保证图片可以正常显示
|
|
let temp = {};
|
|
let cropperData = {};
|
|
if (IMG_RATIO >= 1) {
|
|
cropperData = {
|
|
cropperW: SCREEN_WIDTH,
|
|
cropperH: SCREEN_WIDTH / IMG_RATIO,
|
|
// 初始化left right
|
|
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2),
|
|
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2)
|
|
}
|
|
if(ratio > 1){
|
|
temp = {
|
|
cutL: (SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2,
|
|
cutT: (SCREEN_WIDTH / IMG_RATIO - SCREEN_WIDTH / IMG_RATIO / ratio ) / 2,
|
|
cutR: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO) / 2 - SCREEN_WIDTH / IMG_RATIO,
|
|
cutB: SCREEN_WIDTH / IMG_RATIO - (SCREEN_WIDTH / IMG_RATIO - SCREEN_WIDTH / IMG_RATIO / ratio ) / 2 - SCREEN_WIDTH / IMG_RATIO / ratio
|
|
}
|
|
}else{
|
|
temp = {
|
|
cutT:0,
|
|
cutB:0,
|
|
cutL:(SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO * ratio) / 2,
|
|
cutR: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH / IMG_RATIO * ratio) / 2 - SCREEN_WIDTH / IMG_RATIO * ratio
|
|
}
|
|
}
|
|
} else {
|
|
cropperData = {
|
|
cropperW: SCREEN_WIDTH * IMG_RATIO,
|
|
cropperH: SCREEN_WIDTH,
|
|
// 初始化left right
|
|
cropperL: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2),
|
|
cropperT: Math.ceil((SCREEN_WIDTH - SCREEN_WIDTH) / 2)
|
|
}
|
|
if(ratio > 1){
|
|
temp = {
|
|
cutL:0,
|
|
cutR:0,
|
|
cutT: (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO / ratio) / 2,
|
|
cutB: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO / ratio) / 2 - SCREEN_WIDTH * IMG_RATIO / ratio
|
|
}
|
|
}else{
|
|
temp = {
|
|
cutL: (SCREEN_WIDTH * IMG_RATIO - SCREEN_WIDTH * IMG_RATIO * ratio) / 2,
|
|
cutR: SCREEN_WIDTH * IMG_RATIO - (SCREEN_WIDTH * IMG_RATIO - SCREEN_WIDTH * IMG_RATIO * ratio) / 2 - SCREEN_WIDTH * IMG_RATIO * ratio,
|
|
cutT: (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2,
|
|
cutB: SCREEN_WIDTH - (SCREEN_WIDTH - SCREEN_WIDTH * IMG_RATIO) / 2 - SCREEN_WIDTH * IMG_RATIO
|
|
}
|
|
|
|
}
|
|
}
|
|
this.setData({
|
|
C_CONSTANTS:Object.assign({},this.data.C_CONSTANTS,{
|
|
IMG_REAL_W,
|
|
IMG_REAL_H,
|
|
IMG_RATIO,
|
|
IMG_TYPE
|
|
}),
|
|
isShowCropper: true,
|
|
// 图片缩放值
|
|
scaleP: IMG_REAL_W / SCREEN_WIDTH,
|
|
qualityWidth: IMG_REAL_W,
|
|
innerAspectRadio: IMG_RATIO,
|
|
...temp,
|
|
...cropperData
|
|
})
|
|
}
|
|
});
|
|
|
|
},
|
|
contentStartMove(e) {
|
|
this.setData({
|
|
'C_CONSTANTS.PAGE_X':e.touches[0].pageX,
|
|
'C_CONSTANTS.PAGE_Y':e.touches[0].pageY
|
|
})
|
|
},
|
|
// 拖动时候触发的touchMove事件
|
|
contentMoveing(e) {
|
|
let {PAGE_X,PAGE_Y,DRAFG_MOVE_RATIO} = this.data.C_CONSTANTS;
|
|
let {cutL,cutR,cutT,cutB} = this.data;
|
|
let dragLengthX = (PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
|
|
let dragLengthY = (PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
|
|
// 左移
|
|
if (dragLengthX > 0) {
|
|
if (cutL - dragLengthX < 0) dragLengthX = cutL
|
|
} else {
|
|
if (cutR + dragLengthX < 0) dragLengthX = -cutR
|
|
}
|
|
|
|
if (dragLengthY > 0) {
|
|
if (cutT - dragLengthY < 0) dragLengthY = cutT
|
|
} else {
|
|
if (cutB + dragLengthY < 0) dragLengthY = -cutB
|
|
}
|
|
this.setData({
|
|
cutL: cutL - dragLengthX,
|
|
cutT: cutT - dragLengthY,
|
|
cutR: cutR + dragLengthX,
|
|
cutB: cutB + dragLengthY,
|
|
'C_CONSTANTS.PAGE_X':e.touches[0].pageX,
|
|
'C_CONSTANTS.PAGE_Y':e.touches[0].pageY
|
|
});
|
|
},
|
|
// 设置大小的时候触发的touchStart事件
|
|
dragStart(e) {
|
|
let {cutL,cutR,cutT,cutB} = this.data;
|
|
this.setData({
|
|
C_CONSTANTS:Object.assign({},this.data.C_CONSTANTS,{
|
|
T_PAGE_X : e.touches[0].pageX,
|
|
T_PAGE_Y : e.touches[0].pageY,
|
|
CUT_L : cutL,
|
|
CUT_R : cutR,
|
|
CUT_B : cutB,
|
|
CUT_T : cutT
|
|
})
|
|
})
|
|
|
|
},
|
|
// 设置大小的时候触发的touchMove事件
|
|
dragMove(e) {
|
|
let dragType = e.target.dataset.drag
|
|
let {ratio,cropperW,cropperH,cutL,cutT,cutR,cutB,enableScale} = this.data;
|
|
let {CUT_R,CUT_L,CUT_T,CUT_B,T_PAGE_X,T_PAGE_Y,DRAFG_MOVE_RATIO} = this.data.C_CONSTANTS;
|
|
let dragLength;
|
|
switch (dragType) {
|
|
case 'right':
|
|
dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
|
|
if (CUT_R + dragLength < 0) dragLength = -CUT_R
|
|
cutR = CUT_R + dragLength;
|
|
if(enableScale){
|
|
cutT = CUT_T + dragLength / ratio;
|
|
}
|
|
if(cutR < 0 || cutT < 0 || cutT > cropperH || cutR > cropperW) return;
|
|
break;
|
|
case 'left':
|
|
dragLength = (T_PAGE_X - e.touches[0].pageX) * DRAFG_MOVE_RATIO
|
|
if (CUT_L - dragLength < 0) dragLength = CUT_L
|
|
if ((CUT_L - dragLength) > (this.data.cropperW - this.data.cutR)) dragLength = CUT_L - (this.data.cropperW - this.data.cutR)
|
|
cutL = CUT_L - dragLength;
|
|
if(enableScale){
|
|
cutT = CUT_T - dragLength / ratio;
|
|
}
|
|
if(cutL < 0 || cutT < 0 || cutT > cropperH || cutL > cropperW) return;
|
|
break;
|
|
case 'top':
|
|
dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
|
|
if (CUT_T - dragLength < 0) dragLength = CUT_T
|
|
if ((CUT_T - dragLength) > (this.data.cropperH - this.data.cutB)) dragLength = CUT_T - (this.data.cropperH - this.data.cutB)
|
|
cutT = CUT_T - dragLength;
|
|
if(enableScale){
|
|
cutR = CUT_R - dragLength * ratio;
|
|
}
|
|
break;
|
|
case 'bottom':
|
|
dragLength = (T_PAGE_Y - e.touches[0].pageY) * DRAFG_MOVE_RATIO
|
|
if (CUT_B + dragLength < 0) dragLength = -CUT_B
|
|
cutB = CUT_B + dragLength;
|
|
if(enableScale){
|
|
cutR = CUT_R + dragLength * ratio;
|
|
}
|
|
if(cutR < 0 || cutT < 0 || cutT > cropperH || cutR > cropperW) return;
|
|
break;
|
|
default:'';
|
|
}
|
|
this.setData({
|
|
cutL,
|
|
cutT,
|
|
cutR,
|
|
cutB
|
|
});
|
|
},
|
|
contentTouchEnd(){},
|
|
// 获取图片
|
|
confirmCropper() {
|
|
const {isCircleCrop} = this.data;;
|
|
if(isCircleCrop){
|
|
this.circleCrop()
|
|
}else{
|
|
this.normalCropper();
|
|
}
|
|
},
|
|
|
|
normalCropper(){
|
|
let {imageSrc,cropperW,cropperH,cutL,cutT,cutR,cutB} = this.data;
|
|
let {IMG_REAL_W,IMG_REAL_H,IMG_TYPE} = this.data.C_CONSTANTS;
|
|
// 将图片写入画布
|
|
const ctx = wx.createCanvasContext('cropper',this)
|
|
ctx.drawImage(imageSrc, 0, 0, IMG_REAL_W, IMG_REAL_H);
|
|
ctx.draw(true, () => {
|
|
// 获取画布要裁剪的位置和宽度 均为百分比 * 画布中图片的宽度 保证了在微信小程序中裁剪的图片模糊 位置不对的问题 canvasT = (_this.data.cutT / _this.data.cropperH) * (_this.data.imageH / pixelRatio)
|
|
let canvasW = ((cropperW - cutL - cutR) / cropperW) * IMG_REAL_W
|
|
let canvasH = ((cropperH - cutT - cutB) / cropperH) * IMG_REAL_H
|
|
let canvasL = (cutL / cropperW) * IMG_REAL_W
|
|
let canvasT = (cutT / cropperH) * IMG_REAL_H
|
|
wx.canvasToTempFilePath({
|
|
x: canvasL,
|
|
y: canvasT,
|
|
width: canvasW,
|
|
height: canvasH,
|
|
destWidth: canvasW,
|
|
destHeight: canvasH,
|
|
fileType:IMG_TYPE || 'jpg',
|
|
canvasId: 'cropper',
|
|
success: (res) => {
|
|
//图片裁剪成功
|
|
this.cancelCropper();
|
|
this.triggerEvent('cropperDone', {
|
|
src:res.tempFilePath,
|
|
cropperData:{
|
|
x: canvasL,
|
|
y: canvasT,
|
|
width: canvasW,
|
|
height: canvasH
|
|
}
|
|
})
|
|
},
|
|
fail:err =>{
|
|
this.triggerEvent('cropperFail',err)
|
|
}
|
|
},this);
|
|
})
|
|
},
|
|
|
|
circleCrop(){
|
|
let {imageSrc,cropperW,cropperH,cutL,cutT,cutR,cutB} = this.data;
|
|
let {IMG_REAL_W,IMG_REAL_H,IMG_TYPE} = this.data.C_CONSTANTS;
|
|
// 将图片写入画布
|
|
const ctx = wx.createCanvasContext('cropper',this)
|
|
let canvasW = ((cropperW - cutL - cutR) / cropperW) * IMG_REAL_W
|
|
let canvasL = (cutL / cropperW) * IMG_REAL_W
|
|
let canvasT = (cutT / cropperH) * IMG_REAL_H
|
|
|
|
this.setData({
|
|
canvasW:canvasW,
|
|
canvasH:canvasW
|
|
},() => {
|
|
ctx.arc(canvasW / 2,canvasW / 2,canvasW / 2,0,2 * Math.PI);
|
|
ctx.clip();
|
|
ctx.drawImage(imageSrc, canvasL, canvasT, canvasW, canvasW,0,0,canvasW,canvasW);
|
|
ctx.draw(true, () => {
|
|
wx.canvasToTempFilePath({
|
|
fileType:IMG_TYPE || 'jpg',
|
|
canvasId: 'cropper',
|
|
success: (res) => {
|
|
//图片裁剪成功
|
|
this.cancelCropper();
|
|
this.triggerEvent('cropperDone', {
|
|
src:res.tempFilePath,
|
|
cropperData:{
|
|
x: canvasL,
|
|
y: canvasT,
|
|
width: canvasW,
|
|
height: canvasW
|
|
}
|
|
})
|
|
},
|
|
fail:err =>{
|
|
this.triggerEvent('cropperFail',err)
|
|
}
|
|
},this);
|
|
})
|
|
})
|
|
},
|
|
|
|
cancelCropper(){
|
|
let originData = {}
|
|
try{
|
|
originData = JSON.parse(JSON.stringify(defaultData))
|
|
}catch(e){};
|
|
|
|
this.setData({
|
|
...originData
|
|
});
|
|
this.triggerEvent('cropperCancel')
|
|
}
|
|
}
|
|
}) |