city_card/vant/dist/cropper/index.js
2023-07-15 14:25:28 +08:00

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