<template name="cropper">
	<view>
		<image :src="imgSrc.imgSrc" class="my-avatar" mode="aspectFill" @click="fSelect" :style="imgStyle"></image>
		<!-- 上传图片 -->
		<canvas canvas-id="avatar-canvas" id="avatar-canvas" class="my-canvas" :style="{top: styleTop, height: cvsStyleHeight}"
		 disable-scroll="false"></canvas>
		<!-- 截取边框 -->
		<canvas canvas-id="oper-canvas" id="oper-canvas" class="oper-canvas" :style="{top: styleTop, height: cvsStyleHeight}"
		 disable-scroll="false" @touchstart="fStart" @touchmove="fMove" @touchend="fEnd"></canvas>
		<view class="oper-wrapper" :style="{display: styleDisplay}">
			<view class="btn-wrapper" v-if="showOper">
				<view @click="fClose" hover-class="hover">取消</view>
				<view @click="fUpload" hover-class="hover">选取</view>
			</view>
		</view>
	</view>
</template>

<script>
	const tabHeight = 70;
	export default {
		name: "cropper",
		data() {
			return {
				cvsStyleHeight: '0px',
				styleDisplay: 'none',
				styleTop: '-10000px',
				prvTop: '-10000px',
				imgStyle: {},
				selStyle: {},
				showOper: true,
				imgSrc: {
					imgSrc: ''
				},
				qlty: 0.9,
				postWidthFirst: {},
			};
		},
		watch: {
			avatarSrc() {
				this.imgSrc.imgSrc = this.avatarSrc;
			}
		},
		props: {
			avatarSrc: '',
			avatarStyle: '',
			selWidth: '',
			selHeight: '',
			expWidth: '',
			expHeight: '',
			minScale: '',
			maxScale: '',
			canScale: '',
			noTop: '',
			quality: '',
			index: ''
		},
		created() {
			this.ctxCanvas = uni.createCanvasContext('avatar-canvas', this);
			this.ctxCanvasOper = uni.createCanvasContext('oper-canvas', this);

			this.qlty = parseInt(this.quality) || 0.9;
			this.imgSrc.imgSrc = this.avatarSrc;
			this.letScale = this.canScale === 'false' ? 0 : 1;
			this.indx = this.index || undefined;
			this.mnScale = this.minScale || 0.3;
			this.mxScale = this.maxScale || 4;
			this.noBar = this.noTop ? false : true;
			if (!!this.noBar) {
				this.moreHeight = 0;
				this.fWindowResize();
			} else {
				uni.showTabBar({
					complete: (res) => {
						this.moreHeight = (res.errMsg === 'showTabBar:ok') ? 50 : 0;
						this.fWindowResize();
					}
				});
			}
		},
		methods: {
			fWindowResize() {
				let sysInfo = uni.getSystemInfoSync();
				this.platform = sysInfo.platform;
				this.pixelRatio = sysInfo.pixelRatio;
				this.windowWidth = sysInfo.windowWidth;
				// #ifdef H5
				this.drawTop = sysInfo.windowTop;
				this.windowHeight = sysInfo.windowHeight + sysInfo.windowBottom;
				this.cvsStyleHeight = this.windowHeight - tabHeight + 'px';
				// #endif
				// #ifdef MP-WEIXIN
				this.windowHeight = sysInfo.windowHeight;
				this.cvsStyleHeight = this.windowHeight - tabHeight + 'px';
				this.cvsStyleHeight = this.windowHeight - tabHeight + 'px'
				// #endif
				this.pxRatio = this.windowWidth / 750;

				let style = this.avatarStyle;
				this.imgStyle = style;
				this.expWidth && (this.exportWidth = this.expWidth.indexOf('rpx') >= 0 ? parseInt(this.expWidth) * this.pxRatio :
					parseInt(this.expWidth));
				this.expHeight && (this.exportHeight = this.expHeight.indexOf('rpx') >= 0 ? parseInt(this.expHeight) * this.pxRatio :
					parseInt(this.expHeight));

				if (this.styleDisplay === 'flex') {
					this.fDrawInit(true);
				}
				this.fHideImg();
			},
			fSelect() {
        let self=this;
				if (this.fSelecting) return;
				this.fSelecting = true;
				setTimeout(() => {
					this.fSelecting = false;
				}, 500);

				uni.chooseImage({
					count: 1,
					sizeType: ['original', 'compressed'],
					sourceType: ['camera', 'album'],
					success: (r) => {
						uni.showLoading({
							mask: true
						});
						let path = this.imgPath = r.tempFilePaths[0];
						uni.getImageInfo({
							src: path,
							success: r => {
								this.imgWidth = r.width;
								this.imgHeight = r.height;
								this.path = path;
								if (!this.hasSel) {
									let style = this.selStyle || {};
									if (this.selWidth && this.selHeight) {
										let selWidth = this.selWidth.indexOf('rpx') >= 0 ? parseInt(this.selWidth) * this.pxRatio :
											parseInt(this.selWidth),
											selHeight = this.selHeight.indexOf('rpx') >= 0 ? parseInt(this.selHeight) * this.pxRatio :
											parseInt(this.selHeight);
										style.width = parseInt(selWidth);
										style.height = parseInt(selHeight);
										style.top = parseInt((this.windowHeight - style.height - tabHeight) / 2);
										style.left = parseInt((this.windowWidth - style.width) / 2);
									} else {
										uni.showModal({
											title: '裁剪框的宽或高没有设置',
											showCancel: false
										})
										return;
									}
									this.selStyle = style;

								}

								if (!!self.noBar) {
									self.fDrawInit(true);
								} else {
									uni.hideTabBar({
										complete: () => {
											self.fDrawInit(true);
										}
									});
								}
							},
							fail: () => {
								uni.showToast({
									title: "error3",
									duration: 2000,
								})
							},
							complete() {
								uni.hideLoading();
							}
						});
					}
				})
			},
			fUpload() {
				let that = this;
				if (this.fUploading) return;
				this.fUploading = true;
				setTimeout(() => {
					this.fUploading = false;
				}, 1000)

				let style = this.selStyle,
					x = parseInt(style.left),
					y = parseInt(style.top),
					width = parseInt(style.width),
					height = parseInt(style.height),
					expWidth = this.exportWidth || width,
					expHeight = this.exportHeight || height;

				// #ifdef H5
				// x *= this.pixelRatio;
				// y *= this.pixelRatio;
				// expWidth = width;
				// expHeight = height;
				// #endif

				this.styleDisplay = 'none';
				this.styleTop = '-10000px';
				this.hasSel = false;
				this.fHideImg();
				uni.canvasToTempFilePath({
					x: x,
					y: y,
					width: width,
					height: height,
					destWidth: expWidth,
					destHeight: expHeight,
					canvasId: 'avatar-canvas',
					fileType: 'png',
					quality: this.qlty,
					success: (r) => {
						r = r.tempFilePath;
						let rFile = that.base64toFile(r,Math.floor((Math.random()*100000)+1)+".png");
						// #ifdef H5
						this.btop(r).then((r) => {
							if (this.exportWidth && this.exportHeight) {
								let ctxCanvas = this.ctxCanvas;
								expWidth = this.exportWidth,
									expHeight = this.exportHeight;

								ctxCanvas.drawImage(r, 0, 0, expWidth, expHeight);
								ctxCanvas.draw(false, () => {
									uni.canvasToTempFilePath({
										x: 0,
										y: 0,
										width: expWidth,
										height: expHeight,
										destWidth: expWidth,
										destHeight: expHeight,
										canvasId: 'avatar-canvas',
										fileType: 'png',
										quality: this.qlty,
										success: (r) => {
											r = r.tempFilePath;
											let rdFile = that.base64toFile(r,Math.floor((Math.random()*100000)+1)+".png");
											this.btop(r).then((r) => {
												this.$emit("upload", {
													avatar: this.imgSrc,
													path: r,
													file:rdFile,
													index: this.indx
												});
											});
										},
										fail: () => {
											uni.showToast({
												title: "error0",
												duration: 2000,
											})
										}
									});
								});
							} else {
								this.$emit("upload", {
									avatar: this.imgSrc,
									path: r,
									file:rFile,
									index: this.indx
								});
							}
						})
						// #endif
						// #ifndef H5
						this.$emit("upload", {
							avatar: this.imgSrc,
							path: r,
							file:rFile,
							index: this.indx
						});
						// #endif
					},
					fail: (res) => {
						uni.showToast({
							title: "error1",
							duration: 2000,
						})
					},
					complete: () => {
						this.noBar || uni.showTabBar();
					}
				}, this);
			},
			fDrawInit(ini = false) {
				let allWidth = this.windowWidth,
					allHeight = this.windowHeight,
					imgWidth = this.imgWidth,
					imgHeight = this.imgHeight,
					imgRadio = imgWidth / imgHeight,
					useWidth = allWidth,
					useHeight = allHeight - tabHeight,
					pixelRatio = this.pixelRatio,
					selWidth = parseInt(this.selStyle.width),
					selHeight = parseInt(this.selStyle.height);

				this.fixWidth = 0;
				this.fixHeight = 0;

				if (this.fixWidth) {
					useWidth = selWidth;
					useHeight = useWidth / imgRadio;
				} else if (this.fixHeight) {
					useHeight = selHeight;
					useWidth = useHeight * imgRadio;
				} else if (imgRadio < 1) {
					useWidth = selWidth;
					useHeight = parseInt(useWidth / imgRadio);
				} else {
					useHeight = selHeight;
					useWidth = parseInt(useHeight * imgRadio);
				}

				this.scaleSize = 1;
				this.rotateDeg = 0;
				this.posWidth = parseInt((allWidth - useWidth) / 2);
				this.posHeight = parseInt((allHeight - useHeight - tabHeight) / 2);
				this.useWidth = useWidth;
				this.useHeight = useHeight;
				let style = this.selStyle,
					left = parseInt(style.left),
					top = parseInt(style.top),
					width = parseInt(style.width),
					height = parseInt(style.height),
					canvas = this.canvas,
					canvasOper = this.canvasOper,
					ctxCanvas = this.ctxCanvas,
					ctxCanvasOper = this.ctxCanvasOper;
				ctxCanvasOper.setFillStyle('rgba(0,0,0, 0.5)');
				ctxCanvasOper.fillRect(0, 0, this.windowWidth, top);
				ctxCanvasOper.fillRect(0, top, left, height);
				ctxCanvasOper.fillRect(0, top + height, this.windowWidth, this.windowHeight - height - tabHeight - top);
				ctxCanvasOper.fillRect(left + width, top, this.windowWidth - width - left, height);
				ctxCanvasOper.setLineWidth(1);
				ctxCanvasOper.setStrokeStyle('rgba(255, 255, 255,1)'); //细线的颜色
				ctxCanvasOper.strokeRect(left, top, width, height);
       	// #ifdef H5
        ctxCanvasOper.draw();
        // #endif
				ctxCanvasOper.setLineWidth(3);
				ctxCanvasOper.setStrokeStyle('rgba(255, 255, 255, 1)'); //粗线的颜色
				ctxCanvasOper.moveTo(left + 20, top);
				ctxCanvasOper.lineTo(left, top);
				ctxCanvasOper.lineTo(left, top + 20);
				ctxCanvasOper.moveTo(left + width - 20, top);
				ctxCanvasOper.lineTo(left + width, top);
				ctxCanvasOper.lineTo(left + width, top + 20);
				ctxCanvasOper.moveTo(left + 20, top + height);
				ctxCanvasOper.lineTo(left, top + height);
				ctxCanvasOper.lineTo(left, top + height - 20);
				ctxCanvasOper.moveTo(left + width - 20, top + height);
				ctxCanvasOper.lineTo(left + width, top + height);
				ctxCanvasOper.lineTo(left + width, top + height - 20);
				ctxCanvasOper.stroke();
				this.postFirst = {
					left: left,
					top: top,
					width: width,
					height: selWidth,
					posWidth: this.posWidth,
					posHeight: this.posHeight
				};
          // #ifdef MP-WEIXIN
				ctxCanvasOper.draw(false, () => {
					if (ini) {
						this.styleDisplay = 'flex';
						this.styleTop = '0';
						ctxCanvas.setFillStyle('black');
						this.fDrawImage();
					}
				});
        // #endif
        // #ifdef H5
        ctxCanvasOper.draw(true, () => {
        	if (ini) {
        		this.styleDisplay = 'flex';
        		this.styleTop = this.drawTop + 'px';
        		ctxCanvas.setFillStyle('black');
        		this.fDrawImage();
        	}
        });

        	// #endif

				this.$emit("avtinit");
			},
			fDrawImage() {
				let tm_now = Date.now();
				if ((tm_now - this.drawTm )< 20) return;
				this.drawTm = tm_now;
				let ctxCanvas = this.ctxCanvas;
				ctxCanvas.fillRect(0, 0, this.windowWidth, this.windowHeight - tabHeight);
				//中心点坐标
				ctxCanvas.translate(this.posWidth + this.useWidth / 2, this.posHeight + this.useHeight / 2);
				//比例缩放
				ctxCanvas.scale(this.scaleSize, this.scaleSize);
				ctxCanvas.drawImage(this.imgPath, -this.useWidth / 2, -this.useHeight / 2, this.useWidth, this.useHeight);
				ctxCanvas.draw(false);
			},
			fHideImg() {
				this.prvImg = '';
				this.prvTop = '-10000px';
				this.showOper = true;
				this.prvImgData = null;
				this.target = null;
			},
			fClose() {
				this.styleDisplay = 'none';
				this.styleTop = '-10000px';
				this.hasSel = false;
				this.fHideImg();
				this.noBar || uni.showTabBar();
			},
      // #ifdef MP-WEIXIN
			fStart(e) {
				let touches = e.touches,
					touch0 = touches[0],
					touch1 = touches[1];

				this.touch0 = touch0;
				this.touch1 = touch1;

				if (touch1) {
         let x = touch1.x - touch0.x,
         	y = touch1.y - touch0.y;
         this.fgDistance = Math.sqrt(x * x + y * y);

				}
			},
      // #endif
      // #ifdef H5
      fStart(e) {
      	let touches = e.touches,
      		touch0 = touches[0],
      		touch1 = touches[1];

      	this.touch0 = touch0;
      	this.touch1 = touch1;

      	if (touch1) {
            let x = touch1.clientX - touch0.clientX,
            	y = touch1.clientY - touch0.clientY;
            this.fgDistance = Math.sqrt(x * x + y * y);
      	}
      },
      // #endif
      // #ifdef MP-WEIXIN
			fMove(e) {
				let touches = e.touches,
					touch0 = touches[0],
					touch1 = touches[1];

				if (touch1) {
					let x = touch1.x - touch0.x,
						y = touch1.y - touch0.y,
						fgDistance = Math.sqrt(x * x + y * y),
						scaleSize = 0.005 * (fgDistance - this.fgDistance),
						beScaleSize = this.scaleSize + scaleSize;

					do {
						if (!this.letScale) break;
						if (beScaleSize < this.mnScale) break;
						if (beScaleSize > this.mxScale) break;
						this.scaleSize = beScaleSize;
					} while (0);
					this.fgDistance = fgDistance;

					if (touch1.x !== touch0.x && this.letRotate) {
						x = (this.touch1.y - this.touch0.y) / (this.touch1.x - this.touch0.x);
						y = (touch1.y - touch0.y) / (touch1.x - touch0.x);
						this.rotateDeg += Math.atan((y - x) / (1 + x * y)) * 180 / Math.PI;
						this.touch0 = touch0;
						this.touch1 = touch1;
					}

					this.fDrawImage();
				} else if (this.touch0) {
					let x = touch0.x - this.touch0.x,
						y = touch0.y - this.touch0.y,
						beX = this.posWidth + x,
						beY = this.posHeight + y;
						if (Math.abs(x) < 100 && !this.lckWidth) this.posWidth = beX;
						if (Math.abs(y) < 100 && !this.lckHeight) this.posHeight = beY;
					this.touch0 = touch0;
					this.fDrawImage();
				}
			},
        // #endif
      	// #ifdef H5
        fMove(e) {
        	let touches = e.touches,
        		touch0 = touches[0],
        		touch1 = touches[1];

        	if (touch1) {
        		let x = touch1.clientX - touch0.clientX,
        			y = touch1.clientY - touch0.clientY,
        			fgDistance = Math.sqrt(x * x + y * y),
        			scaleSize = 0.005 * (fgDistance - this.fgDistance),
        			beScaleSize = this.scaleSize + scaleSize;

        		do {
        			if (!this.letScale) break;
        			if (beScaleSize < this.mnScale) break;
        			if (beScaleSize > this.mxScale) break;
        			this.scaleSize = beScaleSize;
        		} while (0);
        		this.fgDistance = fgDistance;

        		if (touch1.x !== touch0.x && this.letRotate) {
        			x = (this.touch1.clientY - this.touch0.clientY) / (this.touch1.clientX - this.touch0.clientX);
        			y = (touch1.clientY - touch0.clientY) / (touch1.clientX - touch0.clientX);
        			this.rotateDeg += Math.atan((y - x) / (1 + x * y)) * 180 / Math.PI;
        			this.touch0 = touch0;
        			this.touch1 = touch1;
        		}

        		this.fDrawImage();
        	} else if (this.touch0) {
            let x=touch0.clientX - this.touch0.clientX,
            y=touch0.clientY - this.touch0.clientY,
        		// let x = touch0.x - this.touch0.x,
        		// 	y = touch0.y - this.touch0.y,
        			beX = this.posWidth + x,
        			beY = this.posHeight + y;
        			if (Math.abs(x) < 100 && !this.lckWidth) this.posWidth = beX;
        			if (Math.abs(y) < 100 && !this.lckHeight) this.posHeight = beY;
        		this.touch0 = touch0;
        		this.fDrawImage();
        	}
        },
        	// #endif
			async fEnd(e) {
				let self = this;
				let touches = e.touches,
					touch0 = touches && touches[0],
					touch1 = touches && touches[1];
				if (self.scaleSize < 1) {
					let style = self.selStyle;
					let imgRadio = self.imgWidth / self.imgHeight;
					//高长宽短
					if (imgRadio < 1 && self.scaleSize * self.useWidth < style.width) {
						self.posWidth = style.left;
						self.scaleSize = 1
						setTimeout(function() {
							self.fDrawImage();
						}, 100)
					} else if (self.scaleSize * self.useHeight < style.width) {
						//高短宽长
						self.posHeight = style.top;
						self.scaleSize = 1
						setTimeout(function() {
							self.fDrawImage();
						}, 100)
					}
				} else if (this.scaleSize == 1) {
					let endWidth = this.posWidth - this.postFirst.posWidth,
						firstWidth = this.postFirst.left - this.postFirst.posWidth;
					let endHeight = this.posHeight - this.postFirst.posHeight,
						firstHigth = this.postFirst.top - this.postFirst.posHeight;
					if (endWidth > 0 && this.posWidth > this.postFirst.left) {
						//右滑动过长
						this.posWidth = this.postFirst.left;
					} else if (endWidth < 0 && endWidth < firstWidth) {
						//左滑动过长
						this.posWidth = -this.postFirst.left + this.postFirst.posWidth * 2;
					}

					if (endHeight < 0 && this.posHeight < this.postFirst.top) {
						//上滑动过长
						this.posHeight = -this.postFirst.top + this.postFirst.posHeight * 2 ;
					} else if (endHeight > 0 && endHeight > firstHigth) {
						//下滑动过长
						this.posHeight = this.postFirst.top;
					}
					setTimeout(function() {
						self.fDrawImage();
					}, 100);

				}
				if (touch0) {
					this.touch0 = touch0;
				} else {
					this.touch0 = null;
					this.touch1 = null;
				}
			},
			btop(base64) {
				let that = this;
				return new Promise(function(resolve, reject) {
					let b = that.base64toBlob(base64);
					let dataUrl = (window.URL || window.webkitURL).createObjectURL(b);
					return resolve(dataUrl);
				});
			},			
			base64toBlob(base64) {
			    var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1],
			        bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
			    while (n--) {
			        u8arr[n] = bstr.charCodeAt(n);
			    }
			    return new Blob([u8arr], { type: mime });
			},
			base64toFile(base64, filename) {//将base64转换为文件
				var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1],
					bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
				while(n--){
					u8arr[n] = bstr.charCodeAt(n);
				}
				return new File([u8arr], filename, {type:mime});
			}
		}
	}
</script>

<style lang="less">
	.my-canvas {
		display: flex;
		position: fixed !important;
		background: #000000;
		left: 0;
		z-index: 100;
		width: 100%;
	}

	.my-avatar {
		width: 100vw;
		height: 100vw;
	}

	.oper-canvas {
		display: flex;
		position: fixed !important;
		left: 0;
		z-index: 101;
		width: 100%;
	}

	.oper-wrapper {
		height: 71px;
		position: fixed !important;
		box-sizing: border-box;
		width: 100%;
		left: 0;
		bottom: 0;
		z-index: 200;
		flex-direction: row;
	}

	.btn-wrapper {
		background-color: #000000;
		color: #ffffff;
		display: flex;
		height: 100%;
		width: 100%;
		justify-content: space-around;
		align-items: center
	}

	.btn-wrapper view {
		width: 160rpx;
		height: 80rpx;
		line-height: 80rpx;
		text-align: center;
		font-size: 16px;
		color: #ffffff;
		z-index: 300;
	}

	.hover {
		color: #f1f1f1;
	}
</style>
